-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAstCore.java
More file actions
193 lines (156 loc) · 6.44 KB
/
Copy pathAstCore.java
File metadata and controls
193 lines (156 loc) · 6.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package processing.mode.cpp;
import java.util.List;
/*
* Consolidated core AST support types -- Node (the base interface every
* AST node implements for position/comment tracking), TypeRef and its
* three variants, and Param (shared by FunctionDecl and LambdaExpr).
* Formerly 6 separate files; merged for the same reason as AstExpr.java.
*/
/**
* Common contract for every AST node: source position (for diagnostics and
* #line-directive emission during codegen) and any comment tokens that
* lexically preceded this node and were attached to it by the parser.
*
* Comments are attached at parse time (not stripped, not handled by a separate
* regex pass) specifically so semantic passes walking the tree never need to
* worry about comment text being mistaken for code -- see CppLexer's COMMENT
* handling notes.
*/
interface Node {
int line();
int col();
List<CppLexerToken> leadingComments();
}
/**
* Represents a C++ type as it appears in source: in a variable/field declaration,
* a function return type, a parameter type, a template argument, etc.
*
* This is a sealed hierarchy with three concrete shapes, confirmed necessary by
* walking the real CppMode test corpus:
*
* - {@link NamedType}: the common case. Covers everything from "int" to
* "ArrayList<Handle>*" to "const std::string&" to the outer "std::function"
* wrapper of "std::function<void(int)>" (the inner "void(int)" signature
* becomes a {@link FunctionSignatureType} nested inside this type's templateArgs).
*
* - {@link FunctionPointerType}: the raw C-style function pointer declarator
* shape, e.g. "int (*funcPtr)(int, int)". This does NOT fit NamedType at all --
* there is no single "name" being qualified by pointer/template syntax; the
* pointer-ness applies to an entire function signature. Confirmed as a genuine
* structural fork during corpus validation.
*
* - {@link FunctionSignatureType}: a bare function signature with no pointer
* declarator, used only as a template argument inside std::function<...>.
*
* Note on std::function<void(int)>: this parses as a NamedType with
* baseName="std::function" and a single templateArg that is itself a
* FunctionSignatureType -- NOT a FunctionPointerType (no '(*)' declarator is
* present in std::function's syntax, it's purely a template argument).
*/
sealed interface TypeRef permits NamedType, FunctionPointerType, FunctionSignatureType {
/** Plain-English rendering for diagnostics; not used for codegen fidelity. */
String describe();
}
/**
* The common-case type reference.
*
* @param baseName e.g. "int", "ArrayList", "std::string", "T", "auto"
* @param templateArgs empty for non-template types; each element is itself a
* TypeRef so nested templates (Pair<int, ArrayList<T>>)
* and function-signature template args (std::function<...>)
* both work without a separate node
* @param pointerDepth number of '*' suffixes; 0 for a plain value type
* @param isReference true for a '&' suffix
* @param isConst true if a leading 'const' qualifier was present
*/
record NamedType(
String baseName,
List<TypeRef> templateArgs,
int pointerDepth,
boolean isReference,
boolean isConst,
boolean isRvalueRef
) implements TypeRef {
public static NamedType simple(String baseName) {
return new NamedType(baseName, List.of(), 0, false, false, false);
}
@Override
public String describe() {
StringBuilder sb = new StringBuilder();
if (isConst) sb.append("const ");
sb.append(baseName);
if (!templateArgs.isEmpty()) {
sb.append("<");
for (int i = 0; i < templateArgs.size(); i++) {
if (i > 0) sb.append(", ");
sb.append(templateArgs.get(i).describe());
}
sb.append(">");
}
sb.append("*".repeat(pointerDepth));
if (isReference) sb.append("&");
return sb.toString();
}
}
/**
* The raw C-style function pointer declarator: "ReturnType (*)(ParamType, ...)".
* Confirmed necessary by the corpus's useRawFunctionPointer fixture
* ("int (*funcPtr)(int, int) = someFunc;") -- this does not fit NamedType's shape,
* since the pointer applies to an entire function signature, not a named type.
*/
record FunctionPointerType(
TypeRef returnType,
List<TypeRef> paramTypes
) implements TypeRef {
@Override
public String describe() {
StringBuilder sb = new StringBuilder(returnType.describe());
sb.append(" (*)(");
for (int i = 0; i < paramTypes.size(); i++) {
if (i > 0) sb.append(", ");
sb.append(paramTypes.get(i).describe());
}
sb.append(")");
return sb.toString();
}
}
/**
* A bare function signature with no pointer declarator, used only as a template
* argument inside std::function<...> (e.g. the "void(int)" inside
* "std::function<void(int)>"). Distinct from FunctionPointerType because no
* '(*)' appears in the source -- confirmed as a separate shape during corpus
* validation rather than reusing FunctionPointerType for both cases.
*/
record FunctionSignatureType(
TypeRef returnType,
List<TypeRef> paramTypes
) implements TypeRef {
@Override
public String describe() {
StringBuilder sb = new StringBuilder(returnType.describe());
sb.append("(");
for (int i = 0; i < paramTypes.size(); i++) {
if (i > 0) sb.append(", ");
sb.append(paramTypes.get(i).describe());
}
sb.append(")");
return sb.toString();
}
}
/**
* A single function/lambda parameter: type, name, and an optional default
* value. Confirmed necessary by the corpus's withDefaultParam fixture
* ("void withDefaultParam(int x, int y = 5)") -- defaultValue is null when
* absent.
*
* Shared between FunctionDecl and LambdaExpr since both need identical shape;
* confirmed by corpus that lambda parameter lists ("[](int n) { ... }") use
* the same grammar as ordinary function parameter lists, just without default
* values being exercised in practice (though nothing in the grammar forbids
* them on a lambda either).
*/
record Param(TypeRef type, String name, Expr defaultValue, List<Integer> innerArrayDims, boolean isVariadic) {
Param(TypeRef type, String name, Expr defaultValue) {
this(type, name, defaultValue, List.of(), false);
}
}