Skip to content

Commit df1f105

Browse files
Generate PatternPlaceholder nodes
1 parent bbfac3c commit df1f105

File tree

13 files changed

+78
-526
lines changed

13 files changed

+78
-526
lines changed

ICSharpCode.Decompiler.Generators.Attributes/DecompilerAstNodeAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
44
{
55
public sealed class DecompilerAstNodeAttribute : Attribute
66
{
7-
public DecompilerAstNodeAttribute(bool hasNullNode) { }
7+
public DecompilerAstNodeAttribute(bool hasNullNode = false, bool hasPatternPlaceholder = false) { }
88
}
99

1010
public sealed class ExcludeFromMatchAttribute : Attribute

ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace ICSharpCode.Decompiler.Generators;
1414
[Generator]
1515
internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
1616
{
17-
record AstNodeAdditions(string NodeName, bool NeedsAcceptImpls, bool NeedsVisitor, bool NeedsNullNode, int NullNodeBaseCtorParamCount, bool IsTypeNode, string VisitMethodName, string VisitMethodParamType, EquatableArray<(string Member, string TypeName, bool RecursiveMatch, bool MatchAny)>? MembersToMatch);
17+
record AstNodeAdditions(string NodeName, bool NeedsAcceptImpls, bool NeedsVisitor, bool NeedsNullNode, bool NeedsPatternPlaceholder, int NullNodeBaseCtorParamCount, bool IsTypeNode, string VisitMethodName, string VisitMethodParamType, EquatableArray<(string Member, string TypeName, bool RecursiveMatch, bool MatchAny)>? MembersToMatch);
1818

1919
AstNodeAdditions GetAstNodeAdditions(GeneratorAttributeSyntaxContext context, CancellationToken ct)
2020
{
@@ -63,6 +63,7 @@ string s when s.Contains("AstType") => (s.Replace("AstType", "Type"), s),
6363
return new(targetSymbol.Name, !targetSymbol.MemberNames.Contains("AcceptVisitor"),
6464
NeedsVisitor: !targetSymbol.IsAbstract && targetSymbol.BaseType!.IsAbstract,
6565
NeedsNullNode: (bool)attribute.ConstructorArguments[0].Value!,
66+
NeedsPatternPlaceholder: (bool)attribute.ConstructorArguments[1].Value!,
6667
NullNodeBaseCtorParamCount: targetSymbol.InstanceConstructors.Min(m => m.Parameters.Length),
6768
IsTypeNode: targetSymbol.Name == "AstType" || targetSymbol.BaseType?.Name == "AstType",
6869
visitMethodName, paramTypeName, membersToMatch?.ToEquatableArray());
@@ -75,6 +76,13 @@ void WriteGeneratedMembers(SourceProductionContext context, AstNodeAdditions sou
7576
builder.AppendLine("namespace ICSharpCode.Decompiler.CSharp.Syntax;");
7677
builder.AppendLine();
7778

79+
if (source.NeedsPatternPlaceholder)
80+
{
81+
builder.AppendLine("using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;");
82+
}
83+
84+
builder.AppendLine();
85+
7886
builder.AppendLine("#nullable enable");
7987
builder.AppendLine();
8088

@@ -140,6 +148,63 @@ public override Decompiler.TypeSystem.ITypeReference ToTypeReference(Resolver.Na
140148

141149
}
142150

151+
if (source.NeedsPatternPlaceholder)
152+
{
153+
const string toTypeReferenceCode = @"
154+
155+
public override Decompiler.TypeSystem.ITypeReference ToTypeReference(Resolver.NameLookupMode lookupMode, Decompiler.TypeSystem.InterningProvider? interningProvider = null)
156+
{
157+
throw new System.NotSupportedException();
158+
}";
159+
160+
builder.Append(
161+
$@" public static implicit operator {source.NodeName}?(PatternMatching.Pattern? pattern)
162+
{{
163+
return pattern != null ? new PatternPlaceholder(pattern) : null;
164+
}}
165+
166+
sealed class PatternPlaceholder : {source.NodeName}, INode
167+
{{
168+
readonly PatternMatching.Pattern child;
169+
170+
public PatternPlaceholder(PatternMatching.Pattern child)
171+
{{
172+
this.child = child;
173+
}}
174+
175+
public override NodeType NodeType {{
176+
get {{ return NodeType.Pattern; }}
177+
}}
178+
179+
public override void AcceptVisitor(IAstVisitor visitor)
180+
{{
181+
visitor.VisitPatternPlaceholder(this, child);
182+
}}
183+
184+
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
185+
{{
186+
return visitor.VisitPatternPlaceholder(this, child);
187+
}}
188+
189+
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
190+
{{
191+
return visitor.VisitPatternPlaceholder(this, child, data);
192+
}}
193+
194+
protected internal override bool DoMatch(AstNode? other, PatternMatching.Match match)
195+
{{
196+
return child.DoMatch(other, match);
197+
}}
198+
199+
bool PatternMatching.INode.DoMatchCollection(Role? role, PatternMatching.INode? pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
200+
{{
201+
return child.DoMatchCollection(role, pos, match, backtrackingInfo);
202+
}}{(source.NodeName == "AstType" ? toTypeReferenceCode : "")}
203+
}}
204+
"
205+
);
206+
}
207+
143208
if (source.NeedsAcceptImpls && source.NeedsVisitor)
144209
{
145210
builder.Append($@" public override void AcceptVisitor(IAstVisitor visitor)
@@ -202,7 +267,7 @@ private void WriteVisitors(SourceProductionContext context, ImmutableArray<AstNo
202267
builder.AppendLine("namespace ICSharpCode.Decompiler.CSharp.Syntax;");
203268

204269
source = source
205-
.Concat([new("NullNode", false, true, false, 0, false, "NullNode", "AstNode", null), new("PatternPlaceholder", false, true, false, 0, false, "PatternPlaceholder", "AstNode", null)])
270+
.Concat([new("NullNode", false, true, false, false, 0, false, "NullNode", "AstNode", null), new("PatternPlaceholder", false, true, false, false, 0, false, "PatternPlaceholder", "AstNode", null)])
206271
.ToImmutableArray();
207272

208273
WriteInterface("IAstVisitor", "void", "");

ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -37,58 +37,12 @@
3737

3838
namespace ICSharpCode.Decompiler.CSharp.Syntax
3939
{
40-
[DecompilerAstNode(hasNullNode: true)]
40+
[DecompilerAstNode(hasNullNode: true, hasPatternPlaceholder: true)]
4141
public abstract partial class AstNode : AbstractAnnotatable, IFreezable, INode, ICloneable
4242
{
4343
// the Root role must be available when creating the null nodes, so we can't put it in the Roles class
4444
internal static readonly Role<AstNode?> RootRole = new Role<AstNode?>("Root", null);
4545

46-
#region PatternPlaceholder
47-
public static implicit operator AstNode?(PatternMatching.Pattern? pattern)
48-
{
49-
return pattern != null ? new PatternPlaceholder(pattern) : null;
50-
}
51-
52-
sealed class PatternPlaceholder : AstNode, INode
53-
{
54-
readonly PatternMatching.Pattern child;
55-
56-
public PatternPlaceholder(PatternMatching.Pattern child)
57-
{
58-
this.child = child;
59-
}
60-
61-
public override NodeType NodeType {
62-
get { return NodeType.Pattern; }
63-
}
64-
65-
public override void AcceptVisitor(IAstVisitor visitor)
66-
{
67-
visitor.VisitPatternPlaceholder(this, child);
68-
}
69-
70-
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
71-
{
72-
return visitor.VisitPatternPlaceholder(this, child);
73-
}
74-
75-
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
76-
{
77-
return visitor.VisitPatternPlaceholder(this, child, data);
78-
}
79-
80-
protected internal override bool DoMatch(AstNode? other, PatternMatching.Match match)
81-
{
82-
return child.DoMatch(other, match);
83-
}
84-
85-
bool PatternMatching.INode.DoMatchCollection(Role? role, PatternMatching.INode? pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
86-
{
87-
return child.DoMatchCollection(role, pos, match, backtrackingInfo);
88-
}
89-
}
90-
#endregion
91-
9246
AstNode? parent;
9347
AstNode? prevSibling;
9448
AstNode? nextSibling;

ICSharpCode.Decompiler/CSharp/Syntax/AstType.cs

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,72 +16,19 @@
1616
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1717
// DEALINGS IN THE SOFTWARE.
1818

19-
using System;
2019
using System.Collections.Generic;
2120

2221
using ICSharpCode.Decompiler.CSharp.Resolver;
23-
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
2422
using ICSharpCode.Decompiler.TypeSystem;
2523

2624
namespace ICSharpCode.Decompiler.CSharp.Syntax
2725
{
2826
/// <summary>
2927
/// A type reference in the C# AST.
3028
/// </summary>
31-
[DecompilerAstNode(hasNullNode: true)]
29+
[DecompilerAstNode(hasNullNode: true, hasPatternPlaceholder: true)]
3230
public abstract partial class AstType : AstNode
3331
{
34-
#region PatternPlaceholder
35-
public static implicit operator AstType(PatternMatching.Pattern pattern)
36-
{
37-
return pattern != null ? new PatternPlaceholder(pattern) : null;
38-
}
39-
40-
sealed class PatternPlaceholder : AstType, INode
41-
{
42-
readonly PatternMatching.Pattern child;
43-
44-
public PatternPlaceholder(PatternMatching.Pattern child)
45-
{
46-
this.child = child;
47-
}
48-
49-
public override NodeType NodeType {
50-
get { return NodeType.Pattern; }
51-
}
52-
53-
public override void AcceptVisitor(IAstVisitor visitor)
54-
{
55-
visitor.VisitPatternPlaceholder(this, child);
56-
}
57-
58-
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
59-
{
60-
return visitor.VisitPatternPlaceholder(this, child);
61-
}
62-
63-
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
64-
{
65-
return visitor.VisitPatternPlaceholder(this, child, data);
66-
}
67-
68-
public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider)
69-
{
70-
throw new NotSupportedException();
71-
}
72-
73-
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
74-
{
75-
return child.DoMatch(other, match);
76-
}
77-
78-
bool PatternMatching.INode.DoMatchCollection(Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
79-
{
80-
return child.DoMatchCollection(role, pos, match, backtrackingInfo);
81-
}
82-
}
83-
#endregion
84-
8532
public override NodeType NodeType {
8633
get { return NodeType.TypeReference; }
8734
}

ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ArrayInitializerExpression.cs

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -94,52 +94,6 @@ public override bool IsSingleElement {
9494
}
9595

9696
}
97-
98-
#region PatternPlaceholder
99-
public static implicit operator ArrayInitializerExpression(PatternMatching.Pattern pattern)
100-
{
101-
return pattern != null ? new PatternPlaceholder(pattern) : null;
102-
}
103-
104-
sealed class PatternPlaceholder : ArrayInitializerExpression, PatternMatching.INode
105-
{
106-
readonly PatternMatching.Pattern child;
107-
108-
public PatternPlaceholder(PatternMatching.Pattern child)
109-
{
110-
this.child = child;
111-
}
112-
113-
public override NodeType NodeType {
114-
get { return NodeType.Pattern; }
115-
}
116-
117-
public override void AcceptVisitor(IAstVisitor visitor)
118-
{
119-
visitor.VisitPatternPlaceholder(this, child);
120-
}
121-
122-
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
123-
{
124-
return visitor.VisitPatternPlaceholder(this, child);
125-
}
126-
127-
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
128-
{
129-
return visitor.VisitPatternPlaceholder(this, child, data);
130-
}
131-
132-
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
133-
{
134-
return child.DoMatch(other, match);
135-
}
136-
137-
bool PatternMatching.INode.DoMatchCollection(Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
138-
{
139-
return child.DoMatchCollection(role, pos, match, backtrackingInfo);
140-
}
141-
}
142-
#endregion
14397
}
14498
}
14599

ICSharpCode.Decompiler/CSharp/Syntax/Expressions/Expression.cs

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -27,55 +27,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
2727
/// This class is useful even though it doesn't provide any additional functionality:
2828
/// It can be used to communicate more information in APIs, e.g. "this subnode will always be an expression"
2929
/// </remarks>
30-
[DecompilerAstNode(hasNullNode: true)]
30+
[DecompilerAstNode(hasNullNode: true, hasPatternPlaceholder: true)]
3131
public abstract partial class Expression : AstNode
3232
{
33-
#region PatternPlaceholder
34-
public static implicit operator Expression(PatternMatching.Pattern pattern)
35-
{
36-
return pattern != null ? new PatternPlaceholder(pattern) : null;
37-
}
38-
39-
sealed class PatternPlaceholder : Expression, PatternMatching.INode
40-
{
41-
readonly PatternMatching.Pattern child;
42-
43-
public PatternPlaceholder(PatternMatching.Pattern child)
44-
{
45-
this.child = child;
46-
}
47-
48-
public override NodeType NodeType {
49-
get { return NodeType.Pattern; }
50-
}
51-
52-
public override void AcceptVisitor(IAstVisitor visitor)
53-
{
54-
visitor.VisitPatternPlaceholder(this, child);
55-
}
56-
57-
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
58-
{
59-
return visitor.VisitPatternPlaceholder(this, child);
60-
}
61-
62-
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
63-
{
64-
return visitor.VisitPatternPlaceholder(this, child, data);
65-
}
66-
67-
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
68-
{
69-
return child.DoMatch(other, match);
70-
}
71-
72-
bool PatternMatching.INode.DoMatchCollection(Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
73-
{
74-
return child.DoMatchCollection(role, pos, match, backtrackingInfo);
75-
}
76-
}
77-
#endregion
78-
7933
public override NodeType NodeType {
8034
get {
8135
return NodeType.Expression;

0 commit comments

Comments
 (0)