Skip to content

Commit 98ba7ce

Browse files
author
James Brundage
committed
Core Transpiler: Enabling changing nearby context (Fixes #292)
1 parent a318dab commit 98ba7ce

File tree

1 file changed

+110
-45
lines changed

1 file changed

+110
-45
lines changed

Transpilers/Core/Pipescript.psx.ps1

Lines changed: 110 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -91,38 +91,45 @@ process {
9191
@(
9292
# check each ScriptBlock attribute
9393
foreach ($attrAst in $ScriptBlock.Ast.ParamBlock.Attributes) {
94-
94+
# and see if it is a real type.
9595
$attrRealType =
9696
if ($attrAst.TypeName.GetReflectionType) {
9797
$attrAst.TypeName.GetReflectionType()
9898
} elseif ($attrAst.TypeName.ToString) {
9999
$attrAst.TypeName.ToString() -as [type]
100100
}
101-
101+
102+
# If it is not a real type,
102103
if (-not $attrRealType) {
103-
$attrAst
104+
$attrAst # we will transpile it with the whole script block as input.
104105
}
105106
}
106107
)
107108

109+
# Now, we strip away any Attribute Based Composition.
108110
$replacements = [Ordered]@{}
109111
$myOffset = 0
110-
foreach ($moreTo in $moreToPreTranspile) {
112+
# To do this effeciently, we collect all of the attributes left to pretranspile
113+
foreach ($moreTo in $moreToPreTranspile) {
111114
$TranspilerAttributes += $moreTo.Extent.ToString()
112115
$start = $scriptText.IndexOf($moreTo.extent.text, $myOffset)
113116
$end = $start + $moreTo.Extent.Text.Length
114-
$replacements["$start,$end"] = ''
117+
$replacements["$start,$end"] = '' # and replace each of them with a blank.
115118
}
116119

120+
# get the updated script,
117121
$UpdatedScript = Update-PipeScript -ScriptReplacement $replacements -ScriptBlock $ScriptBlock
118-
119-
$scriptBlock = $UpdatedScript
122+
$scriptBlock = $UpdatedScript # and replace $ScriptBlock.
120123
}
121124

125+
126+
# Now we set the to the contents of the scriptblock.
122127
$scriptText = "$scriptBlock"
123-
124128

125-
$PreTranspile =
129+
# If there was no ScriptBlock, return
130+
if (-not $ScriptBlock) { return }
131+
132+
$PreTranspile =
126133
if ($transpilerAttributes) {
127134
[ScriptBlock]::Create(
128135
($TranspilerAttributes -join [Environment]::NewLine) + $(
@@ -133,8 +140,6 @@ process {
133140
)
134141
}
135142

136-
if (-not $ScriptBlock) { return }
137-
138143
# If there were any attributes that can be pre-transpiled, convert them.
139144
if ($PreTranspile.Ast.ParamBlock.Attributes) {
140145
# Get the list of transpilation attributes
@@ -206,9 +211,11 @@ process {
206211

207212
$itemTypeName = $item.GetType().Fullname
208213
if (-not $script:TranspilerAstTypes[$itemTypeName]) {
209-
$script:TranspilerAstTypes[$itemTypeName] = Get-Transpiler -CouldPipe $item |
210-
Where-Object {
211-
$_.ExtensionCommand.CouldRun(@{} + $_.ExtensionParameter)
214+
$script:TranspilerAstTypes[$itemTypeName] =
215+
foreach ($couldPipe in Get-Transpiler -CouldPipe $item) {
216+
if ($couldPipe.ExtensionCommand.CouldRun(@{} + $couldPipe.ExtensionParameter)) {
217+
$couldPipe
218+
}
212219
}
213220
}
214221

@@ -228,44 +235,102 @@ process {
228235
}
229236

230237
# If we found any matching pipescripts
231-
if ($pipescripts) {
232-
:NextPipeScript
233-
foreach ($ps in $pipescripts) {
234-
$pipeScriptOutput = Invoke-PipeScript -InputObject $item -CommandInfo $ps.ExtensionCommand
235-
foreach ($pso in $pipeScriptOutput) {
236-
if ($pso -is [Collections.IDictionary]) {
237-
$psoCopy = [Ordered]@{} + $pso
238-
foreach ($kv in @($psoCopy.GetEnumerator())) {
239-
if ($kv.Key -is [Management.Automation.Language.Ast]) {
240-
$astReplacements[$kv.Key] = $kv.Value
241-
$psoCopy.Remove($kv.Key)
242-
} elseif ($kv.Key -match '^\d,\d$') {
243-
$textReplacements["$($kv.Key)"] = $kv.Value
244-
$psoCopy.Remove($kv.Key)
245-
}
238+
if ($pipescripts) {
239+
# try to run each one.
240+
:NextPipeScript foreach ($ps in $pipescripts) {
241+
# If it had output
242+
$pipeScriptOutput = Invoke-PipeScript -InputObject $item -CommandInfo $ps.ExtensionCommand
243+
# Walk over each potential output
244+
foreach ($pso in $pipeScriptOutput) {
245+
# If the output was a dictionary, treat it as a series of replacements.
246+
if ($pso -is [Collections.IDictionary]) {
247+
$psoCopy = [Ordered]@{} + $pso
248+
foreach ($kv in @($psoCopy.GetEnumerator())) {
249+
# If the key was an AST element
250+
if ($kv.Key -is [Management.Automation.Language.Ast]) {
251+
# replace the element with it's value
252+
$astReplacements[$kv.Key] = $kv.Value
253+
$psoCopy.Remove($kv.Key)
254+
} elseif ($kv.Key -match '^\d+,\d+$') {
255+
# otherwise, it the key was a pair of digits, replace that span.
256+
$Replacements["$($kv.Key)"] = $kv.Value
257+
$psoCopy.Remove($kv.Key)
246258
}
247-
if ($psoCopy.Count) {
248-
$updateSplats += $psoCopy
249-
}
250259
}
251-
# If we have ouput from any of the scripts (and we have not yet replaced anything)
252-
elseif ($pso -and -not $AstReplacements[$item])
253-
{
254-
# determine the end of this AST element
255-
$start = $scriptText.IndexOf($item.Extent.Text, $myOffset)
256-
$end = $start + $item.Extent.Text.Length
257-
$skipUntil = $end # set SkipUntil
258-
$AstReplacements[$item] = $pso # and store the replacement.
260+
if ($psoCopy.Count) {
261+
$updateSplats += $psoCopy
262+
}
263+
}
264+
# If we have ouput from any of the scripts (and we have not yet replaced anything)
265+
elseif ($pso -and -not $AstReplacements[$item])
266+
{
267+
# determine the end of this AST element
268+
$start = $scriptText.IndexOf($item.Extent.Text, $myOffset)
269+
$end = $start + $item.Extent.Text.Length
270+
$skipUntil = $end # set SkipUntil
271+
$AstReplacements[$item] = $pso # and store the replacement.
272+
273+
#region Special Properties
274+
# Because PowerShell can attach properties to any object,
275+
# we can use the presence of attached properties to change context around the replacement.
276+
277+
# .SkipUntil or .IgnoreUntil can specify a new index or AST end point
278+
foreach ($toSkipAlias in 'SkipUntil', 'IgnoreUntil') {
279+
foreach ($toSkipUntil in $pso.$toSkipAlias) {
280+
if ($toSkipUntil -is [int] -and $toSkipUntil -gt $end) {
281+
$skipUntil = $toSkipUntil
282+
} elseif ($toSkipUntil -is [Management.Automation.Language.Ast]) {
283+
$newSkipStart = $scriptText.IndexOf($toSkipUntil.Extent.Text, $myOffset)
284+
if ($newSkipStart -ne -1) {
285+
$end = $newSkipStart + $toSkipUntil.Extent.Text.Length
286+
if ($end -gt $skipUntil) {
287+
$skipUntil = $end
288+
}
289+
if ($toSkipUntil -ne $item) {
290+
$AstReplacements[$toSkipUntil] = ''
291+
}
292+
}
293+
}
294+
}
295+
}
296+
297+
#.ToRemove,.RemoveAST, or .RemoveElement will remove AST elements or ranges
298+
foreach ($toRemoveAlias in 'ToRemove','RemoveAST','RemoveElement') {
299+
foreach ($toRemove in $pso.$toRemoveAlias) {
300+
if ($toRemove -is [Management.Automation.Language.Ast]) {
301+
$AstReplacements[$toRemove] = ''
302+
} elseif ($toRemove -match '^\d+,\d+$') {
303+
$Replacements[$toRemove] = ''
304+
}
305+
}
306+
}
307+
308+
#.ToReplace,.ReplaceAST or .ReplaceElement will replace elements or ranges.
309+
foreach ($toReplaceAlias in 'ToReplace','ReplaceAST','ReplaceElement') {
310+
foreach ($toReplace in $pso.$toReplaceAlias) {
311+
if ($toReplace -isnot [Collections.IDictionary]) {
312+
continue
313+
}
314+
foreach ($tr in $toReplace.GetEnumerator()) {
315+
if ($tr.Key -is [Management.Automaton.Language.Ast]) {
316+
$AstReplacements[$tr.Key] = $tr.Value
317+
} elseif ($tr.Key -match '^\d+,\d+$') {
318+
$textReplacements["$($tr.Key)"] = $tr.Value
319+
}
320+
}
321+
}
259322
}
323+
#endregion Special Properties
260324
}
261-
# If the transpiler had output, do not process any more transpilers.
262-
if ($pipeScriptOutput) { break }
263-
}
325+
}
326+
# If the transpiler had output, do not process any more transpilers.
327+
if ($pipeScriptOutput) { break }
328+
}
264329
}
265330
}
266331

267-
$newScript =
268-
if ($AstReplacements.Count) {
332+
$newScript =
333+
if ($AstReplacements.Count) {
269334
Update-PipeScript -ScriptBlock $ScriptBlock -ScriptReplacement $replacements -AstReplacement $AstReplacements
270335
} elseif ($updateSplats) {
271336
foreach ($upSplat in $updateSplats) {

0 commit comments

Comments
 (0)