Line | Branch | Exec | Source |
---|---|---|---|
1 | #ifndef LYTHON_SEXPR_HEADER | ||
2 | #define LYTHON_SEXPR_HEADER | ||
3 | |||
4 | #include <memory> | ||
5 | |||
6 | #include "ast/nodekind.h" | ||
7 | #include "constant.h" | ||
8 | #include "dtypes.h" | ||
9 | #include "lexer/token.h" | ||
10 | #include "logging/logging.h" | ||
11 | #include "utilities/names.h" | ||
12 | #include "utilities/object.h" | ||
13 | #include "utilities/optional.h" | ||
14 | |||
15 | namespace lython { | ||
16 | |||
17 | using Identifier = StringRef; | ||
18 | |||
19 | String str(NodeKind k); | ||
20 | |||
21 | enum class NodeFamily : int8_t | ||
22 | { | ||
23 | Module, | ||
24 | Statement, | ||
25 | Expression, | ||
26 | Pattern, | ||
27 | }; | ||
28 | |||
29 | // col_offset is the byte offset in the utf8 string the parser uses | ||
30 | struct CommonAttributes { | ||
31 | int lineno = -2; | ||
32 | int col_offset = -2; | ||
33 | Optional<int> end_lineno; | ||
34 | Optional<int> end_col_offset; | ||
35 | }; | ||
36 | |||
37 | template <typename T> | ||
38 | struct NodeTrait { | ||
39 | enum Constants | ||
40 | { kind = int(NodeKind::Invalid) }; | ||
41 | }; | ||
42 | |||
43 | template <typename T> | ||
44 | NodeKind nodekind() { | ||
45 | 1045 | return NodeKind(NodeTrait<T>::kind); | |
46 | } | ||
47 | |||
48 | struct Node: public GCObject { | ||
49 | String __str__() const; | ||
50 | |||
51 | Node(NodeKind _kind): kind(_kind) {} | ||
52 | |||
53 | virtual NodeFamily family() const = 0; | ||
54 | |||
55 | const NodeKind kind; | ||
56 | |||
57 | template <typename T> | ||
58 | bool is_instance() const { | ||
59 | 2129 | return kind == nodekind<T>(); | |
60 | } | ||
61 | |||
62 | Node const* get_parent() const { return static_cast<Node*>(get_gc_parent()); } | ||
63 | }; | ||
64 | |||
65 | struct ModNode: public Node { | ||
66 | ModNode(NodeKind kind): Node(kind) {} | ||
67 | |||
68 | NodeFamily family() const override { return NodeFamily::Module; } | ||
69 | }; | ||
70 | |||
71 | struct Comment; | ||
72 | |||
73 | struct StmtNode: public CommonAttributes, public Node { | ||
74 | StmtNode(NodeKind kind): Node(kind) {} | ||
75 | |||
76 | NodeFamily family() const override { return NodeFamily::Statement; } | ||
77 | |||
78 | // inline comments are inserted to its matching statement | ||
79 | // example: | ||
80 | // <stmt> # comment | ||
81 | // | ||
82 | // Some statements can have multiple comment | ||
83 | // | ||
84 | // if <expr>: # comment | ||
85 | // ... | ||
86 | // else: # commnet | ||
87 | // | ||
88 | Comment* comment = nullptr; | ||
89 | |||
90 | bool is_one_line() const { | ||
91 |
2/2✓ Branch 1 taken 1697 times.
✓ Branch 2 taken 669 times.
|
2366 | if (end_lineno.has_value()) { |
92 | 1697 | return lineno == end_lineno.value(); | |
93 | } | ||
94 | 669 | return true; | |
95 | } | ||
96 | }; | ||
97 | |||
98 | struct ExprNode: public CommonAttributes, public Node { | ||
99 | ExprNode(NodeKind kind): Node(kind) {} | ||
100 | |||
101 | NodeFamily family() const override { return NodeFamily::Expression; } | ||
102 | }; | ||
103 | |||
104 | enum class ConversionKind : int8_t | ||
105 | { | ||
106 | None = -1, | ||
107 | String = 115, | ||
108 | Representation = 114, | ||
109 | ASCII = 97 | ||
110 | }; | ||
111 | |||
112 | enum class BinaryOperator : int8_t | ||
113 | { | ||
114 | #define BINARY_OPERATORS(OP) \ | ||
115 | OP(None, "", na) \ | ||
116 | OP(Add, "+", add) \ | ||
117 | OP(Sub, "-", sub) \ | ||
118 | OP(Mult, "*", mul) \ | ||
119 | OP(MatMult, "@", matmul) \ | ||
120 | OP(Div, "/", truediv) \ | ||
121 | OP(Mod, "%", divmod) \ | ||
122 | OP(Pow, "^", pow) \ | ||
123 | OP(LShift, "<<", lshift) \ | ||
124 | OP(RShift, ">>", rshift) \ | ||
125 | OP(BitOr, "|", or) \ | ||
126 | OP(BitXor, "^", xor) \ | ||
127 | OP(BitAnd, "&", and) \ | ||
128 | OP(FloorDiv, "//", floordiv) \ | ||
129 | OP(EltMult, ".*", eltmult) \ | ||
130 | OP(EltDiv, "./", eltiv) | ||
131 | |||
132 | #define OP(name, _, n) name, | ||
133 | BINARY_OPERATORS(OP) | ||
134 | #undef OP | ||
135 | }; | ||
136 | |||
137 | enum class BoolOperator : int8_t | ||
138 | { | ||
139 | None, | ||
140 | #define BOOL_OPERATORS(OP) \ | ||
141 | OP(And, and, and) \ | ||
142 | OP(Or, or, or) | ||
143 | |||
144 | #define OP(name, kw, _) name, | ||
145 | BOOL_OPERATORS(OP) | ||
146 | #undef OP | ||
147 | }; | ||
148 | |||
149 | enum class UnaryOperator : int8_t | ||
150 | { | ||
151 | #define UNARY_OPERATORS(OP) \ | ||
152 | OP(None, "", na) \ | ||
153 | OP(Invert, "~", invert) \ | ||
154 | OP(Not, "!", not ) \ | ||
155 | OP(UAdd, "+", pos) \ | ||
156 | OP(USub, "-", neg) | ||
157 | |||
158 | #define CONV(OP) \ | ||
159 | OP(abs, "abs", abs) \ | ||
160 | OP(int, "int", int) \ | ||
161 | OP(float, "float", float) \ | ||
162 | OP(index, "index", index) \ | ||
163 | OP(complex, "complex", complex) \ | ||
164 | OP(round, "round", round) \ | ||
165 | OP(trunc, "trunc", trunc) \ | ||
166 | OP(floor, "floor", floor) \ | ||
167 | OP(ceil, "ceil", ceil) | ||
168 | |||
169 | #define OP(name, kw, n) name, | ||
170 | UNARY_OPERATORS(OP) | ||
171 | #undef OP | ||
172 | }; | ||
173 | |||
174 | enum class CmpOperator : int8_t | ||
175 | { | ||
176 | |||
177 | #define COMP_OPERATORS(OP) \ | ||
178 | OP(None, "", na) \ | ||
179 | OP(Eq, "==", eq) \ | ||
180 | OP(NotEq, "!=", ne) \ | ||
181 | OP(Lt, "<", lt) \ | ||
182 | OP(LtE, "<=", le) \ | ||
183 | OP(Gt, ">", gt) \ | ||
184 | OP(GtE, ">=", ge) \ | ||
185 | OP(Is, "is", is) \ | ||
186 | OP(IsNot, "is not", isnot) \ | ||
187 | OP(In, "in", in) \ | ||
188 | OP(NotIn, "not in", notin) | ||
189 | |||
190 | #define OP(name, _, n) name, | ||
191 | COMP_OPERATORS(OP) | ||
192 | #undef OP | ||
193 | }; | ||
194 | |||
195 | enum class ExprContext : int8_t | ||
196 | { | ||
197 | Load, | ||
198 | Store, | ||
199 | Del | ||
200 | }; | ||
201 | void print(BoolOperator const&, std::ostream& out); | ||
202 | void print(BinaryOperator const&, std::ostream& out); | ||
203 | void print(CmpOperator const&, std::ostream& out); | ||
204 | void print(UnaryOperator const&, std::ostream& out); | ||
205 | |||
206 | // stp | ||
207 | StringRef operator_magic_name(BoolOperator const& v, bool reverse = false); | ||
208 | StringRef operator_magic_name(BinaryOperator const& v, bool reverse = false); | ||
209 | StringRef operator_magic_name(CmpOperator const& v, bool reverse = false); | ||
210 | StringRef operator_magic_name(UnaryOperator const& v, bool reverse = false); | ||
211 | // test | ||
212 | |||
213 | struct Comprehension { | ||
214 | ExprNode* target = nullptr; | ||
215 | ExprNode* iter = nullptr; | ||
216 | Array<ExprNode*> ifs; | ||
217 | int is_async : 1; | ||
218 | }; | ||
219 | |||
220 | struct ExceptHandler: public CommonAttributes { | ||
221 | Optional<ExprNode*> type; | ||
222 | Optional<Identifier> name; | ||
223 | Array<StmtNode*> body; | ||
224 | Comment* comment = nullptr; | ||
225 | }; | ||
226 | |||
227 | struct Arg: public CommonAttributes { | ||
228 | Identifier arg; | ||
229 | Optional<ExprNode*> annotation; | ||
230 | Optional<String> type_comment; | ||
231 | }; | ||
232 | |||
233 | struct Arguments { | ||
234 | Arguments() = default; | ||
235 | |||
236 | Arguments(Arguments const&) = default; | ||
237 | |||
238 | Array<Arg> posonlyargs; | ||
239 | Array<Arg> args; | ||
240 | Optional<Arg> vararg; // *args | ||
241 | Array<Arg> kwonlyargs; | ||
242 | Array<ExprNode*> kw_defaults; | ||
243 | Optional<Arg> kwarg; // **kwargs | ||
244 | Array<ExprNode*> defaults; | ||
245 | |||
246 | int size() const { return int(posonlyargs.size() + args.size() + kwonlyargs.size()); } | ||
247 | }; | ||
248 | |||
249 | struct Keyword: public CommonAttributes { | ||
250 | Identifier arg; // why is this optional ? | ||
251 | // it is marked as optional in the python AST | ||
252 | ExprNode* value = nullptr; | ||
253 | }; | ||
254 | |||
255 | struct Alias { | ||
256 | Identifier name; | ||
257 | Optional<Identifier> asname; | ||
258 | }; | ||
259 | |||
260 | struct WithItem { | ||
261 | ExprNode* context_expr = nullptr; | ||
262 | Optional<ExprNode*> optional_vars; | ||
263 | }; | ||
264 | |||
265 | struct TypeIgnore { | ||
266 | int lineno; | ||
267 | String tag; | ||
268 | }; | ||
269 | |||
270 | struct Pattern: public CommonAttributes, public Node { | ||
271 | Pattern(NodeKind kind): Node(kind) {} | ||
272 | |||
273 | NodeFamily family() const override { return NodeFamily::Pattern; } | ||
274 | }; | ||
275 | |||
276 | struct MatchValue: public Pattern { | ||
277 | ExprNode* value; | ||
278 | |||
279 | MatchValue(): Pattern(NodeKind::MatchValue) {} | ||
280 | }; | ||
281 | |||
282 | struct MatchSingleton: public Pattern { | ||
283 | ConstantValue value; | ||
284 | |||
285 | MatchSingleton(): Pattern(NodeKind::MatchSingleton) {} | ||
286 | }; | ||
287 | |||
288 | struct MatchSequence: public Pattern { | ||
289 | Array<Pattern*> patterns; | ||
290 | |||
291 | MatchSequence(): Pattern(NodeKind::MatchSequence) {} | ||
292 | }; | ||
293 | |||
294 | // The optional "rest" MatchMapping parameter handles capturing extra mapping keys | ||
295 | struct MatchMapping: public Pattern { | ||
296 | Array<ExprNode*> keys; | ||
297 | Array<Pattern*> patterns; | ||
298 | Optional<Identifier> rest; | ||
299 | |||
300 | MatchMapping(): Pattern(NodeKind::MatchMapping) {} | ||
301 | }; | ||
302 | |||
303 | struct MatchClass: public Pattern { | ||
304 | ExprNode* cls; | ||
305 | Array<Pattern*> patterns; | ||
306 | Array<Identifier> kwd_attrs; | ||
307 | Array<Pattern*> kwd_patterns; | ||
308 | |||
309 | MatchClass(): Pattern(NodeKind::MatchClass) {} | ||
310 | }; | ||
311 | |||
312 | struct MatchStar: public Pattern { | ||
313 | Optional<Identifier> name; | ||
314 | |||
315 | MatchStar(): Pattern(NodeKind::MatchStar) {} | ||
316 | }; | ||
317 | |||
318 | struct MatchAs: public Pattern { | ||
319 | Optional<Pattern*> pattern; | ||
320 | Optional<Identifier> name; | ||
321 | |||
322 | MatchAs(): Pattern(NodeKind::MatchAs) {} | ||
323 | }; | ||
324 | |||
325 | struct MatchOr: public Pattern { | ||
326 | Array<Pattern*> patterns; | ||
327 | |||
328 | MatchOr(): Pattern(NodeKind::MatchOr) {} | ||
329 | }; | ||
330 | |||
331 | struct MatchCase { | ||
332 | Pattern* pattern; | ||
333 | Optional<ExprNode*> guard; | ||
334 | Array<StmtNode*> body; | ||
335 | Comment* comment = nullptr; | ||
336 | }; | ||
337 | |||
338 | // Expressions | ||
339 | // ----------- | ||
340 | |||
341 | // So currently comment are tokens | ||
342 | // maybe it should be its own single string token | ||
343 | // so I do not have to worry about the formatting | ||
344 | // | ||
345 | // currently the tokens are formatted back using the unlex | ||
346 | // which tries to output tokens following python code style | ||
347 | struct Comment: public ExprNode { | ||
348 | |||
349 | Comment(): ExprNode(NodeKind::Comment) {} | ||
350 | |||
351 | String comment; | ||
352 | }; | ||
353 | |||
354 | struct Constant: public ExprNode { | ||
355 | ConstantValue value; | ||
356 | Optional<String> kind; | ||
357 | |||
358 | template <typename T> | ||
359 | Constant(T const& v): ExprNode(NodeKind::Constant), value(v) {} | ||
360 | |||
361 | Constant(): Constant(ConstantValue::invalid_t()) {} | ||
362 | }; | ||
363 | |||
364 | /* | ||
365 | >>> print(ast.dump(ast.parse("1 < 2 < 3"), indent=4)) | ||
366 | Module( | ||
367 | body=[ | ||
368 | Expr( | ||
369 | value=Compare( | ||
370 | left=Constant(value=1), | ||
371 | ops=[ | ||
372 | Lt(), | ||
373 | Lt()], | ||
374 | comparators=[ | ||
375 | Constant(value=2), | ||
376 | Constant(value=3)]))], | ||
377 | type_ignores=[]) | ||
378 | */ | ||
379 | struct BoolOp: public ExprNode { | ||
380 | using NativeBoolyOp = ConstantValue (*)(ConstantValue const&, ConstantValue const&); | ||
381 | |||
382 | BoolOperator op; | ||
383 | Array<ExprNode*> values; | ||
384 | |||
385 | // this is used to know if we have a partial expression or not | ||
386 | // if the expression is valid we should have values == opcount + 1 | ||
387 | int opcount = 0; | ||
388 | |||
389 | // Function to apply, resolved by the sema | ||
390 | StmtNode* resolved_operator = nullptr; | ||
391 | NativeBoolyOp native_operator = nullptr; | ||
392 | int varid = -1; | ||
393 | |||
394 | BoolOp(): ExprNode(NodeKind::BoolOp) {} | ||
395 | |||
396 | bool safe_value_add(ExprNode* value) { | ||
397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (value == this) { |
398 | ✗ | return false; | |
399 | } | ||
400 | |||
401 |
2/2✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
|
14 | for (auto& expr: values) { |
402 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (value == expr) { |
403 | ✗ | return false; | |
404 | } | ||
405 | } | ||
406 | |||
407 | 7 | values.push_back(value); | |
408 | 7 | return true; | |
409 | } | ||
410 | }; | ||
411 | |||
412 | // need sequences for compare to distinguish between | ||
413 | // x < 4 < 3 and (x < 4) < 3 | ||
414 | struct Compare: public ExprNode { | ||
415 | using NativeCompOp = ConstantValue (*)(ConstantValue const&, ConstantValue const&); | ||
416 | |||
417 | ExprNode* left = nullptr; | ||
418 | Array<CmpOperator> ops; | ||
419 | Array<ExprNode*> comparators; | ||
420 | |||
421 | // Function to apply, resolved by the sema | ||
422 | Array<StmtNode*> resolved_operator; | ||
423 | Array<NativeCompOp> native_operator; | ||
424 | |||
425 | bool safe_comparator_add(ExprNode* comp) { | ||
426 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
|
100 | if (comp == this) { |
427 | ✗ | return false; | |
428 | } | ||
429 | |||
430 |
2/2✓ Branch 5 taken 32 times.
✓ Branch 6 taken 100 times.
|
132 | for (auto& expr: comparators) { |
431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | if (comp == expr) { |
432 | ✗ | return false; | |
433 | } | ||
434 | } | ||
435 | |||
436 | 100 | comparators.push_back(comp); | |
437 | 100 | return true; | |
438 | } | ||
439 | |||
440 | Compare(): ExprNode(NodeKind::Compare) {} | ||
441 | }; | ||
442 | |||
443 | struct NamedExpr: public ExprNode { | ||
444 | ExprNode* target = nullptr; | ||
445 | ExprNode* value = nullptr; | ||
446 | |||
447 | NamedExpr(): ExprNode(NodeKind::NamedExpr) {} | ||
448 | }; | ||
449 | |||
450 | struct BinOp: public ExprNode { | ||
451 | using NativeBinaryOp = ConstantValue (*)(ConstantValue const&, ConstantValue const&); | ||
452 | |||
453 | ExprNode* left = nullptr; | ||
454 | BinaryOperator op; | ||
455 | ExprNode* right = nullptr; | ||
456 | |||
457 | // Function to apply, resolved by the sema | ||
458 | StmtNode* resolved_operator = nullptr; | ||
459 | NativeBinaryOp native_operator = nullptr; | ||
460 | int varid = -1; | ||
461 | |||
462 | BinOp(): ExprNode(NodeKind::BinOp) {} | ||
463 | }; | ||
464 | |||
465 | struct UnaryOp: public ExprNode { | ||
466 | using NativeUnaryOp = ConstantValue (*)(ConstantValue const&); | ||
467 | |||
468 | UnaryOperator op; | ||
469 | ExprNode* operand; | ||
470 | |||
471 | // Function to apply, resolved by the sema | ||
472 | StmtNode* resolved_operator = nullptr; | ||
473 | NativeUnaryOp native_operator = nullptr; | ||
474 | |||
475 | UnaryOp(): ExprNode(NodeKind::UnaryOp) {} | ||
476 | }; | ||
477 | |||
478 | struct Lambda: public ExprNode { | ||
479 | Arguments args; | ||
480 | ExprNode* body = nullptr; | ||
481 | |||
482 | Lambda(): ExprNode(NodeKind::Lambda) {} | ||
483 | }; | ||
484 | |||
485 | struct IfExp: public ExprNode { | ||
486 | ExprNode* test = nullptr; | ||
487 | ExprNode* body = nullptr; | ||
488 | ExprNode* orelse = nullptr; | ||
489 | |||
490 | IfExp(): ExprNode(NodeKind::IfExp) {} | ||
491 | }; | ||
492 | |||
493 | struct DictExpr: public ExprNode { | ||
494 | Array<ExprNode*> keys; | ||
495 | Array<ExprNode*> values; | ||
496 | |||
497 | DictExpr(): ExprNode(NodeKind::DictExpr) {} | ||
498 | }; | ||
499 | |||
500 | struct SetExpr: public ExprNode { | ||
501 | Array<ExprNode*> elts; | ||
502 | |||
503 | SetExpr(): ExprNode(NodeKind::SetExpr) {} | ||
504 | }; | ||
505 | |||
506 | struct ListComp: public ExprNode { | ||
507 | ExprNode* elt = nullptr; | ||
508 | Array<Comprehension> generators; | ||
509 | |||
510 | ListComp(): ExprNode(NodeKind::ListComp) {} | ||
511 | }; | ||
512 | |||
513 | struct GeneratorExp: public ExprNode { | ||
514 | ExprNode* elt = nullptr; | ||
515 | Array<Comprehension> generators; | ||
516 | |||
517 | GeneratorExp(): ExprNode(NodeKind::GeneratorExp) {} | ||
518 | }; | ||
519 | |||
520 | struct SetComp: public ExprNode { | ||
521 | ExprNode* elt = nullptr; | ||
522 | Array<Comprehension> generators; | ||
523 | |||
524 | SetComp(): ExprNode(NodeKind::SetComp) {} | ||
525 | }; | ||
526 | |||
527 | struct DictComp: public ExprNode { | ||
528 | ExprNode* key = nullptr; | ||
529 | ExprNode* value = nullptr; | ||
530 | Array<Comprehension> generators; | ||
531 | |||
532 | DictComp(): ExprNode(NodeKind::DictComp) {} | ||
533 | }; | ||
534 | |||
535 | // the grammar constrains where yield expressions can occur | ||
536 | struct Await: public ExprNode { | ||
537 | ExprNode* value; | ||
538 | |||
539 | Await(): ExprNode(NodeKind::Await) {} | ||
540 | }; | ||
541 | |||
542 | #undef Yield | ||
543 | struct Yield: public ExprNode { | ||
544 | Optional<ExprNode*> value; | ||
545 | |||
546 | Yield(): ExprNode(NodeKind::Yield) {} | ||
547 | }; | ||
548 | |||
549 | struct YieldFrom: public ExprNode { | ||
550 | ExprNode* value = nullptr; | ||
551 | |||
552 | YieldFrom(): ExprNode(NodeKind::YieldFrom) {} | ||
553 | }; | ||
554 | |||
555 | struct Call: public ExprNode { | ||
556 | ExprNode* func = nullptr; | ||
557 | Array<ExprNode*> args; | ||
558 | Array<Keyword> keywords; | ||
559 | |||
560 | Call(): ExprNode(NodeKind::Call) {} | ||
561 | }; | ||
562 | |||
563 | struct JoinedStr: public ExprNode { | ||
564 | Array<ExprNode*> values; | ||
565 | |||
566 | JoinedStr(): ExprNode(NodeKind::JoinedStr) {} | ||
567 | }; | ||
568 | |||
569 | struct FormattedValue: public ExprNode { | ||
570 | ExprNode* value = nullptr; | ||
571 | 15 | Optional<ConversionKind> conversion = ConversionKind::None; | |
572 | // defined as ExprNode* | ||
573 | JoinedStr* format_spec; | ||
574 | |||
575 | FormattedValue(): ExprNode(NodeKind::FormattedValue) {} | ||
576 | }; | ||
577 | |||
578 | // the following expression can appear in assignment context | ||
579 | struct Attribute: public ExprNode { | ||
580 | ExprNode* value = nullptr; | ||
581 | Identifier attr; | ||
582 | ExprContext ctx; | ||
583 | |||
584 | // SEMA | ||
585 | int attrid = 0; | ||
586 | |||
587 | Attribute(): ExprNode(NodeKind::Attribute) {} | ||
588 | }; | ||
589 | |||
590 | struct Subscript: public ExprNode { | ||
591 | ExprNode* value = nullptr; | ||
592 | ExprNode* slice = nullptr; | ||
593 | ExprContext ctx; | ||
594 | |||
595 | Subscript(): ExprNode(NodeKind::Subscript) {} | ||
596 | }; | ||
597 | |||
598 | struct Starred: public ExprNode { | ||
599 | ExprNode* value = nullptr; | ||
600 | ExprContext ctx; | ||
601 | |||
602 | Starred(): ExprNode(NodeKind::Starred) {} | ||
603 | }; | ||
604 | |||
605 | struct Name: public ExprNode { | ||
606 | Identifier id; | ||
607 | ExprContext ctx; | ||
608 | |||
609 | // Variable id, resolved by SEMA | ||
610 | int varid = -1; | ||
611 | int size = -1; // size of the context when it was defined | ||
612 | int offset = -1; // reverse offset to use for lookup | ||
613 | bool dynamic = false; // if true we will do a reverse lookup to take into account that | ||
614 | // recursive call make the binding table offset | ||
615 | |||
616 | Name(): ExprNode(NodeKind::Name) {} | ||
617 | }; | ||
618 | |||
619 | struct ListExpr: public ExprNode { | ||
620 | Array<ExprNode*> elts; | ||
621 | ExprContext ctx; | ||
622 | |||
623 | ListExpr(): ExprNode(NodeKind::ListExpr) {} | ||
624 | }; | ||
625 | |||
626 | struct TupleExpr: public ExprNode { | ||
627 | Array<ExprNode*> elts; | ||
628 | ExprContext ctx; | ||
629 | |||
630 | TupleExpr(): ExprNode(NodeKind::TupleExpr) {} | ||
631 | }; | ||
632 | |||
633 | // can appear only in Subscript | ||
634 | struct Slice: public ExprNode { | ||
635 | Optional<ExprNode*> lower; | ||
636 | Optional<ExprNode*> upper; | ||
637 | Optional<ExprNode*> step; | ||
638 | |||
639 | Slice(): ExprNode(NodeKind::Slice) {} | ||
640 | }; | ||
641 | |||
642 | // Modules | ||
643 | // ------- | ||
644 | struct Module: public ModNode { | ||
645 | Array<StmtNode*> body; | ||
646 | |||
647 | Optional<String> docstring; | ||
648 | |||
649 | Module(): ModNode(NodeKind::Module) {} | ||
650 | }; | ||
651 | |||
652 | struct Interactive: public ModNode { | ||
653 | Array<StmtNode*> body; | ||
654 | |||
655 | Interactive(): ModNode(NodeKind::Interactive) {} | ||
656 | }; | ||
657 | |||
658 | struct Expression: public ModNode { | ||
659 | ExprNode* body = nullptr; | ||
660 | |||
661 | Expression(): ModNode(NodeKind::Expression) {} | ||
662 | }; | ||
663 | |||
664 | struct FunctionType: public ModNode { | ||
665 | Array<ExprNode*> argtypes; | ||
666 | ExprNode* returns = nullptr; | ||
667 | |||
668 | FunctionType(): ModNode(NodeKind::FunctionType) {} | ||
669 | }; | ||
670 | |||
671 | // Statements | ||
672 | // ---------- | ||
673 | |||
674 | // This is used for error recovery | ||
675 | struct InvalidStatement: public StmtNode { | ||
676 | // FIXME: this node should take ownership of the parsing error | ||
677 | // struct ParsingError* error = nullptr; | ||
678 | |||
679 | Array<Token> tokens; | ||
680 | |||
681 | InvalidStatement(): StmtNode(NodeKind::InvalidStatement) {} | ||
682 | }; | ||
683 | |||
684 | struct Inline: public StmtNode { | ||
685 | // <stmt>; <stmt> | ||
686 | Array<StmtNode*> body; | ||
687 | |||
688 | Inline(): StmtNode(NodeKind::Inline) {} | ||
689 | }; | ||
690 | |||
691 | struct Decorator { | ||
692 | ExprNode* expr = nullptr; | ||
693 | Comment* comment = nullptr; | ||
694 | |||
695 | Decorator(ExprNode* deco, Comment* com = nullptr): expr(deco), comment(com) {} | ||
696 | }; | ||
697 | |||
698 | struct Docstring { | ||
699 | String docstring; | ||
700 | Comment* comment = nullptr; | ||
701 | |||
702 | Docstring(String const& doc, Comment* com = nullptr): docstring(doc), comment(com) {} | ||
703 | }; | ||
704 | |||
705 | struct FunctionDef: public StmtNode { | ||
706 | Identifier name; | ||
707 | Arguments args; | ||
708 | Array<StmtNode*> body; | ||
709 | Array<Decorator> decorator_list = {}; | ||
710 | Optional<ExprNode*> returns; | ||
711 | String type_comment; | ||
712 | Optional<Docstring> docstring; | ||
713 | |||
714 | bool async : 1; | ||
715 | // SEMA | ||
716 | bool generator : 1; | ||
717 | struct Arrow* type = nullptr; | ||
718 | |||
719 | FunctionDef(): StmtNode(NodeKind::FunctionDef), async(false), generator(false) {} | ||
720 | }; | ||
721 | |||
722 | struct AsyncFunctionDef: public FunctionDef {}; | ||
723 | |||
724 | struct ClassDef: public StmtNode { | ||
725 | Identifier name; | ||
726 | Array<ExprNode*> bases; | ||
727 | Array<Keyword> keywords; | ||
728 | Array<StmtNode*> body; | ||
729 | Array<Decorator> decorator_list = {}; | ||
730 | Optional<Docstring> docstring; | ||
731 | |||
732 | ClassDef(): StmtNode(NodeKind::ClassDef) {} | ||
733 | |||
734 | // Sema populates this, this is for nested classes | ||
735 | String cls_namespace; | ||
736 | |||
737 | // To match python AST the body of the class is a simple Array of statement | ||
738 | // but this is not very convenient for semantic analysis | ||
739 | // | ||
740 | |||
741 | struct Attr { | ||
742 | Attr(StringRef name, int offset = -1, StmtNode* stmt = nullptr, ExprNode* type = nullptr): | ||
743 | 21 | name(name), offset(offset), stmt(stmt), type(type) | |
744 | // | ||
745 | 21 | {} | |
746 | |||
747 | StringRef name; | ||
748 | int offset = -1; | ||
749 | StmtNode* stmt = nullptr; | ||
750 | ExprNode* type = nullptr; | ||
751 | |||
752 | operator bool() { return name != StringRef(); } | ||
753 | |||
754 | void dump(std::ostream& out); | ||
755 | }; | ||
756 | // Dict<StringRef, Attr> attributes; | ||
757 | Array<Attr> attributes; // <= Instantiated Object | ||
758 | // Array<Attr> static_attributes; // <= Namespaced Globals | ||
759 | Array<Attr> methods; | ||
760 | |||
761 | void dump(std::ostream& out) { | ||
762 | out << "Attributes:\n"; | ||
763 | for (auto& item: attributes) { | ||
764 | out << "`" << item.name << "` "; | ||
765 | item.dump(out); | ||
766 | out << "\n"; | ||
767 | } | ||
768 | } | ||
769 | |||
770 | int get_attribute(StringRef name) { | ||
771 | |||
772 | 49 | int i = 0; | |
773 |
2/2✓ Branch 4 taken 32 times.
✓ Branch 5 taken 34 times.
|
66 | for (Attr& att: attributes) { |
774 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 17 times.
|
32 | if (att.name == name) { |
775 | 15 | return i; | |
776 | } | ||
777 | |||
778 | 17 | i += 1; | |
779 | } | ||
780 | |||
781 | 34 | return -1; | |
782 | } | ||
783 | |||
784 | bool insert_method(StringRef name, StmtNode* stmt = nullptr, ExprNode* type = nullptr) { | ||
785 |
1/1✓ Branch 1 taken 8 times.
|
8 | int attrid = get_attribute(name); |
786 | |||
787 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (attrid == -1) { |
788 |
1/1✓ Branch 2 taken 8 times.
|
8 | methods.emplace_back(name, int(methods.size()), stmt, type); |
789 | 8 | return true; | |
790 | } | ||
791 | |||
792 | ✗ | Attr& v = methods[attrid]; | |
793 | |||
794 | ✗ | if (!v.type && type) { | |
795 | ✗ | v.type = type; | |
796 | } | ||
797 | |||
798 | ✗ | return false; | |
799 | } | ||
800 | |||
801 | bool insert_attribute(StringRef name, StmtNode* stmt = nullptr, ExprNode* type = nullptr) { | ||
802 |
1/1✓ Branch 1 taken 15 times.
|
15 | int attrid = get_attribute(name); |
803 | |||
804 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
|
15 | if (attrid == -1) { |
805 |
1/1✓ Branch 2 taken 13 times.
|
13 | attributes.emplace_back(name, int(attributes.size()), stmt, type); |
806 | 13 | return true; | |
807 | } | ||
808 | |||
809 | 2 | Attr& v = attributes[attrid]; | |
810 | |||
811 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if (!v.type && type) { |
812 | ✗ | v.type = type; | |
813 | } | ||
814 | |||
815 | 2 | return false; | |
816 | } | ||
817 | }; | ||
818 | |||
819 | struct Return: public StmtNode { | ||
820 | Optional<ExprNode*> value; | ||
821 | |||
822 | Return(): StmtNode(NodeKind::Return) {} | ||
823 | }; | ||
824 | |||
825 | struct Delete: public StmtNode { | ||
826 | Array<ExprNode*> targets; | ||
827 | |||
828 | Delete(): StmtNode(NodeKind::Delete) {} | ||
829 | }; | ||
830 | |||
831 | struct Assign: public StmtNode { | ||
832 | // The array is useless; | ||
833 | // only the first element is ever populated ? | ||
834 | // a, b = c | ||
835 | // Tuple(a, b) = c | ||
836 | // | ||
837 | Array<ExprNode*> targets; | ||
838 | ExprNode* value = nullptr; | ||
839 | Optional<String> type_comment; | ||
840 | |||
841 | Assign(): StmtNode(NodeKind::Assign) {} | ||
842 | }; | ||
843 | |||
844 | struct AugAssign: public StmtNode { | ||
845 | using NativeBinaryOp = ConstantValue (*)(ConstantValue const&, ConstantValue const&); | ||
846 | |||
847 | ExprNode* target = nullptr; | ||
848 | BinaryOperator op; | ||
849 | ExprNode* value = nullptr; | ||
850 | |||
851 | // Function to apply, resolved by the sema | ||
852 | StmtNode* resolved_operator = nullptr; | ||
853 | NativeBinaryOp native_operator = nullptr; | ||
854 | |||
855 | AugAssign(): StmtNode(NodeKind::AugAssign) {} | ||
856 | }; | ||
857 | |||
858 | // 'simple' indicates that we annotate simple name without parens | ||
859 | struct AnnAssign: public StmtNode { | ||
860 | ExprNode* target = nullptr; | ||
861 | ExprNode* annotation = nullptr; | ||
862 | Optional<ExprNode*> value; | ||
863 | int simple; | ||
864 | |||
865 | AnnAssign(): StmtNode(NodeKind::AnnAssign) {} | ||
866 | }; | ||
867 | |||
868 | // use 'orelse' because else is a keyword in target languages | ||
869 | struct For: public StmtNode { | ||
870 | ExprNode* target = nullptr; | ||
871 | ExprNode* iter = nullptr; | ||
872 | Array<StmtNode*> body; | ||
873 | Array<StmtNode*> orelse; | ||
874 | Optional<String> type_comment; | ||
875 | |||
876 | bool async = false; | ||
877 | |||
878 | For(): StmtNode(NodeKind::For) {} | ||
879 | |||
880 | Comment* else_comment = nullptr; | ||
881 | }; | ||
882 | |||
883 | // Keeping it for consistency with python docs, but useless | ||
884 | struct AsyncFor: public For {}; | ||
885 | |||
886 | struct While: public StmtNode { | ||
887 | ExprNode* test = nullptr; | ||
888 | Array<StmtNode*> body; | ||
889 | Array<StmtNode*> orelse; | ||
890 | |||
891 | While(): StmtNode(NodeKind::While) {} | ||
892 | |||
893 | Comment* else_comment = nullptr; | ||
894 | }; | ||
895 | |||
896 | struct If: public StmtNode { | ||
897 | ExprNode* test = nullptr; | ||
898 | Array<StmtNode*> body; | ||
899 | Array<StmtNode*> orelse; | ||
900 | |||
901 | // alternative representation that diverges from | ||
902 | // the python ast | ||
903 | Array<ExprNode*> tests; | ||
904 | Array<Array<StmtNode*>> bodies; | ||
905 | |||
906 | If(): StmtNode(NodeKind::If) {} | ||
907 | |||
908 | Array<Comment*> tests_comment; | ||
909 | Comment* else_comment = nullptr; | ||
910 | }; | ||
911 | |||
912 | struct With: public StmtNode { | ||
913 | Array<WithItem> items; | ||
914 | Array<StmtNode*> body; | ||
915 | Optional<String> type_comment; | ||
916 | |||
917 | bool async = false; | ||
918 | |||
919 | With(): StmtNode(NodeKind::With) {} | ||
920 | }; | ||
921 | |||
922 | // Keeping it for consistency with python docs, but useless | ||
923 | struct AsyncWith: public With {}; | ||
924 | |||
925 | struct Raise: public StmtNode { | ||
926 | Optional<ExprNode*> exc; | ||
927 | Optional<ExprNode*> cause; | ||
928 | |||
929 | Raise(): StmtNode(NodeKind::Raise) {} | ||
930 | }; | ||
931 | |||
932 | struct Try: public StmtNode { | ||
933 | Array<StmtNode*> body; | ||
934 | Array<ExceptHandler> handlers; | ||
935 | Array<StmtNode*> orelse; | ||
936 | Array<StmtNode*> finalbody; | ||
937 | |||
938 | Try(): StmtNode(NodeKind::Try) {} | ||
939 | |||
940 | Comment* else_comment = nullptr; | ||
941 | Comment* finally_comment = nullptr; | ||
942 | }; | ||
943 | |||
944 | struct Assert: public StmtNode { | ||
945 | ExprNode* test = nullptr; | ||
946 | Optional<ExprNode*> msg; | ||
947 | |||
948 | Assert(): StmtNode(NodeKind::Assert) {} | ||
949 | }; | ||
950 | |||
951 | struct Import: public StmtNode { | ||
952 | Array<Alias> names; | ||
953 | |||
954 | Import(): StmtNode(NodeKind::Import) {} | ||
955 | }; | ||
956 | |||
957 | struct ImportFrom: public StmtNode { | ||
958 | Optional<Identifier> module; | ||
959 | Array<Alias> names; | ||
960 | Optional<int> level; | ||
961 | |||
962 | ImportFrom(): StmtNode(NodeKind::ImportFrom) {} | ||
963 | }; | ||
964 | |||
965 | struct Global: public StmtNode { | ||
966 | Array<Identifier> names; | ||
967 | |||
968 | Global(): StmtNode(NodeKind::Global) {} | ||
969 | }; | ||
970 | |||
971 | struct Nonlocal: public StmtNode { | ||
972 | Array<Identifier> names; | ||
973 | |||
974 | Nonlocal(): StmtNode(NodeKind::Nonlocal) {} | ||
975 | }; | ||
976 | |||
977 | struct Expr: public StmtNode { | ||
978 | ExprNode* value = nullptr; | ||
979 | |||
980 | Expr(): StmtNode(NodeKind::Expr) {} | ||
981 | }; | ||
982 | |||
983 | struct Pass: public StmtNode { | ||
984 | |||
985 | Pass(): StmtNode(NodeKind::Pass) {} | ||
986 | }; | ||
987 | |||
988 | struct Break: public StmtNode { | ||
989 | |||
990 | Break(): StmtNode(NodeKind::Break) {} | ||
991 | }; | ||
992 | |||
993 | struct Continue: public StmtNode { | ||
994 | |||
995 | Continue(): StmtNode(NodeKind::Continue) {} | ||
996 | }; | ||
997 | |||
998 | struct Match: public StmtNode { | ||
999 | ExprNode* subject; | ||
1000 | Array<MatchCase> cases; | ||
1001 | |||
1002 | Match(): StmtNode(NodeKind::Match) {} | ||
1003 | }; | ||
1004 | |||
1005 | // | ||
1006 | struct NotImplementedStmt: public StmtNode { | ||
1007 | NotImplementedStmt(): StmtNode(NodeKind::Invalid) {} | ||
1008 | }; | ||
1009 | |||
1010 | struct NotImplementedExpr: public ExprNode { | ||
1011 | NotImplementedExpr(): ExprNode(NodeKind::Invalid) {} | ||
1012 | }; | ||
1013 | |||
1014 | struct NotAllowedEpxr: public ExprNode { | ||
1015 | NotAllowedEpxr(): ExprNode(NodeKind::Invalid) {} | ||
1016 | |||
1017 | String msg; | ||
1018 | }; | ||
1019 | |||
1020 | // Record a function type as positional arguments only | ||
1021 | // makes it easier to re-order the arguments and insert defaults | ||
1022 | struct Arrow: public ExprNode { | ||
1023 | Arrow(): ExprNode(NodeKind::Arrow) {} | ||
1024 | |||
1025 | // TODO: check how to resolve circular types | ||
1026 | // | ||
1027 | bool add_arg_type(ExprNode* arg_type); | ||
1028 | bool set_arg_type(int i, ExprNode* arg_type); | ||
1029 | |||
1030 | Array<StringRef> names; // Allow the names to be there as well | ||
1031 | Dict<StringRef, bool> defaults; // | ||
1032 | ExprNode* returns = nullptr; | ||
1033 | |||
1034 | int arg_count() const { return int(args.size()); } | ||
1035 | |||
1036 | Array<ExprNode*> args; | ||
1037 | }; | ||
1038 | |||
1039 | struct DictType: public ExprNode { | ||
1040 | DictType(): ExprNode(NodeKind::DictType) {} | ||
1041 | |||
1042 | ExprNode* key = nullptr; | ||
1043 | ExprNode* value = nullptr; | ||
1044 | }; | ||
1045 | |||
1046 | struct SetType: public ExprNode { | ||
1047 | SetType(): ExprNode(NodeKind::SetType) {} | ||
1048 | |||
1049 | ExprNode* value = nullptr; | ||
1050 | }; | ||
1051 | |||
1052 | struct ArrayType: public ExprNode { | ||
1053 | ArrayType(): ExprNode(NodeKind::ArrayType) {} | ||
1054 | |||
1055 | ExprNode* value = nullptr; | ||
1056 | }; | ||
1057 | |||
1058 | struct TupleType: public ExprNode { | ||
1059 | TupleType(): ExprNode(NodeKind::TupleType) {} | ||
1060 | |||
1061 | Array<ExprNode*> types; | ||
1062 | }; | ||
1063 | |||
1064 | struct BuiltinType: public ExprNode { | ||
1065 | using NativeFunction = ConstantValue (*)(Array<Constant*> const& args); | ||
1066 | using NativeMacro = ExprNode* (*)(Array<Node*> const& args); | ||
1067 | |||
1068 | BuiltinType(): ExprNode(NodeKind::BuiltinType), native_function(nullptr) {} | ||
1069 | StringRef name; | ||
1070 | |||
1071 | // Maybe I need a native function Expr/Stmt instead ? | ||
1072 | NativeFunction native_function; | ||
1073 | NativeMacro native_macro; | ||
1074 | }; | ||
1075 | |||
1076 | // we need that to convert ClassDef which is a statement | ||
1077 | // into an expression | ||
1078 | // | ||
1079 | // Actually: I can use a Name for that | ||
1080 | // | ||
1081 | struct ClassType: public ExprNode { | ||
1082 | ClassType(): ExprNode(NodeKind::ClassType) {} | ||
1083 | ClassDef* def; | ||
1084 | }; | ||
1085 | |||
1086 | // This is essentially compile time lookup | ||
1087 | // no-need for the function to actually exist at runtime | ||
1088 | #define SPECGEN(name) \ | ||
1089 | template <> \ | ||
1090 | struct NodeTrait<name> { \ | ||
1091 | enum Constants \ | ||
1092 | { kind = int(NodeKind::name) }; \ | ||
1093 | }; | ||
1094 | |||
1095 | #define X(name, _) | ||
1096 | #define SSECTION(name) | ||
1097 | #define EXPR(name, _) SPECGEN(name) | ||
1098 | #define STMT(name, _) SPECGEN(name) | ||
1099 | #define MOD(name, _) SPECGEN(name) | ||
1100 | #define MATCH(name, _) SPECGEN(name) | ||
1101 | |||
1102 | NODEKIND_ENUM(X, SSECTION, EXPR, STMT, MOD, MATCH) | ||
1103 | |||
1104 | #undef X | ||
1105 | #undef SSECTION | ||
1106 | #undef EXPR | ||
1107 | #undef STMT | ||
1108 | #undef MOD | ||
1109 | #undef MATCH | ||
1110 | |||
1111 | #undef SPECGEN | ||
1112 | |||
1113 | // Safe cast | ||
1114 | template <typename T> | ||
1115 | 1036 | T* cast(Node* obj) { | |
1116 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 297 times.
|
1333 | if (obj == nullptr) { |
1117 | 183 | return nullptr; | |
1118 | } | ||
1119 |
2/2✓ Branch 1 taken 285 times.
✓ Branch 2 taken 12 times.
|
1150 | if (obj->is_instance<T>()) { |
1120 | 834 | return (T*)obj; | |
1121 | } | ||
1122 | 316 | return nullptr; | |
1123 | } | ||
1124 | |||
1125 | template <typename T> | ||
1126 | T const* cast(Node const* obj) { | ||
1127 | if (obj == nullptr) { | ||
1128 | return nullptr; | ||
1129 | } | ||
1130 | if (obj->is_instance<T>()) { | ||
1131 | return (T const*)obj; | ||
1132 | } | ||
1133 | return nullptr; | ||
1134 | } | ||
1135 | |||
1136 | template <typename T> | ||
1137 | T* checked_cast(Node* obj) { | ||
1138 | assert(obj->is_instance<T>(), | ||
1139 | fmt::format("Cast type is not compatible {} != {}", str(obj->kind), str(nodekind<T>()))); | ||
1140 | return cast<T>(obj); | ||
1141 | } | ||
1142 | |||
1143 | } // namespace lython | ||
1144 | #endif | ||
1145 |