mirror of https://github.com/icsharpcode/ILSpy.git
31 changed files with 1237 additions and 245 deletions
@ -1,103 +0,0 @@
@@ -1,103 +0,0 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
using Mono.Cecil; |
||||
|
||||
namespace ICSharpCode.Decompiler.ILAst |
||||
{ |
||||
/// <summary>
|
||||
/// IL AST transformation that introduces array initializers.
|
||||
/// </summary>
|
||||
public static class ArrayInitializers |
||||
{ |
||||
public static PeepholeTransform Transform(ILBlock method) |
||||
{ |
||||
var newArrPattern = new StoreToVariable(new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand))); |
||||
var arg1 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true }; |
||||
var arg2 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true }; |
||||
var initializeArrayPattern = new ILCall( |
||||
"System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray", |
||||
new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand)); |
||||
|
||||
return delegate(ILBlock block, ref int i) { |
||||
if (!newArrPattern.Match(block.Body[i])) |
||||
return; |
||||
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0]; |
||||
int arrayLength = (int)newArrInst.Arguments[0].Operand; |
||||
if (arrayLength == 0) |
||||
return; |
||||
if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) { |
||||
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) { |
||||
if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) { |
||||
i -= new ILInlining(method).InlineInto(block, i + 1) - 1; |
||||
} |
||||
return; |
||||
} |
||||
} |
||||
if (i + 1 + arrayLength > block.Body.Count) |
||||
return; |
||||
List<ILExpression> operands = new List<ILExpression>(); |
||||
for (int j = 0; j < arrayLength; j++) { |
||||
ILExpression expr = block.Body[i + 1 + j] as ILExpression; |
||||
if (expr == null || !IsStoreToArray(expr.Code)) |
||||
break; |
||||
if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable)) |
||||
break; |
||||
if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j)) |
||||
break; |
||||
operands.Add(expr.Arguments[2]); |
||||
} |
||||
if (operands.Count == arrayLength) { |
||||
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression( |
||||
ILCode.InitArray, newArrInst.Operand, operands.ToArray()); |
||||
block.Body.RemoveRange(i + 1, arrayLength); |
||||
i -= new ILInlining(method).InlineInto(block, i + 1) - 1; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
static bool IsStoreToArray(ILCode code) |
||||
{ |
||||
switch (code) { |
||||
case ILCode.Stelem_Any: |
||||
case ILCode.Stelem_I: |
||||
case ILCode.Stelem_I1: |
||||
case ILCode.Stelem_I2: |
||||
case ILCode.Stelem_I4: |
||||
case ILCode.Stelem_I8: |
||||
case ILCode.Stelem_R4: |
||||
case ILCode.Stelem_R8: |
||||
case ILCode.Stelem_Ref: |
||||
return true; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
static bool HandleStaticallyInitializedArray(StoreToVariable arg2, ILBlock block, int i, ILExpression newArrInst, int arrayLength) |
||||
{ |
||||
FieldDefinition field = ((ILExpression)block.Body[i + 3]).Arguments[1].Operand as FieldDefinition; |
||||
if (field == null || field.InitialValue == null) |
||||
return false; |
||||
switch (TypeAnalysis.GetTypeCode(newArrInst.Operand as TypeReference)) { |
||||
case TypeCode.Int32: |
||||
case TypeCode.UInt32: |
||||
if (field.InitialValue.Length == arrayLength * 4) { |
||||
ILExpression[] newArr = new ILExpression[arrayLength]; |
||||
for (int j = 0; j < newArr.Length; j++) { |
||||
newArr[j] = new ILExpression(ILCode.Ldc_I4, BitConverter.ToInt32(field.InitialValue, j * 4)); |
||||
} |
||||
block.Body[i] = new ILExpression(ILCode.Stloc, arg2.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr)); |
||||
block.Body.RemoveRange(i + 1, 3); |
||||
return true; |
||||
} |
||||
break; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,213 @@
@@ -0,0 +1,213 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
using Mono.Cecil; |
||||
|
||||
namespace ICSharpCode.Decompiler.ILAst |
||||
{ |
||||
/// <summary>
|
||||
/// IL AST transformation that introduces array, object and collection initializers.
|
||||
/// </summary>
|
||||
public class InitializerPeepholeTransforms |
||||
{ |
||||
readonly ILBlock method; |
||||
|
||||
#region Array Initializers
|
||||
StoreToVariable newArrPattern; |
||||
ILCall initializeArrayPattern; |
||||
|
||||
public InitializerPeepholeTransforms(ILBlock method) |
||||
{ |
||||
this.method = method; |
||||
newArrPattern = new StoreToVariable(new ILExpression( |
||||
ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand))); |
||||
initializeArrayPattern = new ILCall( |
||||
"System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray", |
||||
new LoadFromVariable(newArrPattern), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand)); |
||||
} |
||||
|
||||
public void TransformArrayInitializers(ILBlock block, ref int i) |
||||
{ |
||||
if (!newArrPattern.Match(block.Body[i])) |
||||
return; |
||||
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0]; |
||||
int arrayLength = (int)newArrInst.Arguments[0].Operand; |
||||
if (arrayLength == 0) |
||||
return; |
||||
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 1))) { |
||||
if (HandleStaticallyInitializedArray(newArrPattern, block, i, newArrInst, arrayLength)) { |
||||
i -= new ILInlining(method).InlineInto(block, i + 1, aggressive: true) - 1; |
||||
} |
||||
return; |
||||
} |
||||
List<ILExpression> operands = new List<ILExpression>(); |
||||
int numberOfInstructionsToRemove = 0; |
||||
for (int j = i + 1; j < block.Body.Count; j++) { |
||||
ILExpression expr = block.Body[j] as ILExpression; |
||||
if (expr == null || !IsStoreToArray(expr.Code)) |
||||
break; |
||||
if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable)) |
||||
break; |
||||
if (expr.Arguments[1].Code != ILCode.Ldc_I4) |
||||
break; |
||||
int pos = (int)expr.Arguments[1].Operand; |
||||
const int maxConsecutiveDefaultValueExpressions = 10; |
||||
if (pos < operands.Count || pos > operands.Count + maxConsecutiveDefaultValueExpressions) |
||||
break; |
||||
while (operands.Count < pos) |
||||
operands.Add(new ILExpression(ILCode.DefaultValue, newArrInst.Operand)); |
||||
operands.Add(expr.Arguments[2]); |
||||
numberOfInstructionsToRemove++; |
||||
} |
||||
if (operands.Count == arrayLength) { |
||||
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression( |
||||
ILCode.InitArray, newArrInst.Operand, operands.ToArray()); |
||||
block.Body.RemoveRange(i + 1, numberOfInstructionsToRemove); |
||||
i -= new ILInlining(method).InlineInto(block, i + 1, aggressive: true) - 1; |
||||
} |
||||
} |
||||
|
||||
static bool IsStoreToArray(ILCode code) |
||||
{ |
||||
switch (code) { |
||||
case ILCode.Stelem_Any: |
||||
case ILCode.Stelem_I: |
||||
case ILCode.Stelem_I1: |
||||
case ILCode.Stelem_I2: |
||||
case ILCode.Stelem_I4: |
||||
case ILCode.Stelem_I8: |
||||
case ILCode.Stelem_R4: |
||||
case ILCode.Stelem_R8: |
||||
case ILCode.Stelem_Ref: |
||||
return true; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
static bool HandleStaticallyInitializedArray(StoreToVariable newArrPattern, ILBlock block, int i, ILExpression newArrInst, int arrayLength) |
||||
{ |
||||
FieldDefinition field = ((ILExpression)block.Body[i + 1]).Arguments[1].Operand as FieldDefinition; |
||||
if (field == null || field.InitialValue == null) |
||||
return false; |
||||
ILExpression[] newArr = new ILExpression[arrayLength]; |
||||
if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(newArrInst.Operand as TypeReference), field.InitialValue, newArr)) { |
||||
block.Body[i] = new ILExpression(ILCode.Stloc, newArrPattern.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr)); |
||||
block.Body.RemoveAt(i + 1); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
static bool DecodeArrayInitializer(TypeCode elementType, byte[] initialValue, ILExpression[] output) |
||||
{ |
||||
switch (elementType) { |
||||
case TypeCode.Boolean: |
||||
case TypeCode.SByte: |
||||
case TypeCode.Byte: |
||||
if (initialValue.Length == output.Length) { |
||||
for (int j = 0; j < output.Length; j++) { |
||||
output[j] = new ILExpression(ILCode.Ldc_I4, (int)initialValue[j]); |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
case TypeCode.Char: |
||||
case TypeCode.Int16: |
||||
case TypeCode.UInt16: |
||||
if (initialValue.Length == output.Length * 2) { |
||||
for (int j = 0; j < output.Length; j++) { |
||||
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToInt16(initialValue, j * 2)); |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
case TypeCode.Int32: |
||||
case TypeCode.UInt32: |
||||
if (initialValue.Length == output.Length * 4) { |
||||
for (int j = 0; j < output.Length; j++) { |
||||
output[j] = new ILExpression(ILCode.Ldc_I4, BitConverter.ToInt32(initialValue, j * 4)); |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
case TypeCode.Int64: |
||||
case TypeCode.UInt64: |
||||
if (initialValue.Length == output.Length * 8) { |
||||
for (int j = 0; j < output.Length; j++) { |
||||
output[j] = new ILExpression(ILCode.Ldc_I8, BitConverter.ToInt64(initialValue, j * 8)); |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
case TypeCode.Single: |
||||
if (initialValue.Length == output.Length * 4) { |
||||
for (int j = 0; j < output.Length; j++) { |
||||
output[j] = new ILExpression(ILCode.Ldc_R4, BitConverter.ToSingle(initialValue, j * 4)); |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
case TypeCode.Double: |
||||
if (initialValue.Length == output.Length * 8) { |
||||
for (int j = 0; j < output.Length; j++) { |
||||
output[j] = new ILExpression(ILCode.Ldc_R8, BitConverter.ToDouble(initialValue, j * 8)); |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region Collection Initilializers
|
||||
public void TransformCollectionInitializers(ILBlock block, ref int i) |
||||
{ |
||||
ILVariable v; |
||||
ILExpression expr; |
||||
if (!block.Body[i].Match(ILCode.Stloc, out v, out expr) || expr.Code != ILCode.Newobj) |
||||
return; |
||||
MethodReference ctor = (MethodReference)expr.Operand; |
||||
TypeDefinition td = ctor.DeclaringType.Resolve(); |
||||
if (td == null || !td.Interfaces.Any(intf => intf.Name == "IEnumerable" && intf.Namespace == "System.Collections")) |
||||
return; |
||||
// This is a collection: we can convert Add() calls into a collection initializer
|
||||
ILExpression collectionInitializer = new ILExpression(ILCode.InitCollection, null, expr); |
||||
for (int j = i + 1; j < block.Body.Count; j++) { |
||||
MethodReference addMethod; |
||||
List<ILExpression> args; |
||||
if (!block.Body[j].Match(ILCode.Callvirt, out addMethod, out args)) |
||||
break; |
||||
if (addMethod.Name != "Add" || !addMethod.HasThis || args.Count < 2 || args[0].Code != ILCode.Ldloc || args[0].Operand != v) |
||||
break; |
||||
collectionInitializer.Arguments.Add((ILExpression)block.Body[j]); |
||||
} |
||||
// ensure we added at least one additional arg to the collection initializer:
|
||||
if (collectionInitializer.Arguments.Count == 1) |
||||
return; |
||||
ILInlining inline = new ILInlining(method); |
||||
ILExpression followingExpr = block.Body.ElementAtOrDefault(i + collectionInitializer.Arguments.Count) as ILExpression; |
||||
if (inline.CanInlineInto(followingExpr, v, collectionInitializer)) { |
||||
block.Body.RemoveRange(i + 1, collectionInitializer.Arguments.Count - 1); |
||||
((ILExpression)block.Body[i]).Arguments[0] = collectionInitializer; |
||||
|
||||
// Change add methods into InitCollectionAddMethod:
|
||||
for (int j = 1; j < collectionInitializer.Arguments.Count; j++) { |
||||
collectionInitializer.Arguments[j].Arguments.RemoveAt(0); |
||||
collectionInitializer.Arguments[j].Code = ILCode.InitCollectionAddMethod; |
||||
} |
||||
|
||||
inline = new ILInlining(method); // refresh variable usage info
|
||||
if (inline.InlineIfPossible(block, ref i)) |
||||
i++; // retry transformations on the new combined instruction
|
||||
} |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
||||
@ -1,36 +0,0 @@
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
|
||||
public class ArrayInitializers |
||||
{ |
||||
// Helper methods used to ensure array initializers used within expressions work correctly
|
||||
static void X(object a, object b) |
||||
{ |
||||
} |
||||
|
||||
static object Y() |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
public static void Array1() |
||||
{ |
||||
X(Y(), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
||||
} |
||||
|
||||
public static void Array2(int a, int b, int c) |
||||
{ |
||||
X(Y(), new int[] { a, b, c }); |
||||
} |
||||
|
||||
public static void NestedArray(int a, int b, int c) |
||||
{ |
||||
X(Y(), new int[][] { |
||||
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, |
||||
new int[] { a, b, c }, |
||||
new int[] { 1, 2, 3, 4, 5, 6 } |
||||
}); |
||||
} |
||||
} |
||||
@ -0,0 +1,118 @@
@@ -0,0 +1,118 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
public class InitializerTests |
||||
{ |
||||
// Helper methods used to ensure initializers used within expressions work correctly
|
||||
static void X(object a, object b) |
||||
{ |
||||
} |
||||
|
||||
static object Y() |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
#region Array Initializers
|
||||
public static void Array1() |
||||
{ |
||||
X(Y(), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
||||
} |
||||
|
||||
public static void Array2(int a, int b, int c) |
||||
{ |
||||
X(Y(), new int[] { a, 0, b, 0, c }); |
||||
} |
||||
|
||||
public static void NestedArray(int a, int b, int c) |
||||
{ |
||||
X(Y(), new int[][] { |
||||
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, |
||||
new int[] { a, b, c }, |
||||
new int[] { 1, 2, 3, 4, 5, 6 } |
||||
}); |
||||
} |
||||
|
||||
public static void ArrayBoolean() |
||||
{ |
||||
X(Y(), new bool[] { true, false, true, false, false, false, true, true }); |
||||
} |
||||
|
||||
public static void ArrayByte() |
||||
{ |
||||
X(Y(), new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 254, 255 }); |
||||
} |
||||
|
||||
public static void ArraySByte() |
||||
{ |
||||
X(Y(), new sbyte[] { -128, -127, 0, 1, 2, 3, 4, 127 }); |
||||
} |
||||
|
||||
public static void ArrayShort() |
||||
{ |
||||
X(Y(), new short[] { -32768, -1, 0, 1, 32767 }); |
||||
} |
||||
|
||||
public static void ArrayUShort() |
||||
{ |
||||
X(Y(), new ushort[] { 0, 1, 32767, 32768, 65534, 65535 }); |
||||
} |
||||
|
||||
public static void ArrayInt() |
||||
{ |
||||
X(Y(), new int[] { 1, -2, 2000000000, 4, 5, -6, 7, 8, 9, 10 }); |
||||
} |
||||
|
||||
public static void ArrayUInt() |
||||
{ |
||||
X(Y(), new uint[] { 1, 2000000000, 3000000000, 4, 5, 6, 7, 8, 9, 10 }); |
||||
} |
||||
|
||||
public static void ArrayLong() |
||||
{ |
||||
X(Y(), new long[] { -4999999999999999999, -1, 0, 1, 4999999999999999999 }); |
||||
} |
||||
|
||||
public static void ArrayULong() |
||||
{ |
||||
X(Y(), new ulong[] { 1, 2000000000, 3000000000, 4, 5, 6, 7, 8, 4999999999999999999, 9999999999999999999 }); |
||||
} |
||||
|
||||
public static void ArrayFloat() |
||||
{ |
||||
X(Y(), new float[] { -1.5f, 0f, 1.5f, float.NegativeInfinity, float.PositiveInfinity, float.NaN }); |
||||
} |
||||
|
||||
public static void ArrayDouble() |
||||
{ |
||||
X(Y(), new double[] { -1.5, 0.0, 1.5, double.NegativeInfinity, double.PositiveInfinity, double.NaN }); |
||||
} |
||||
|
||||
public static void ArrayDecimal() |
||||
{ |
||||
X(Y(), new decimal[] { -100m, 0m, 100m, decimal.MinValue, decimal.MaxValue, 0.0000001m }); |
||||
} |
||||
|
||||
public static void ArrayString() |
||||
{ |
||||
X(Y(), new string[] { "", null, "Hello", "World" }); |
||||
} |
||||
#endregion
|
||||
|
||||
public static void CollectionInitializerList() |
||||
{ |
||||
X(Y(), new List<int> { 1, 2, 3 }); |
||||
} |
||||
|
||||
public static void CollectionInitializerDictionary() |
||||
{ |
||||
X(Y(), new Dictionary<string, int> { |
||||
{ "First", 1 }, |
||||
{ "Second", 2 }, |
||||
{ "Third" , 3 } |
||||
}); |
||||
} |
||||
} |
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
|
||||
public static class Switch |
||||
{ |
||||
public static string ShortSwitchOverString(string text) |
||||
{ |
||||
switch (text) { |
||||
case "First case": |
||||
return "Text"; |
||||
default: |
||||
return "Default"; |
||||
} |
||||
} |
||||
|
||||
public static string SwitchOverString1(string text) |
||||
{ |
||||
switch (text) { |
||||
case "First case": |
||||
return "Text1"; |
||||
case "Second case": |
||||
case "2nd case": |
||||
return "Text2"; |
||||
case "Third case": |
||||
return "Text3"; |
||||
case "Fourth case": |
||||
return "Text4"; |
||||
case "Fifth case": |
||||
return "Text5"; |
||||
case "Sixth case": |
||||
return "Text6"; |
||||
case null: |
||||
return null; |
||||
default: |
||||
return "Default"; |
||||
} |
||||
} |
||||
|
||||
public static string SwitchOverString2() |
||||
{ |
||||
switch (Environment.UserName) { |
||||
case "First case": |
||||
return "Text1"; |
||||
case "Second case": |
||||
return "Text2"; |
||||
case "Third case": |
||||
return "Text3"; |
||||
case "Fourth case": |
||||
return "Text4"; |
||||
case "Fifth case": |
||||
return "Text5"; |
||||
case "Sixth case": |
||||
return "Text6"; |
||||
default: |
||||
return "Default"; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.PatternMatching |
||||
{ |
||||
public class OptionalNode : Pattern |
||||
{ |
||||
public static readonly Role<AstNode> ElementRole = new Role<AstNode>("Element", AstNode.Null); |
||||
|
||||
public OptionalNode(AstNode childNode) |
||||
{ |
||||
AddChild(childNode, ElementRole); |
||||
} |
||||
|
||||
public OptionalNode(string groupName, AstNode childNode) : this(new NamedNode(groupName, childNode)) |
||||
{ |
||||
} |
||||
|
||||
internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack<Pattern.PossibleMatch> backtrackingStack) |
||||
{ |
||||
backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); |
||||
return GetChildByRole(ElementRole).DoMatch(pos, match); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
if (other == null || other.IsNull) |
||||
return true; |
||||
else |
||||
return GetChildByRole(ElementRole).DoMatch(other, match); |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitOptionalNode(this, data); |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue