Browse Source

Generate DoMatch for the expression nodes

Replace the hand-written DoMatch overrides on the expression nodes with
generated ones. The generator matches every real child and structural member,
so several matchers become stricter than the hand-written versions that
under-matched (for example a previously-skipped child or an ignored flag),
while Pretty output is unaffected. Convenience-string identifier slots are
excluded so the name string is matched once rather than also via its token.
Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3807/head
Siegfried Pammer 3 weeks ago committed by Siegfried Pammer
parent
commit
a2c765e2bd
  1. 13
      ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs
  3. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IndexerExpression.cs
  4. 20
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InterpolatedStringExpression.cs
  5. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InvocationExpression.cs
  6. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IsExpression.cs
  7. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/LambdaExpression.cs
  8. 8
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs
  9. 8
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedArgumentExpression.cs
  10. 10
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedExpression.cs

13
ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs

@ -270,6 +270,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -270,6 +270,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
{{
return visitor.Visit{source.VisitMethodName}(this, data);
}}
");
}
@ -310,6 +311,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -310,6 +311,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
builder.Append(@";
}
");
}
@ -338,6 +340,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -338,6 +340,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
builder.AppendLine($"\t\tset => SetChildNode(ref {field}, value, {roleExpr});");
builder.AppendLine("\t}");
}
builder.AppendLine();
}
// Flattened child-index space: slots in declaration order, a single slot occupying one index
@ -345,6 +348,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -345,6 +348,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
builder.Append("\tinternal override int GetChildCount() => ");
builder.Append(string.Join(" + ", slots.Select(s => s.IsCollection ? $"({FieldName(s.PropertyName)}?.Count ?? 0)" : "1")));
builder.AppendLine(";");
builder.AppendLine();
builder.AppendLine("\tinternal override AstNode? GetChild(int index)");
builder.AppendLine("\t{");
@ -363,6 +367,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -363,6 +367,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
}
builder.AppendLine("\t\tthrow new System.ArgumentOutOfRangeException(nameof(index));");
builder.AppendLine("\t}");
builder.AppendLine();
builder.AppendLine("\tinternal override void SetChild(int index, AstNode? value)");
builder.AppendLine("\t{");
@ -381,6 +386,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -381,6 +386,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
}
builder.AppendLine("\t\tthrow new System.ArgumentOutOfRangeException(nameof(index));");
builder.AppendLine("\t}");
builder.AppendLine();
builder.AppendLine("\tinternal override Role GetChildSlot(int index)");
builder.AppendLine("\t{");
@ -394,10 +400,12 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -394,10 +400,12 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
}
builder.AppendLine("\t\tthrow new System.ArgumentOutOfRangeException(nameof(index));");
builder.AppendLine("\t}");
builder.AppendLine();
// One CSharpSlotInfo static per slot; node.Slot compares against these by object identity.
foreach (var s in slots)
builder.AppendLine($"\tpublic static readonly CSharpSlotInfo {s.PropertyName}Slot = new CSharpSlotInfo(\"{s.PropertyName}\", typeof({s.ElementType}), {(s.IsCollection ? "true" : "false")}, SlotKind.{s.KindName});");
builder.AppendLine();
builder.AppendLine("\tinternal override CSharpSlotInfo GetChildSlotInfo(int index)");
builder.AppendLine("\t{");
@ -411,6 +419,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -411,6 +419,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
}
builder.AppendLine("\t\tthrow new System.ArgumentOutOfRangeException(nameof(index));");
builder.AppendLine("\t}");
builder.AppendLine();
if (slots.Any(s => s.IsCollection))
{
@ -420,6 +429,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -420,6 +429,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
builder.AppendLine($"\t\tif (role == {s.RoleExpr}) return {s.PropertyName};");
builder.AppendLine("\t\treturn base.GetCollectionByRole(role);");
builder.AppendLine("\t}");
builder.AppendLine();
}
builder.AppendLine("\tinternal override void CloneChildrenInto(AstNode copyNode)");
@ -436,11 +446,12 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -436,11 +446,12 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
builder.AppendLine($"\t\tif ({field} != null) copy.{s.PropertyName} = ({s.PropertyType}){field}.Clone();");
}
builder.AppendLine("\t}");
builder.AppendLine();
}
builder.AppendLine("}");
context.AddSource(source.NodeName + ".g.cs", SourceText.From(builder.ToString(), Encoding.UTF8));
context.AddSource(source.NodeName + ".g.cs", SourceText.From(builder.ToString().Replace("\r\n", "\n"), Encoding.UTF8));
}
void WriteVisitors(SourceProductionContext context, ImmutableArray<AstNodeAdditions> source)

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs

