Browse Source

Add ILAst base for Deconstruction and Pattern Matching

pull/2119/head
Siegfried Pammer 5 years ago
parent
commit
95f2ae7aef
  1. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/DeclarationExpression.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/Syntax/VariableDesignation.cs
  3. 5
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 256
      ICSharpCode.Decompiler/IL/Instructions.cs
  5. 19
      ICSharpCode.Decompiler/IL/Instructions.tt
  6. 190
      ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs
  7. 44
      ICSharpCode.Decompiler/IL/Instructions/DeconstructResultInstruction.cs
  8. 5
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  9. 76
      ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/DeclarationExpression.cs

@ -31,8 +31,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -31,8 +31,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
public VariableDesignation Designation {
get { return GetChildByRole(VariableDesignation.Role); }
set { SetChildByRole(VariableDesignation.Role, value); }
get { return GetChildByRole(VariableDesignation.VariableDesignationRole); }
set { SetChildByRole(VariableDesignation.VariableDesignationRole, value); }
}
public override void AcceptVisitor(IAstVisitor visitor)

4
ICSharpCode.Decompiler/CSharp/Syntax/VariableDesignation.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public abstract class VariableDesignation : AstNode
{
public static Role<VariableDesignation> Role = new Role<VariableDesignation>("VariableDesignation");
public static Role<VariableDesignation> VariableDesignationRole = new Role<VariableDesignation>("VariableDesignation");
}
/// <summary>
@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
public AstNodeCollection<VariableDesignation> VariableDesignations {
get { return GetChildrenByRole(VariableDesignation.Role); }
get { return GetChildrenByRole(VariableDesignation.VariableDesignationRole); }
}
public CSharpTokenNode RParToken {

5
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -70,10 +70,13 @@ @@ -70,10 +70,13 @@
<Compile Include="CSharp\SequencePointBuilder.cs" />
<Compile Include="CSharp\ProjectDecompiler\TargetFramework.cs" />
<Compile Include="CSharp\ProjectDecompiler\TargetServices.cs" />
<Compile Include="CSharp\Syntax\DeclarationExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\DeclarationExpression.cs" />
<Compile Include="CSharp\Syntax\FunctionPointerType.cs" />
<Compile Include="CSharp\Syntax\VariableDesignation.cs" />
<Compile Include="IL\Transforms\FixLoneIsInst.cs" />
<Compile Include="IL\Instructions\DeconstructInstruction.cs" />
<Compile Include="IL\Instructions\DeconstructResultInstruction.cs" />
<Compile Include="IL\Instructions\MatchInstruction.cs" />
<Compile Include="IL\Transforms\IndexRangeTransform.cs" />
<Compile Include="CSharp\TranslatedStatement.cs" />
<Compile Include="DebugInfo\KnownGuids.cs" />

256
ICSharpCode.Decompiler/IL/Instructions.cs

@ -220,6 +220,8 @@ namespace ICSharpCode.Decompiler.IL @@ -220,6 +220,8 @@ namespace ICSharpCode.Decompiler.IL
DynamicInvokeInstruction,
/// <summary>ILAst representation of a call to the Binder.IsEvent method inside a dynamic expression.</summary>
DynamicIsEventInstruction,
/// <summary>ILAst representation of C# patterns</summary>
MatchInstruction,
/// <summary>Push a typed reference of type class onto the stack.</summary>
MakeRefAny,
/// <summary>Push the type token stored in a typed reference.</summary>
@ -230,6 +232,10 @@ namespace ICSharpCode.Decompiler.IL @@ -230,6 +232,10 @@ namespace ICSharpCode.Decompiler.IL
YieldReturn,
/// <summary>C# await operator.</summary>
Await,
/// <summary>Deconstruction statement</summary>
DeconstructInstruction,
/// <summary>Represents a deconstructed value</summary>
DeconstructResultInstruction,
/// <summary>Matches any node</summary>
AnyNode,
}
@ -6084,6 +6090,147 @@ namespace ICSharpCode.Decompiler.IL @@ -6084,6 +6090,147 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>ILAst representation of C# patterns</summary>
public sealed partial class MatchInstruction : ILInstruction, IStoreInstruction, IInstructionWithMethodOperand
{
public MatchInstruction(ILVariable variable, IMethod method, ILInstruction testedOperand, params ILInstruction[] subPatterns) : base(OpCode.MatchInstruction)
{
Debug.Assert(variable != null);
this.variable = variable;
this.method = method;
this.TestedOperand = testedOperand;
this.SubPatterns = new InstructionCollection<ILInstruction>(this, 1);
this.SubPatterns.AddRange(subPatterns);
}
ILVariable variable;
public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
if (IsConnected)
variable.RemoveStoreInstruction(this);
variable = value;
if (IsConnected)
variable.AddStoreInstruction(this);
}
}
public int IndexInStoreInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IStoreInstruction)this).IndexInStoreInstructionList; }
set { ((IStoreInstruction)this).IndexInStoreInstructionList = value; }
}
protected override void Connected()
{
base.Connected();
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.RemoveStoreInstruction(this);
base.Disconnected();
}
readonly IMethod method;
/// <summary>Returns the method operand.</summary>
public IMethod Method { get { return method; } }
public bool Deconstruct;
public bool MatchType;
public bool MatchesNull;
public static readonly SlotInfo TestedOperandSlot = new SlotInfo("TestedOperand", canInlineInto: true);
ILInstruction testedOperand;
public ILInstruction TestedOperand {
get { return this.testedOperand; }
set {
ValidateChild(value);
SetChildInstruction(ref this.testedOperand, value, 0);
}
}
public static readonly SlotInfo SubPatternsSlot = new SlotInfo("SubPatterns");
public InstructionCollection<ILInstruction> SubPatterns { get; private set; }
protected sealed override int GetChildCount()
{
return 1 + SubPatterns.Count;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.testedOperand;
default:
return this.SubPatterns[index - 1];
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.TestedOperand = value;
break;
default:
this.SubPatterns[index - 1] = (ILInstruction)value;
break;
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return TestedOperandSlot;
default:
return SubPatternsSlot;
}
}
public sealed override ILInstruction Clone()
{
var clone = (MatchInstruction)ShallowClone();
clone.TestedOperand = this.testedOperand.Clone();
clone.SubPatterns = new InstructionCollection<ILInstruction>(clone, 1);
clone.SubPatterns.AddRange(this.SubPatterns.Select(arg => (ILInstruction)arg.Clone()));
return clone;
}
public override StackType ResultType { get { return StackType.I4; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayWriteLocals | testedOperand.Flags | SubPatterns.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.SideEffect | InstructionFlags.MayThrow | InstructionFlags.ControlFlow;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayWriteLocals | InstructionFlags.SideEffect | InstructionFlags.MayThrow | InstructionFlags.ControlFlow;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitMatchInstruction(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitMatchInstruction(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitMatchInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as MatchInstruction;
return o != null && variable == o.variable && object.Equals(method, o.method) && this.Deconstruct == o.Deconstruct && this.MatchType == o.MatchType && this.MatchesNull == o.MatchesNull && this.testedOperand.PerformMatch(o.testedOperand, ref match) && Patterns.ListMatch.DoMatch(this.SubPatterns, o.SubPatterns, ref match);
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
Debug.Assert(phase <= ILPhase.InILReader || variable.Function.Variables[variable.IndexInFunction] == variable);
Debug.Assert(testedOperand.ResultType == StackType.O);
AdditionalInvariants();
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Push a typed reference of type class onto the stack.</summary>
public sealed partial class MakeRefAny : UnaryInstruction
@ -6396,6 +6543,62 @@ namespace ICSharpCode.Decompiler.IL @@ -6396,6 +6543,62 @@ namespace ICSharpCode.Decompiler.IL
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Deconstruction statement</summary>
public sealed partial class DeconstructInstruction : ILInstruction
{
public override StackType ResultType { get { return StackType.O; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitDeconstructInstruction(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitDeconstructInstruction(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitDeconstructInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DeconstructInstruction;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Represents a deconstructed value</summary>
public sealed partial class DeconstructResultInstruction : UnaryInstruction
{
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return type.GetStackType(); } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitDeconstructResultInstruction(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitDeconstructResultInstruction(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitDeconstructResultInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DeconstructResultInstruction;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL.Patterns
{
/// <summary>Matches any node</summary>
@ -6807,6 +7010,10 @@ namespace ICSharpCode.Decompiler.IL @@ -6807,6 +7010,10 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitMatchInstruction(MatchInstruction inst)
{
Default(inst);
}
protected internal virtual void VisitMakeRefAny(MakeRefAny inst)
{
Default(inst);
@ -6827,6 +7034,14 @@ namespace ICSharpCode.Decompiler.IL @@ -6827,6 +7034,14 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitDeconstructInstruction(DeconstructInstruction inst)
{
Default(inst);
}
protected internal virtual void VisitDeconstructResultInstruction(DeconstructResultInstruction inst)
{
Default(inst);
}
}
/// <summary>
@ -7193,6 +7408,10 @@ namespace ICSharpCode.Decompiler.IL @@ -7193,6 +7408,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitMatchInstruction(MatchInstruction inst)
{
return Default(inst);
}
protected internal virtual T VisitMakeRefAny(MakeRefAny inst)
{
return Default(inst);
@ -7213,6 +7432,14 @@ namespace ICSharpCode.Decompiler.IL @@ -7213,6 +7432,14 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitDeconstructInstruction(DeconstructInstruction inst)
{
return Default(inst);
}
protected internal virtual T VisitDeconstructResultInstruction(DeconstructResultInstruction inst)
{
return Default(inst);
}
}
/// <summary>
@ -7579,6 +7806,10 @@ namespace ICSharpCode.Decompiler.IL @@ -7579,6 +7806,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitMatchInstruction(MatchInstruction inst, C context)
{
return Default(inst, context);
}
protected internal virtual T VisitMakeRefAny(MakeRefAny inst, C context)
{
return Default(inst, context);
@ -7599,6 +7830,14 @@ namespace ICSharpCode.Decompiler.IL @@ -7599,6 +7830,14 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitDeconstructInstruction(DeconstructInstruction inst, C context)
{
return Default(inst, context);
}
protected internal virtual T VisitDeconstructResultInstruction(DeconstructResultInstruction inst, C context)
{
return Default(inst, context);
}
}
partial class InstructionOutputExtensions
@ -7693,11 +7932,14 @@ namespace ICSharpCode.Decompiler.IL @@ -7693,11 +7932,14 @@ namespace ICSharpCode.Decompiler.IL
"dynamic.invokeconstructor",
"dynamic.invoke",
"dynamic.isevent",
"match",
"mkrefany",
"refanytype",
"refanyval",
"yield.return",
"await",
"deconstruct",
"deconstruct.result",
"AnyNode",
};
}
@ -8254,6 +8496,20 @@ namespace ICSharpCode.Decompiler.IL @@ -8254,6 +8496,20 @@ namespace ICSharpCode.Decompiler.IL
right = default(ILInstruction);
return false;
}
public bool MatchMatchInstruction(out ILVariable variable, out IMethod method, out ILInstruction testedOperand)
{
var inst = this as MatchInstruction;
if (inst != null) {
variable = inst.Variable;
method = inst.Method;
testedOperand = inst.TestedOperand;
return true;
}
variable = default(ILVariable);
method = default(IMethod);
testedOperand = default(ILInstruction);
return false;
}
public bool MatchMakeRefAny(out ILInstruction argument, out IType type)
{
var inst = this as MakeRefAny;

19
ICSharpCode.Decompiler/IL/Instructions.tt

@ -334,6 +334,13 @@ @@ -334,6 +334,13 @@
new OpCode("dynamic.isevent", "ILAst representation of a call to the Binder.IsEvent method inside a dynamic expression.",
CustomClassName("DynamicIsEventInstruction"), Dynamic, CustomArguments(("argument", new[] { "O" })), CustomWriteTo),
new OpCode("match", "ILAst representation of C# patterns",
CustomClassName("MatchInstruction"), HasVariableOperand("Store"), HasMethodOperand,
BoolFlag("Deconstruct"), BoolFlag("MatchType"), BoolFlag("MatchesNull"),
CustomChildren(new []{
new ChildInfo("testedOperand") { CanInlineInto = true, ExpectedTypes = new[] { "O" } },
new ChildInfo("subPatterns") { IsCollection = true }
}), ResultType("I4"), CustomWriteTo, SideEffect, MayThrow, ControlFlow, CustomInvariant("AdditionalInvariants();")),
new OpCode("mkrefany", "Push a typed reference of type class onto the stack.",
CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")),
@ -351,6 +358,11 @@ @@ -351,6 +358,11 @@
SideEffect, // other code can run with arbitrary side effects while we're waiting
CustomArguments(("value", null)), ResultType("GetResultMethod?.ReturnType.GetStackType() ?? StackType.Unknown")),
new OpCode("deconstruct", "Deconstruction statement",
CustomClassName("DeconstructInstruction"), CustomConstructor, ResultType("O"), CustomWriteTo),
new OpCode("deconstruct.result", "Represents a deconstructed value",
CustomClassName("DeconstructResultInstruction"), CustomConstructor, Unary, HasTypeOperand, ResultType("type.GetStackType()"), CustomWriteTo),
// patterns
new OpCode("AnyNode", "Matches any node", Pattern, CustomArguments(), CustomConstructor),
};
@ -1167,6 +1179,13 @@ protected override void Disconnected() @@ -1167,6 +1179,13 @@ protected override void Disconnected()
};
}
static Action<OpCode> CustomInvariant(string code)
{
return opCode => {
opCode.Invariants.Add(code);
};
}
static Action<OpCode> Pattern = opCode => {
BaseClass("PatternInstruction")(opCode);
opCode.Namespace = "ICSharpCode.Decompiler.IL.Patterns";

190
ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs

@ -0,0 +1,190 @@ @@ -0,0 +1,190 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.Decompiler.IL
{
partial class DeconstructInstruction
{
public static readonly SlotInfo InitSlot = new SlotInfo("Init", canInlineInto: true, isCollection: true);
public static readonly SlotInfo DeconstructSlot = new SlotInfo("Deconstruct", canInlineInto: true);
public static readonly SlotInfo ConversionsSlot = new SlotInfo("Conversions");
public static readonly SlotInfo AssignmentsSlot = new SlotInfo("Assignments");
public DeconstructInstruction()
: base(OpCode.DeconstructInstruction)
{
this.Init = new InstructionCollection<StLoc>(this, 0);
}
public readonly InstructionCollection<StLoc> Init;
ILInstruction deconstruct;
public ILInstruction Deconstruct {
get { return this.deconstruct; }
set {
ValidateChild(value);
SetChildInstruction(ref this.deconstruct, value, Init.Count);
}
}
Block conversions;
public Block Conversions {
get { return this.conversions; }
set {
ValidateChild(value);
SetChildInstruction(ref this.conversions, value, Init.Count + 1);
}
}
Block assignments;
public Block Assignments {
get { return this.assignments; }
set {
ValidateChild(value);
SetChildInstruction(ref this.assignments, value, Init.Count + 2);
}
}
protected sealed override int GetChildCount()
{
return Init.Count + 3;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index - Init.Count) {
case 0:
return this.deconstruct;
case 1:
return this.conversions;
case 2:
return this.assignments;
default:
return this.Init[index];
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index - Init.Count) {
case 0:
this.Deconstruct = value;
break;
case 1:
this.Conversions = (Block)value;
break;
case 2:
this.Assignments = (Block)value;
break;
default:
this.Init[index] = (StLoc)value;
break;
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index - Init.Count) {
case 0:
return DeconstructSlot;
case 1:
return ConversionsSlot;
case 2:
return AssignmentsSlot;
default:
return InitSlot;
}
}
public sealed override ILInstruction Clone()
{
var clone = new DeconstructInstruction();
clone.Init.AddRange(this.Init.Select(inst => (StLoc)inst.Clone()));
clone.Deconstruct = this.deconstruct.Clone();
clone.Conversions = (Block)this.conversions.Clone();
clone.Assignments = (Block)this.assignments.Clone();
return clone;
}
protected override InstructionFlags ComputeFlags()
{
var flags = InstructionFlags.None;
foreach (var inst in Init) {
flags |= inst.Flags;
}
flags |= deconstruct.Flags | conversions.Flags | assignments.Flags;
return flags;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.None;
}
}
protected internal override void InstructionCollectionUpdateComplete()
{
base.InstructionCollectionUpdateComplete();
if (deconstruct.Parent == this)
deconstruct.ChildIndex = Init.Count;
if (conversions.Parent == this)
conversions.ChildIndex = Init.Count + 1;
if (assignments.Parent == this)
assignments.ChildIndex = Init.Count + 2;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
WriteILRange(output, options);
output.Write("deconstruct");
output.MarkFoldStart("{...}");
output.WriteLine("{");
output.Indent();
output.WriteLine("init:");
output.Indent();
foreach (var inst in this.Init) {
inst.WriteTo(output, options);
output.WriteLine();
}
output.Unindent();
output.WriteLine("deconstruct:");
output.Indent();
deconstruct.WriteTo(output, options);
output.Unindent();
output.Write("conversions:");
conversions.WriteTo(output, options);
output.Write("assignments: ");
assignments.WriteTo(output, options);
output.Unindent();
output.Write('}');
output.MarkFoldEnd();
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
foreach (var init in this.Init) {
Debug.Assert(init.Variable.IsSingleDefinition && init.Variable.LoadCount == 1);
Debug.Assert(init.Variable.LoadInstructions[0].IsDescendantOf(assignments));
}
}
}
}

44
ICSharpCode.Decompiler/IL/Instructions/DeconstructResultInstruction.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace ICSharpCode.Decompiler.IL
{
partial class DeconstructResultInstruction
{
public int Index { get; set; }
public DeconstructResultInstruction(int index, ILInstruction argument)
: base(OpCode.DeconstructResultInstruction, argument)
{
Index = index;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
output.Write(' ');
output.Write(Index.ToString());
output.Write('(');
this.Argument.WriteTo(output, options);
output.Write(')');
}
}
}

5
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -632,9 +632,10 @@ namespace ICSharpCode.Decompiler.IL @@ -632,9 +632,10 @@ namespace ICSharpCode.Decompiler.IL
/// <param name="childPointer">Reference to the field holding the child</param>
/// <param name="newValue">New child</param>
/// <param name="index">Index of the field in the Children collection</param>
protected internal void SetChildInstruction(ref ILInstruction childPointer, ILInstruction newValue, int index)
protected internal void SetChildInstruction<T>(ref T childPointer, T newValue, int index)
where T : ILInstruction
{
ILInstruction oldValue = childPointer;
T oldValue = childPointer;
Debug.Assert(oldValue == GetChild(index));
if (oldValue == newValue && newValue?.parent == this && newValue.ChildIndex == index)
return;

76
ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Diagnostics;
namespace ICSharpCode.Decompiler.IL
{
partial class MatchInstruction : ILInstruction
{
public bool IsPattern(ILInstruction inst, out ILInstruction testedOperand)
{
switch (inst) {
case MatchInstruction m:
testedOperand = m.testedOperand;
return true;
case Comp comp:
testedOperand = comp.Left;
return IsConstant(comp.Right);
case ILInstruction logicNot when logicNot.MatchLogicNot(out var operand):
return IsPattern(operand, out testedOperand);
default:
testedOperand = null;
return false;
}
}
private static bool IsConstant(ILInstruction inst)
{
return inst.OpCode switch
{
OpCode.LdcDecimal => true,
OpCode.LdcF4 => true,
OpCode.LdcF8 => true,
OpCode.LdcI4 => true,
OpCode.LdcI8 => true,
OpCode.LdNull => true,
_ => false
};
}
void AdditionalInvariants()
{
foreach (var subPattern in SubPatterns) {
ILInstruction operand;
Debug.Assert(IsPattern(subPattern, out operand));
}
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
output.Write('(');
Variable.WriteTo(output);
output.Write(" = ");
TestedOperand.WriteTo(output, options);
output.Write(')');
}
}
}
Loading…
Cancel
Save