-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAstExpr.java
More file actions
418 lines (309 loc) · 11.2 KB
/
Copy pathAstExpr.java
File metadata and controls
418 lines (309 loc) · 11.2 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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
package processing.mode.cpp;
import java.util.List;
/*
* Consolidated expression AST node types -- formerly 18 separate files
* under tools/cpp-parser's ast/expr/ package. Merged into one file to
* reduce src/java/'s file count; every type here is otherwise unchanged,
* just package-private now (no "public" modifier) instead of public,
* since nothing outside this package ever references them -- Parser,
* CodeGen, and the passes/ files all live in this same flat package.
*/
/**
* Root of the expression AST hierarchy. Every concrete expression node lives in
* this package and implements this interface, in addition to {@link Node} for
* position/comment tracking.
*
* Confirmed shapes (see project corpus-validation notes for the reasoning behind
* each one -- this list is the consolidated result of walking LSystem, Mandelbrot,
* Button, Handles, and two rounds of synthetic kitchen-sink fixtures):
*
* Literal, Identifier, ScopedName, BinaryExpr, UnaryExpr, PostfixExpr,
* AssignExpr, CallExpr, MemberAccessExpr, IndexExpr, CastExpr, TernaryExpr,
* NewExpr, ArrayNewExpr, LambdaExpr, InitializerListExpr
*/
sealed interface Expr extends Node
permits Literal, Identifier, ScopedName, BinaryExpr, UnaryExpr, PostfixExpr,
AssignExpr, CallExpr, MemberAccessExpr, IndexExpr, CastExpr,
TernaryExpr, NewExpr, ArrayNewExpr, LambdaExpr, InitializerListExpr {
}
/**
* A literal value: int, float, string, char, or bool.
*
* The raw lexer text is preserved verbatim in {@code text} (including quotes for
* strings, the leading 0x for hex, suffixes like f/L/u, escape sequences as
* written) rather than being eagerly converted to a Java int/double/etc. Parsing
* the actual numeric/string value is a later concern (codegen just re-emits the
* text; a semantic pass that needs the real value can parse {@code text} itself).
* This avoids the parser making lossy decisions about e.g. whether "0xFF" should
* become an int or a long -- that's not the parser's call to make.
*/
record Literal(
Kind kind,
String text,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
public enum Kind { INT, FLOAT, STRING, CHAR, BOOL }
}
/** A bare identifier reference, e.g. "x", "drawLength", "production". */
record Identifier(
String name,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* A "::"-qualified name, e.g. "std::string", "MyNamespace::someFunction",
* "Direction::UP". Confirmed as its own node (rather than just baking "::" into
* raw identifier text) since semantic passes care about namespace/scope
* structure separately from a plain identifier reference -- e.g. resolving
* "Direction::UP" needs to know "Direction" is the scope and "UP" is the member,
* not just see one opaque token "Direction::UP".
*
* @param parts the dot-free, "::"-separated segments in order, e.g.
* ["std", "string"] or ["MyNamespace", "someFunction"]
*/
record ScopedName(
List<String> parts,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
public String joined() {
return String.join("::", parts);
}
}
/**
* A binary operator expression: arithmetic (+ - * / %), comparison
* (== != < > <= >=), logical (&& ||), bitwise (& | ^ << >>),
* and compound-assignment (+= -= *= /= %= &= |= ^= <<= >>=) all share this
* shape -- the operator is carried as raw text rather than an enum, since the
* grammar treats them identically (same precedence-climbing parse logic) and an
* enum would need a near-1:1 mirror of every operator string with no real
* structural benefit.
*
* Plain "=" assignment is intentionally NOT here -- see {@link AssignExpr},
* which is its own node because assignment is right-associative and can itself
* appear as the right-hand side of another assignment (confirmed by the corpus's
* "circleOver = rectOver = false;" chained-assignment case), a property compound
* operators don't need to share.
*/
record BinaryExpr(
String op,
Expr left,
Expr right,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* A prefix unary operator expression: negation (-x), logical-not (!x),
* address-of (&x), bitwise-not (~x), and prefix increment/decrement
* (++x, --x).
*
* Postfix increment/decrement (x++, x--) is a separate node, {@link PostfixExpr},
* since it has different precedence/associativity and applies to the left rather
* than wrapping to the right.
*/
record UnaryExpr(
String op,
Expr operand,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/** A postfix increment/decrement expression: "x++" or "x--". */
record PostfixExpr(
String op,
Expr operand,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* Plain "=" assignment. Right-associative and usable as the right-hand side of
* another AssignExpr -- confirmed necessary by the corpus's chained-assignment
* case ("circleOver = rectOver = false;").
*
* {@code target} may be an Identifier, a MemberAccessExpr, or an IndexExpr --
* confirmed by the corpus that array-index ("pixels[i + j * width] = ...") and
* (implicitly) member-access targets both need to be valid assignment LHS forms,
* not just plain identifiers. The parser does not restrict which Expr subtype
* appears here at parse time; rejecting non-lvalue targets (e.g. assigning to a
* literal) is left to a later semantic check if one is ever needed, not encoded
* in the grammar itself.
*/
record AssignExpr(
Expr target,
Expr value,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* A function call: "callee(args...)".
*
* Deliberately also covers the "bare construction call" pattern confirmed in
* the corpus -- "ps = PenroseSnowflakeLSystem();" and
* "handles = ArrayList<Handle>();" both parse as an ordinary CallExpr whose
* callee happens to be a type name rather than a function name. The parser
* cannot tell these apart without a symbol table (a free function and a
* same-named type constructor are syntactically identical at this stage), so
* disambiguating "is this a real call or a construction" is left to a later
* semantic pass, not encoded as a separate node here. See project notes on why
* a dedicated ConstructExpr node was considered and rejected.
*
* isBraceInit added for brace-init of a templated type
* ("Rect<float>{x, y, w, h}"), distinct from paren-init/ordinary calls.
*/
record CallExpr(
Expr callee,
List<Expr> args,
boolean isBraceInit,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
CallExpr(Expr callee, List<Expr> args, int line, int col, List<CppLexerToken> leadingComments) {
this(callee, args, false, line, col, leadingComments);
}
}
/**
* Member access via "." or "->": "object.member" or "pointer->member".
*
* Confirmed by the corpus to need an explicit isArrow flag (rather than two
* separate node types) since both forms compose identically in every other
* respect, including chaining arbitrarily ("others->get(i)->locked",
* "handles.get(i)->releaseEvent()") and mixing dot/arrow within one chain.
*/
record MemberAccessExpr(
Expr target,
String memberName,
boolean isArrow,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* Array/container subscript: "target[index]".
*
* Covers both real array indexing and std::string character indexing
* uniformly -- the corpus showed "production[i]" (string char access) and
* "pixels[i + j * width]" (array access, also confirmed valid as an
* AssignExpr target) using identical syntax. Disambiguating "is this a
* string or an array" is a type-resolution concern for a later pass, not
* something the grammar needs to know.
*/
record IndexExpr(
Expr target,
Expr index,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* A C-style cast: "(TargetType)expr", e.g. "(int)production.length()".
* Confirmed as common in the real corpus (appears repeatedly in LSystem).
* Only the C-style parenthesized-type form is supported -- static_cast/
* dynamic_cast/etc. are out of scope per the original grammar-scope decision.
*/
record CastExpr(
TypeRef targetType,
Expr expr,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* The ternary conditional: "cond ? thenExpr : elseExpr".
* Confirmed by the kitchen-sink fixture to nest (a ? b : (c ? d : e)) and to
* appear as a call argument and as an array index -- no special handling
* needed for those positions beyond ordinary expression-grammar composition.
*/
record TernaryExpr(
Expr condition,
Expr thenExpr,
Expr elseExpr,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* Heap allocation of a single object: "new Type(args...)", e.g.
* "new Handle(width / 2, 10 + i * 15, ...)" or "new int(42)".
*
* Distinct from {@link ArrayNewExpr} ("new Type[size]") and from the bare
* construction-call pattern handled by {@link CallExpr} (no "new" keyword,
* e.g. "PenroseSnowflakeLSystem()") -- all three are different syntactic forms
* confirmed present in the real corpus.
*/
record NewExpr(
TypeRef type,
List<Expr> args,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* Heap allocation of an array: "new Type[sizeExpr]", e.g. "new int[10]".
* Paired at the statement/codegen level with "delete[] ptr;" (a flag on the
* delete statement, not on this node -- allocation and deallocation are
* separate statements in the source and the parser doesn't try to link them).
*/
record ArrayNewExpr(
TypeRef elementType,
Expr sizeExpr,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* A lambda expression: "[captures](params) [-> ReturnType] { body }".
*
* returnType is null when the trailing "-> Type" is omitted (the common case --
* confirmed by the corpus that most lambdas skip it and rely on return-type
* deduction; the parser doesn't perform deduction itself, it simply records
* "no explicit return type was written").
*/
record LambdaExpr(
List<Capture> captures,
List<Param> params,
TypeRef returnType,
boolean isMutable,
Block body,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* A brace-enclosed initializer list: "{1, 2, 3, 4, 5}", used as an array
* initializer (confirmed by the corpus's "int initialized[5] = {1,2,3,4,5};"
* fixture). Not yet confirmed for other contexts (e.g. aggregate
* initialization of a struct) but the shape generalizes trivially if needed.
*/
record InitializerListExpr(
List<Expr> elements,
int line,
int col,
List<CppLexerToken> leadingComments
) implements Expr {
}
/**
* A single entry in a lambda capture list: a captured variable name and
* whether it's captured by reference ([&x]) or by value ([x]).
*/
record Capture(String name, boolean byRef) {
}