@ -55,6 +55,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -55,6 +55,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
// The Identifier string is what DoMatch compares; the token slot is excluded to avoid matching it twice.
[ExcludeFromMatch]
[Slot("Roles.Identifier")]
public partial Identifier IdentifierToken { get; set; }

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IndexerExpression.cs

@ -59,11 +59,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -59,11 +59,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public IndexerExpression(Expression target, params Expression[] arguments) : this(target, (IEnumerable<Expression>)arguments)
{
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
IndexerExpression o = other as IndexerExpression;
return o != null && this.Target.DoMatch(o.Target, match) && this.Arguments.DoMatch(o.Arguments, match);
}
}
}

20
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InterpolatedStringExpression.cs

@ -1,7 +1,5 @@ @@ -1,7 +1,5 @@
using System.Collections.Generic;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -25,12 +23,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -25,12 +23,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
Content.AddRange(content);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
InterpolatedStringExpression o = other as InterpolatedStringExpression;
return o != null && !o.IsNull && this.Content.DoMatch(o.Content, match);
}
}
[DecompilerAstNode(hasNullNode: true)]
@ -68,12 +60,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -68,12 +60,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Alignment = alignment;
Suffix = suffix;
}
protected internal override bool DoMatch(AstNode other, Match match)
{
Interpolation o = other as Interpolation;
return o != null && this.Expression.DoMatch(o.Expression, match);
}
}
/// <summary>
@ -93,11 +79,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -93,11 +79,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
Text = text;
}
protected internal override bool DoMatch(AstNode other, Match match)
{
InterpolatedStringText o = other as InterpolatedStringText;
return o != null && o.Text == this.Text;
}
}
}

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InvocationExpression.cs

@ -59,11 +59,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -59,11 +59,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public InvocationExpression(Expression target, params Expression[] arguments) : this(target, (IEnumerable<Expression>)arguments)
{
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
InvocationExpression o = other as InvocationExpression;
return o != null && this.Target.DoMatch(o.Target, match) && this.Arguments.DoMatch(o.Arguments, match);
}
}
}

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IsExpression.cs

@ -50,12 +50,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -50,12 +50,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
AddChild(expression, Roles.Expression);
AddChild(type, Roles.Type);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
IsExpression o = other as IsExpression;
return o != null && this.Expression.DoMatch(o.Expression, match) && this.Type.DoMatch(o.Type, match);
}
}
}

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/LambdaExpression.cs

@ -51,11 +51,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -51,11 +51,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[Slot("BodyRole")]
public partial AstNode Body { get; set; }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
LambdaExpression o = other as LambdaExpression;
return o != null && this.IsAsync == o.IsAsync && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match);
}
}
}

8
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs

@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
// DoMatch compares the MemberName string; exclude the token slot to avoid matching it twice.
[ExcludeFromMatch]
[Slot("Roles.Identifier")]
public partial Identifier MemberNameToken { get; set; }
@ -72,11 +74,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -72,11 +74,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public MemberReferenceExpression(Expression target, string memberName, params AstType[] arguments) : this(target, memberName, (IEnumerable<AstType>)arguments)
{
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
MemberReferenceExpression o = other as MemberReferenceExpression;
return o != null && this.Target.DoMatch(o.Target, match) && MatchString(this.MemberName, o.MemberName) && this.TypeArguments.DoMatch(o.TypeArguments, match);
}
}
}

8
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedArgumentExpression.cs

@ -44,16 +44,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -44,16 +44,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
// DoMatch compares the Name string; exclude the token slot to avoid matching it twice.
[ExcludeFromMatch]
[Slot("Roles.Identifier")]
public partial Identifier NameToken { get; set; }
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
NamedArgumentExpression o = other as NamedArgumentExpression;
return o != null && MatchString(this.Name, o.Name) && this.Expression.DoMatch(o.Expression, match);
}
}
}

10
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedExpression.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
/// No standalone expression production: 'name = value' as used in object initializers (member_initializer), anonymous-object members (member_declarator), and named attribute arguments.
/// <c>named_expression : identifier '=' expression ;</c>
/// <c>named_expression ::= identifier '=' expression</c>
/// </summary>
[DecompilerAstNode(hasNullNode: false)]
public partial class NamedExpression : Expression
@ -52,16 +52,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -52,16 +52,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
// DoMatch compares the Name string; exclude the token slot to avoid matching it twice.
[ExcludeFromMatch]
[Slot("Roles.Identifier")]
public partial Identifier NameToken { get; set; }
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
var o = other as NamedExpression;
return o != null && MatchString(this.Name, o.Name) && this.Expression.DoMatch(o.Expression, match);
}
}
}

Loading…
Cancel
Save