Transpilers/Keywords/Assert.psx.ps1
<# .SYNOPSIS Assert keyword .DESCRIPTION Assert is a common keyword in many programming languages. In PipeScript, Asset will take a condition and an optional action. The condtion may be contained in either parenthesis or a [ScriptBlock]. If there is no action, the assertion will throw an exception containing the condition. If the action is a string, the assertion will throw that error as a string. If the action is a ScriptBlock, it will be run if the assertion is false. Assertions will not be transpiled or included if -Verbose or -Debug has not been set. Additionally, while running, Assertions will be ignored if -Verbose or -Debug has not been set. .EXAMPLE # With no second argument, assert will throw an error with the condition of the assertion. Invoke-PipeScript { assert (1 -eq 1) } -Debug .EXAMPLE # With a second argument of a string, assert will throw an error Invoke-PipeScript { assert ($true) "It's true" } -Debug .EXAMPLE # Conditions can also be written as a ScriptBlock Invoke-PipeScript { assert {$true} "Process id '$pid' Asserted" } -Verbose .EXAMPLE # If the assertion action was a ScriptBlock, no exception is automatically thrown Invoke-PipeScript { assert ($true) { Write-Information "Assertion was true"} } -Verbose #> [ValidateScript({ # This transpiler should run if the command is literally 'assert' $commandAst = $_ return ($commandAst -and $CommandAst.CommandElements[0].Value -eq 'assert') })] param( # The CommandAst [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='CommandAst')] [Management.Automation.Language.CommandAst] $CommandAst ) process { $CommandName, $CommandArgs = $commandAst.CommandElements $firstArg, $secondArg = $CommandArgs # If the first arg can be a condition in simple or complex form if (-not $firstArg -or $firstArg.GetType().Name -notin 'ParenExpressionAst', 'ScriptBlockExpressionAst', 'VariableExpressionAst', 'MemberExpressionAst', 'StringConstantExpressionAst', 'ExpandableStringExpressionAst') { # If it was the wrong type, let them know. Write-Error "Assert must be followed by one of the following expressions: * Variable * Member * String * Parenthesis * ScriptBlock " return } # If there was a second argument, it must be a string or ScriptBlock. if ($secondArg -and $secondArg.GetType().Name -notin 'ScriptBlockExpressionAst', 'StringConstantExpressionAst', 'ExpandableStringExpressionAst') { Write-Error "Assert must be followed by a ScriptBlock or string" return } # We need to create a [ScriptBlock] for the condition so we can transpile it. $firstArgTypeName = $firstArg.GetType().Name # The condition will always check for -DebugPreference or -VerbosePreference. $checkDebugPreference = '($debugPreference,$verbosePreference -ne ''silentlyContinue'')' $condition = [ScriptBlock]::Create("($checkDebugPreference -and $( # If the condition is already in parenthesis, if ($firstArgTypeName -eq 'ParenExpressionAst') { "$FirstArg" # leave it alone. } # If the condition is a ScriptBlockExpression, elseif ($firstArgTypeName -eq 'ScriptBlockExpressionAst') { # put it in parenthesis. "($($FirstArg -replace '^\{' -replace '\}$'))" } # Otherwise else { "($FirstArg)" # embed the condition in parenthesis. } ))") # Transpile the condition. $condition = $condition | .>Pipescript # Now we create the entire assertion script $newScript = # If there was no second argument if (-not $secondArg) { # Rethrow the condition "if $condition { throw '{$($firstArg -replace "'", "''")}' } " } elseif ($secondArg.GetType().Name -eq 'ScriptBlockExpressionAst') { # If the second argument was a script, transpile and embed it. "if $condition {$([ScriptBlock]::Create( ($secondArg -replace '^\{' -replace '\}$') ) | .>Pipescript)}" } else { # Otherwise, throw the second argument. "if $condition { throw $secondArg } " } if ($DebugPreference, $VerbosePreference -ne 'silentlyContinue') { [scriptblock]::Create($newScript) } else { {} } } |