Skip to content

Commit 059c06c

Browse files
author
James Brundage
committed
Adding 'new' keyword (#128)
1 parent 83e8434 commit 059c06c

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

Transpilers/Keywords/New.psx.ps1

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<#
2+
.SYNOPSIS
3+
'new' keyword
4+
.DESCRIPTION
5+
This transpiler enables the use of the keyword 'new'.
6+
7+
new acts as it does in many other languages.
8+
9+
It creates an instance of an object.
10+
11+
'new' can be followed by a typename and any number of arguments or hashtables.
12+
13+
If 'new' is followed by a single string, and the type has a ::Parse method, new will parse the value.
14+
15+
If 'new'
16+
.EXAMPLE
17+
.> { new DateTime }
18+
.EXAMPLE
19+
.> { new byte 1 }
20+
.EXAMPLE
21+
.> { new int[] 5 }
22+
.EXAMPLE
23+
.> { new datetime 12/31/1999 }
24+
.EXAMPLE
25+
.> { new @{RandomNumber = Get-Random; A ='b'}}
26+
.EXAMPLE
27+
.> { new Diagnostics.ProcessStartInfo @{FileName='f'} }
28+
#>
29+
[ValidateScript({
30+
$CommandAst = $_
31+
return ($commandAst -and $CommandAst.CommandElements[0].Value -eq 'new')
32+
})]
33+
param(
34+
[Parameter(Mandatory,ValueFromPipeline)]
35+
[Management.Automation.Language.CommandAst]
36+
$CommandAst
37+
)
38+
39+
process {
40+
$null, $newTypeName, $newArgs = $CommandAst.CommandElements
41+
$maybeGeneric = $false
42+
$propertiesToCreate = @()
43+
44+
$newTypeName =
45+
# Non-generic types will be a bareword constant
46+
if ($newTypeName.Value) {
47+
$newTypeName.Value
48+
}
49+
elseif ($newTypeName -is [Management.Automation.Language.HashtableAst]) {
50+
$propertiesToCreate += $newTypeName
51+
}
52+
else {
53+
# generic types will be an ArrayLiteralAst
54+
$maybeGeneric = $true
55+
$newTypeName.Extent.ToString()
56+
}
57+
if ($newTypeName -match '^\[' -and $newTypeName -match '\]$' ) {
58+
$newTypeName = $newTypeName -replace '^\[' -replace '\]$'
59+
}
60+
61+
62+
63+
$constructorArguments = @(
64+
foreach ($newArg in $newArgs) {
65+
# If the argument is a hashtable, treat it as properties to set after creation.
66+
if ($newArg -is [Management.Automation.Language.HashtableAst]) {
67+
$propertiesToCreate += $newArg
68+
} else {
69+
# Otherwise, treat it as arguments.
70+
$newArg
71+
}
72+
}
73+
)
74+
75+
$constructorArguments = @(
76+
foreach ($constructorArg in $constructorArguments) {
77+
if ($constructorArg.StringConstantType -eq 'BareWord') {
78+
"'" + $constructorArg.Value.Replace("'","''") + "'"
79+
} else {
80+
$constructorArg
81+
}
82+
}
83+
)
84+
85+
$realNewType = $newTypeName -as [type]
86+
if (-not $realNewType -and $maybeGeneric) {
87+
$realNewType = "Collections.Generic.$newTypeName" -as [type]
88+
if ($realNewType) {
89+
$newTypeName = "Collections.Generic.$newTypeName"
90+
}
91+
}
92+
93+
$newNew =
94+
if ($realNewType) {
95+
if ($realNewType::parse -and
96+
$constructorArguments.Length -eq 1 -and
97+
$constructorArguments[0] -is [string]) {
98+
"[$newTypeName]::parse(" + ($constructorArguments -join ',') + ")"
99+
} elseif ($realNewType::new) {
100+
"[$newTypeName]::new(" + ($constructorArguments -join ',') + ")"
101+
} elseif ($realNewType.IsPrimitive) {
102+
if ($constructorArguments) {
103+
if ($constructorArguments.Length -eq 1) {
104+
"[$newTypeName]$constructorArguments"
105+
} else {
106+
"[$newTypeName]($($constructorArguments -join ','))"
107+
}
108+
} else {
109+
"[$newTypeName]::new()"
110+
}
111+
}
112+
} elseif ($propertiesToCreate.Count -eq 1 -and -not $newTypeName) {
113+
"[PSCustomObject][Ordered]$propertiesToCreate"
114+
} else {
115+
Write-Error "Unknown type '$newTypeName'"
116+
return
117+
}
118+
119+
if ($propertiesToCreate -and $newTypeName) {
120+
$newNew = '$newObject = ' + $newNew + [Environment]::NewLine
121+
$newNew += (@(foreach ($propSet in $propertiesToCreate) {
122+
'foreach ($kvp in ' + "([Ordered]" + $propSet + ').GetEnumerator()) {
123+
$newObject.$($kvp.Key) = $kvp.Value
124+
}'
125+
}) -join [Environment]::NewLine)
126+
$newNew += [Environment]::NewLine + '$newObject'
127+
$newNew = "`$($newNew)"
128+
}
129+
130+
if ($newNew) {
131+
[scriptblock]::Create($newNew)
132+
}
133+
}

Transpilers/Keywords/README.ps1.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
This directory and it's subdirectories contain additional language keywords within PipeScript.
2+
3+
Most keywords will be implemented as a Transpiler that tranforms a CommandAST.
4+
5+
~~~PipeScript{
6+
[PSCustomObject]@{
7+
Table = Get-Transpiler -TranspilerPath $pwd |
8+
Select-Object DisplayName, Synopsis, @{
9+
Name='Link'
10+
Expression = { $_.Name }
11+
}
12+
}}
13+
~~~
14+
15+
16+
~~~PipeScript{
17+
@(foreach ($transpiler in Get-Transpiler -TranspilerPath $pwd) {
18+
$examples = @($transpiler.Examples)
19+
if (-not $examples) { continue }
20+
for ($exampleNumber = 1; $exampleNumber -le $examples.Length; $exampleNumber++) {
21+
@("## $($transpiler.DisplayName) Example $($exampleNumber)",
22+
[Environment]::Newline,
23+
"~~~PowerShell",
24+
$examples[$exampleNumber - 1],
25+
"~~~") -join [Environment]::Newline
26+
}
27+
}) -join ([Environment]::Newline * 2)
28+
}
29+
~~~

0 commit comments

Comments
 (0)