Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 0.0.12:
* Adding assert keyword (#143)
* Fixing new keyword for blank constructors (#142 )
* Rest Transpiler:
* Handling multiple QueryString values (#139)
* Only passing ContentType to invoker if invoker supports it (#141)
* Defaulting to JSON body when ContentType is unspecified (#140)
---

## 0.0.11:
* Source Generators Now Support Parameters / Arguments (#75)
* Invoke-PipeScript Terminating Build Errors (#135)
Expand Down
25 changes: 18 additions & 7 deletions PipeScript.psd1
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
@{
ModuleVersion = '0.0.11'
ModuleVersion = '0.0.12'
Description = 'An Extensible Transpiler for PowerShell (and anything else)'
RootModule = 'PipeScript.psm1'
PowerShellVersion = '4.0'
AliasesToExport = '*'
FormatsToProcess = 'PipeScript.format.ps1xml'
TypesToProcess = 'PipeScript.types.ps1xml'
Guid = 'fc054786-b1ce-4ed8-a90f-7cc9c27edb06'
CompanyName='Start-Automating'
Copyright='2022 Start-Automating'
Author='James Brundage'
Guid = 'fc054786-b1ce-4ed8-a90f-7cc9c27edb06'
CompanyName = 'Start-Automating'
Copyright = '2022 Start-Automating'
Author = 'James Brundage'
PrivateData = @{
PSData = @{
ProjectURI = 'https://github.com/StartAutomating/PipeScript'
LicenseURI = 'https://github.com/StartAutomating/PipeScript/blob/main/LICENSE'

Tags = 'PipeScript','PowerShell', 'Transpilation', 'Compiler'
RecommendModule = @('PSMinifier')
RelatedModule = @()
BuildModule = @('EZOut','Piecemeal','PipeScript','HelpOut', 'PSDevOps')
Tags = 'PipeScript','PowerShell', 'Transpilation', 'Compiler'
ReleaseNotes = @'
## 0.0.12:
* Adding assert keyword (#143)
* Fixing new keyword for blank constructors (#142 )
* Rest Transpiler:
* Handling multiple QueryString values (#139)
* Only passing ContentType to invoker if invoker supports it (#141)
* Defaulting to JSON body when ContentType is unspecified (#140)
---

## 0.0.11:
* Source Generators Now Support Parameters / Arguments (#75)
* Invoke-PipeScript Terminating Build Errors (#135)
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@

# What Is PipeScript?

> PipeScript is a transpiled scripting language built atop of PowerShell.
PipeScript is a scripting language built atop PowerShell.

> PipeScript can be run interactively

> PipeScript can embedded within many languages to dynamically generate source code
PipeScript is transpiled into PowerShell.


PipeScript can be run interactively, or used to build more PowerShell with less code.


PipeScript can also be embedded in many other languages to dynamically generate source code.

## What's a Transpiler?

Expand Down
133 changes: 133 additions & 0 deletions Transpilers/Keywords/Assert.psx.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<#
.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 {
{}
}
}
10 changes: 9 additions & 1 deletion Transpilers/Keywords/New.psx.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
.> { new byte 1 }
.EXAMPLE
.> { new int[] 5 }
.EXAMPLE
.> { new Timespan }
.EXAMPLE
.> { new datetime 12/31/1999 }
.EXAMPLE
Expand Down Expand Up @@ -97,7 +99,13 @@ process {
$constructorArguments[0] -is [string]) {
"[$newTypeName]::parse(" + ($constructorArguments -join ',') + ")"
} elseif ($realNewType::new) {
"[$newTypeName]::new(" + ($constructorArguments -join ',') + ")"
if ($constructorArguments) {
"[$newTypeName]::new(" + ($constructorArguments -join ',') + ")"
} elseif ($realNewType::new.overloadDefinitions -notmatch '\(\)$') {
"[$newTypeName]::new(`$null)"
} else {
"[$newTypeName]::new()"
}
} elseif ($realNewType.IsPrimitive) {
if ($constructorArguments) {
if ($constructorArguments.Length -eq 1) {
Expand Down
58 changes: 53 additions & 5 deletions Transpilers/Keywords/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,54 @@ This directory and it's subdirectories contain additional language keywords with
Most keywords will be implemented as a Transpiler that tranforms a CommandAST.


|DisplayName |Synopsis |
|------------------|----------------------------|
|[New](New.psx.ps1)|['new' keyword](New.psx.ps1)|
|DisplayName |Synopsis |
|------------------------|--------------------------------|
|[Assert](Assert.psx.ps1)|[Assert keyword](Assert.psx.ps1)|
|[New](New.psx.ps1) |['new' keyword](New.psx.ps1) |




## Assert Example 1


~~~PowerShell
# With no second argument, assert will throw an error with the condition of the assertion.
Invoke-PipeScript {
assert (1 -eq 1)
} -Debug
~~~

## Assert Example 2


~~~PowerShell
# With a second argument of a string, assert will throw an error
Invoke-PipeScript {
assert ($true) "It's true"
} -Debug
~~~

## Assert Example 3


~~~PowerShell
# Conditions can also be written as a ScriptBlock
Invoke-PipeScript {
assert {$true} "Process id '$pid' Asserted"
} -Verbose
~~~

## Assert Example 4


~~~PowerShell
# If the assertion action was a ScriptBlock, no exception is automatically thrown
Invoke-PipeScript {
assert ($true) { Write-Information "Assertion was true"}
} -Verbose
~~~

## New Example 1


Expand All @@ -35,19 +76,26 @@ Most keywords will be implemented as a Transpiler that tranforms a CommandAST.


~~~PowerShell
.> { new datetime 12/31/1999 }
.> { new Timespan }
~~~

## New Example 5


~~~PowerShell
.> { new @{RandomNumber = Get-Random; A ='b'}}
.> { new datetime 12/31/1999 }
~~~

## New Example 6


~~~PowerShell
.> { new @{RandomNumber = Get-Random; A ='b'}}
~~~

## New Example 7


~~~PowerShell
.> { new Diagnostics.ProcessStartInfo @{FileName='f'} }
~~~
Expand Down
Loading