GCC Code Coverage Report


Directory: ./
File: src/ast/nodes.h
Date: 2023-04-27 00:55:30
Exec Total Coverage
Lines: 41 50 82.0%
Functions: 120 125 96.0%
Branches: 25 38 65.8%

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