Last active
April 12, 2025 16:51
-
-
Save SeeminglyScience/2f38c96a09d63f3bdac4d37781e8d9c7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using namespace System | |
using namespace System.Linq | |
using namespace System.Collections | |
using namespace System.Collections.Generic | |
using namespace System.Management.Automation | |
using namespace System.Management.Automation.Language | |
using namespace System.Reflection | |
# Hey person reading this! Don't do this, alright? You'll have a bad time. ty | |
# Example: | |
# [System.AppDomain]::CurrentDomain.GetAssemblies(). | |
# SelectMany{ $assembly => { try { $assembly.GetTypes() } catch { }}}. | |
# SelectMany{ $type => $type.GetMembers()}. | |
# OrderByDescending{ $member => { $member -is [System.Reflection.FieldInfo] }}. | |
# ThenByDescending{ $member => $member.IsLiteral }. | |
# Take(5). | |
# ToDictionary({ $field => $field.Name }, { $field => $field.GetRawConstantValue() }) | |
Update-TypeData -Force -TypeName scriptblock -MemberType ScriptMethod -MemberName ConvertFromLambdaSyntax -Value { | |
return [DelegateSyntaxRebuilder]::ConvertFromLambda($this) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName _AsEnumerable -Value { | |
if ($null -eq $this) { | |
return ,@() | |
} | |
if ($this -isnot [IEnumerable]) { | |
return ,@($this) | |
} | |
if ($this -isnot [IEnumerable[object]]) { | |
return ,[Enumerable]::Cast[object]($this) | |
} | |
return ,$this | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName ToDictionary -Value { | |
if ($args.Count -eq 3) { | |
return [Enumerable]::ToDictionary[object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[IEqualityComparer[object]] $args[2]) | |
} | |
if ($args.Count -eq 2) { | |
if ($args[1] -is [scriptblock]) { | |
return [Enumerable]::ToDictionary[object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax()) | |
} | |
return [Enumerable]::ToDictionary[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax(), | |
[IEqualityComparer[object]]$args[1]) | |
} | |
return [Enumerable]::ToDictionary[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName GetAggregate -Value { | |
if ($args.Length -eq 3) { | |
return ,[Enumerable]::Aggregate[object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[object] $args[0], | |
[Func[object, object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[2].ConvertFromLambdaSyntax()) | |
} | |
if ($args.Length -eq 2) { | |
return ,[Enumerable]::Aggregate[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[object] $args[0], | |
[Func[object, object, object]]$args[1].ConvertFromLambdaSyntax()) | |
} | |
return ,[Enumerable]::Aggregate[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Reverse -Value { | |
# If you see thise while checking for overloads, do `$obj.psbase.Reverse` instead | |
if ($existing = $this.psbase.psobject.Methods['Reverse']) { | |
return ,$existing.Invoke($args) | |
} | |
return ,[Enumerable]::Reverse[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName All -Value { | |
return [Enumerable]::All[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, bool]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Append -Value { | |
# If you see thise while checking for overloads, do `$obj.psbase.Append` instead | |
if ($existing = $this.psbase.psobject.Methods['Append']) { | |
return ,$existing.Invoke($args) | |
} | |
return ,[Enumerable]::Append[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[object]$args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Prepend -Value { | |
return ,[Enumerable]::Prepend[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[object]$args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName GetAverage -Value { | |
if ($args.Length -eq 0) { | |
if ($this -is [IEnumerable[int]]) { | |
return [Enumerable]::Average([IEnumerable[int]]$this) | |
} | |
if ($this -is [IEnumerable[long]]) { | |
return [Enumerable]::Average([IEnumerable[long]]$this) | |
} | |
if ($this -is [IEnumerable[float]]) { | |
return [Enumerable]::Average([IEnumerable[float]]$this) | |
} | |
if ($this -is [IEnumerable[double]]) { | |
return [Enumerable]::Average([IEnumerable[double]]$this) | |
} | |
if ($this -is [IEnumerable[decimal]]) { | |
return [Enumerable]::Average([IEnumerable[decimal]]$this) | |
} | |
return [Enumerable]::Average([IEnumerable[long]]$this.ForEach([long])) | |
} | |
return [Enumerable]::Average[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, long]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Any -Value { | |
if ($args.Length -eq 0) { | |
return [Enumerable]::Any[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
return [Enumerable]::Any[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName OrderBy -Value { | |
return ,[Enumerable]::OrderBy[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName OrderByDescending -Value { | |
return ,[Enumerable]::OrderByDescending[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName ThenBy -Value { | |
if ($this -isnot [IOrderedEnumerable[object]]) { | |
throw [ArgumentException]::new('Must use OrderBy* before ThenBy*', 'source') | |
} | |
return ,[Enumerable]::ThenBy[object, object]( | |
[IOrderedEnumerable[object]]$this, | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName ThenByDescending -Value { | |
if ($this -isnot [IOrderedEnumerable[object]]) { | |
throw [ArgumentException]::new('Must use OrderBy* before ThenBy*', 'source') | |
} | |
return ,[Enumerable]::ThenByDescending[object, object]( | |
[IOrderedEnumerable[object]]$this, | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName ToArray -Value { | |
# If you see thise while checking for overloads, do `$obj.psbase.ToArray` instead | |
if ($existing = $this.psbase.psobject.Methods['ToArray']) { | |
return ,$existing.Invoke() | |
} | |
return ,[Enumerable]::ToArray[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName ToList -Value { | |
return ,[Enumerable]::ToList[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName ToHashSet -Value { | |
if ($args.Length -ne 0) { | |
if ($args[0] -is [scriptblock]) { | |
return ,[Enumerable]::ToHashSet[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[ScriptBlockEqualityComparer]::Create($args[0])) | |
} | |
return ,[Enumerable]::ToHashSet[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEqualityComparer[object]]$args[0]) | |
} | |
return ,[Enumerable]::ToHashSet[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[PSEqualityComparer]::Instance) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Select -Value { | |
return ,[Enumerable]::Select[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, int, object]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
class SelectManyDelegate { | |
hidden [scriptblock] $_sb | |
static [Func[object, int, IEnumerable[object]]] Create([scriptblock] $sb) { | |
$delegate = [SelectManyDelegate]::new() | |
$delegate._sb = $sb.ConvertFromLambdaSyntax() | |
return [SelectManyDelegate].GetMethod('SelectMany'). | |
CreateDelegate( | |
[Func[object, int, System.Collections.Generic.IEnumerable[object]]], | |
$delegate) | |
} | |
[IEnumerable[object]] SelectMany([object] $item, [int] $index) { | |
$result = & $this._sb $item $index | |
if ($null -eq $result) { | |
return @() | |
} | |
return $result._AsEnumerable() | |
} | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName SelectMany -Value { | |
return ,[Enumerable]::SelectMany[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[SelectManyDelegate]::Create($args[0])) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName GetChunks -Value { | |
return ,[Enumerable]::Chunk[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[int] $args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Concat -Value { | |
# If you see thise while checking for overloads, do `$obj.psbase.Concat` instead | |
if ($existing = $this.psbase.psobject.Methods['Concat']) { | |
return ,$existing.Invoke($args) | |
} | |
return ,[Enumerable]::Concat[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName GetCount -Value { | |
if ($args.Length -eq 0) { | |
return [Enumerable]::Count[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
return ,[Enumerable]::Count[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, bool]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName DefaultIfEmpty -Value { | |
if ($args.Length -eq 0) { | |
return ,[Enumerable]::DefaultIfEmpty[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
return ,[Enumerable]::DefaultIfEmpty[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[object]$args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName GetDistinct -Value { | |
if ($args.Length -eq 1) { | |
if ($args[0] -is [scriptblock]) { | |
return ,[Enumerable]::Distinct[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[ScriptBlockEqualityComparer]::Create($args[0])) | |
} | |
return ,[Enumerable]::Distinct[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEqualityComparer[object]]$args[0]) | |
} | |
return ,[Enumerable]::Distinct[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[PSEqualityComparer]::Instance) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName ElementAt -Value { | |
return ,[Enumerable]::ElementAtOrDefault[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[int] $args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Except -Value { | |
if ($args.Length -eq 2) { | |
if ($args[1] -is [scriptblock]) { | |
return ,[Enumerable]::Except[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[ScriptBlockEqualityComparer]::Create($args[1])) | |
} | |
return ,[Enumerable]::Except[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[IEqualityComparer[object]]$args[1]) | |
} | |
return ,[Enumerable]::Except[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[PSEqualityComparer]::Instance) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName First -Value { | |
if ($args.Length -eq 1) { | |
return ,[Enumerable]::FirstOrDefault[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, bool]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
return ,[Enumerable]::FirstOrDefault[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Single -Value { | |
if ($args.Length -eq 1) { | |
return ,[Enumerable]::SingleOrDefault[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, bool]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
return ,[Enumerable]::SingleOrDefault[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Last -Value { | |
if ($args.Length -eq 1) { | |
return ,[Enumerable]::LastOrDefault[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, bool]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
return ,[Enumerable]::LastOrDefault[object]([IEnumerable[object]]$this._AsEnumerable()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Take -Value { | |
return ,[Enumerable]::Take[object]([IEnumerable[object]]$this._AsEnumerable(), $args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName TakeLast -Value { | |
return ,[Enumerable]::TakeLast[object]([IEnumerable[object]]$this._AsEnumerable(), [int]$args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName TakeWhile -Value { | |
return ,[Enumerable]::TakeWhile[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, int, bool]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Skip -Value { | |
return ,[Enumerable]::Skip[object]([IEnumerable[object]]$this._AsEnumerable(), [int]$args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName SkipLast -Value { | |
return ,[Enumerable]::SkipLast[object]([IEnumerable[object]]$this._AsEnumerable(), [int]$args[0]) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName SkipWhile -Value { | |
return ,[Enumerable]::SkipWhile[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, int, bool]]$args[0].ConvertFromLambdaSyntax()) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName LinqGroupBy -Value { | |
if ($args.Length -eq 1) { | |
return ,[Enumerable]::GroupBy[object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax(), | |
[PSEqualityComparer]::Instance) | |
} | |
if ($args.Length -eq 2) { | |
return ,[Enumerable]::GroupBy[object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[PSEqualityComparer]::Instance) | |
} | |
if ($args.Length -eq 3) { | |
return ,[Enumerable]::GroupBy[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, IEnumerable[object], object]]$args[2].ConvertFromLambdaSyntax(), | |
[PSEqualityComparer]::Instance) | |
} | |
return ,[Enumerable]::GroupBy[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[Func[object, object]]$args[0].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, IEnumerable[object], object]]$args[2].ConvertFromLambdaSyntax(), | |
[ScriptBlockEqualityComparer]::Create($args[3])) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName GroupJoin -Value { | |
if ($args.Length -eq 5) { | |
if ($args[4] -is [scriptblock]) { | |
return ,[Enumerable]::GroupJoin[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[2].ConvertFromLambdaSyntax(), | |
[Func[object, IEnumerable[object], object]]$args[3].ConvertFromLambdaSyntax(), | |
[ScriptBlockEqualityComparer]::Create($args[4])) | |
} | |
return ,[Enumerable]::GroupJoin[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[2].ConvertFromLambdaSyntax(), | |
[Func[object, IEnumerable[object], object]]$args[3].ConvertFromLambdaSyntax(), | |
[IEqualityComparer[object]]$args[4]) | |
} | |
return ,[Enumerable]::GroupJoin[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[2].ConvertFromLambdaSyntax(), | |
[Func[object, IEnumerable[object], object]]$args[3].ConvertFromLambdaSyntax(), | |
[PSEqualityComparer]::Instance) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Intersect -Value { | |
if ($args.Length -eq 2) { | |
if ($args[1] -is [scriptblock]) { | |
return ,[Enumerable]::Intersect[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[ScriptBlockEqualityComparer]::Create($args[1])) | |
} | |
return ,[Enumerable]::Intersect[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[IEqualityComparer[object]]$args[1]) | |
} | |
return ,[Enumerable]::Intersect[object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[PSEqualityComparer]::Instance) | |
} | |
Update-TypeData -Force -TypeName System.Object -MemberType ScriptMethod -MemberName Join -Value { | |
# If you see thise while checking for overloads, do `$obj.psbase.Join` instead | |
if ($existing = $this.psbase.psobject.Methods['Join']) { | |
return ,$existing.Invoke($args) | |
} | |
if ($args.Length -eq 5) { | |
if ($args[4] -is [scriptblock]) { | |
return ,[Enumerable]::Join[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[2].ConvertFromLambdaSyntax(), | |
[Func[object, object, object]]$args[3].ConvertFromLambdaSyntax(), | |
[ScriptBlockEqualityComparer]::Create($args[4])) | |
} | |
return ,[Enumerable]::Join[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[2].ConvertFromLambdaSyntax(), | |
[Func[object, object, object]]$args[3].ConvertFromLambdaSyntax(), | |
[IEqualityComparer[object]]$args[4]) | |
} | |
return ,[Enumerable]::Join[object, object, object, object]( | |
[IEnumerable[object]]$this._AsEnumerable(), | |
[IEnumerable[object]]$args[0]._AsEnumerable(), | |
[Func[object, object]]$args[1].ConvertFromLambdaSyntax(), | |
[Func[object, object]]$args[2].ConvertFromLambdaSyntax(), | |
[Func[object, object, object]]$args[3].ConvertFromLambdaSyntax(), | |
[PSEqualityComparer]::Instance) | |
} | |
class ScriptBlockEqualityComparer : IEqualityComparer[object] { | |
hidden [scriptblock] $_sb | |
ScriptBlockEqualityComparer([scriptblock] $sb) { | |
$this._sb = $sb | |
} | |
static [ScriptBlockEqualityComparer] Create([scriptblock] $sb) { | |
return [ScriptBlockEqualityComparer]::new($sb.ConvertFromLambdaSyntax()) | |
} | |
[bool] Equals([Object] $x, [Object] $y) { | |
return & $this._sb $x $y | |
} | |
[int] GetHashCode([Object] $obj) { | |
return ($obj)?.GetHashCode() ?? 0 | |
} | |
} | |
class PSEqualityComparer : IEqualityComparer[object] { | |
static [PSEqualityComparer] $Instance = [PSEqualityComparer]::new() | |
[bool] Equals([Object] $x, [Object] $y) { | |
return $x -eq $y | |
} | |
[int] GetHashCode([Object] $obj) { | |
return ($obj)?.GetHashCode() ?? 0 | |
} | |
} | |
class AstRebuilder : ICustomAstVisitor2 { | |
[object[]] VisitAll([Ast[]] $asts) { | |
return & { | |
foreach ($a in $asts) { | |
$a.Visit($this) | |
} | |
} | |
} | |
[object] Visit([Ast] $ast) { | |
return ($ast)?.Visit($this) | |
} | |
[Object] VisitTypeDefinition([TypeDefinitionAst] $typeDefinitionAst) { | |
return [TypeDefinitionAst]::new( | |
$typeDefinitionAst.Extent, | |
$typeDefinitionAst.Name, | |
[AttributeAst[]]$this.VisitAll($typeDefinitionAst.Attributes), | |
[MemberAst[]]$this.VisitAll($typeDefinitionAst.Members), | |
$typeDefinitionAst.TypeAttributes, | |
[TypeConstraintAst[]]$this.VisitAll($typeDefinitionAst.BaseTypes)) | |
} | |
[Object] VisitPropertyMember([PropertyMemberAst] $propertyMemberAst) { | |
return [PropertyMemberAst]::new( | |
$propertyMemberAst.Extent, | |
$propertyMemberAst.Name, | |
$this.Visit($propertyMemberAst.PropertyType), | |
[AttributeAst[]]$this.VisitAll($propertyMemberAst.Attributes), | |
$propertyMemberAst.PropertyAttributes, | |
$this.Visit($propertyMemberAst.InitialValue)) | |
} | |
[Object] VisitFunctionMember([FunctionMemberAst] $functionMemberAst) { | |
return [FunctionMemberAst]::new( | |
$functionMemberAst.Extent, | |
$this.Visit($functionMemberAst.Body.Parent), | |
$this.Visit($functionMemberAst.ReturnType), | |
[AttributeAst[]]$this.VisitAll($functionMemberAst.Attributes), | |
$functionMemberAst.MethodAttributes) | |
} | |
[Object] VisitBaseCtorInvokeMemberExpression([BaseCtorInvokeMemberExpressionAst] $baseCtorInvokeMemberExpressionAst) { | |
return [BaseCtorInvokeMemberExpressionAst]::new( | |
$baseCtorInvokeMemberExpressionAst.Expression.Extent, | |
$baseCtorInvokeMemberExpressionAst.Member.Extent, | |
[ExpressionAst[]]$this.VisitAll($baseCtorInvokeMemberExpressionAst.Arguments)) | |
} | |
[Object] VisitUsingStatement([UsingStatementAst] $usingStatement) { | |
if ($usingStatement.ModuleSpecification) { | |
if ($usingStatement.Alias) { | |
return [UsingStatementAst]::new( | |
$usingStatement.Extent, | |
$this.Visit($usingStatement.Alias), | |
$this.Visit($usingStatement.ModuleSpecification)) | |
} | |
return [UsingStatementAst]::new( | |
$usingStatement.Extent, | |
$this.Visit($usingStatement.ModuleSpecification)) | |
} | |
if ($usingStatement.Alias) { | |
return [UsingStatementAst]::new( | |
$usingStatement.Extent, | |
$usingStatement.UsingStatementKind, | |
$this.Visit($usingStatement.Name), | |
$this.Visit($usingStatement.Alias)) | |
} | |
return [UsingStatementAst]::new( | |
$usingStatement.Extent, | |
$usingStatement.UsingStatementKind, | |
$this.Visit($usingStatement.Name)) | |
} | |
[Object] VisitConfigurationDefinition([ConfigurationDefinitionAst] $configurationDefinitionAst) { | |
return [ConfigurationDefinitionAst]::new( | |
$configurationDefinitionAst.Extent, | |
$this.Visit($configurationDefinitionAst.Body), | |
$configurationDefinitionAst.ConfigurationType, | |
$this.Visit($configurationDefinitionAst.InstanceName)) | |
} | |
[Object] VisitDynamicKeywordStatement([DynamicKeywordStatementAst] $dynamicKeywordAst) { | |
return [DynamicKeywordStatementAst]::new( | |
$dynamicKeywordAst.Extent, | |
[CommandElementAst[]]$this.VisitAll($dynamicKeywordAst.CommandElements)) | |
} | |
[Object] VisitTernaryExpression([TernaryExpressionAst] $ternaryExpressionAst) { | |
return [TernaryExpressionAst]::new( | |
$ternaryExpressionAst.Extent, | |
$this.Visit($ternaryExpressionAst.Condition), | |
$this.Visit($ternaryExpressionAst.IfTrue), | |
$this.Visit($ternaryExpressionAst.IfFalse)) | |
} | |
[Object] VisitPipelineChain([PipelineChainAst] $statementChainAst) { | |
return [PipelineChainAst]::new( | |
$statementChainAst.Extent, | |
$this.Visit($statementChainAst.LhsPipelineChain), | |
$this.Visit($statementChainAst.RhsPipeline), | |
$statementChainAst.Operator, | |
$statementChainAst.Background) | |
} | |
[Object] DefaultVisit([Ast] $ast) { | |
return $ast.Copy() | |
} | |
[Object] VisitErrorStatement([ErrorStatementAst] $errorStatementAst) { | |
$errorFlags = [Dictionary[string, Tuple[Token, Ast]]]::new($errorStatementAst.Flags.Comparer) | |
foreach ($flag in $errorStatementAst.Flags.GetEnumerator()) { | |
$errorFlags.Add( | |
$flag.Key, | |
[Tuple[Token, Ast]]::new($flag.Value.Item1, $this.Visit($flag.Value.Item2))) | |
} | |
$flags = [BindingFlags]::Instance -bor 'NonPublic' | |
return [ErrorStatementAst]. | |
GetConstructor( | |
$flags, | |
([IScriptExtent], [Token], [IEnumerable[KeyValuePair[string, Tuple[Token, Ast]]]], [IEnumerable[Ast]], [IEnumerable[Ast]])). | |
Invoke(( | |
$errorStatementAst.Extent, | |
$errorStatementAst.Kind, | |
$errorFlags.GetEnumerator(), | |
[Ast[]]$this.VisitAll($errorStatementAst.Conditions), | |
[Ast[]]$this.VisitAll($errorStatementAst.Bodies))) | |
} | |
[Object] VisitErrorExpression([ErrorExpressionAst] $errorExpressionAst) { | |
$flags = [BindingFlags]::Instance -bor 'NonPublic' | |
return [ErrorExpressionAst]. | |
GetConstructor( | |
$flags, | |
([IScriptExtent], [IEnumerable[Ast]])). | |
Invoke(( | |
$errorExpressionAst.Extent, | |
[Ast[]]$this.VisitAll($errorExpressionAst.NestedAst))) | |
} | |
[Object] VisitScriptBlock([ScriptBlockAst] $scriptBlockAst) { | |
return [ScriptBlockAst]::new( | |
$scriptBlockAst.Extent, | |
[UsingStatementAst[]]$this.VisitAll($scriptBlockAst.UsingStatements), | |
[AttributeAst[]]$this.VisitAll($scriptBlockAst.Attributes), | |
$this.Visit($scriptBlockAst.ParamBlock), | |
$this.Visit($scriptBlockAst.BeginBlock), | |
$this.Visit($scriptBlockAst.ProcessBlock), | |
$this.Visit($scriptBlockAst.EndBlock), | |
$this.Visit($scriptBlockAst.CleanBlock), | |
$this.Visit($scriptBlockAst.DynamicParamBlock)) | |
} | |
[Object] VisitParamBlock([ParamBlockAst] $paramBlockAst) { | |
return [ParamBlockAst]::new( | |
$paramBlockAst.Extent, | |
[AttributeAst[]]$this.VisitAll($paramBlockAst.Attributes), | |
[ParameterAst[]]$this.VisitAll($paramBlockAst.Parameters)) | |
} | |
[Object] VisitNamedBlock([NamedBlockAst] $namedBlockAst) { | |
return [NamedBlockAst]::new( | |
$namedBlockAst.Extent, | |
$namedBlockAst.BlockKind, | |
[StatementBlockAst]::new( | |
$namedBlockAst.Extent, | |
[StatementAst[]]$this.VisitAll($namedBlockAst.Statements), | |
[TrapStatementAst[]]$this.Visitall($namedBlockAst.Traps)), | |
$namedBlockAst.Unnamed) | |
} | |
[Object] VisitTypeConstraint([TypeConstraintAst] $typeConstraintAst) { | |
return $typeConstraintAst.Copy() | |
} | |
[Object] VisitAttribute([AttributeAst] $attributeAst) { | |
return [AttributeAst]::new( | |
$attributeAst.Extent, | |
$attributeAst.TypeName, | |
[ExpressionAst[]]$this.VisitAll($attributeAst.PositionalArguments), | |
[NamedAttributeArgumentAst[]]$this.VisitAll($attributeAst.NamedArguments)) | |
} | |
[Object] VisitNamedAttributeArgument([NamedAttributeArgumentAst] $namedAttributeArgumentAst) { | |
return [NamedAttributeArgumentAst]::new( | |
$namedAttributeArgumentAst.Extent, | |
$namedAttributeArgumentAst.ArgumentName, | |
$this.Visit($namedAttributeArgumentAst.Argument), | |
$namedAttributeArgumentAst.ExpressionOmitted) | |
} | |
[Object] VisitParameter([ParameterAst] $parameterAst) { | |
return [ParameterAst]::new( | |
$parameterAst.Extent, | |
$this.Visit($parameterAst.Name), | |
[AttributeBaseAst[]]$this.VisitAll($parameterAst.Attributes), | |
$this.Visit($parameterAst.DefaultValue)) | |
} | |
[Object] VisitFunctionDefinition([FunctionDefinitionAst] $functionDefinitionAst) { | |
return [FunctionDefinitionAst]::new( | |
$functionDefinitionAst.Extent, | |
$functionDefinitionAst.IsFilter, | |
$functionDefinitionAst.IsWorkflow, | |
$functionDefinitionAst.Name, | |
[ParameterAst[]]$this.VisitAll($functionDefinitionAst.Parameters), | |
$this.Visit($functionDefinitionAst.Body)) | |
} | |
[Object] VisitStatementBlock([StatementBlockAst] $statementBlockAst) { | |
return [StatementBlockAst]::new( | |
$statementBlockAst.Extent, | |
[StatementAst[]]$this.VisitAll($statementBlockAst.Statements), | |
[TrapStatementAst[]]$this.Visitall($statementBlockAst.Traps)) | |
} | |
[Object] VisitIfStatement([IfStatementAst] $ifStmtAst) { | |
[Tuple[PipelineBaseAst, StatementBlockAst][]] $clauses = foreach ($clause in $ifStmtAst.Clauses) { | |
[Tuple[PipelineBaseAst, StatementBlockAst]]::new( | |
$this.Visit($clause.Item1), | |
$this.Visit($clause.Item2)) | |
} | |
return [IfStatementAst]::new( | |
$ifStmtAst.Extent, | |
$clauses, | |
$this.Visit($ifStmtAst.ElseClause)) | |
} | |
[Object] VisitTrap([TrapStatementAst] $trapStatementAst) { | |
return [TrapStatementAst]::new( | |
$trapStatementAst.Extent, | |
$this.Visit($trapStatementAst.TrapType), | |
$this.Visit($trapStatementAst.Body)) | |
} | |
[Object] VisitSwitchStatement([SwitchStatementAst] $switchStatementAst) { | |
[Tuple[ExpressionAst, StatementBlockAst][]] $clauses = foreach ($clause in $switchStatementAst.Clauses) { | |
[Tuple[ExpressionAst, StatementBlockAst]]::new( | |
$this.Visit($clause.Item1), | |
$this.Visit($clause.Item2)) | |
} | |
return [SwitchStatementAst]::new( | |
$switchStatementAst.Extent, | |
$switchStatementAst.Label, | |
$this.Visit($switchStatementAst.Condition), | |
$switchStatementAst.Flags, | |
$clauses, | |
$this.Visit($switchStatementAst.Default)) | |
} | |
[Object] VisitDataStatement([DataStatementAst] $dataStatementAst) { | |
return [DataStatementAst]::new( | |
$dataStatementAst.Extent, | |
$dataStatementAst.Variable, | |
[ExpressionAst[]]$this.VisitAll($dataStatementAst.Variable), | |
$this.Visit($dataStatementAst.Body)) | |
} | |
[Object] VisitForEachStatement([ForEachStatementAst] $forEachStatementAst) { | |
return [ForEachStatementAst]::new( | |
$forEachStatementAst.Extent, | |
$forEachStatementAst.Label, | |
$forEachStatementAst.Flags, | |
$this.Visit($forEachStatementAst.Variable), | |
$this.Visit($forEachStatementAst.Condition), | |
$this.Visit($forEachStatementAst.Body)) | |
} | |
[Object] VisitDoWhileStatement([DoWhileStatementAst] $doWhileStatementAst) { | |
return [DoWhileStatementAst]::new( | |
$doWhileStatementAst.Extent, | |
$doWhileStatementAst.Label, | |
$this.Visit($doWhileStatementAst.Condition), | |
$this.Visit($doWhileStatementAst.Body)) | |
} | |
[Object] VisitForStatement([ForStatementAst] $forStatementAst) { | |
return [ForStatementAst]::new( | |
$forStatementAst.Extent, | |
$forStatementAst.Label, | |
$this.Visit($forStatementAst.Initializer), | |
$this.Visit($forStatementAst.Condition), | |
$this.Visit($forStatementAst.Iterator), | |
$this.Visit($forStatementAst.Body)) | |
} | |
[Object] VisitWhileStatement([WhileStatementAst] $whileStatementAst) { | |
return [WhileStatementAst]::new( | |
$whileStatementAst.Extent, | |
$whileStatementAst.Label, | |
$this.Visit($whileStatementAst.Condition), | |
$this.Visit($whileStatementAst.Body)) | |
} | |
[Object] VisitCatchClause([CatchClauseAst] $catchClauseAst) { | |
return [CatchClauseAst]::new( | |
$catchClauseAst.Extent, | |
[TypeConstraintAst[]]$this.VisitAll($catchClauseAst.CatchTypes), | |
$this.Visit($catchClauseAst.Body)) | |
} | |
[Object] VisitTryStatement([TryStatementAst] $tryStatementAst) { | |
return [TryStatementAst]::new( | |
$tryStatementAst.Extent, | |
$this.Visit($tryStatementAst.Body), | |
[CatchClauseAst[]]$this.VisitAll($tryStatementAst.CatchClauses), | |
$this.Visit($tryStatementAst.Finally)) | |
} | |
[Object] VisitBreakStatement([BreakStatementAst] $breakStatementAst) { | |
return [BreakStatementAst]::new( | |
$breakStatementAst.Extent, | |
$this.Visit($breakStatementAst.Label)) | |
} | |
[Object] VisitContinueStatement([ContinueStatementAst] $continueStatementAst) { | |
return [ContinueStatementAst]::new( | |
$continueStatementAst.Extent, | |
$this.Visit($continueStatementAst.Label)) | |
} | |
[Object] VisitReturnStatement([ReturnStatementAst] $returnStatementAst) { | |
return [ReturnStatementAst]::new( | |
$returnStatementAst.Extent, | |
$this.Visit($returnStatementAst.Label)) | |
} | |
[Object] VisitExitStatement([ExitStatementAst] $exitStatementAst) { | |
return [ExitStatementAst]::new( | |
$exitStatementAst.Extent, | |
$this.Visit($exitStatementAst.Pipeline)) | |
} | |
[Object] VisitThrowStatement([ThrowStatementAst] $throwStatementAst) { | |
return [ThrowStatementAst]::new( | |
$throwStatementAst.Extent, | |
$this.Visit($throwStatementAst.Pipeline)) | |
} | |
[Object] VisitDoUntilStatement([DoUntilStatementAst] $doUntilStatementAst) { | |
return [DoUntilStatementAst]::new( | |
$doUntilStatementAst.Extent, | |
$doUntilStatementAst.Label, | |
$this.Visit($doUntilStatementAst.Condition), | |
$this.Visit($doUntilStatementAst.Body)) | |
} | |
[Object] VisitAssignmentStatement([AssignmentStatementAst] $assignmentStatementAst) { | |
return [AssignmentStatementAst]::new( | |
$assignmentStatementAst.Extent, | |
$this.Visit($assignmentStatementAst.Left), | |
$assignmentStatementAst.Operator, | |
$this.Visit($assignmentStatementAst.Right), | |
$assignmentStatementAst.ErrorPosition) | |
} | |
[Object] VisitPipeline([PipelineAst] $pipelineAst) { | |
return [PipelineAst]::new( | |
$pipelineAst.Extent, | |
[CommandBaseAst[]]$this.VisitAll($pipelineAst.PipelineElements), | |
$pipelineAst.Background) | |
} | |
[Object] VisitCommand([CommandAst] $commandAst) { | |
return [CommandAst]::new( | |
$commandAst.Extent, | |
[CommandElementAst[]]$this.VisitAll($commandAst.CommandElements), | |
$commandAst.InvocationOperator, | |
[RedirectionAst[]]$this.VisitAll($commandAst.Redirections)) | |
} | |
[Object] VisitCommandExpression([CommandExpressionAst] $commandExpressionAst) { | |
return [CommandExpressionAst]::new( | |
$commandExpressionAst.Extent, | |
$this.Visit($commandExpressionAst.Expression), | |
[RedirectionAst[]]$this.VisitAll($commandExpressionAst.Redirections)) | |
} | |
[Object] VisitCommandParameter([CommandParameterAst] $commandParameterAst) { | |
return [CommandParameterAst]::new( | |
$commandParameterAst.Extent, | |
$commandParameterAst.ParameterName, | |
$this.Visit($commandParameterAst.Argument), | |
$commandParameterAst.Extent) | |
} | |
[Object] VisitFileRedirection([FileRedirectionAst] $fileRedirectionAst) { | |
return [FileRedirectionAst]::new( | |
$fileRedirectionAst.Extent, | |
$fileRedirectionAst.FromStream, | |
$this.Visit($fileRedirectionAst.Location), | |
$fileRedirectionAst.Append) | |
} | |
[Object] VisitMergingRedirection([MergingRedirectionAst] $mergingRedirectionAst) { | |
return [MergingRedirectionAst]::new( | |
$mergingRedirectionAst.Extent, | |
$mergingRedirectionAst.FromStream, | |
$mergingRedirectionAst.ToStream) | |
} | |
[Object] VisitBinaryExpression([BinaryExpressionAst] $binaryExpressionAst) { | |
return [BinaryExpressionAst]::new( | |
$binaryExpressionAst.Extent, | |
$this.Visit($binaryExpressionAst.Left), | |
$binaryExpressionAst.Operator, | |
$this.Visit($binaryExpressionAst.Right), | |
$binaryExpressionAst.ErrorPosition) | |
} | |
[Object] VisitUnaryExpression([UnaryExpressionAst] $unaryExpressionAst) { | |
return [UnaryExpressionAst]::new( | |
$unaryExpressionAst.Extent, | |
$unaryExpressionAst.TokenKind, | |
$this.Visit($unaryExpressionAst.Child)) | |
} | |
[Object] VisitConvertExpression([ConvertExpressionAst] $convertExpressionAst) { | |
return [ConvertExpressionAst]::new( | |
$convertExpressionAst.Extent, | |
$this.Visit($convertExpressionAst.Type), | |
$this.Visit($convertExpressionAst.Child)) | |
} | |
[Object] VisitConstantExpression([ConstantExpressionAst] $constantExpressionAst) { | |
return $constantExpressionAst.Copy() | |
} | |
[Object] VisitStringConstantExpression([StringConstantExpressionAst] $stringConstantExpressionAst) { | |
return $stringConstantExpressionAst.Copy() | |
} | |
[Object] VisitSubExpression([SubExpressionAst] $subExpressionAst) { | |
return [SubExpressionAst]::new( | |
$subExpressionAst.Extent, | |
$this.Visit($subExpressionAst.SubExpression)) | |
} | |
[Object] VisitUsingExpression([UsingExpressionAst] $usingExpressionAst) { | |
return [UsingExpressionAst]::new( | |
$usingExpressionAst.Extent, | |
$this.Visit($usingExpressionAst.SubExpression)) | |
} | |
[Object] VisitVariableExpression([VariableExpressionAst] $variableExpressionAst) { | |
return [VariableExpressionAst]::new( | |
$variableExpressionAst.Extent, | |
$variableExpressionAst.VariablePath, | |
$variableExpressionAst.Splatted) | |
} | |
[Object] VisitTypeExpression([TypeExpressionAst] $typeExpressionAst) { | |
return [TypeExpressionAst]::new( | |
$typeExpressionAst.Extent, | |
$typeExpressionAst.TypeName) | |
} | |
[Object] VisitMemberExpression([MemberExpressionAst] $memberExpressionAst) { | |
return [MemberExpressionAst]::new( | |
$memberExpressionAst.Extent, | |
$this.Visit($memberExpressionAst.Expression), | |
$this.Visit($memberExpressionAst.Member), | |
$memberExpressionAst.Static, | |
$memberExpressionAst.NullConditional) | |
} | |
[Object] VisitInvokeMemberExpression([InvokeMemberExpressionAst] $invokeMemberExpressionAst) { | |
return [InvokeMemberExpressionAst]::new( | |
$invokeMemberExpressionAst.Extent, | |
$this.Visit($invokeMemberExpressionAst.Expression), | |
$this.Visit($invokeMemberExpressionAst.Member), | |
[ExpressionAst[]]$this.VisitAll($invokeMemberExpressionAst.Arguments), | |
$invokeMemberExpressionAst.Static, | |
$invokeMemberExpressionAst.NullConditional) | |
} | |
[Object] VisitArrayExpression([ArrayExpressionAst] $arrayExpressionAst) { | |
return [ArrayExpressionAst]::new( | |
$arrayExpressionAst.Extent, | |
$this.Visit($arrayExpressionAst.SubExpression)) | |
} | |
[Object] VisitArrayLiteral([ArrayLiteralAst] $arrayLiteralAst) { | |
return [ArrayLiteralAst]::new( | |
$arrayLiteralAst.Extent, | |
[ExpressionAst[]]$this.VisitAll($arrayLiteralAst.Elements)) | |
} | |
[Object] VisitHashtable([HashtableAst] $hashtableAst) { | |
[Tuple[ExpressionAst, StatementAst][]] $clauses = foreach ($clause in $hashtableAst.KeyValuePairs) { | |
[Tuple[ExpressionAst, StatementAst]]::new( | |
$this.Visit($clause.Item1), | |
$this.Visit($clause.Item2)) | |
} | |
return [HashtableAst]::new( | |
$hashtableAst.Extent, | |
$clauses) | |
} | |
[Object] VisitScriptBlockExpression([ScriptBlockExpressionAst] $scriptBlockExpressionAst) { | |
return [ScriptBlockExpressionAst]::new( | |
$scriptBlockExpressionAst.Extent, | |
$this.Visit($scriptBlockExpressionAst.ScriptBlock)) | |
} | |
[Object] VisitParenExpression([ParenExpressionAst] $parenExpressionAst) { | |
return [ParenExpressionAst]::new( | |
$parenExpressionAst.Extent, | |
$this.Visit($parenExpressionAst.Pipeline)) | |
} | |
[Object] VisitExpandableStringExpression([ExpandableStringExpressionAst] $expandableStringExpressionAst) { | |
return $this.MakeExpandableString( | |
$expandableStringExpressionAst.Extent, | |
$expandableStringExpressionAst.Value, | |
$this.GetFormatString($expandableStringExpressionAst), | |
$expandableStringExpressionAst.StringConstantType, | |
[ExpressionAst[]]$this.VisitAll($expandableStringExpressionAst.NestedExpressions)) | |
} | |
[string] GetFormatString([ExpandableStringExpressionAst] $expandableStringExpressionAst) { | |
$flags = [BindingFlags]::Instance -bor 'NonPublic' | |
return [ExpandableStringExpressionAst]. | |
GetProperty('FormatExpression', $flags). | |
GetValue($expandableStringExpressionAst) | |
} | |
[ExpandableStringExpressionAst] MakeExpandableString( | |
[IScriptExtent] $extent, | |
[string] $value, | |
[string] $formatExpression, | |
[StringConstantType] $kind, | |
[ExpressionAst[]] $nestedExpressions) | |
{ | |
$flags = [BindingFlags]::Instance -bor 'NonPublic' | |
return [ExpandableStringExpressionAst]. | |
GetConstructor( | |
$flags, | |
([IScriptExtent], [string], [string], [StringConstantType], [IEnumerable[ExpressionAst]])). | |
Invoke(( | |
$extent, | |
$value, | |
$formatExpression, | |
$kind, | |
$nestedExpressions)) | |
} | |
[Object] VisitIndexExpression([IndexExpressionAst] $indexExpressionAst) { | |
return [IndexExpressionAst]::new( | |
$indexExpressionAst.Extent, | |
$this.Visit($indexExpressionAst.Target), | |
$this.Visit($indexExpressionAst.Index), | |
$indexExpressionAst.NullConditional) | |
} | |
[Object] VisitAttributedExpression([AttributedExpressionAst] $attributedExpressionAst) { | |
return [AttributedExpressionAst]::new( | |
$attributedExpressionAst.Extent, | |
$this.Visit($attributedExpressionAst.Attribute), | |
$this.Visit($attributedExpressionAst.Child)) | |
} | |
[Object] VisitBlockStatement([BlockStatementAst] $blockStatementAst) { | |
return [BlockStatementAst]::new( | |
$blockStatementAst.Extent, | |
$blockStatementAst.Kind, | |
$this.Visit($blockStatementAst.Body)) | |
} | |
} | |
class DelegateSyntaxRebuilder : AstRebuilder { | |
hidden static [Reflection.MethodInfo] $s_getSessionStateInternal | |
hidden static [Reflection.MethodInfo] $s_setSessionStateInternal | |
hidden [bool] $_alreadyDone | |
[bool] $IsNotLambda | |
static DelegateSyntaxRebuilder() { | |
$property = [scriptblock].GetProperty('SessionStateInternal', [Reflection.BindingFlags]::Instance -bor 'NonPublic') | |
[DelegateSyntaxRebuilder]::s_getSessionStateInternal = $property.GetGetMethod($true) | |
[DelegateSyntaxRebuilder]::s_setSessionStateInternal = $property.GetSetMethod($true) | |
} | |
static [scriptblock] ConvertFromLambda([scriptblock] $source) { | |
$visitor = [DelegateSyntaxRebuilder]::new() | |
$result = $source.Ast.Visit($visitor) | |
if ($visitor.IsNotLambda) { | |
return $source | |
} | |
$result = $result.GetScriptBlock() | |
[DelegateSyntaxRebuilder]::s_setSessionStateInternal.Invoke( | |
$result, | |
@([DelegateSyntaxRebuilder]::s_getSessionStateInternal.Invoke($source, @()))) | |
return $result | |
} | |
[object] VisitScriptBlock([ScriptBlockAst] $scriptBlockAst) { | |
if ($this._alreadyDone) { | |
return ([AstRebuilder]$this).VisitScriptBlock($scriptBlockAst) | |
} | |
$this._alreadyDone = $true | |
$this.IsNotLambda = $scriptBlockAst.ParamBlock -or | |
$scriptBlockAst.EndBlock.Statements[0] -isnot [AssignmentStatementAst] -or | |
$scriptBlockAst.EndBlock.Statements[0].Right -isnot [PipelineAst] -or | |
$scriptBlockAst.EndBlock.Statements[0].Right.PipelineElements[0] -isnot [CommandAst] -or | |
$scriptBlockAst.EndBlock.Statements[0].Right.PipelineElements[0].CommandElements[0].Value -ne '>' | |
if ($this.IsNotLambda) { | |
return $scriptBlockAst | |
} | |
$params = $scriptBlockAst.EndBlock.Statements[0].Left | |
if ($params -is [ParenExpressionAst]) { | |
$params = $params.Pipeline.PipelineElements[0].Expression | |
} | |
if ($params -is [ArrayLiteralAst]) { | |
$params = $params.Elements | |
} | |
$params = foreach ($param in $params) { | |
[ParameterAst]::new( | |
$param.Extent, | |
$this.Visit($param), | |
[AttributeBaseAst[]]@(), | |
$null) | |
} | |
$paramBlock = [ParamBlockAst]::new( | |
$scriptBlockAst.EndBlock.Statements[0].Left.Extent, | |
[AttributeAst[]]@(), | |
[ParameterAst[]]$params) | |
for ($parent = $scriptBlockAst; $null -ne $parent; $parent = $parent.Parent) { } | |
$commandElements = $scriptBlockAst.EndBlock.Statements[0].Right.PipelineElements[0].CommandElements | |
if ($commandElements.Count -gt 2 -or $commandElements[1].StringConstantType -eq 'BareWord') { | |
throw [ParseException]::new( | |
[ParseError]::new( | |
$commandElements[$commandElements.Count -gt 2 ? 2 : 1].Extent, | |
'UnexpectedElementInLambda', | |
'Expressions more complex than a member expression or variable expression must be wrapped in a scriptblock. e.g. $x, $y => { $x + $y }')) | |
} | |
$firstCommandElement = $this.Visit($scriptBlockAst.EndBlock.Statements[0].Right.PipelineElements[0].CommandElements[1]) | |
$newEndBlock = $null | |
if ($firstCommandElement.ScriptBlock) { | |
$newEndBlock = $this.Visit($firstCommandElement.ScriptBlock.EndBlock) | |
} else { | |
$newEndBlock = [NamedBlockAst]::new( | |
$firstCommandElement.Extent, | |
[TokenKind]::End, | |
[StatementBlockAst]::new( | |
$firstCommandElement.Extent, | |
[StatementAst[]]( | |
[PipelineAst]::new( | |
$firstCommandElement.Extent, | |
[CommandExpressionAst]::new( | |
$firstCommandElement.Extent, | |
$this.Visit($firstCommandElement), | |
[RedirectionAst[]]@()))), | |
[TrapStatementAst[]]@()), | |
<# unnamed: #> $true) | |
} | |
return [ScriptBlockAst]::new( | |
$scriptBlockAst.Extent, | |
[UsingStatementAst[]]$this.VisitAll($parent.UsingStatements), | |
$paramBlock, | |
$null, | |
$null, | |
$newEndBlock, | |
$null) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
the world deserves this :)