Transpilers/Syntax/ConditionalKeyword.psx.ps1

using namespace System.Management.Automation.Language

<#
.SYNOPSIS
    Conditional Keyword Expansion
.DESCRIPTION
    Allows for conditional Keywords.

    A coniditional keyword is a continue or break statement, followed by a partial if clause.
.EXAMPLE
    Invoke-PipeScript {
        $n = 1
        do {
            $n = $n * 2
            $n
            break if (-not ($n % 16))
        } while ($true)
    }
.EXAMPLE
    Import-PipeScript {
        
        function Get-Primes([ValidateRange(2,64kb)][int]$UpTo) {
            $KnownPrimes = new Collections.ArrayList @(2)
            $SieveOfEratosthenes = new Collections.Generic.Dictionary[uint32,bool]
            $n = 2
            :nextNumber for (; $n++;) {
                # Break if past our point of interest
                break if ($n -ge $upTo)
                # Skip if an even number
                continue if (-not ($n -band 1))
                # Check our sieve
                continue if $SieveOfEratosthenes.ContainsKey($n)
                # Determine half of the number
                $halfN = $n /2
                # If this is divisible by the known primes
                foreach ($k in $knownPrimes) {
                    continue nextNumber if (($n % $k) -eq 0) {}
                    break if ($k -ge $halfN)
                }
                foreach ($k in $knownPrimes) {
                    $SieveOfEratosthenes[$n * $k] = $true
                }
                $null = $knownPrimes.Add($n)
            }
            $knownPrimes -le $UpTo
        }
    }
#>

[ValidateScript({
    $ast = $_
    if ($ast -isnot [ContinueStatementAst] -and 
        $ast -isnot [BreakStatementAst] -and
        $ast -isnot [ReturnStatementAst] -and
        $ast -isnot [ThrowStatementAst]
    ) {
        return $false
    }
    if (-not $ast.Pipeline) {
        $nextStatement = $ast.Parent.Statements[$ast.Parent.Statements.IndexOf($ast) + 1]
        if (-not $nextStatement) { 
            return $false
        }
    

        if ('if' -ne $ast.Label) {
            if ($nextStatement -is [IfStatementAst]) {
                return $true
            }
            return $false
        }

        return $true
    }
    else {
        return $ast.Pipeline -match '^if'
    }    
})]
param(
# A Continue Statement.
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='ContinueStatement')]
[ContinueStatementAst]
$ContinueStatement,

# A Break Statement.
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='BreakStatement')]
[BreakStatementAst]
$BreakStatement,

# A Return Statement.
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='ReturnStatement')]
[ReturnStatementAst]
$ReturnStatement,

# A Throw Statement.
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='ThrowStatement')]
[ThrowStatementAst]
$ThrowStatement
)

process {
    
    $statement = $($PSBoundParameters[$PSBoundParameters.Keys -like '*Statement'])
    if (-not $statement) { return }
    $statementType = ($statement.GetType().Name -replace 'StatementAst').ToLower()
    $PipelineClauses = @()
    $nextStatement = 
        if ($statement.Pipeline) {
            $firstElement = $statement.Pipeline.PipelineElements[0]
            $commandElements = $firstElement.CommandElements[1..($firstElement.CommandElements.Count)]
            foreach ($CommandElement in $commandElements) {
                if ($commandElement -is [ScriptBlockExpressionAst]) {
                    $PipelineClauses += $CommandElement.ScriptBlock.GetScriptBlock()
                } else {
                    $CommandElement
                }
            }
        } else {
            $statement.Parent.Statements[$statement.Parent.Statements.IndexOf($statement) + 1]
        }
        
    
    $(if ($nextStatement -is [IfStatementAst]) {
        [ScriptBlock]::Create("if ($($nextStatement.Clauses[0].Item1)) {
            $(
                $ReplacedClause = $nextStatement.Clauses[0].Item2 -replace '^\s{0,}\{\s{0,}' -replace '\s{0,}\}\s{0,}$'
                if ($ReplacedClause) {
                    $ReplacedClause + ';' + "$statementType $($statement.Label)"
                } else {
                    "$statementType $($statement.Label)"
                }
            )
        }"
)
    } 
    elseif ($PipelineClauses) {        
        [ScriptBlock]::Create("if ($nextStatement) { $statementType $pipelineClauses}")
    }
    else {
        [ScriptBlock]::Create("if ($nextStatement) { $statementType }")
    })
        | Add-Member NoteProperty SkipUntil $nextStatement -PassThru    
}