Line data Source code
1 : #ifndef RUST_AST_EXPR_H
2 : #define RUST_AST_EXPR_H
3 :
4 : #include "optional.h"
5 : #include "rust-ast.h"
6 : #include "rust-common.h"
7 : #include "rust-path.h"
8 : #include "rust-macro.h"
9 : #include "rust-operators.h"
10 :
11 : namespace Rust {
12 : namespace AST {
13 : /* TODO: if GCC moves to C++17 or allows boost, replace some boolean
14 : * "has_whatever" pairs with
15 : * optional types (std::optional or boost::optional)? */
16 :
17 : // Loop label expression AST node used with break and continue expressions
18 : // TODO: inline?
19 549 : class LoopLabel /*: public Visitable*/
20 : {
21 : Lifetime label; // or type LIFETIME_OR_LABEL
22 : location_t locus;
23 :
24 : NodeId node_id;
25 :
26 : public:
27 : std::string as_string () const;
28 :
29 63 : LoopLabel (Lifetime loop_label, location_t locus = UNDEF_LOCATION)
30 63 : : label (std::move (loop_label)), locus (locus),
31 63 : node_id (Analysis::Mappings::get ().get_next_node_id ())
32 63 : {}
33 :
34 : // Returns whether the LoopLabel is in an error state.
35 81 : location_t get_locus () const { return locus; }
36 :
37 1089 : Lifetime &get_lifetime () { return label; }
38 :
39 36 : NodeId get_node_id () const { return node_id; }
40 : };
41 :
42 : // AST node for an expression with an accompanying block - abstract
43 48546 : class ExprWithBlock : public Expr
44 : {
45 : protected:
46 : // pure virtual clone implementation
47 : virtual ExprWithBlock *clone_expr_with_block_impl () const = 0;
48 :
49 : // prevent having to define multiple clone expressions
50 13546 : ExprWithBlock *clone_expr_impl () const final override
51 : {
52 13546 : return clone_expr_with_block_impl ();
53 : }
54 :
55 17975 : bool is_expr_without_block () const final override { return false; };
56 :
57 : public:
58 : // Unique pointer custom clone function
59 1689 : std::unique_ptr<ExprWithBlock> clone_expr_with_block () const
60 : {
61 1689 : return std::unique_ptr<ExprWithBlock> (clone_expr_with_block_impl ());
62 : }
63 : };
64 :
65 : // Literals? Or literal base?
66 : class LiteralExpr : public ExprWithoutBlock
67 : {
68 : std::vector<Attribute> outer_attrs;
69 : Literal literal;
70 : location_t locus;
71 :
72 : public:
73 6695 : std::string as_string () const override { return literal.as_string (); }
74 :
75 6648 : Literal::LitType get_lit_type () const { return literal.get_lit_type (); }
76 :
77 37724 : LiteralExpr (std::string value_as_string, Literal::LitType type,
78 : PrimitiveCoreType type_hint, std::vector<Attribute> outer_attrs,
79 : location_t locus)
80 75448 : : outer_attrs (std::move (outer_attrs)),
81 37724 : literal (std::move (value_as_string), type, type_hint), locus (locus)
82 37724 : {}
83 :
84 0 : LiteralExpr (Literal literal, std::vector<Attribute> outer_attrs,
85 : location_t locus)
86 0 : : outer_attrs (std::move (outer_attrs)), literal (std::move (literal)),
87 0 : locus (locus)
88 0 : {}
89 :
90 : // Unique pointer custom clone function
91 : std::unique_ptr<LiteralExpr> clone_literal_expr () const
92 : {
93 : return std::unique_ptr<LiteralExpr> (clone_literal_expr_impl ());
94 : }
95 :
96 43243 : location_t get_locus () const override final { return locus; }
97 :
98 233 : bool is_literal () const override final { return true; }
99 :
100 22393 : Literal get_literal () const { return literal; }
101 :
102 : void accept_vis (ASTVisitor &vis) override;
103 :
104 : // Invalid if literal is in error state, so base stripping on that.
105 0 : void mark_for_strip () override { literal = Literal::create_error (); }
106 612258 : bool is_marked_for_strip () const override { return literal.is_error (); }
107 :
108 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
109 2776755 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
110 :
111 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
112 : {
113 0 : outer_attrs = std::move (new_attrs);
114 0 : }
115 :
116 18851 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Literal; }
117 :
118 : protected:
119 : /* Use covariance to implement clone function as returning this object rather
120 : * than base */
121 43868 : LiteralExpr *clone_expr_without_block_impl () const final override
122 : {
123 43868 : return clone_literal_expr_impl ();
124 : }
125 :
126 : /* not virtual as currently no subclasses of LiteralExpr, but could be in
127 : * future */
128 43868 : /*virtual*/ LiteralExpr *clone_literal_expr_impl () const
129 : {
130 43868 : return new LiteralExpr (*this);
131 : }
132 : };
133 :
134 : // Literal expression attribute body (non-macro attribute)
135 42812 : class AttrInputLiteral : public AttrInput
136 : {
137 : LiteralExpr literal_expr;
138 :
139 : public:
140 11747 : AttrInputLiteral (LiteralExpr lit_expr) : literal_expr (std::move (lit_expr))
141 : {}
142 :
143 57 : std::string as_string () const override
144 : {
145 114 : return " = " + literal_expr.as_string ();
146 : }
147 :
148 : void accept_vis (ASTVisitor &vis) override;
149 :
150 : /* this can never be a cfg predicate - cfg and cfg_attr require a token-tree
151 : * cfg */
152 0 : bool check_cfg_predicate (const Session &) const override { return false; }
153 :
154 0 : bool is_meta_item () const override { return false; }
155 :
156 175786 : LiteralExpr &get_literal () { return literal_expr; }
157 :
158 22519 : AttrInputType get_attr_input_type () const final override
159 : {
160 22519 : return AttrInput::AttrInputType::LITERAL;
161 : }
162 :
163 : protected:
164 : /* Use covariance to implement clone function as returning this object rather
165 : * than base */
166 42812 : AttrInputLiteral *clone_attr_input_impl () const override
167 : {
168 42812 : return new AttrInputLiteral (*this);
169 : }
170 : };
171 :
172 : class AttrInputExpr : public AttrInput
173 : {
174 : std::unique_ptr<Expr> expr;
175 :
176 : public:
177 1 : AttrInputExpr (std::unique_ptr<Expr> expr) : expr (std::move (expr)) {}
178 :
179 : AttrInputExpr (const AttrInputExpr &oth);
180 :
181 : AttrInputExpr (AttrInputExpr &&oth) : expr (std::move (oth.expr)) {}
182 :
183 0 : AttrInputType get_attr_input_type () const final override
184 : {
185 0 : return AttrInput::AttrInputType::EXPR;
186 : }
187 :
188 : AttrInputExpr &operator= (const AttrInputExpr &oth);
189 :
190 : AttrInputExpr &operator= (AttrInputExpr &&oth)
191 : {
192 : expr = std::move (oth.expr);
193 : return *this;
194 : }
195 :
196 : std::string as_string () const override;
197 :
198 : void accept_vis (ASTVisitor &vis) override;
199 :
200 0 : bool check_cfg_predicate (const Session &) const override { return false; }
201 :
202 : // assuming this is like AttrInputLiteral
203 0 : bool is_meta_item () const override { return false; }
204 :
205 5 : Expr &get_expr () { return *expr; }
206 :
207 0 : AttrInputExpr *clone_attr_input_impl () const override
208 : {
209 0 : return new AttrInputExpr (*this);
210 : }
211 : };
212 :
213 : // Like an AttrInputLiteral, but stores a MacroInvocation
214 : class AttrInputMacro : public AttrInput
215 : {
216 : std::unique_ptr<MacroInvocation> macro;
217 :
218 : public:
219 4 : AttrInputMacro (std::unique_ptr<MacroInvocation> macro)
220 4 : : macro (std::move (macro))
221 : {}
222 :
223 : AttrInputMacro (const AttrInputMacro &oth);
224 :
225 : AttrInputMacro (AttrInputMacro &&oth) : macro (std::move (oth.macro)) {}
226 :
227 : AttrInputMacro &operator= (const AttrInputMacro &oth);
228 :
229 : AttrInputMacro &operator= (AttrInputMacro &&oth)
230 : {
231 : macro = std::move (oth.macro);
232 : return *this;
233 : }
234 :
235 : std::string as_string () const override;
236 :
237 : void accept_vis (ASTVisitor &vis) override;
238 :
239 : // assuming this can't be a cfg predicate
240 0 : bool check_cfg_predicate (const Session &) const override { return false; }
241 :
242 : // assuming this is like AttrInputLiteral
243 0 : bool is_meta_item () const override { return false; }
244 :
245 34 : std::unique_ptr<MacroInvocation> &get_macro () { return macro; }
246 :
247 1 : AttrInputType get_attr_input_type () const final override
248 : {
249 1 : return AttrInput::AttrInputType::MACRO;
250 : }
251 :
252 : protected:
253 16 : AttrInputMacro *clone_attr_input_impl () const override
254 : {
255 16 : return new AttrInputMacro (*this);
256 : }
257 : };
258 :
259 : /* literal expr only meta item inner - TODO possibly replace with inheritance of
260 : * LiteralExpr itself? */
261 0 : class MetaItemLitExpr : public MetaItemInner
262 : {
263 : LiteralExpr lit_expr;
264 :
265 : public:
266 28 : MetaItemLitExpr (LiteralExpr lit_expr) : lit_expr (std::move (lit_expr)) {}
267 :
268 8 : std::string as_string () const override { return lit_expr.as_string (); }
269 :
270 1 : location_t get_locus () const override { return lit_expr.get_locus (); }
271 :
272 : LiteralExpr get_literal () const { return lit_expr; }
273 :
274 0 : LiteralExpr &get_literal () { return lit_expr; }
275 :
276 : void accept_vis (ASTVisitor &vis) override;
277 :
278 : bool check_cfg_predicate (const Session &session) const override;
279 :
280 0 : MetaItemInner::Kind get_kind () override
281 : {
282 0 : return MetaItemInner::Kind::LitExpr;
283 : }
284 :
285 : protected:
286 : // Use covariance to implement clone function as returning this type
287 0 : MetaItemLitExpr *clone_meta_item_inner_impl () const override
288 : {
289 0 : return new MetaItemLitExpr (*this);
290 : }
291 : };
292 :
293 : // more generic meta item "path = expr" form
294 : class MetaItemPathExpr : public MetaItem
295 : {
296 : SimplePath path;
297 : std::unique_ptr<Expr> expr;
298 :
299 : public:
300 2 : MetaItemPathExpr (SimplePath path, std::unique_ptr<Expr> expr)
301 2 : : path (std::move (path)), expr (std::move (expr))
302 : {}
303 :
304 0 : MetaItemPathExpr (const MetaItemPathExpr &other)
305 0 : : MetaItem (other), path (other.path), expr (other.expr->clone_expr ())
306 0 : {}
307 :
308 : MetaItemPathExpr (MetaItemPathExpr &&) = default;
309 :
310 : MetaItemPathExpr &operator= (MetaItemPathExpr &&) = default;
311 :
312 : MetaItemPathExpr operator= (const MetaItemPathExpr &other)
313 : {
314 : MetaItem::operator= (other);
315 : path = other.path;
316 : expr = other.expr->clone_expr ();
317 : return *this;
318 : }
319 :
320 : SimplePath get_path () const { return path; }
321 :
322 1 : SimplePath &get_path () { return path; }
323 :
324 4 : Expr &get_expr () { return *expr; }
325 :
326 0 : std::unique_ptr<Expr> &get_expr_ptr () { return expr; }
327 :
328 1 : std::string as_string () const override
329 : {
330 1 : return path.as_string () + " = " + expr->as_string ();
331 : }
332 :
333 0 : MetaItem::ItemKind get_item_kind () const override
334 : {
335 0 : return MetaItem::ItemKind::PathExpr;
336 : }
337 :
338 1 : location_t get_locus () const override { return path.get_locus (); }
339 :
340 : void accept_vis (ASTVisitor &vis) override;
341 :
342 : bool check_cfg_predicate (const Session &session) const override;
343 : /* TODO: return true if "ident" is defined and value of it is "lit", return
344 : * false otherwise */
345 :
346 : Attribute to_attribute () const override;
347 :
348 : protected:
349 : // Use covariance to implement clone function as returning this type
350 0 : MetaItemPathExpr *clone_meta_item_inner_impl () const override
351 : {
352 0 : return new MetaItemPathExpr (*this);
353 : }
354 : };
355 :
356 : /* Represents an expression using unary or binary operators as AST node. Can be
357 : * overloaded. */
358 : class OperatorExpr : public ExprWithoutBlock
359 : {
360 : // TODO: create binary and unary operator subclasses?
361 : private:
362 : location_t locus;
363 :
364 : protected:
365 : /* Variables must be protected to allow derived classes to use them as first
366 : * class citizens */
367 : std::vector<Attribute> outer_attrs;
368 : std::unique_ptr<Expr> main_or_left_expr;
369 :
370 : // Constructor (only for initialisation of expr purposes)
371 22571 : OperatorExpr (std::unique_ptr<Expr> main_or_left_expr,
372 : std::vector<Attribute> outer_attribs, location_t locus)
373 45142 : : locus (locus), outer_attrs (std::move (outer_attribs)),
374 22571 : main_or_left_expr (std::move (main_or_left_expr))
375 22571 : {}
376 :
377 : // Copy constructor (only for initialisation of expr purposes)
378 41391 : OperatorExpr (OperatorExpr const &other)
379 41391 : : locus (other.locus), outer_attrs (other.outer_attrs)
380 : {
381 : // guard to prevent null dereference (only required if error state)
382 41391 : if (other.main_or_left_expr != nullptr)
383 41391 : main_or_left_expr = other.main_or_left_expr->clone_expr ();
384 41391 : }
385 :
386 : // Overload assignment operator to deep copy expr
387 : OperatorExpr &operator= (OperatorExpr const &other)
388 : {
389 : ExprWithoutBlock::operator= (other);
390 : locus = other.locus;
391 : outer_attrs = other.outer_attrs;
392 :
393 : // guard to prevent null dereference (only required if error state)
394 : if (other.main_or_left_expr != nullptr)
395 : main_or_left_expr = other.main_or_left_expr->clone_expr ();
396 : else
397 : main_or_left_expr = nullptr;
398 :
399 : return *this;
400 : }
401 :
402 : // move constructors
403 : OperatorExpr (OperatorExpr &&other) = default;
404 : OperatorExpr &operator= (OperatorExpr &&other) = default;
405 :
406 : public:
407 40320 : location_t get_locus () const override final { return locus; }
408 :
409 : // Invalid if expr is null, so base stripping on that.
410 14 : void mark_for_strip () override { main_or_left_expr = nullptr; }
411 656065 : bool is_marked_for_strip () const override
412 : {
413 656065 : return main_or_left_expr == nullptr;
414 : }
415 :
416 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
417 2088554 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
418 :
419 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
420 : {
421 0 : outer_attrs = std::move (new_attrs);
422 0 : }
423 :
424 0 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Operator; }
425 : };
426 :
427 : /* Unary prefix & or &mut (or && and &&mut) borrow operator. Cannot be
428 : * overloaded. */
429 : class BorrowExpr : public OperatorExpr
430 : {
431 : Mutability mutability;
432 : bool raw_borrow;
433 : bool double_borrow;
434 :
435 : public:
436 : std::string as_string () const override;
437 :
438 1951 : BorrowExpr (std::unique_ptr<Expr> borrow_lvalue, Mutability mutability,
439 : bool raw_borrow, bool is_double_borrow,
440 : std::vector<Attribute> outer_attribs, location_t locus)
441 1951 : : OperatorExpr (std::move (borrow_lvalue), std::move (outer_attribs),
442 : locus),
443 1951 : mutability (mutability), raw_borrow (raw_borrow),
444 1951 : double_borrow (is_double_borrow)
445 1951 : {}
446 :
447 : void accept_vis (ASTVisitor &vis) override;
448 :
449 : // TODO: is this better? Or is a "vis_block" better?
450 55078 : Expr &get_borrowed_expr ()
451 : {
452 55078 : rust_assert (main_or_left_expr != nullptr);
453 55078 : return *main_or_left_expr;
454 : }
455 :
456 6739 : std::unique_ptr<Expr> &get_borrowed_expr_ptr ()
457 : {
458 6739 : rust_assert (main_or_left_expr != nullptr);
459 6739 : return main_or_left_expr;
460 : }
461 :
462 237 : bool has_borrow_expr () const { return main_or_left_expr != nullptr; }
463 :
464 474 : bool get_is_mut () const { return mutability == Mutability::Mut; }
465 :
466 1959 : Mutability get_mutability () const { return mutability; }
467 :
468 2173 : bool get_is_double_borrow () const { return double_borrow; }
469 4362 : bool is_raw_borrow () const { return raw_borrow; }
470 :
471 1942 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Borrow; }
472 :
473 : protected:
474 : /* Use covariance to implement clone function as returning this object rather
475 : * than base */
476 2154 : BorrowExpr *clone_expr_without_block_impl () const override
477 : {
478 2154 : return new BorrowExpr (*this);
479 : }
480 : };
481 :
482 : // Unary prefix * deference operator
483 14550 : class DereferenceExpr : public OperatorExpr
484 : {
485 : public:
486 : std::string as_string () const override;
487 :
488 : // Constructor calls OperatorExpr's protected constructor
489 3965 : DereferenceExpr (std::unique_ptr<Expr> deref_lvalue,
490 : std::vector<Attribute> outer_attribs, location_t locus)
491 3965 : : OperatorExpr (std::move (deref_lvalue), std::move (outer_attribs), locus)
492 3965 : {}
493 :
494 : void accept_vis (ASTVisitor &vis) override;
495 :
496 : // TODO: is this better? Or is a "vis_block" better?
497 67729 : Expr &get_dereferenced_expr ()
498 : {
499 67729 : rust_assert (main_or_left_expr != nullptr);
500 67729 : return *main_or_left_expr;
501 : }
502 :
503 13913 : std::unique_ptr<Expr> &get_dereferenced_expr_ptr ()
504 : {
505 13913 : rust_assert (main_or_left_expr != nullptr);
506 13913 : return main_or_left_expr;
507 : }
508 :
509 3963 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Dereference; }
510 :
511 : protected:
512 : /* Use covariance to implement clone function as returning this object rather
513 : * than base */
514 7275 : DereferenceExpr *clone_expr_without_block_impl () const override
515 : {
516 7275 : return new DereferenceExpr (*this);
517 : }
518 : };
519 :
520 : // Unary postfix ? error propogation operator. Cannot be overloaded.
521 4 : class ErrorPropagationExpr : public OperatorExpr
522 : {
523 : public:
524 : std::string as_string () const override;
525 :
526 : // Constructor calls OperatorExpr's protected constructor
527 1 : ErrorPropagationExpr (std::unique_ptr<Expr> potential_error_value,
528 : std::vector<Attribute> outer_attribs, location_t locus)
529 1 : : OperatorExpr (std::move (potential_error_value),
530 1 : std::move (outer_attribs), locus)
531 1 : {}
532 :
533 : void accept_vis (ASTVisitor &vis) override;
534 :
535 : // TODO: is this better? Or is a "vis_block" better?
536 14 : Expr &get_propagating_expr ()
537 : {
538 14 : rust_assert (main_or_left_expr != nullptr);
539 14 : return *main_or_left_expr;
540 : }
541 :
542 2 : std::unique_ptr<Expr> &get_propagating_expr_ptr ()
543 : {
544 2 : rust_assert (main_or_left_expr != nullptr);
545 2 : return main_or_left_expr;
546 : }
547 :
548 2 : Expr::Kind get_expr_kind () const override
549 : {
550 2 : return Expr::Kind::ErrorPropagation;
551 : }
552 :
553 : protected:
554 : /* Use covariance to implement clone function as returning this object rather
555 : * than base */
556 1 : ErrorPropagationExpr *clone_expr_without_block_impl () const override
557 : {
558 1 : return new ErrorPropagationExpr (*this);
559 : }
560 : };
561 :
562 : // Unary prefix - or ! negation or NOT operators.
563 1070 : class NegationExpr : public OperatorExpr
564 : {
565 : public:
566 : using ExprType = NegationOperator;
567 :
568 : private:
569 : /* Note: overload negation via std::ops::Neg and not via std::ops::Not
570 : * Negation only works for signed integer and floating-point types, NOT only
571 : * works for boolean and integer types (via bitwise NOT) */
572 : ExprType expr_type;
573 :
574 : public:
575 : std::string as_string () const override;
576 :
577 705 : ExprType get_expr_type () const { return expr_type; }
578 :
579 : // Constructor calls OperatorExpr's protected constructor
580 535 : NegationExpr (std::unique_ptr<Expr> negated_value, ExprType expr_kind,
581 : std::vector<Attribute> outer_attribs, location_t locus)
582 535 : : OperatorExpr (std::move (negated_value), std::move (outer_attribs),
583 : locus),
584 535 : expr_type (expr_kind)
585 535 : {}
586 :
587 : void accept_vis (ASTVisitor &vis) override;
588 :
589 : // TODO: is this better? Or is a "vis_block" better?
590 11193 : Expr &get_negated_expr ()
591 : {
592 11193 : rust_assert (main_or_left_expr != nullptr);
593 11193 : return *main_or_left_expr;
594 : }
595 :
596 1710 : std::unique_ptr<Expr> &get_negated_expr_ptr ()
597 : {
598 1710 : rust_assert (main_or_left_expr != nullptr);
599 1710 : return main_or_left_expr;
600 : }
601 :
602 534 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Negation; }
603 :
604 : protected:
605 : /* Use covariance to implement clone function as returning this object rather
606 : * than base */
607 535 : NegationExpr *clone_expr_without_block_impl () const override
608 : {
609 535 : return new NegationExpr (*this);
610 : }
611 : };
612 :
613 : // Infix binary operators. +, -, *, /, %, &, |, ^, <<, >>
614 : class ArithmeticOrLogicalExpr : public OperatorExpr
615 : {
616 : public:
617 : using ExprType = ArithmeticOrLogicalOperator;
618 :
619 : private:
620 : // Note: overloading trait specified in comments
621 : ExprType expr_type;
622 :
623 : std::unique_ptr<Expr> right_expr;
624 :
625 : public:
626 : std::string as_string () const override;
627 :
628 3708 : ExprType get_expr_type () const { return expr_type; }
629 :
630 : // Constructor calls OperatorExpr's protected constructor
631 4568 : ArithmeticOrLogicalExpr (std::unique_ptr<Expr> left_value,
632 : std::unique_ptr<Expr> right_value,
633 : ExprType expr_kind, location_t locus)
634 13704 : : OperatorExpr (std::move (left_value), std::vector<Attribute> (), locus),
635 4568 : expr_type (expr_kind), right_expr (std::move (right_value))
636 4568 : {}
637 : // outer attributes not allowed
638 :
639 : // Copy constructor - probably required due to unique pointer
640 11892 : ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr const &other)
641 23784 : : OperatorExpr (other), expr_type (other.expr_type),
642 11892 : right_expr (other.right_expr->clone_expr ())
643 11892 : {}
644 :
645 : // Overload assignment operator
646 : ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr const &other)
647 : {
648 : OperatorExpr::operator= (other);
649 : // main_or_left_expr = other.main_or_left_expr->clone_expr();
650 : right_expr = other.right_expr->clone_expr ();
651 : expr_type = other.expr_type;
652 :
653 : return *this;
654 : }
655 :
656 : // move constructors
657 : ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr &&other) = default;
658 : ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr &&other)
659 : = default;
660 :
661 : void accept_vis (ASTVisitor &vis) override;
662 :
663 : // TODO: is this better? Or is a "vis_block" better?
664 2171588 : Expr &get_left_expr ()
665 : {
666 2171588 : rust_assert (main_or_left_expr != nullptr);
667 2171588 : return *main_or_left_expr;
668 : }
669 :
670 535056 : std::unique_ptr<Expr> &get_left_expr_ptr ()
671 : {
672 535056 : rust_assert (main_or_left_expr != nullptr);
673 535056 : return main_or_left_expr;
674 : }
675 :
676 : // TODO: is this better? Or is a "vis_block" better?
677 2171588 : Expr &get_right_expr ()
678 : {
679 2171588 : rust_assert (right_expr != nullptr);
680 2171588 : return *right_expr;
681 : }
682 :
683 535056 : std::unique_ptr<Expr> &get_right_expr_ptr ()
684 : {
685 535056 : rust_assert (right_expr != nullptr);
686 535056 : return right_expr;
687 : }
688 :
689 : void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); }
690 : void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); }
691 :
692 3384 : Expr::Kind get_expr_kind () const override
693 : {
694 3384 : return Expr::Kind::ArithmeticOrLogical;
695 : }
696 :
697 : protected:
698 : /* Use covariance to implement clone function as returning this object rather
699 : * than base */
700 11892 : ArithmeticOrLogicalExpr *clone_expr_without_block_impl () const override
701 : {
702 11892 : return new ArithmeticOrLogicalExpr (*this);
703 : }
704 : };
705 :
706 : // Infix binary comparison operators. ==, !=, <, <=, >, >=
707 : class ComparisonExpr : public OperatorExpr
708 : {
709 : public:
710 : using ExprType = ComparisonOperator;
711 :
712 : private:
713 : // Note: overloading trait specified in comments
714 : ExprType expr_type;
715 :
716 : std::unique_ptr<Expr> right_expr;
717 :
718 : public:
719 : std::string as_string () const override;
720 :
721 2957 : ExprType get_expr_type () const { return expr_type; }
722 :
723 : // Constructor requires pointers for polymorphism
724 2783 : ComparisonExpr (std::unique_ptr<Expr> left_value,
725 : std::unique_ptr<Expr> right_value, ExprType comparison_kind,
726 : location_t locus)
727 8349 : : OperatorExpr (std::move (left_value), std::vector<Attribute> (), locus),
728 2783 : expr_type (comparison_kind), right_expr (std::move (right_value))
729 2783 : {}
730 : // outer attributes not allowed
731 :
732 : // Copy constructor also calls OperatorExpr's protected constructor
733 2766 : ComparisonExpr (ComparisonExpr const &other)
734 5532 : : OperatorExpr (other), expr_type (other.expr_type),
735 2766 : right_expr (other.right_expr->clone_expr ())
736 2766 : {}
737 :
738 : // Overload assignment operator to deep copy
739 : ComparisonExpr &operator= (ComparisonExpr const &other)
740 : {
741 : OperatorExpr::operator= (other);
742 : // main_or_left_expr = other.main_or_left_expr->clone_expr();
743 : right_expr = other.right_expr->clone_expr ();
744 : expr_type = other.expr_type;
745 : // outer_attrs = other.outer_attrs;
746 :
747 : return *this;
748 : }
749 :
750 : // move constructors
751 : ComparisonExpr (ComparisonExpr &&other) = default;
752 : ComparisonExpr &operator= (ComparisonExpr &&other) = default;
753 :
754 : void accept_vis (ASTVisitor &vis) override;
755 :
756 : // TODO: is this better? Or is a "vis_block" better?
757 59802 : Expr &get_left_expr ()
758 : {
759 59802 : rust_assert (main_or_left_expr != nullptr);
760 59802 : return *main_or_left_expr;
761 : }
762 :
763 9773 : std::unique_ptr<Expr> &get_left_expr_ptr ()
764 : {
765 9773 : rust_assert (main_or_left_expr != nullptr);
766 9773 : return main_or_left_expr;
767 : }
768 :
769 : // TODO: is this better? Or is a "vis_block" better?
770 59802 : Expr &get_right_expr ()
771 : {
772 59802 : rust_assert (right_expr != nullptr);
773 59802 : return *right_expr;
774 : }
775 :
776 9773 : std::unique_ptr<Expr> &get_right_expr_ptr ()
777 : {
778 9773 : rust_assert (right_expr != nullptr);
779 9773 : return right_expr;
780 : }
781 :
782 : ExprType get_kind () { return expr_type; }
783 :
784 2771 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Comparison; }
785 :
786 : /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2)
787 : * maybe? */
788 : protected:
789 : /* Use covariance to implement clone function as returning this object rather
790 : * than base */
791 2766 : ComparisonExpr *clone_expr_without_block_impl () const override
792 : {
793 2766 : return new ComparisonExpr (*this);
794 : }
795 : };
796 :
797 : // Infix binary lazy boolean logical operators && and ||.
798 : class LazyBooleanExpr : public OperatorExpr
799 : {
800 : public:
801 : using ExprType = LazyBooleanOperator;
802 :
803 : private:
804 : ExprType expr_type;
805 :
806 : std::unique_ptr<Expr> right_expr;
807 :
808 : public:
809 : // Constructor calls OperatorExpr's protected constructor
810 385 : LazyBooleanExpr (std::unique_ptr<Expr> left_bool_expr,
811 : std::unique_ptr<Expr> right_bool_expr, ExprType expr_kind,
812 : location_t locus)
813 1155 : : OperatorExpr (std::move (left_bool_expr), std::vector<Attribute> (),
814 : locus),
815 385 : expr_type (expr_kind), right_expr (std::move (right_bool_expr))
816 385 : {}
817 : // outer attributes not allowed
818 :
819 : // Copy constructor also calls OperatorExpr's protected constructor
820 316 : LazyBooleanExpr (LazyBooleanExpr const &other)
821 632 : : OperatorExpr (other), expr_type (other.expr_type),
822 316 : right_expr (other.right_expr->clone_expr ())
823 316 : {}
824 :
825 : // Overload assignment operator to deep copy
826 : LazyBooleanExpr &operator= (LazyBooleanExpr const &other)
827 : {
828 : OperatorExpr::operator= (other);
829 : // main_or_left_expr = other.main_or_left_expr->clone_expr();
830 : right_expr = other.right_expr->clone_expr ();
831 : expr_type = other.expr_type;
832 :
833 : return *this;
834 : }
835 :
836 : // move constructors
837 : LazyBooleanExpr (LazyBooleanExpr &&other) = default;
838 : LazyBooleanExpr &operator= (LazyBooleanExpr &&other) = default;
839 :
840 : std::string as_string () const override;
841 :
842 420 : ExprType get_expr_type () const { return expr_type; }
843 :
844 : void accept_vis (ASTVisitor &vis) override;
845 :
846 : // TODO: is this better? Or is a "vis_block" better?
847 7376 : Expr &get_left_expr ()
848 : {
849 7376 : rust_assert (main_or_left_expr != nullptr);
850 7376 : return *main_or_left_expr;
851 : }
852 :
853 1231 : std::unique_ptr<Expr> &get_left_expr_ptr ()
854 : {
855 1231 : rust_assert (main_or_left_expr != nullptr);
856 1231 : return main_or_left_expr;
857 : }
858 :
859 : // TODO: is this better? Or is a "vis_block" better?
860 7376 : Expr &get_right_expr ()
861 : {
862 7376 : rust_assert (right_expr != nullptr);
863 7376 : return *right_expr;
864 : }
865 :
866 1231 : std::unique_ptr<Expr> &get_right_expr_ptr ()
867 : {
868 1231 : rust_assert (right_expr != nullptr);
869 1231 : return right_expr;
870 : }
871 :
872 : ExprType get_kind () { return expr_type; }
873 :
874 385 : Expr::Kind get_expr_kind () const override { return Expr::Kind::LazyBoolean; }
875 :
876 : protected:
877 : /* Use covariance to implement clone function as returning this object rather
878 : * than base */
879 316 : LazyBooleanExpr *clone_expr_without_block_impl () const override
880 : {
881 316 : return new LazyBooleanExpr (*this);
882 : }
883 : };
884 :
885 : // Binary infix "as" cast expression.
886 : class TypeCastExpr : public OperatorExpr
887 : {
888 : std::unique_ptr<TypeNoBounds> type_to_convert_to;
889 :
890 : // Note: only certain type casts allowed, outlined in reference
891 : public:
892 : std::string as_string () const override;
893 :
894 : // Constructor requires calling protected constructor of OperatorExpr
895 5160 : TypeCastExpr (std::unique_ptr<Expr> expr_to_cast,
896 : std::unique_ptr<TypeNoBounds> type_to_cast_to, location_t locus)
897 15480 : : OperatorExpr (std::move (expr_to_cast), std::vector<Attribute> (), locus),
898 5160 : type_to_convert_to (std::move (type_to_cast_to))
899 5160 : {}
900 : // outer attributes not allowed
901 :
902 : // Copy constructor also requires calling protected constructor
903 8074 : TypeCastExpr (TypeCastExpr const &other)
904 8074 : : OperatorExpr (other),
905 8074 : type_to_convert_to (other.type_to_convert_to->clone_type_no_bounds ())
906 8074 : {}
907 :
908 : // Overload assignment operator to deep copy
909 : TypeCastExpr &operator= (TypeCastExpr const &other)
910 : {
911 : OperatorExpr::operator= (other);
912 : // main_or_left_expr = other.main_or_left_expr->clone_expr();
913 : type_to_convert_to = other.type_to_convert_to->clone_type_no_bounds ();
914 :
915 : return *this;
916 : }
917 :
918 : // move constructors
919 : TypeCastExpr (TypeCastExpr &&other) = default;
920 : TypeCastExpr &operator= (TypeCastExpr &&other) = default;
921 :
922 : void accept_vis (ASTVisitor &vis) override;
923 :
924 : // TODO: is this better? Or is a "vis_block" better?
925 163286 : Expr &get_casted_expr ()
926 : {
927 163286 : rust_assert (main_or_left_expr != nullptr);
928 163286 : return *main_or_left_expr;
929 : }
930 :
931 16883 : std::unique_ptr<Expr> &get_casted_expr_ptr ()
932 : {
933 16883 : rust_assert (main_or_left_expr != nullptr);
934 16883 : return main_or_left_expr;
935 : }
936 :
937 : // TODO: is this better? Or is a "vis_block" better?
938 163286 : TypeNoBounds &get_type_to_cast_to ()
939 : {
940 163286 : rust_assert (type_to_convert_to != nullptr);
941 163286 : return *type_to_convert_to;
942 : }
943 :
944 16883 : std::unique_ptr<TypeNoBounds> &get_type_to_cast_to_ptr ()
945 : {
946 16883 : rust_assert (type_to_convert_to != nullptr);
947 16883 : return type_to_convert_to;
948 : }
949 :
950 5114 : Expr::Kind get_expr_kind () const override { return Expr::Kind::TypeCast; }
951 :
952 : protected:
953 : /* Use covariance to implement clone function as returning this object rather
954 : * than base */
955 8074 : TypeCastExpr *clone_expr_without_block_impl () const override
956 : {
957 8074 : return new TypeCastExpr (*this);
958 : }
959 : };
960 :
961 : // Binary assignment expression.
962 : class AssignmentExpr : public OperatorExpr
963 : {
964 : std::unique_ptr<Expr> right_expr;
965 :
966 : public:
967 : std::string as_string () const override;
968 :
969 : // Call OperatorExpr constructor to initialise left_expr
970 2541 : AssignmentExpr (std::unique_ptr<Expr> value_to_assign_to,
971 : std::unique_ptr<Expr> value_to_assign,
972 : std::vector<Attribute> outer_attribs, location_t locus)
973 2541 : : OperatorExpr (std::move (value_to_assign_to), std::move (outer_attribs),
974 : locus),
975 2541 : right_expr (std::move (value_to_assign))
976 2541 : {}
977 : // outer attributes not allowed
978 :
979 : // Call OperatorExpr constructor in copy constructor, as well as clone
980 6159 : AssignmentExpr (AssignmentExpr const &other)
981 6159 : : OperatorExpr (other), right_expr (other.right_expr->clone_expr ())
982 6159 : {}
983 :
984 : // Overload assignment operator to clone unique_ptr right_expr
985 : AssignmentExpr &operator= (AssignmentExpr const &other)
986 : {
987 : OperatorExpr::operator= (other);
988 : // main_or_left_expr = other.main_or_left_expr->clone_expr();
989 : right_expr = other.right_expr->clone_expr ();
990 : // outer_attrs = other.outer_attrs;
991 :
992 : return *this;
993 : }
994 :
995 : // move constructors
996 : AssignmentExpr (AssignmentExpr &&other) = default;
997 : AssignmentExpr &operator= (AssignmentExpr &&other) = default;
998 :
999 : void accept_vis (ASTVisitor &vis) override;
1000 :
1001 228 : void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); }
1002 228 : void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); }
1003 :
1004 : // TODO: is this better? Or is a "vis_block" better?
1005 57635 : Expr &get_left_expr ()
1006 : {
1007 57635 : rust_assert (main_or_left_expr != nullptr);
1008 57635 : return *main_or_left_expr;
1009 : }
1010 :
1011 7049 : std::unique_ptr<Expr> &get_left_expr_ptr ()
1012 : {
1013 7049 : rust_assert (main_or_left_expr != nullptr);
1014 7049 : return main_or_left_expr;
1015 : }
1016 :
1017 7049 : std::unique_ptr<Expr> &get_right_expr_ptr ()
1018 : {
1019 7049 : rust_assert (right_expr != nullptr);
1020 7049 : return right_expr;
1021 : }
1022 :
1023 : // TODO: is this better? Or is a "vis_block" better?
1024 57635 : Expr &get_right_expr ()
1025 : {
1026 57635 : rust_assert (right_expr != nullptr);
1027 57635 : return *right_expr;
1028 : }
1029 :
1030 2504 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Assignment; }
1031 :
1032 : protected:
1033 : /* Use covariance to implement clone function as returning this object rather
1034 : * than base */
1035 6159 : AssignmentExpr *clone_expr_without_block_impl () const override
1036 : {
1037 6159 : return new AssignmentExpr (*this);
1038 : }
1039 : };
1040 :
1041 : /* Binary infix compound assignment (arithmetic or logic then assignment)
1042 : * expressions. */
1043 : class CompoundAssignmentExpr : public OperatorExpr
1044 : {
1045 : public:
1046 : using ExprType = CompoundAssignmentOperator;
1047 :
1048 : private:
1049 : // Note: overloading trait specified in comments
1050 : ExprType expr_type;
1051 : std::unique_ptr<Expr> right_expr;
1052 :
1053 : public:
1054 : std::string as_string () const override;
1055 :
1056 681 : ExprType get_expr_type () const { return expr_type; }
1057 :
1058 : // Use pointers in constructor to enable polymorphism
1059 682 : CompoundAssignmentExpr (std::unique_ptr<Expr> value_to_assign_to,
1060 : std::unique_ptr<Expr> value_to_assign,
1061 : ExprType expr_kind, location_t locus)
1062 2046 : : OperatorExpr (std::move (value_to_assign_to), std::vector<Attribute> (),
1063 : locus),
1064 682 : expr_type (expr_kind), right_expr (std::move (value_to_assign))
1065 682 : {}
1066 : // outer attributes not allowed
1067 :
1068 : // Have clone in copy constructor
1069 2218 : CompoundAssignmentExpr (CompoundAssignmentExpr const &other)
1070 4436 : : OperatorExpr (other), expr_type (other.expr_type),
1071 2218 : right_expr (other.right_expr->clone_expr ())
1072 2218 : {}
1073 :
1074 : // Overload assignment operator to clone
1075 : CompoundAssignmentExpr &operator= (CompoundAssignmentExpr const &other)
1076 : {
1077 : OperatorExpr::operator= (other);
1078 : // main_or_left_expr = other.main_or_left_expr->clone_expr();
1079 : right_expr = other.right_expr->clone_expr ();
1080 : expr_type = other.expr_type;
1081 : // outer_attrs = other.outer_attrs;
1082 :
1083 : return *this;
1084 : }
1085 :
1086 : // move constructors
1087 : CompoundAssignmentExpr (CompoundAssignmentExpr &&other) = default;
1088 : CompoundAssignmentExpr &operator= (CompoundAssignmentExpr &&other) = default;
1089 :
1090 : void accept_vis (ASTVisitor &vis) override;
1091 :
1092 : // TODO: is this better? Or is a "vis_block" better?
1093 19681 : Expr &get_left_expr ()
1094 : {
1095 19681 : rust_assert (main_or_left_expr != nullptr);
1096 19681 : return *main_or_left_expr;
1097 : }
1098 :
1099 1957 : std::unique_ptr<Expr> &get_left_expr_ptr ()
1100 : {
1101 1957 : rust_assert (main_or_left_expr != nullptr);
1102 1957 : return main_or_left_expr;
1103 : }
1104 :
1105 : // TODO: is this better? Or is a "vis_block" better?
1106 19681 : Expr &get_right_expr ()
1107 : {
1108 19681 : rust_assert (right_expr != nullptr);
1109 19681 : return *right_expr;
1110 : }
1111 :
1112 1957 : std::unique_ptr<Expr> &get_right_expr_ptr ()
1113 : {
1114 1957 : rust_assert (right_expr != nullptr);
1115 1957 : return right_expr;
1116 : }
1117 :
1118 682 : Expr::Kind get_expr_kind () const override
1119 : {
1120 682 : return Expr::Kind::CompoundAssignment;
1121 : }
1122 :
1123 : protected:
1124 : /* Use covariance to implement clone function as returning this object rather
1125 : * than base */
1126 2218 : CompoundAssignmentExpr *clone_expr_without_block_impl () const override
1127 : {
1128 2218 : return new CompoundAssignmentExpr (*this);
1129 : }
1130 : };
1131 :
1132 : // Expression in parentheses (i.e. like literally just any 3 + (2 * 6))
1133 : class GroupedExpr : public ExprWithoutBlock
1134 : {
1135 : std::vector<Attribute> outer_attrs;
1136 : std::vector<Attribute> inner_attrs;
1137 : std::unique_ptr<Expr> expr_in_parens;
1138 : location_t locus;
1139 :
1140 : public:
1141 : std::string as_string () const override;
1142 :
1143 : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1144 8235 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1145 :
1146 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1147 10394 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1148 :
1149 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1150 : {
1151 0 : outer_attrs = std::move (new_attrs);
1152 0 : }
1153 :
1154 313 : GroupedExpr (std::unique_ptr<Expr> parenthesised_expr,
1155 : std::vector<Attribute> inner_attribs,
1156 : std::vector<Attribute> outer_attribs, location_t locus)
1157 626 : : outer_attrs (std::move (outer_attribs)),
1158 313 : inner_attrs (std::move (inner_attribs)),
1159 313 : expr_in_parens (std::move (parenthesised_expr)), locus (locus)
1160 313 : {}
1161 :
1162 : // Copy constructor includes clone for expr_in_parens
1163 484 : GroupedExpr (GroupedExpr const &other)
1164 484 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1165 484 : inner_attrs (other.inner_attrs), locus (other.locus)
1166 : {
1167 : // guard to prevent null dereference (only required if error state)
1168 484 : if (other.expr_in_parens != nullptr)
1169 484 : expr_in_parens = other.expr_in_parens->clone_expr ();
1170 484 : }
1171 :
1172 : // Overloaded assignment operator to clone expr_in_parens
1173 : GroupedExpr &operator= (GroupedExpr const &other)
1174 : {
1175 : ExprWithoutBlock::operator= (other);
1176 : inner_attrs = other.inner_attrs;
1177 : locus = other.locus;
1178 : outer_attrs = other.outer_attrs;
1179 :
1180 : // guard to prevent null dereference (only required if error state)
1181 : if (other.expr_in_parens != nullptr)
1182 : expr_in_parens = other.expr_in_parens->clone_expr ();
1183 : else
1184 : expr_in_parens = nullptr;
1185 :
1186 : return *this;
1187 : }
1188 :
1189 : // move constructors
1190 : GroupedExpr (GroupedExpr &&other) = default;
1191 : GroupedExpr &operator= (GroupedExpr &&other) = default;
1192 :
1193 940 : location_t get_locus () const override final { return locus; }
1194 :
1195 : void accept_vis (ASTVisitor &vis) override;
1196 :
1197 : // Invalid if inner expr is null, so base stripping on that.
1198 0 : void mark_for_strip () override { expr_in_parens = nullptr; }
1199 2143 : bool is_marked_for_strip () const override
1200 : {
1201 2143 : return expr_in_parens == nullptr;
1202 : }
1203 :
1204 : // TODO: is this better? Or is a "vis_block" better?
1205 7982 : Expr &get_expr_in_parens ()
1206 : {
1207 7982 : rust_assert (expr_in_parens != nullptr);
1208 7982 : return *expr_in_parens;
1209 : }
1210 :
1211 1064 : std::unique_ptr<Expr> &get_expr_in_parens_ptr ()
1212 : {
1213 1064 : rust_assert (expr_in_parens != nullptr);
1214 1064 : return expr_in_parens;
1215 : }
1216 :
1217 313 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Grouped; }
1218 :
1219 : protected:
1220 : /* Use covariance to implement clone function as returning this object rather
1221 : * than base */
1222 484 : GroupedExpr *clone_expr_without_block_impl () const override
1223 : {
1224 484 : return new GroupedExpr (*this);
1225 : }
1226 : };
1227 :
1228 : // Base array initialisation internal element representation thing (abstract)
1229 : // aka ArrayElements
1230 : class ArrayElems
1231 : {
1232 : public:
1233 : virtual ~ArrayElems () {}
1234 :
1235 : // Unique pointer custom clone ArrayElems function
1236 613 : std::unique_ptr<ArrayElems> clone_array_elems () const
1237 : {
1238 613 : return std::unique_ptr<ArrayElems> (clone_array_elems_impl ());
1239 : }
1240 :
1241 : virtual std::string as_string () const = 0;
1242 :
1243 : virtual void accept_vis (ASTVisitor &vis) = 0;
1244 :
1245 431 : NodeId get_node_id () const { return node_id; }
1246 :
1247 : protected:
1248 1048 : ArrayElems () : node_id (Analysis::Mappings::get ().get_next_node_id ()) {}
1249 :
1250 : // pure virtual clone implementation
1251 : virtual ArrayElems *clone_array_elems_impl () const = 0;
1252 :
1253 : NodeId node_id;
1254 : };
1255 :
1256 : // Value array elements
1257 : class ArrayElemsValues : public ArrayElems
1258 : {
1259 : std::vector<std::unique_ptr<Expr>> values;
1260 : location_t locus;
1261 :
1262 : public:
1263 312 : ArrayElemsValues (std::vector<std::unique_ptr<Expr>> elems, location_t locus)
1264 312 : : ArrayElems (), values (std::move (elems)), locus (locus)
1265 312 : {}
1266 :
1267 : // copy constructor with vector clone
1268 491 : ArrayElemsValues (ArrayElemsValues const &other)
1269 491 : {
1270 491 : values.reserve (other.values.size ());
1271 13847 : for (const auto &e : other.values)
1272 13356 : values.push_back (e->clone_expr ());
1273 491 : }
1274 :
1275 : // overloaded assignment operator with vector clone
1276 : ArrayElemsValues &operator= (ArrayElemsValues const &other)
1277 : {
1278 : values.reserve (other.values.size ());
1279 : for (const auto &e : other.values)
1280 : values.push_back (e->clone_expr ());
1281 :
1282 : return *this;
1283 : }
1284 :
1285 : // move constructors
1286 : ArrayElemsValues (ArrayElemsValues &&other) = default;
1287 : ArrayElemsValues &operator= (ArrayElemsValues &&other) = default;
1288 :
1289 : std::string as_string () const override;
1290 :
1291 : location_t get_locus () const { return locus; }
1292 :
1293 : void accept_vis (ASTVisitor &vis) override;
1294 :
1295 : // TODO: this mutable getter seems really dodgy. Think up better way.
1296 : const std::vector<std::unique_ptr<Expr>> &get_values () const
1297 : {
1298 : return values;
1299 : }
1300 5397 : std::vector<std::unique_ptr<Expr>> &get_values () { return values; }
1301 :
1302 : size_t get_num_values () const { return values.size (); }
1303 :
1304 : protected:
1305 491 : ArrayElemsValues *clone_array_elems_impl () const override
1306 : {
1307 491 : return new ArrayElemsValues (*this);
1308 : }
1309 : };
1310 :
1311 : // Copied array element and number of copies
1312 : class ArrayElemsCopied : public ArrayElems
1313 : {
1314 : std::unique_ptr<Expr> elem_to_copy;
1315 :
1316 : // TODO: This should be replaced by a ConstExpr
1317 : std::unique_ptr<Expr> num_copies;
1318 : location_t locus;
1319 :
1320 : public:
1321 : // Constructor requires pointers for polymorphism
1322 123 : ArrayElemsCopied (std::unique_ptr<Expr> copied_elem,
1323 : std::unique_ptr<Expr> copy_amount, location_t locus)
1324 246 : : ArrayElems (), elem_to_copy (std::move (copied_elem)),
1325 123 : num_copies (std::move (copy_amount)), locus (locus)
1326 : {}
1327 :
1328 : // Copy constructor required due to unique_ptr - uses custom clone
1329 122 : ArrayElemsCopied (ArrayElemsCopied const &other)
1330 366 : : elem_to_copy (other.elem_to_copy->clone_expr ()),
1331 122 : num_copies (other.num_copies->clone_expr ())
1332 122 : {}
1333 :
1334 : // Overloaded assignment operator for deep copying
1335 : ArrayElemsCopied &operator= (ArrayElemsCopied const &other)
1336 : {
1337 : elem_to_copy = other.elem_to_copy->clone_expr ();
1338 : num_copies = other.num_copies->clone_expr ();
1339 :
1340 : return *this;
1341 : }
1342 :
1343 : // move constructors
1344 : ArrayElemsCopied (ArrayElemsCopied &&other) = default;
1345 : ArrayElemsCopied &operator= (ArrayElemsCopied &&other) = default;
1346 :
1347 : std::string as_string () const override;
1348 :
1349 : location_t get_locus () const { return locus; }
1350 :
1351 : void accept_vis (ASTVisitor &vis) override;
1352 :
1353 : // TODO: is this better? Or is a "vis_block" better?
1354 2286 : Expr &get_elem_to_copy ()
1355 : {
1356 2286 : rust_assert (elem_to_copy != nullptr);
1357 2286 : return *elem_to_copy;
1358 : }
1359 :
1360 366 : std::unique_ptr<Expr> &get_elem_to_copy_ptr ()
1361 : {
1362 366 : rust_assert (elem_to_copy != nullptr);
1363 366 : return elem_to_copy;
1364 : }
1365 :
1366 : // TODO: is this better? Or is a "vis_block" better?
1367 2286 : Expr &get_num_copies ()
1368 : {
1369 2286 : rust_assert (num_copies != nullptr);
1370 2286 : return *num_copies;
1371 : }
1372 :
1373 366 : std::unique_ptr<Expr> &get_num_copies_ptr ()
1374 : {
1375 366 : rust_assert (num_copies != nullptr);
1376 366 : return num_copies;
1377 : }
1378 :
1379 : protected:
1380 122 : ArrayElemsCopied *clone_array_elems_impl () const override
1381 : {
1382 122 : return new ArrayElemsCopied (*this);
1383 : }
1384 : };
1385 :
1386 : // Array definition-ish expression
1387 : class ArrayExpr : public ExprWithoutBlock
1388 : {
1389 : std::vector<Attribute> outer_attrs;
1390 : std::vector<Attribute> inner_attrs;
1391 : std::unique_ptr<ArrayElems> internal_elements;
1392 : location_t locus;
1393 :
1394 : // TODO: find another way to store this to save memory?
1395 : bool marked_for_strip = false;
1396 :
1397 : public:
1398 : std::string as_string () const override;
1399 :
1400 : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1401 9201 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1402 :
1403 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1404 10865 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1405 :
1406 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1407 : {
1408 0 : outer_attrs = std::move (new_attrs);
1409 0 : }
1410 :
1411 : // Constructor requires ArrayElems pointer
1412 435 : ArrayExpr (std::unique_ptr<ArrayElems> array_elems,
1413 : std::vector<Attribute> inner_attribs,
1414 : std::vector<Attribute> outer_attribs, location_t locus)
1415 870 : : outer_attrs (std::move (outer_attribs)),
1416 435 : inner_attrs (std::move (inner_attribs)),
1417 435 : internal_elements (std::move (array_elems)), locus (locus)
1418 : {
1419 435 : rust_assert (internal_elements != nullptr);
1420 435 : }
1421 :
1422 : // Copy constructor requires cloning ArrayElems for polymorphism to hold
1423 613 : ArrayExpr (ArrayExpr const &other)
1424 613 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1425 613 : inner_attrs (other.inner_attrs), locus (other.locus),
1426 1226 : marked_for_strip (other.marked_for_strip)
1427 : {
1428 613 : internal_elements = other.internal_elements->clone_array_elems ();
1429 613 : rust_assert (internal_elements != nullptr);
1430 613 : }
1431 :
1432 : // Overload assignment operator to clone internal_elements
1433 : ArrayExpr &operator= (ArrayExpr const &other)
1434 : {
1435 : ExprWithoutBlock::operator= (other);
1436 : inner_attrs = other.inner_attrs;
1437 : locus = other.locus;
1438 : marked_for_strip = other.marked_for_strip;
1439 : outer_attrs = other.outer_attrs;
1440 :
1441 : internal_elements = other.internal_elements->clone_array_elems ();
1442 :
1443 : rust_assert (internal_elements != nullptr);
1444 : return *this;
1445 : }
1446 :
1447 : // move constructors
1448 : ArrayExpr (ArrayExpr &&other) = default;
1449 : ArrayExpr &operator= (ArrayExpr &&other) = default;
1450 :
1451 883 : location_t get_locus () const override final { return locus; }
1452 :
1453 : void accept_vis (ASTVisitor &vis) override;
1454 :
1455 : // Can't think of any invalid invariants, so store boolean.
1456 0 : void mark_for_strip () override { marked_for_strip = true; }
1457 1626 : bool is_marked_for_strip () const override { return marked_for_strip; }
1458 :
1459 : // TODO: is this better? Or is a "vis_block" better?
1460 7583 : std::unique_ptr<ArrayElems> &get_array_elems ()
1461 : {
1462 7583 : rust_assert (internal_elements != nullptr);
1463 7583 : return internal_elements;
1464 : }
1465 :
1466 431 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Array; }
1467 :
1468 : protected:
1469 : /* Use covariance to implement clone function as returning this object rather
1470 : * than base */
1471 613 : ArrayExpr *clone_expr_without_block_impl () const override
1472 : {
1473 613 : return new ArrayExpr (*this);
1474 : }
1475 : };
1476 :
1477 : // Aka IndexExpr (also applies to slices)
1478 : /* Apparently a[b] is equivalent to *std::ops::Index::index(&a, b) or
1479 : * *std::ops::Index::index_mut(&mut a, b) */
1480 : /* Also apparently deref operations on a will be repeatedly applied to find an
1481 : * implementation */
1482 : class ArrayIndexExpr : public ExprWithoutBlock
1483 : {
1484 : std::vector<Attribute> outer_attrs;
1485 : std::unique_ptr<Expr> array_expr;
1486 : std::unique_ptr<Expr> index_expr;
1487 : location_t locus;
1488 :
1489 : public:
1490 : std::string as_string () const override;
1491 :
1492 302 : ArrayIndexExpr (std::unique_ptr<Expr> array_expr,
1493 : std::unique_ptr<Expr> array_index_expr,
1494 : std::vector<Attribute> outer_attribs, location_t locus)
1495 604 : : outer_attrs (std::move (outer_attribs)),
1496 302 : array_expr (std::move (array_expr)),
1497 302 : index_expr (std::move (array_index_expr)), locus (locus)
1498 302 : {}
1499 :
1500 : // Copy constructor requires special cloning due to unique_ptr
1501 322 : ArrayIndexExpr (ArrayIndexExpr const &other)
1502 322 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1503 322 : locus (other.locus)
1504 : {
1505 : // guard to prevent null dereference (only required if error state)
1506 322 : if (other.array_expr != nullptr)
1507 322 : array_expr = other.array_expr->clone_expr ();
1508 322 : if (other.index_expr != nullptr)
1509 322 : index_expr = other.index_expr->clone_expr ();
1510 322 : }
1511 :
1512 : // Overload assignment operator to clone unique_ptrs
1513 : ArrayIndexExpr &operator= (ArrayIndexExpr const &other)
1514 : {
1515 : ExprWithoutBlock::operator= (other);
1516 : outer_attrs = other.outer_attrs;
1517 : locus = other.locus;
1518 :
1519 : // guard to prevent null dereference (only required if error state)
1520 : if (other.array_expr != nullptr)
1521 : array_expr = other.array_expr->clone_expr ();
1522 : else
1523 : array_expr = nullptr;
1524 : if (other.index_expr != nullptr)
1525 : index_expr = other.index_expr->clone_expr ();
1526 : else
1527 : index_expr = nullptr;
1528 :
1529 : return *this;
1530 : }
1531 :
1532 : // move constructors
1533 : ArrayIndexExpr (ArrayIndexExpr &&other) = default;
1534 : ArrayIndexExpr &operator= (ArrayIndexExpr &&other) = default;
1535 :
1536 694 : location_t get_locus () const override final { return locus; }
1537 :
1538 : void accept_vis (ASTVisitor &vis) override;
1539 :
1540 : // Invalid if either expr is null, so base stripping on that.
1541 0 : void mark_for_strip () override
1542 : {
1543 0 : array_expr = nullptr;
1544 0 : index_expr = nullptr;
1545 0 : }
1546 1404 : bool is_marked_for_strip () const override
1547 : {
1548 1404 : return array_expr == nullptr && index_expr == nullptr;
1549 : }
1550 :
1551 : // TODO: is this better? Or is a "vis_block" better?
1552 6068 : Expr &get_array_expr ()
1553 : {
1554 6068 : rust_assert (array_expr != nullptr);
1555 6068 : return *array_expr;
1556 : }
1557 :
1558 909 : std::unique_ptr<Expr> &get_array_expr_ptr ()
1559 : {
1560 909 : rust_assert (array_expr != nullptr);
1561 909 : return array_expr;
1562 : }
1563 :
1564 : // TODO: is this better? Or is a "vis_block" better?
1565 6068 : Expr &get_index_expr ()
1566 : {
1567 6068 : rust_assert (index_expr != nullptr);
1568 6068 : return *index_expr;
1569 : }
1570 :
1571 909 : std::unique_ptr<Expr> &get_index_expr_ptr ()
1572 : {
1573 909 : rust_assert (index_expr != nullptr);
1574 909 : return index_expr;
1575 : }
1576 :
1577 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1578 8390 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1579 :
1580 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1581 : {
1582 0 : outer_attrs = std::move (new_attrs);
1583 0 : }
1584 :
1585 298 : Expr::Kind get_expr_kind () const override { return Expr::Kind::ArrayIndex; }
1586 :
1587 : protected:
1588 : /* Use covariance to implement clone function as returning this object rather
1589 : * than base */
1590 322 : ArrayIndexExpr *clone_expr_without_block_impl () const override
1591 : {
1592 322 : return new ArrayIndexExpr (*this);
1593 : }
1594 : };
1595 :
1596 : // AST representation of a tuple
1597 : class TupleExpr : public ExprWithoutBlock
1598 : {
1599 : std::vector<Attribute> outer_attrs;
1600 : std::vector<Attribute> inner_attrs;
1601 : std::vector<std::unique_ptr<Expr>> tuple_elems;
1602 : location_t locus;
1603 :
1604 : // TODO: find another way to store this to save memory?
1605 : bool marked_for_strip = false;
1606 :
1607 : public:
1608 : std::string as_string () const override;
1609 :
1610 : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1611 9423 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1612 :
1613 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1614 12576 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1615 :
1616 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1617 : {
1618 0 : outer_attrs = std::move (new_attrs);
1619 0 : }
1620 :
1621 582 : TupleExpr (std::vector<std::unique_ptr<Expr>> tuple_elements,
1622 : std::vector<Attribute> inner_attribs,
1623 : std::vector<Attribute> outer_attribs, location_t locus)
1624 1164 : : outer_attrs (std::move (outer_attribs)),
1625 582 : inner_attrs (std::move (inner_attribs)),
1626 582 : tuple_elems (std::move (tuple_elements)), locus (locus)
1627 582 : {}
1628 :
1629 : // copy constructor with vector clone
1630 993 : TupleExpr (TupleExpr const &other)
1631 993 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1632 993 : inner_attrs (other.inner_attrs), locus (other.locus),
1633 1986 : marked_for_strip (other.marked_for_strip)
1634 : {
1635 993 : tuple_elems.reserve (other.tuple_elems.size ());
1636 2790 : for (const auto &e : other.tuple_elems)
1637 1797 : tuple_elems.push_back (e->clone_expr ());
1638 993 : }
1639 :
1640 : // overloaded assignment operator to vector clone
1641 : TupleExpr &operator= (TupleExpr const &other)
1642 : {
1643 : ExprWithoutBlock::operator= (other);
1644 : outer_attrs = other.outer_attrs;
1645 : inner_attrs = other.inner_attrs;
1646 : locus = other.locus;
1647 : marked_for_strip = other.marked_for_strip;
1648 :
1649 : tuple_elems.reserve (other.tuple_elems.size ());
1650 : for (const auto &e : other.tuple_elems)
1651 : tuple_elems.push_back (e->clone_expr ());
1652 :
1653 : return *this;
1654 : }
1655 :
1656 : // move constructors
1657 : TupleExpr (TupleExpr &&other) = default;
1658 : TupleExpr &operator= (TupleExpr &&other) = default;
1659 :
1660 : /* Note: syntactically, can disambiguate single-element tuple from parens with
1661 : * comma, i.e. (0,) rather than (0) */
1662 :
1663 1165 : location_t get_locus () const override final { return locus; }
1664 :
1665 : void accept_vis (ASTVisitor &vis) override;
1666 :
1667 : // Can't think of any invalid invariants, so store boolean.
1668 0 : void mark_for_strip () override { marked_for_strip = true; }
1669 2410 : bool is_marked_for_strip () const override { return marked_for_strip; }
1670 :
1671 : // TODO: this mutable getter seems really dodgy. Think up better way.
1672 : const std::vector<std::unique_ptr<Expr>> &get_tuple_elems () const
1673 : {
1674 : return tuple_elems;
1675 : }
1676 10754 : std::vector<std::unique_ptr<Expr>> &get_tuple_elems () { return tuple_elems; }
1677 :
1678 : bool is_unit () const { return tuple_elems.size () == 0; }
1679 :
1680 565 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Tuple; }
1681 :
1682 : protected:
1683 : /* Use covariance to implement clone function as returning this object rather
1684 : * than base */
1685 993 : TupleExpr *clone_expr_without_block_impl () const override
1686 : {
1687 993 : return new TupleExpr (*this);
1688 : }
1689 : };
1690 :
1691 : // aka TupleIndexingExpr
1692 : // AST representation of a tuple indexing expression
1693 : class TupleIndexExpr : public ExprWithoutBlock
1694 : {
1695 : std::vector<Attribute> outer_attrs;
1696 : std::unique_ptr<Expr> tuple_expr;
1697 : // TupleIndex is a decimal int literal with no underscores or suffix
1698 : TupleIndex tuple_index;
1699 :
1700 : location_t locus;
1701 : bool to_strip;
1702 :
1703 : // i.e. pair.0
1704 :
1705 : public:
1706 : std::string as_string () const override;
1707 :
1708 960 : TupleIndex get_tuple_index () const { return tuple_index; }
1709 :
1710 936 : TupleIndexExpr (std::unique_ptr<Expr> tuple_expr, TupleIndex index,
1711 : std::vector<Attribute> outer_attribs, location_t locus)
1712 1872 : : outer_attrs (std::move (outer_attribs)),
1713 936 : tuple_expr (std::move (tuple_expr)), tuple_index (index), locus (locus),
1714 936 : to_strip (false)
1715 936 : {}
1716 :
1717 : // Copy constructor requires a clone for tuple_expr
1718 907 : TupleIndexExpr (TupleIndexExpr const &other)
1719 907 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1720 907 : tuple_index (other.tuple_index), locus (other.locus),
1721 907 : to_strip (other.to_strip)
1722 : {
1723 : // guard to prevent null dereference (only required if error state)
1724 907 : if (other.tuple_expr != nullptr)
1725 907 : tuple_expr = other.tuple_expr->clone_expr ();
1726 907 : }
1727 :
1728 : // Overload assignment operator in order to clone
1729 : TupleIndexExpr &operator= (TupleIndexExpr const &other)
1730 : {
1731 : ExprWithoutBlock::operator= (other);
1732 : tuple_index = other.tuple_index;
1733 : locus = other.locus;
1734 : outer_attrs = other.outer_attrs;
1735 : to_strip = other.to_strip;
1736 :
1737 : // guard to prevent null dereference (only required if error state)
1738 : if (other.tuple_expr != nullptr)
1739 : tuple_expr = other.tuple_expr->clone_expr ();
1740 : else
1741 : tuple_expr = nullptr;
1742 :
1743 : return *this;
1744 : }
1745 :
1746 : // move constructors
1747 : TupleIndexExpr (TupleIndexExpr &&other) = default;
1748 : TupleIndexExpr &operator= (TupleIndexExpr &&other) = default;
1749 :
1750 2000 : location_t get_locus () const override final { return locus; }
1751 :
1752 : void accept_vis (ASTVisitor &vis) override;
1753 :
1754 : // Invalid if tuple expr is null, so base stripping on that.
1755 0 : void mark_for_strip () override { to_strip = true; }
1756 4728 : bool is_marked_for_strip () const override { return to_strip; }
1757 :
1758 : // TODO: is this better? Or is a "vis_block" better?
1759 21240 : Expr &get_tuple_expr ()
1760 : {
1761 21240 : rust_assert (tuple_expr != nullptr);
1762 21240 : return *tuple_expr;
1763 : }
1764 :
1765 2801 : std::unique_ptr<Expr> &get_tuple_expr_ptr ()
1766 : {
1767 2801 : rust_assert (tuple_expr != nullptr);
1768 2801 : return tuple_expr;
1769 : }
1770 :
1771 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1772 29985 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1773 :
1774 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1775 : {
1776 0 : outer_attrs = std::move (new_attrs);
1777 0 : }
1778 :
1779 902 : Expr::Kind get_expr_kind () const override { return Expr::Kind::TupleIndex; }
1780 :
1781 : protected:
1782 : /* Use covariance to implement clone function as returning this object rather
1783 : * than base */
1784 907 : TupleIndexExpr *clone_expr_without_block_impl () const override
1785 : {
1786 907 : return new TupleIndexExpr (*this);
1787 : }
1788 : };
1789 :
1790 : // Base struct/tuple/union value creator AST node (abstract)
1791 : class StructExpr : public ExprWithoutBlock
1792 : {
1793 : std::vector<Attribute> outer_attrs;
1794 : PathInExpression struct_name;
1795 :
1796 : protected:
1797 : // Protected constructor to allow initialising struct_name
1798 1415 : StructExpr (PathInExpression struct_path,
1799 : std::vector<Attribute> outer_attribs)
1800 2830 : : outer_attrs (std::move (outer_attribs)),
1801 1415 : struct_name (std::move (struct_path))
1802 1415 : {}
1803 :
1804 : public:
1805 0 : const PathInExpression &get_struct_name () const { return struct_name; }
1806 32297 : PathInExpression &get_struct_name () { return struct_name; }
1807 :
1808 : std::string as_string () const override;
1809 :
1810 : // Invalid if path is empty, so base stripping on that.
1811 0 : void mark_for_strip () override
1812 : {
1813 0 : struct_name = PathInExpression::create_error ();
1814 0 : }
1815 6042 : bool is_marked_for_strip () const override { return struct_name.is_error (); }
1816 :
1817 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1818 38678 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1819 :
1820 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1821 : {
1822 0 : outer_attrs = std::move (new_attrs);
1823 0 : }
1824 :
1825 1415 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Struct; }
1826 : };
1827 :
1828 : // Actual AST node of the struct creator (with no fields). Not abstract!
1829 : class StructExprStruct : public StructExpr
1830 : {
1831 : std::vector<Attribute> inner_attrs;
1832 :
1833 : location_t locus;
1834 :
1835 : public:
1836 : std::string as_string () const override;
1837 :
1838 : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1839 32167 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1840 :
1841 : // Constructor has to call protected constructor of base class
1842 1415 : StructExprStruct (PathInExpression struct_path,
1843 : std::vector<Attribute> inner_attribs,
1844 : std::vector<Attribute> outer_attribs, location_t locus)
1845 1415 : : StructExpr (std::move (struct_path), std::move (outer_attribs)),
1846 1415 : inner_attrs (std::move (inner_attribs)), locus (locus)
1847 1415 : {}
1848 :
1849 3204 : location_t get_locus () const override final { return locus; }
1850 :
1851 : void accept_vis (ASTVisitor &vis) override;
1852 :
1853 : protected:
1854 : /* Use covariance to implement clone function as returning this object rather
1855 : * than base */
1856 78 : StructExprStruct *clone_expr_without_block_impl () const override
1857 : {
1858 78 : return new StructExprStruct (*this);
1859 : }
1860 : };
1861 :
1862 : /* AST node representing expression used to fill a struct's fields from another
1863 : * struct */
1864 : struct StructBase
1865 : {
1866 : private:
1867 : std::unique_ptr<Expr> base_struct;
1868 : location_t locus;
1869 :
1870 : public:
1871 1397 : StructBase (std::unique_ptr<Expr> base_struct_ptr, location_t locus)
1872 1397 : : base_struct (std::move (base_struct_ptr)), locus (locus)
1873 : {}
1874 :
1875 : // Copy constructor requires clone
1876 1338 : StructBase (StructBase const &other)
1877 1338 : {
1878 : /* HACK: gets around base_struct pointer being null (e.g. if no struct base
1879 : * exists) */
1880 1338 : if (other.base_struct != nullptr)
1881 63 : base_struct = other.base_struct->clone_expr ();
1882 1338 : }
1883 :
1884 : // Destructor
1885 2698 : ~StructBase () = default;
1886 :
1887 : // Overload assignment operator to clone base_struct
1888 : StructBase &operator= (StructBase const &other)
1889 : {
1890 : // prevent null pointer dereference
1891 : if (other.base_struct != nullptr)
1892 : base_struct = other.base_struct->clone_expr ();
1893 : else
1894 : base_struct = nullptr;
1895 :
1896 : return *this;
1897 : }
1898 :
1899 : // move constructors
1900 1334 : StructBase (StructBase &&other) = default;
1901 63 : StructBase &operator= (StructBase &&other) = default;
1902 :
1903 : // Returns a null expr-ed StructBase - error state
1904 1334 : static StructBase error () { return StructBase (nullptr, UNDEF_LOCATION); }
1905 :
1906 : // Returns whether StructBase is in error state
1907 30993 : bool is_invalid () const { return base_struct == nullptr; }
1908 :
1909 : std::string as_string () const;
1910 :
1911 : location_t get_locus () const { return locus; }
1912 :
1913 : // TODO: is this better? Or is a "vis_block" better?
1914 1218 : Expr &get_base_struct ()
1915 : {
1916 1218 : rust_assert (base_struct != nullptr);
1917 1218 : return *base_struct;
1918 : }
1919 :
1920 189 : std::unique_ptr<Expr> &get_base_struct_ptr ()
1921 : {
1922 189 : rust_assert (base_struct != nullptr);
1923 189 : return base_struct;
1924 : }
1925 : };
1926 :
1927 : /* Base AST node for a single struct expression field (in struct instance
1928 : * creation) - abstract */
1929 : class StructExprField
1930 : {
1931 : public:
1932 : virtual ~StructExprField () {}
1933 :
1934 : // Unique pointer custom clone function
1935 2351 : std::unique_ptr<StructExprField> clone_struct_expr_field () const
1936 : {
1937 2351 : return std::unique_ptr<StructExprField> (clone_struct_expr_field_impl ());
1938 : }
1939 :
1940 : virtual std::string as_string () const = 0;
1941 :
1942 : virtual void accept_vis (ASTVisitor &vis) = 0;
1943 :
1944 : virtual location_t get_locus () const = 0;
1945 :
1946 2508 : NodeId get_node_id () const { return node_id; }
1947 :
1948 2133 : const std::vector<AST::Attribute> &get_outer_attrs () const
1949 : {
1950 2133 : return outer_attrs;
1951 : }
1952 :
1953 10617 : std::vector<AST::Attribute> &get_outer_attrs () { return outer_attrs; }
1954 :
1955 : protected:
1956 : // pure virtual clone implementation
1957 : virtual StructExprField *clone_struct_expr_field_impl () const = 0;
1958 :
1959 : StructExprField () : node_id (Analysis::Mappings::get ().get_next_node_id ())
1960 : {}
1961 :
1962 4428 : StructExprField (AST::AttrVec outer_attrs)
1963 4428 : : outer_attrs (std::move (outer_attrs)),
1964 4428 : node_id (Analysis::Mappings::get ().get_next_node_id ())
1965 4428 : {}
1966 :
1967 : AST::AttrVec outer_attrs;
1968 : NodeId node_id;
1969 : };
1970 :
1971 : // Identifier-only variant of StructExprField AST node
1972 : class StructExprFieldIdentifier : public StructExprField
1973 : {
1974 : Identifier field_name;
1975 : location_t locus;
1976 :
1977 : public:
1978 216 : StructExprFieldIdentifier (Identifier field_identifier,
1979 : AST::AttrVec outer_attrs, location_t locus)
1980 216 : : StructExprField (std::move (outer_attrs)),
1981 216 : field_name (std::move (field_identifier)), locus (locus)
1982 216 : {}
1983 :
1984 0 : std::string as_string () const override { return field_name.as_string (); }
1985 :
1986 433 : location_t get_locus () const override final { return locus; }
1987 :
1988 : void accept_vis (ASTVisitor &vis) override;
1989 :
1990 433 : Identifier get_field_name () const { return field_name; }
1991 :
1992 : protected:
1993 : /* Use covariance to implement clone function as returning this object rather
1994 : * than base */
1995 218 : StructExprFieldIdentifier *clone_struct_expr_field_impl () const override
1996 : {
1997 218 : return new StructExprFieldIdentifier (*this);
1998 : }
1999 : };
2000 :
2001 : /* Base AST node for a single struct expression field with an assigned value -
2002 : * abstract */
2003 : class StructExprFieldWithVal : public StructExprField
2004 : {
2005 : std::unique_ptr<Expr> value;
2006 :
2007 : protected:
2008 2079 : StructExprFieldWithVal (std::unique_ptr<Expr> field_value,
2009 : AST::AttrVec outer_attrs)
2010 2079 : : StructExprField (std::move (outer_attrs)), value (std::move (field_value))
2011 2079 : {}
2012 :
2013 : // Copy constructor requires clone
2014 2133 : StructExprFieldWithVal (StructExprFieldWithVal const &other)
2015 2133 : : StructExprField (other.get_outer_attrs ()),
2016 2133 : value (other.value->clone_expr ())
2017 2133 : {}
2018 :
2019 : // Overload assignment operator to clone unique_ptr
2020 : StructExprFieldWithVal &operator= (StructExprFieldWithVal const &other)
2021 : {
2022 : value = other.value->clone_expr ();
2023 : outer_attrs = other.get_outer_attrs ();
2024 :
2025 : return *this;
2026 : }
2027 :
2028 : // move constructors
2029 : StructExprFieldWithVal (StructExprFieldWithVal &&other) = default;
2030 : StructExprFieldWithVal &operator= (StructExprFieldWithVal &&other) = default;
2031 :
2032 : public:
2033 : std::string as_string () const override;
2034 :
2035 : // TODO: is this better? Or is a "vis_block" better?
2036 43202 : Expr &get_value ()
2037 : {
2038 43202 : rust_assert (value != nullptr);
2039 43202 : return *value;
2040 : }
2041 :
2042 6691 : std::unique_ptr<Expr> &get_value_ptr ()
2043 : {
2044 6691 : rust_assert (value != nullptr);
2045 6691 : return value;
2046 : }
2047 : };
2048 :
2049 : // Identifier and value variant of StructExprField AST node
2050 : class StructExprFieldIdentifierValue : public StructExprFieldWithVal
2051 : {
2052 : Identifier field_name;
2053 : location_t locus;
2054 :
2055 : public:
2056 2000 : StructExprFieldIdentifierValue (Identifier field_identifier,
2057 : std::unique_ptr<Expr> field_value,
2058 : AST::AttrVec outer_attrs, location_t locus)
2059 2000 : : StructExprFieldWithVal (std::move (field_value), std::move (outer_attrs)),
2060 2000 : field_name (std::move (field_identifier)), locus (locus)
2061 2000 : {}
2062 :
2063 35 : StructExprFieldIdentifierValue (Identifier field_identifier,
2064 : std::unique_ptr<Expr> field_value,
2065 : location_t locus)
2066 35 : : StructExprFieldWithVal (std::move (field_value), {}),
2067 35 : field_name (std::move (field_identifier)), locus (locus)
2068 35 : {}
2069 :
2070 : std::string as_string () const override;
2071 :
2072 : void accept_vis (ASTVisitor &vis) override;
2073 :
2074 4710 : std::string get_field_name () const { return field_name.as_string (); }
2075 :
2076 4387 : location_t get_locus () const override final { return locus; }
2077 :
2078 : protected:
2079 : /* Use covariance to implement clone function as returning this object rather
2080 : * than base */
2081 2089 : StructExprFieldIdentifierValue *clone_struct_expr_field_impl () const override
2082 : {
2083 2089 : return new StructExprFieldIdentifierValue (*this);
2084 : }
2085 : };
2086 :
2087 : // Tuple index and value variant of StructExprField AST node
2088 88 : class StructExprFieldIndexValue : public StructExprFieldWithVal
2089 : {
2090 : TupleIndex index;
2091 : location_t locus;
2092 :
2093 : public:
2094 44 : StructExprFieldIndexValue (TupleIndex tuple_index,
2095 : std::unique_ptr<Expr> field_value,
2096 : AST::AttrVec outer_attrs, location_t locus)
2097 44 : : StructExprFieldWithVal (std::move (field_value), std::move (outer_attrs)),
2098 44 : index (tuple_index), locus (locus)
2099 44 : {}
2100 :
2101 : std::string as_string () const override;
2102 :
2103 : void accept_vis (ASTVisitor &vis) override;
2104 :
2105 44 : TupleIndex get_index () const { return index; }
2106 :
2107 88 : location_t get_locus () const override final { return locus; }
2108 :
2109 : protected:
2110 : /* Use covariance to implement clone function as returning this object rather
2111 : * than base */
2112 44 : StructExprFieldIndexValue *clone_struct_expr_field_impl () const override
2113 : {
2114 44 : return new StructExprFieldIndexValue (*this);
2115 : }
2116 : };
2117 :
2118 : // AST node of a struct creator with fields
2119 : class StructExprStructFields : public StructExprStruct
2120 : {
2121 : // std::vector<StructExprField> fields;
2122 : std::vector<std::unique_ptr<StructExprField>> fields;
2123 :
2124 : // bool has_struct_base;
2125 : StructBase struct_base;
2126 :
2127 : public:
2128 : std::string as_string () const override;
2129 :
2130 30993 : bool has_struct_base () const { return !struct_base.is_invalid (); }
2131 :
2132 : // Constructor for StructExprStructFields when no struct base is used
2133 1334 : StructExprStructFields (
2134 : PathInExpression struct_path,
2135 : std::vector<std::unique_ptr<StructExprField>> expr_fields, location_t locus,
2136 : StructBase base_struct = StructBase::error (),
2137 : std::vector<Attribute> inner_attribs = std::vector<Attribute> (),
2138 : std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
2139 1334 : : StructExprStruct (std::move (struct_path), std::move (inner_attribs),
2140 : std::move (outer_attribs), locus),
2141 1334 : fields (std::move (expr_fields)), struct_base (std::move (base_struct))
2142 1334 : {}
2143 :
2144 : // copy constructor with vector clone
2145 1338 : StructExprStructFields (StructExprStructFields const &other)
2146 1338 : : StructExprStruct (other), struct_base (other.struct_base)
2147 : {
2148 1338 : fields.reserve (other.fields.size ());
2149 3689 : for (const auto &e : other.fields)
2150 2351 : fields.push_back (e->clone_struct_expr_field ());
2151 1338 : }
2152 :
2153 : // overloaded assignment operator with vector clone
2154 : StructExprStructFields &operator= (StructExprStructFields const &other)
2155 : {
2156 : StructExprStruct::operator= (other);
2157 : struct_base = other.struct_base;
2158 :
2159 : fields.reserve (other.fields.size ());
2160 : for (const auto &e : other.fields)
2161 : fields.push_back (e->clone_struct_expr_field ());
2162 :
2163 : return *this;
2164 : }
2165 :
2166 : // move constructors
2167 : StructExprStructFields (StructExprStructFields &&other) = default;
2168 : StructExprStructFields &operator= (StructExprStructFields &&other) = default;
2169 :
2170 : void accept_vis (ASTVisitor &vis) override;
2171 :
2172 : // TODO: this mutable getter seems really dodgy. Think up better way.
2173 5887 : std::vector<std::unique_ptr<StructExprField>> &get_fields ()
2174 : {
2175 30993 : return fields;
2176 : }
2177 : const std::vector<std::unique_ptr<StructExprField>> &get_fields () const
2178 : {
2179 : return fields;
2180 : }
2181 :
2182 1407 : StructBase &get_struct_base () { return struct_base; }
2183 : const StructBase &get_struct_base () const { return struct_base; }
2184 :
2185 : protected:
2186 : /* Use covariance to implement clone function as returning this object rather
2187 : * than base */
2188 1338 : StructExprStructFields *clone_expr_without_block_impl () const override
2189 : {
2190 1338 : return new StructExprStructFields (*this);
2191 : }
2192 : };
2193 :
2194 : // AST node of the functional update struct creator
2195 : /* TODO: remove and replace with StructExprStructFields, except with empty
2196 : * vector of fields? */
2197 : class StructExprStructBase : public StructExprStruct
2198 : {
2199 : StructBase struct_base;
2200 :
2201 : public:
2202 : std::string as_string () const override;
2203 :
2204 : StructExprStructBase (PathInExpression struct_path, StructBase base_struct,
2205 : std::vector<Attribute> inner_attribs,
2206 : std::vector<Attribute> outer_attribs, location_t locus)
2207 : : StructExprStruct (std::move (struct_path), std::move (inner_attribs),
2208 : std::move (outer_attribs), locus),
2209 : struct_base (std::move (base_struct))
2210 : {}
2211 :
2212 : void accept_vis (ASTVisitor &vis) override;
2213 :
2214 0 : StructBase &get_struct_base () { return struct_base; }
2215 : const StructBase &get_struct_base () const { return struct_base; }
2216 :
2217 : protected:
2218 : /* Use covariance to implement clone function as returning this object rather
2219 : * than base */
2220 0 : StructExprStructBase *clone_expr_without_block_impl () const override
2221 : {
2222 0 : return new StructExprStructBase (*this);
2223 : }
2224 : };
2225 :
2226 : // Forward decl for Function - used in CallExpr
2227 : class Function;
2228 :
2229 : // Function call expression AST node
2230 : class CallExpr : public ExprWithoutBlock
2231 : {
2232 : std::vector<Attribute> outer_attrs;
2233 : std::unique_ptr<Expr> function;
2234 : std::vector<std::unique_ptr<Expr>> params;
2235 : location_t locus;
2236 :
2237 : public:
2238 : Function *fndeclRef;
2239 :
2240 : std::string as_string () const override;
2241 :
2242 11290 : CallExpr (std::unique_ptr<Expr> function_expr,
2243 : std::vector<std::unique_ptr<Expr>> function_params,
2244 : std::vector<Attribute> outer_attribs, location_t locus)
2245 22580 : : outer_attrs (std::move (outer_attribs)),
2246 11290 : function (std::move (function_expr)),
2247 11290 : params (std::move (function_params)), locus (locus)
2248 11290 : {}
2249 :
2250 : // copy constructor requires clone
2251 19310 : CallExpr (CallExpr const &other)
2252 19310 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2253 19310 : locus (other.locus)
2254 : {
2255 : // guard to prevent null dereference (only required if error state)
2256 19310 : if (other.function != nullptr)
2257 19310 : function = other.function->clone_expr ();
2258 :
2259 19310 : params.reserve (other.params.size ());
2260 41147 : for (const auto &e : other.params)
2261 21837 : params.push_back (e->clone_expr ());
2262 19310 : }
2263 :
2264 : // Overload assignment operator to clone
2265 : CallExpr &operator= (CallExpr const &other)
2266 : {
2267 : ExprWithoutBlock::operator= (other);
2268 : locus = other.locus;
2269 : outer_attrs = other.outer_attrs;
2270 :
2271 : // guard to prevent null dereference (only required if error state)
2272 : if (other.function != nullptr)
2273 : function = other.function->clone_expr ();
2274 : else
2275 : function = nullptr;
2276 :
2277 : params.reserve (other.params.size ());
2278 : for (const auto &e : other.params)
2279 : params.push_back (e->clone_expr ());
2280 :
2281 : return *this;
2282 : }
2283 :
2284 : // move constructors
2285 : CallExpr (CallExpr &&other) = default;
2286 : CallExpr &operator= (CallExpr &&other) = default;
2287 :
2288 : // Returns whether function call has parameters.
2289 0 : bool has_params () const { return !params.empty (); }
2290 :
2291 22569 : location_t get_locus () const override final { return locus; }
2292 :
2293 : void accept_vis (ASTVisitor &vis) override;
2294 :
2295 : // Invalid if function expr is null, so base stripping on that.
2296 0 : void mark_for_strip () override { function = nullptr; }
2297 62811 : bool is_marked_for_strip () const override { return function == nullptr; }
2298 :
2299 : // TODO: this mutable getter seems really dodgy. Think up better way.
2300 : const std::vector<std::unique_ptr<Expr>> &get_params () const
2301 : {
2302 : return params;
2303 : }
2304 303229 : std::vector<std::unique_ptr<Expr>> &get_params () { return params; }
2305 :
2306 : // TODO: is this better? Or is a "vis_block" better?
2307 292045 : Expr &get_function_expr ()
2308 : {
2309 292045 : rust_assert (function != nullptr);
2310 292045 : return *function;
2311 : }
2312 :
2313 11184 : std::unique_ptr<Expr> &get_function_expr_ptr () { return function; }
2314 :
2315 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2316 352103 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2317 :
2318 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2319 : {
2320 0 : outer_attrs = std::move (new_attrs);
2321 0 : }
2322 :
2323 11191 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Call; }
2324 :
2325 : protected:
2326 : /* Use covariance to implement clone function as returning this object rather
2327 : * than base */
2328 19310 : CallExpr *clone_expr_without_block_impl () const override
2329 : {
2330 19310 : return new CallExpr (*this);
2331 : }
2332 : };
2333 :
2334 : // Method call expression AST node
2335 : class MethodCallExpr : public ExprWithoutBlock
2336 : {
2337 : std::vector<Attribute> outer_attrs;
2338 : std::unique_ptr<Expr> receiver;
2339 : PathExprSegment method_name;
2340 : std::vector<std::unique_ptr<Expr>> params;
2341 : location_t locus;
2342 :
2343 : public:
2344 : std::string as_string () const override;
2345 :
2346 3020 : MethodCallExpr (std::unique_ptr<Expr> call_receiver,
2347 : PathExprSegment method_path,
2348 : std::vector<std::unique_ptr<Expr>> method_params,
2349 : std::vector<Attribute> outer_attribs, location_t locus)
2350 6040 : : outer_attrs (std::move (outer_attribs)),
2351 3020 : receiver (std::move (call_receiver)),
2352 3020 : method_name (std::move (method_path)), params (std::move (method_params)),
2353 3020 : locus (locus)
2354 3020 : {}
2355 :
2356 : // copy constructor required due to cloning
2357 7478 : MethodCallExpr (MethodCallExpr const &other)
2358 7478 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2359 7478 : method_name (other.method_name), locus (other.locus)
2360 : {
2361 : // guard to prevent null dereference (only required if error state)
2362 7478 : if (other.receiver != nullptr)
2363 7478 : receiver = other.receiver->clone_expr ();
2364 :
2365 7478 : params.reserve (other.params.size ());
2366 13594 : for (const auto &e : other.params)
2367 6116 : params.push_back (e->clone_expr ());
2368 7478 : }
2369 :
2370 : // Overload assignment operator to clone receiver object
2371 : MethodCallExpr &operator= (MethodCallExpr const &other)
2372 : {
2373 : ExprWithoutBlock::operator= (other);
2374 : method_name = other.method_name;
2375 : locus = other.locus;
2376 : outer_attrs = other.outer_attrs;
2377 :
2378 : // guard to prevent null dereference (only required if error state)
2379 : if (other.receiver != nullptr)
2380 : receiver = other.receiver->clone_expr ();
2381 : else
2382 : receiver = nullptr;
2383 :
2384 : params.reserve (other.params.size ());
2385 : for (const auto &e : other.params)
2386 : params.push_back (e->clone_expr ());
2387 :
2388 : return *this;
2389 : }
2390 :
2391 : // move constructors
2392 : MethodCallExpr (MethodCallExpr &&other) = default;
2393 : MethodCallExpr &operator= (MethodCallExpr &&other) = default;
2394 :
2395 6360 : location_t get_locus () const override final { return locus; }
2396 :
2397 : void accept_vis (ASTVisitor &vis) override;
2398 :
2399 : // Invalid if receiver expr is null, so base stripping on that.
2400 0 : void mark_for_strip () override { receiver = nullptr; }
2401 19705 : bool is_marked_for_strip () const override { return receiver == nullptr; }
2402 :
2403 : // TODO: this mutable getter seems really dodgy. Think up better way.
2404 : const std::vector<std::unique_ptr<Expr>> &get_params () const
2405 : {
2406 : return params;
2407 : }
2408 81879 : std::vector<std::unique_ptr<Expr>> &get_params () { return params; }
2409 :
2410 : // TODO: is this better? Or is a "vis_block" better?
2411 72732 : Expr &get_receiver_expr ()
2412 : {
2413 72732 : rust_assert (receiver != nullptr);
2414 72732 : return *receiver;
2415 : }
2416 :
2417 9147 : std::unique_ptr<Expr> &get_receiver_expr_ptr ()
2418 : {
2419 9147 : rust_assert (receiver != nullptr);
2420 9147 : return receiver;
2421 : }
2422 :
2423 : const PathExprSegment &get_method_name () const { return method_name; }
2424 81879 : PathExprSegment &get_method_name () { return method_name; }
2425 :
2426 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2427 102419 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2428 :
2429 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2430 : {
2431 0 : outer_attrs = std::move (new_attrs);
2432 0 : }
2433 :
2434 2976 : Expr::Kind get_expr_kind () const override { return Expr::Kind::MethodCall; }
2435 :
2436 : protected:
2437 : /* Use covariance to implement clone function as returning this object rather
2438 : * than base */
2439 7478 : MethodCallExpr *clone_expr_without_block_impl () const override
2440 : {
2441 7478 : return new MethodCallExpr (*this);
2442 : }
2443 : };
2444 :
2445 : // aka FieldExpression
2446 : // Struct or union field access expression AST node
2447 : class FieldAccessExpr : public ExprWithoutBlock
2448 : {
2449 : std::vector<Attribute> outer_attrs;
2450 : std::unique_ptr<Expr> receiver;
2451 : Identifier field;
2452 : location_t locus;
2453 :
2454 : public:
2455 : std::string as_string () const override;
2456 :
2457 5342 : FieldAccessExpr (std::unique_ptr<Expr> field_access_receiver,
2458 : Identifier field_name, std::vector<Attribute> outer_attribs,
2459 : location_t locus)
2460 10684 : : outer_attrs (std::move (outer_attribs)),
2461 5342 : receiver (std::move (field_access_receiver)),
2462 5342 : field (std::move (field_name)), locus (locus)
2463 5342 : {}
2464 :
2465 : // Copy constructor required due to unique_ptr cloning
2466 16346 : FieldAccessExpr (FieldAccessExpr const &other)
2467 16346 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2468 16346 : field (other.field), locus (other.locus)
2469 : {
2470 : // guard to prevent null dereference (only required if error state)
2471 16346 : if (other.receiver != nullptr)
2472 16346 : receiver = other.receiver->clone_expr ();
2473 16346 : }
2474 :
2475 : // Overload assignment operator to clone unique_ptr
2476 : FieldAccessExpr &operator= (FieldAccessExpr const &other)
2477 : {
2478 : ExprWithoutBlock::operator= (other);
2479 : field = other.field;
2480 : locus = other.locus;
2481 : outer_attrs = other.outer_attrs;
2482 :
2483 : // guard to prevent null dereference (only required if error state)
2484 : if (other.receiver != nullptr)
2485 : receiver = other.receiver->clone_expr ();
2486 : else
2487 : receiver = nullptr;
2488 :
2489 : return *this;
2490 : }
2491 :
2492 : // move constructors
2493 : FieldAccessExpr (FieldAccessExpr &&other) = default;
2494 : FieldAccessExpr &operator= (FieldAccessExpr &&other) = default;
2495 :
2496 12819 : location_t get_locus () const override final { return locus; }
2497 :
2498 : void accept_vis (ASTVisitor &vis) override;
2499 :
2500 : // Invalid if receiver expr is null, so base stripping on that.
2501 0 : void mark_for_strip () override { receiver = nullptr; }
2502 36927 : bool is_marked_for_strip () const override { return receiver == nullptr; }
2503 :
2504 : // TODO: is this better? Or is a "vis_block" better?
2505 128544 : Expr &get_receiver_expr ()
2506 : {
2507 128544 : rust_assert (receiver != nullptr);
2508 128544 : return *receiver;
2509 : }
2510 :
2511 13769 : std::unique_ptr<Expr> &get_receiver_expr_ptr ()
2512 : {
2513 13769 : rust_assert (receiver != nullptr);
2514 13769 : return receiver;
2515 : }
2516 :
2517 5112 : Identifier get_field_name () const { return field; }
2518 :
2519 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2520 182625 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2521 :
2522 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2523 : {
2524 0 : outer_attrs = std::move (new_attrs);
2525 0 : }
2526 :
2527 4989 : Expr::Kind get_expr_kind () const override { return Expr::Kind::FieldAccess; }
2528 :
2529 : protected:
2530 : /* Use covariance to implement clone function as returning this object rather
2531 : * than base */
2532 16346 : FieldAccessExpr *clone_expr_without_block_impl () const override
2533 : {
2534 16346 : return new FieldAccessExpr (*this);
2535 : }
2536 : };
2537 :
2538 : // Closure parameter data structure
2539 : struct ClosureParam
2540 : {
2541 : private:
2542 : std::vector<Attribute> outer_attrs;
2543 : std::unique_ptr<Pattern> pattern;
2544 : std::unique_ptr<Type> type;
2545 : location_t locus;
2546 :
2547 : public:
2548 : // Returns whether the type of the parameter has been given.
2549 1463 : bool has_type_given () const { return type != nullptr; }
2550 :
2551 : bool has_outer_attrs () const { return !outer_attrs.empty (); }
2552 :
2553 : // Constructor for closure parameter
2554 72 : ClosureParam (std::unique_ptr<Pattern> param_pattern, location_t locus,
2555 : std::unique_ptr<Type> param_type = nullptr,
2556 : std::vector<Attribute> outer_attrs = {})
2557 0 : : outer_attrs (std::move (outer_attrs)),
2558 0 : pattern (std::move (param_pattern)), type (std::move (param_type)),
2559 72 : locus (locus)
2560 : {}
2561 :
2562 : // Copy constructor required due to cloning as a result of unique_ptrs
2563 63 : ClosureParam (ClosureParam const &other) : outer_attrs (other.outer_attrs)
2564 : {
2565 : // guard to protect from null pointer dereference
2566 63 : if (other.pattern != nullptr)
2567 63 : pattern = other.pattern->clone_pattern ();
2568 63 : if (other.type != nullptr)
2569 58 : type = other.type->clone_type ();
2570 63 : }
2571 :
2572 168 : ~ClosureParam () = default;
2573 :
2574 : // Assignment operator must be overloaded to clone as well
2575 : ClosureParam &operator= (ClosureParam const &other)
2576 : {
2577 : outer_attrs = other.outer_attrs;
2578 :
2579 : // guard to protect from null pointer dereference
2580 : if (other.pattern != nullptr)
2581 : pattern = other.pattern->clone_pattern ();
2582 : else
2583 : pattern = nullptr;
2584 : if (other.type != nullptr)
2585 : type = other.type->clone_type ();
2586 : else
2587 : type = nullptr;
2588 :
2589 : return *this;
2590 : }
2591 :
2592 : // move constructors
2593 83 : ClosureParam (ClosureParam &&other) = default;
2594 0 : ClosureParam &operator= (ClosureParam &&other) = default;
2595 :
2596 : // Returns whether closure parameter is in an error state.
2597 72 : bool is_error () const { return pattern == nullptr; }
2598 :
2599 : // Creates an error state closure parameter.
2600 0 : static ClosureParam create_error ()
2601 : {
2602 0 : return ClosureParam (nullptr, UNDEF_LOCATION);
2603 : }
2604 :
2605 : std::string as_string () const;
2606 :
2607 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2608 1276 : std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
2609 :
2610 1213 : Pattern &get_pattern ()
2611 : {
2612 1213 : rust_assert (pattern != nullptr);
2613 1213 : return *pattern;
2614 : }
2615 :
2616 189 : std::unique_ptr<Pattern> &get_pattern_ptr ()
2617 : {
2618 189 : rust_assert (pattern != nullptr);
2619 189 : return pattern;
2620 : }
2621 :
2622 1124 : Type &get_type ()
2623 : {
2624 1124 : rust_assert (has_type_given ());
2625 1124 : return *type;
2626 : }
2627 :
2628 174 : std::unique_ptr<Type> &get_type_ptr ()
2629 : {
2630 174 : rust_assert (has_type_given ());
2631 174 : return type;
2632 : }
2633 :
2634 83 : location_t get_locus () const { return locus; }
2635 : };
2636 :
2637 : // Base closure definition expression AST node - abstract
2638 : class ClosureExpr : public ExprWithoutBlock
2639 : {
2640 : std::vector<Attribute> outer_attrs;
2641 : bool has_move;
2642 : std::vector<ClosureParam> params; // may be empty
2643 : location_t locus;
2644 :
2645 : protected:
2646 73 : ClosureExpr (std::vector<ClosureParam> closure_params, bool has_move,
2647 : std::vector<Attribute> outer_attribs, location_t locus)
2648 146 : : outer_attrs (std::move (outer_attribs)), has_move (has_move),
2649 73 : params (std::move (closure_params)), locus (locus)
2650 73 : {}
2651 :
2652 : public:
2653 : std::string as_string () const override;
2654 :
2655 133 : location_t get_locus () const override final { return locus; }
2656 :
2657 : // TODO: this mutable getter seems really dodgy. Think up better way.
2658 : const std::vector<ClosureParam> &get_params () const { return params; }
2659 1467 : std::vector<ClosureParam> &get_params () { return params; }
2660 :
2661 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2662 1556 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2663 :
2664 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2665 : {
2666 0 : outer_attrs = std::move (new_attrs);
2667 0 : }
2668 :
2669 95 : bool get_has_move () const { return has_move; }
2670 :
2671 67 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Closure; }
2672 :
2673 : virtual Expr &get_definition_expr () = 0;
2674 : virtual std::unique_ptr<Expr> &get_definition_expr_ptr () = 0;
2675 : };
2676 :
2677 : // Represents a non-type-specified closure expression AST node
2678 : class ClosureExprInner : public ClosureExpr
2679 : {
2680 : std::unique_ptr<Expr> closure_inner;
2681 :
2682 : public:
2683 : std::string as_string () const override;
2684 :
2685 : // Constructor for a ClosureExprInner
2686 42 : ClosureExprInner (std::unique_ptr<Expr> closure_inner_expr,
2687 : std::vector<ClosureParam> closure_params, location_t locus,
2688 : bool is_move = false,
2689 : std::vector<Attribute> outer_attribs
2690 : = std::vector<Attribute> ())
2691 42 : : ClosureExpr (std::move (closure_params), is_move,
2692 : std::move (outer_attribs), locus),
2693 42 : closure_inner (std::move (closure_inner_expr))
2694 42 : {}
2695 :
2696 : // Copy constructor must be defined to allow copying via cloning of unique_ptr
2697 40 : ClosureExprInner (ClosureExprInner const &other) : ClosureExpr (other)
2698 : {
2699 : // guard to prevent null dereference (only required if error state)
2700 40 : if (other.closure_inner != nullptr)
2701 40 : closure_inner = other.closure_inner->clone_expr ();
2702 40 : }
2703 :
2704 : // Overload assignment operator to clone closure_inner
2705 : ClosureExprInner &operator= (ClosureExprInner const &other)
2706 : {
2707 : ClosureExpr::operator= (other);
2708 : // params = other.params;
2709 : // has_move = other.has_move;
2710 : // outer_attrs = other.outer_attrs;
2711 :
2712 : // guard to prevent null dereference (only required if error state)
2713 : if (other.closure_inner != nullptr)
2714 : closure_inner = other.closure_inner->clone_expr ();
2715 : else
2716 : closure_inner = nullptr;
2717 :
2718 : return *this;
2719 : }
2720 :
2721 : // move constructors
2722 : ClosureExprInner (ClosureExprInner &&other) = default;
2723 : ClosureExprInner &operator= (ClosureExprInner &&other) = default;
2724 :
2725 : void accept_vis (ASTVisitor &vis) override;
2726 :
2727 : // Invalid if inner expr is null, so base stripping on that.
2728 0 : void mark_for_strip () override { closure_inner = nullptr; }
2729 352 : bool is_marked_for_strip () const override
2730 : {
2731 352 : return closure_inner == nullptr;
2732 : }
2733 :
2734 695 : Expr &get_definition_expr () override
2735 : {
2736 695 : rust_assert (closure_inner != nullptr);
2737 695 : return *closure_inner;
2738 : }
2739 :
2740 111 : std::unique_ptr<Expr> &get_definition_expr_ptr () override
2741 : {
2742 111 : rust_assert (closure_inner != nullptr);
2743 111 : return closure_inner;
2744 : }
2745 :
2746 : protected:
2747 : /* Use covariance to implement clone function as returning this object rather
2748 : * than base */
2749 40 : ClosureExprInner *clone_expr_without_block_impl () const override
2750 : {
2751 40 : return new ClosureExprInner (*this);
2752 : }
2753 : };
2754 :
2755 : // A block AST node
2756 : class BlockExpr : public ExprWithBlock
2757 : {
2758 : std::vector<Attribute> outer_attrs;
2759 : std::vector<Attribute> inner_attrs;
2760 : std::vector<std::unique_ptr<Stmt>> statements;
2761 : std::unique_ptr<Expr> expr;
2762 : tl::optional<LoopLabel> label;
2763 : location_t start_locus;
2764 : location_t end_locus;
2765 : bool marked_for_strip = false;
2766 :
2767 : public:
2768 : std::string as_string () const override;
2769 :
2770 : // Returns whether the block contains statements.
2771 1 : bool has_statements () const { return !statements.empty (); }
2772 :
2773 : // Returns whether the block contains a final expression.
2774 647776 : bool has_tail_expr () const { return expr != nullptr; }
2775 :
2776 22551 : BlockExpr (std::vector<std::unique_ptr<Stmt>> block_statements,
2777 : std::unique_ptr<Expr> block_expr,
2778 : std::vector<Attribute> inner_attribs,
2779 : std::vector<Attribute> outer_attribs,
2780 : tl::optional<LoopLabel> label, location_t start_locus,
2781 : location_t end_locus)
2782 45102 : : outer_attrs (std::move (outer_attribs)),
2783 22551 : inner_attrs (std::move (inner_attribs)),
2784 22551 : statements (std::move (block_statements)), expr (std::move (block_expr)),
2785 22551 : label (std::move (label)), start_locus (start_locus),
2786 22551 : end_locus (end_locus)
2787 22551 : {}
2788 :
2789 : // Copy constructor with clone
2790 38101 : BlockExpr (BlockExpr const &other)
2791 38101 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
2792 38101 : inner_attrs (other.inner_attrs), label (other.label),
2793 38101 : start_locus (other.start_locus), end_locus (other.end_locus),
2794 76202 : marked_for_strip (other.marked_for_strip)
2795 : {
2796 : // guard to protect from null pointer dereference
2797 38101 : if (other.expr != nullptr)
2798 31314 : expr = other.expr->clone_expr ();
2799 :
2800 38101 : statements.reserve (other.statements.size ());
2801 67324 : for (const auto &e : other.statements)
2802 29223 : statements.push_back (e->clone_stmt ());
2803 38101 : }
2804 :
2805 : // Overloaded assignment operator to clone pointer
2806 : BlockExpr &operator= (BlockExpr const &other)
2807 : {
2808 : ExprWithBlock::operator= (other);
2809 : inner_attrs = other.inner_attrs;
2810 : start_locus = other.start_locus;
2811 : end_locus = other.end_locus;
2812 : marked_for_strip = other.marked_for_strip;
2813 : outer_attrs = other.outer_attrs;
2814 :
2815 : // guard to protect from null pointer dereference
2816 : if (other.expr != nullptr)
2817 : expr = other.expr->clone_expr ();
2818 : else
2819 : expr = nullptr;
2820 :
2821 : statements.reserve (other.statements.size ());
2822 : for (const auto &e : other.statements)
2823 : statements.push_back (e->clone_stmt ());
2824 :
2825 : return *this;
2826 : }
2827 :
2828 : // move constructors
2829 : BlockExpr (BlockExpr &&other) = default;
2830 : BlockExpr &operator= (BlockExpr &&other) = default;
2831 :
2832 : // Unique pointer custom clone function
2833 32790 : std::unique_ptr<BlockExpr> clone_block_expr () const
2834 : {
2835 32790 : return std::unique_ptr<BlockExpr> (clone_block_expr_impl ());
2836 : }
2837 :
2838 4739 : location_t get_locus () const override final { return start_locus; }
2839 :
2840 21984 : location_t get_start_locus () const { return start_locus; }
2841 21984 : location_t get_end_locus () const { return end_locus; }
2842 :
2843 : void accept_vis (ASTVisitor &vis) override;
2844 :
2845 : // Can be completely empty, so have to have a separate flag.
2846 54 : void mark_for_strip () override { marked_for_strip = true; }
2847 96149 : bool is_marked_for_strip () const override { return marked_for_strip; }
2848 :
2849 : size_t num_statements () const { return statements.size (); }
2850 :
2851 : // TODO: this mutable getter seems really dodgy. Think up better way.
2852 : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
2853 507307 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
2854 :
2855 : const std::vector<std::unique_ptr<Stmt>> &get_statements () const
2856 : {
2857 : return statements;
2858 : }
2859 537966 : std::vector<std::unique_ptr<Stmt>> &get_statements () { return statements; }
2860 :
2861 : // TODO: is this better? Or is a "vis_block" better?
2862 337822 : Expr &get_tail_expr ()
2863 : {
2864 337822 : rust_assert (has_tail_expr ());
2865 337822 : return *expr;
2866 : }
2867 :
2868 55960 : std::unique_ptr<Expr> &get_tail_expr_ptr ()
2869 : {
2870 55960 : rust_assert (has_tail_expr ());
2871 55960 : return expr;
2872 : }
2873 :
2874 39897 : std::unique_ptr<Expr> take_tail_expr ()
2875 : {
2876 39897 : rust_assert (has_tail_expr ());
2877 39897 : return std::move (expr);
2878 : }
2879 :
2880 39897 : void set_tail_expr (std::unique_ptr<Expr> expr)
2881 : {
2882 39897 : this->expr = std::move (expr);
2883 : }
2884 :
2885 : // Removes the tail expression from the block.
2886 57 : void strip_tail_expr () { expr = nullptr; }
2887 : // Normalizes a trailing statement without a semicolon to a tail expression.
2888 : void normalize_tail_expr ();
2889 :
2890 : void try_convert_last_stmt ();
2891 :
2892 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2893 564544 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2894 :
2895 1289 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2896 : {
2897 1289 : outer_attrs = std::move (new_attrs);
2898 1289 : }
2899 :
2900 381040 : bool has_label () { return label.has_value (); }
2901 0 : LoopLabel &get_label () { return label.value (); }
2902 :
2903 1537 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Block; }
2904 :
2905 : protected:
2906 : /* Use covariance to implement clone function as returning this object rather
2907 : * than base */
2908 5311 : BlockExpr *clone_expr_with_block_impl () const final override
2909 : {
2910 5311 : return clone_block_expr_impl ();
2911 : }
2912 :
2913 : /* This is the base method as not an abstract class - not virtual but could be
2914 : * in future if required. */
2915 38101 : /*virtual*/ BlockExpr *clone_block_expr_impl () const
2916 : {
2917 38101 : return new BlockExpr (*this);
2918 : }
2919 : };
2920 :
2921 4023 : class AnonConst : public ExprWithBlock
2922 : {
2923 : public:
2924 : enum class Kind
2925 : {
2926 : Explicit,
2927 : DeferredInference,
2928 : };
2929 :
2930 675 : AnonConst (std::unique_ptr<Expr> &&expr, location_t locus = UNKNOWN_LOCATION)
2931 1350 : : ExprWithBlock (), locus (locus), kind (Kind::Explicit),
2932 675 : expr (std::move (expr))
2933 : {
2934 675 : rust_assert (this->expr.value ());
2935 675 : }
2936 :
2937 11 : AnonConst (location_t locus = UNKNOWN_LOCATION)
2938 22 : : ExprWithBlock (), locus (locus), kind (Kind::DeferredInference),
2939 11 : expr (tl::nullopt)
2940 : {}
2941 :
2942 4059 : AnonConst (const AnonConst &other)
2943 4059 : {
2944 4059 : node_id = other.node_id;
2945 4059 : locus = other.locus;
2946 4059 : kind = other.kind;
2947 :
2948 4059 : if (other.expr)
2949 3980 : expr = other.expr.value ()->clone_expr ();
2950 4059 : }
2951 :
2952 : AnonConst operator= (const AnonConst &other)
2953 : {
2954 : node_id = other.node_id;
2955 : locus = other.locus;
2956 : kind = other.kind;
2957 :
2958 : if (other.expr)
2959 : expr = other.expr.value ()->clone_expr ();
2960 :
2961 : return *this;
2962 : }
2963 :
2964 : std::string as_string () const override;
2965 :
2966 0 : Expr::Kind get_expr_kind () const override { return Expr::Kind::ConstExpr; }
2967 :
2968 1370 : location_t get_locus () const override { return locus; }
2969 :
2970 12548 : Expr &get_inner_expr ()
2971 : {
2972 12548 : rust_assert (expr.has_value ());
2973 12548 : return *expr.value ();
2974 : }
2975 :
2976 2264 : std::unique_ptr<Expr> &get_inner_expr_ptr ()
2977 : {
2978 2264 : rust_assert (expr.has_value ());
2979 2264 : return expr.value ();
2980 : }
2981 :
2982 682 : NodeId get_node_id () const override { return node_id; }
2983 :
2984 : /* FIXME: AnonConst are always "internal" and should not have outer attributes
2985 : * - is that true? Or should we instead call
2986 : * expr->get_outer_attrs()/expr->set_outer_attrs() */
2987 :
2988 0 : std::vector<Attribute> &get_outer_attrs () override
2989 : {
2990 14741 : static auto attrs = std::vector<Attribute> ();
2991 0 : return attrs;
2992 : }
2993 :
2994 0 : void set_outer_attrs (std::vector<Attribute>) override {}
2995 :
2996 : /* FIXME: Likewise for mark_for_strip() ? */
2997 0 : void mark_for_strip () override {}
2998 4892 : bool is_marked_for_strip () const override { return false; }
2999 :
3000 : void accept_vis (ASTVisitor &vis) override;
3001 :
3002 15016 : bool is_deferred () const { return kind == Kind::DeferredInference; }
3003 :
3004 : private:
3005 : location_t locus;
3006 : Kind kind;
3007 : tl::optional<std::unique_ptr<Expr>> expr;
3008 :
3009 0 : AnonConst *clone_expr_with_block_impl () const override
3010 : {
3011 0 : return new AnonConst (*this);
3012 : }
3013 : };
3014 :
3015 : class ConstBlock : public ExprWithBlock
3016 : {
3017 : public:
3018 15 : ConstBlock (AnonConst &&expr, location_t locus = UNKNOWN_LOCATION,
3019 : std::vector<Attribute> &&outer_attrs = {})
3020 30 : : ExprWithBlock (), expr (std::move (expr)),
3021 15 : outer_attrs (std::move (outer_attrs)), locus (locus)
3022 15 : {}
3023 :
3024 43 : ConstBlock (const ConstBlock &other)
3025 43 : : ExprWithBlock (other), expr (other.expr), outer_attrs (other.outer_attrs),
3026 43 : locus (other.locus)
3027 43 : {}
3028 :
3029 : ConstBlock operator= (const ConstBlock &other)
3030 : {
3031 : expr = other.expr;
3032 : node_id = other.node_id;
3033 : outer_attrs = other.outer_attrs;
3034 : locus = other.locus;
3035 :
3036 : return *this;
3037 : }
3038 :
3039 : std::string as_string () const override;
3040 :
3041 15 : Expr::Kind get_expr_kind () const override { return Expr::Kind::ConstBlock; }
3042 :
3043 219 : AnonConst &get_const_expr () { return expr; }
3044 :
3045 : void accept_vis (ASTVisitor &vis) override;
3046 :
3047 15 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3048 :
3049 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3050 : {
3051 0 : outer_attrs = std::move (new_attrs);
3052 0 : }
3053 :
3054 30 : location_t get_locus () const override { return locus; }
3055 :
3056 30 : bool is_marked_for_strip () const override { return marked_for_strip; }
3057 0 : void mark_for_strip () override { marked_for_strip = true; }
3058 :
3059 : private:
3060 : AnonConst expr;
3061 :
3062 : std::vector<Attribute> outer_attrs;
3063 : location_t locus;
3064 : bool marked_for_strip = false;
3065 :
3066 43 : ConstBlock *clone_expr_with_block_impl () const override
3067 : {
3068 43 : return new ConstBlock (*this);
3069 : }
3070 : };
3071 :
3072 : // Represents a type-specified closure expression AST node
3073 : class ClosureExprInnerTyped : public ClosureExpr
3074 : {
3075 : // TODO: spec says typenobounds
3076 : std::unique_ptr<Type> return_type;
3077 : std::unique_ptr<Expr> expr; // only used because may be polymorphic in future
3078 :
3079 : public:
3080 : std::string as_string () const override;
3081 :
3082 : // Constructor potentially with a move
3083 31 : ClosureExprInnerTyped (std::unique_ptr<Type> closure_return_type,
3084 : std::unique_ptr<BlockExpr> closure_expr,
3085 : std::vector<ClosureParam> closure_params,
3086 : location_t locus, bool is_move = false,
3087 : std::vector<Attribute> outer_attribs
3088 : = std::vector<Attribute> ())
3089 31 : : ClosureExpr (std::move (closure_params), is_move,
3090 : std::move (outer_attribs), locus),
3091 31 : return_type (std::move (closure_return_type)),
3092 31 : expr (std::move (closure_expr))
3093 31 : {}
3094 :
3095 : // Copy constructor requires cloning
3096 30 : ClosureExprInnerTyped (ClosureExprInnerTyped const &other)
3097 30 : : ClosureExpr (other)
3098 : {
3099 : // guard to prevent null dereference (only required if error state)
3100 30 : if (other.expr != nullptr)
3101 30 : expr = other.expr->clone_expr ();
3102 30 : if (other.return_type != nullptr)
3103 30 : return_type = other.return_type->clone_type ();
3104 30 : }
3105 :
3106 : // Overload assignment operator to clone unique_ptrs
3107 : ClosureExprInnerTyped &operator= (ClosureExprInnerTyped const &other)
3108 : {
3109 : ClosureExpr::operator= (other);
3110 : // params = other.params;
3111 : // has_move = other.has_move;
3112 : // outer_attrs = other.outer_attrs;
3113 :
3114 : // guard to prevent null dereference (only required if error state)
3115 : if (other.expr != nullptr)
3116 : expr = other.expr->clone_expr ();
3117 : else
3118 : expr = nullptr;
3119 : if (other.return_type != nullptr)
3120 : return_type = other.return_type->clone_type ();
3121 : else
3122 : return_type = nullptr;
3123 :
3124 : return *this;
3125 : }
3126 :
3127 : // move constructors
3128 : ClosureExprInnerTyped (ClosureExprInnerTyped &&other) = default;
3129 : ClosureExprInnerTyped &operator= (ClosureExprInnerTyped &&other) = default;
3130 :
3131 : void accept_vis (ASTVisitor &vis) override;
3132 :
3133 : /* Invalid if inner expr is null, so base stripping on that. Technically,
3134 : * type should also not be null. */
3135 0 : void mark_for_strip () override { expr = nullptr; }
3136 300 : bool is_marked_for_strip () const override { return expr == nullptr; }
3137 :
3138 : // TODO: is this better? Or is a "vis_block" better?
3139 631 : Expr &get_definition_expr () override
3140 : {
3141 631 : rust_assert (expr != nullptr);
3142 631 : return *expr;
3143 : }
3144 :
3145 30 : std::unique_ptr<Expr> &get_definition_expr_ptr () override
3146 : {
3147 30 : rust_assert (expr != nullptr);
3148 :
3149 30 : return expr;
3150 : }
3151 :
3152 : // TODO: is this better? Or is a "vis_block" better?
3153 541 : Type &get_return_type ()
3154 : {
3155 541 : rust_assert (return_type != nullptr);
3156 541 : return *return_type;
3157 : }
3158 :
3159 90 : std::unique_ptr<Type> &get_return_type_ptr ()
3160 : {
3161 90 : rust_assert (return_type != nullptr);
3162 90 : return return_type;
3163 : }
3164 :
3165 : protected:
3166 : /* Use covariance to implement clone function as returning this object rather
3167 : * than base */
3168 30 : ClosureExprInnerTyped *clone_expr_without_block_impl () const override
3169 : {
3170 30 : return new ClosureExprInnerTyped (*this);
3171 : }
3172 : };
3173 :
3174 : // AST node representing continue expression within loops
3175 : class ContinueExpr : public ExprWithoutBlock
3176 : {
3177 : std::vector<Attribute> outer_attrs;
3178 : tl::optional<Lifetime> label;
3179 : location_t locus;
3180 :
3181 : // TODO: find another way to store this to save memory?
3182 : bool marked_for_strip = false;
3183 :
3184 : public:
3185 : std::string as_string () const override;
3186 :
3187 : // Returns true if the continue expr has a label.
3188 222 : bool has_label () const { return label.has_value (); }
3189 :
3190 : // Constructor for a ContinueExpr with a label.
3191 17 : ContinueExpr (tl::optional<Lifetime> label,
3192 : std::vector<Attribute> outer_attribs, location_t locus)
3193 51 : : outer_attrs (std::move (outer_attribs)), label (std::move (label)),
3194 17 : locus (locus)
3195 17 : {}
3196 :
3197 34 : location_t get_locus () const override final { return locus; }
3198 :
3199 : void accept_vis (ASTVisitor &vis) override;
3200 :
3201 : // Can't think of any invalid invariants, so store boolean.
3202 0 : void mark_for_strip () override { marked_for_strip = true; }
3203 154 : bool is_marked_for_strip () const override { return marked_for_strip; }
3204 :
3205 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3206 517 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3207 :
3208 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3209 : {
3210 0 : outer_attrs = std::move (new_attrs);
3211 0 : }
3212 :
3213 39 : Lifetime &get_label_unchecked () { return label.value (); }
3214 0 : const Lifetime &get_label_unchecked () const { return label.value (); }
3215 :
3216 : tl::optional<Lifetime> &get_label () { return label; }
3217 : const tl::optional<Lifetime> &get_label () const { return label; }
3218 :
3219 17 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Continue; }
3220 :
3221 : protected:
3222 : /* Use covariance to implement clone function as returning this object rather
3223 : * than base */
3224 17 : ContinueExpr *clone_expr_without_block_impl () const override
3225 : {
3226 17 : return new ContinueExpr (*this);
3227 : }
3228 : };
3229 : // TODO: merge "break" and "continue"? Or even merge in "return"?
3230 :
3231 : // AST node representing break expression within loops
3232 : class BreakExpr : public ExprWithoutBlock
3233 : {
3234 : std::vector<Attribute> outer_attrs;
3235 : tl::optional<LoopLabel> label;
3236 : tl::optional<std::unique_ptr<Expr>> break_expr;
3237 : location_t locus;
3238 :
3239 : // TODO: find another way to store this to save memory?
3240 : bool marked_for_strip = false;
3241 :
3242 : public:
3243 : std::string as_string () const override;
3244 :
3245 : // Returns whether the break expression has a label or not.
3246 1993 : bool has_label () const { return label.has_value (); }
3247 :
3248 : /* Returns whether the break expression has an expression used in the break or
3249 : * not. */
3250 2718 : bool has_break_expr () const { return break_expr.has_value (); }
3251 :
3252 : // Constructor for a break expression
3253 97 : BreakExpr (tl::optional<LoopLabel> break_label,
3254 : tl::optional<std::unique_ptr<Expr>> expr_in_break,
3255 : std::vector<Attribute> outer_attribs, location_t locus)
3256 291 : : outer_attrs (std::move (outer_attribs)), label (std::move (break_label)),
3257 97 : break_expr (std::move (expr_in_break)), locus (locus)
3258 : {
3259 97 : if (this->has_break_expr ())
3260 22 : rust_assert (this->break_expr != nullptr);
3261 97 : }
3262 :
3263 : // Copy constructor defined to use clone for unique pointer
3264 111 : BreakExpr (BreakExpr const &other)
3265 111 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
3266 111 : label (other.label), locus (other.locus),
3267 222 : marked_for_strip (other.marked_for_strip)
3268 : {
3269 111 : if (other.has_break_expr ())
3270 22 : break_expr = other.get_break_expr_unchecked ().clone_expr ();
3271 111 : }
3272 :
3273 : // Overload assignment operator to clone unique pointer
3274 : BreakExpr &operator= (BreakExpr const &other)
3275 : {
3276 : ExprWithoutBlock::operator= (other);
3277 : label = other.label;
3278 : locus = other.locus;
3279 : marked_for_strip = other.marked_for_strip;
3280 : outer_attrs = other.outer_attrs;
3281 :
3282 : // guard to protect from null pointer dereference
3283 : if (other.has_break_expr ())
3284 : break_expr = other.get_break_expr_unchecked ().clone_expr ();
3285 : else
3286 : break_expr = tl::nullopt;
3287 :
3288 : return *this;
3289 : }
3290 :
3291 : // move constructors
3292 : BreakExpr (BreakExpr &&other) = default;
3293 : BreakExpr &operator= (BreakExpr &&other) = default;
3294 :
3295 200 : location_t get_locus () const override final { return locus; }
3296 :
3297 : void accept_vis (ASTVisitor &vis) override;
3298 :
3299 : // Can't think of any invalid invariants, so store boolean.
3300 0 : void mark_for_strip () override { marked_for_strip = true; }
3301 628 : bool is_marked_for_strip () const override { return marked_for_strip; }
3302 :
3303 : // TODO: is this better? Or is a "vis_block" better?
3304 769 : Expr &get_break_expr_unchecked ()
3305 : {
3306 769 : rust_assert (has_break_expr ());
3307 769 : return *break_expr.value ();
3308 : }
3309 :
3310 22 : const Expr &get_break_expr_unchecked () const
3311 : {
3312 22 : rust_assert (has_break_expr ());
3313 22 : return *break_expr.value ();
3314 : }
3315 :
3316 66 : std::unique_ptr<Expr> &get_break_expr_ptr_unchecked ()
3317 : {
3318 66 : rust_assert (has_break_expr ());
3319 66 : return break_expr.value ();
3320 : }
3321 :
3322 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3323 3136 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3324 :
3325 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3326 : {
3327 0 : outer_attrs = std::move (new_attrs);
3328 0 : }
3329 :
3330 441 : LoopLabel &get_label_unchecked () { return label.value (); }
3331 0 : const LoopLabel &get_label_unchecked () const { return label.value (); }
3332 :
3333 : tl::optional<LoopLabel> &get_label () { return label; }
3334 : const tl::optional<LoopLabel> &get_label () const { return label; }
3335 :
3336 95 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Break; }
3337 :
3338 : protected:
3339 : /* Use covariance to implement clone function as returning this object rather
3340 : * than base */
3341 111 : BreakExpr *clone_expr_without_block_impl () const override
3342 : {
3343 111 : return new BreakExpr (*this);
3344 : }
3345 : };
3346 :
3347 : // Base range expression AST node object - abstract
3348 88 : class RangeExpr : public ExprWithoutBlock
3349 : {
3350 : location_t locus;
3351 :
3352 : // Some visitors still check for attributes on RangeExprs, and they will need
3353 : // to be supported in the future - so keep that for now
3354 : std::vector<Attribute> empty_attributes = {};
3355 :
3356 : protected:
3357 : // outer attributes not allowed before range expressions
3358 93 : RangeExpr (location_t locus) : locus (locus) {}
3359 :
3360 : public:
3361 198 : location_t get_locus () const override final { return locus; }
3362 :
3363 0 : std::vector<Attribute> &get_outer_attrs () override final
3364 : {
3365 0 : return empty_attributes;
3366 : }
3367 :
3368 : // should never be called - error if called
3369 0 : void set_outer_attrs (std::vector<Attribute> /* new_attrs */) override {}
3370 :
3371 87 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Range; }
3372 : };
3373 :
3374 : // Range from (inclusive) and to (exclusive) expression AST node object
3375 : // aka RangeExpr; constructs a std::ops::Range object
3376 : class RangeFromToExpr : public RangeExpr
3377 : {
3378 : std::unique_ptr<Expr> from;
3379 : std::unique_ptr<Expr> to;
3380 :
3381 : public:
3382 : std::string as_string () const override;
3383 :
3384 69 : RangeFromToExpr (std::unique_ptr<Expr> range_from,
3385 : std::unique_ptr<Expr> range_to, location_t locus)
3386 138 : : RangeExpr (locus), from (std::move (range_from)),
3387 69 : to (std::move (range_to))
3388 : {}
3389 :
3390 : // Copy constructor with cloning
3391 67 : RangeFromToExpr (RangeFromToExpr const &other) : RangeExpr (other)
3392 : {
3393 : // guard to prevent null dereference (only required if error state)
3394 67 : if (other.from != nullptr)
3395 67 : from = other.from->clone_expr ();
3396 67 : if (other.to != nullptr)
3397 67 : to = other.to->clone_expr ();
3398 67 : }
3399 :
3400 : // Overload assignment operator to clone unique pointers
3401 : RangeFromToExpr &operator= (RangeFromToExpr const &other)
3402 : {
3403 : RangeExpr::operator= (other);
3404 :
3405 : // guard to prevent null dereference (only required if error state)
3406 : if (other.from != nullptr)
3407 : from = other.from->clone_expr ();
3408 : else
3409 : from = nullptr;
3410 : if (other.to != nullptr)
3411 : to = other.to->clone_expr ();
3412 : else
3413 : to = nullptr;
3414 :
3415 : return *this;
3416 : }
3417 :
3418 : // move constructors
3419 : RangeFromToExpr (RangeFromToExpr &&other) = default;
3420 : RangeFromToExpr &operator= (RangeFromToExpr &&other) = default;
3421 :
3422 : void accept_vis (ASTVisitor &vis) override;
3423 :
3424 : // Invalid if either expr is null, so base stripping on that.
3425 0 : void mark_for_strip () override
3426 : {
3427 0 : from = nullptr;
3428 0 : to = nullptr;
3429 0 : }
3430 356 : bool is_marked_for_strip () const override
3431 : {
3432 356 : return from == nullptr && to == nullptr;
3433 : }
3434 :
3435 : // TODO: is this better? Or is a "vis_block" better?
3436 1523 : Expr &get_from_expr ()
3437 : {
3438 1523 : rust_assert (from != nullptr);
3439 1523 : return *from;
3440 : }
3441 :
3442 : // TODO: is this better? Or is a "vis_block" better?
3443 1523 : Expr &get_to_expr ()
3444 : {
3445 1523 : rust_assert (to != nullptr);
3446 1523 : return *to;
3447 : }
3448 :
3449 246 : std::unique_ptr<Expr> &get_from_expr_ptr ()
3450 : {
3451 246 : rust_assert (from != nullptr);
3452 246 : return from;
3453 : }
3454 :
3455 246 : std::unique_ptr<Expr> &get_to_expr_ptr ()
3456 : {
3457 246 : rust_assert (to != nullptr);
3458 246 : return to;
3459 : }
3460 :
3461 : protected:
3462 : /* Use covariance to implement clone function as returning this object rather
3463 : * than base */
3464 67 : RangeFromToExpr *clone_expr_without_block_impl () const override
3465 : {
3466 67 : return new RangeFromToExpr (*this);
3467 : }
3468 : };
3469 :
3470 : // Range from (inclusive) expression AST node object
3471 : // constructs a std::ops::RangeFrom object
3472 : class RangeFromExpr : public RangeExpr
3473 : {
3474 : std::unique_ptr<Expr> from;
3475 :
3476 : public:
3477 : std::string as_string () const override;
3478 :
3479 9 : RangeFromExpr (std::unique_ptr<Expr> range_from, location_t locus)
3480 9 : : RangeExpr (locus), from (std::move (range_from))
3481 : {}
3482 :
3483 : // Copy constructor with clone
3484 7 : RangeFromExpr (RangeFromExpr const &other) : RangeExpr (other)
3485 : {
3486 : // guard to prevent null dereference (only required if error state)
3487 7 : if (other.from != nullptr)
3488 7 : from = other.from->clone_expr ();
3489 7 : }
3490 :
3491 : // Overload assignment operator to clone unique_ptr
3492 : RangeFromExpr &operator= (RangeFromExpr const &other)
3493 : {
3494 : RangeExpr::operator= (other);
3495 :
3496 : // guard to prevent null dereference (only required if error state)
3497 : if (other.from != nullptr)
3498 : from = other.from->clone_expr ();
3499 : else
3500 : from = nullptr;
3501 :
3502 : return *this;
3503 : }
3504 :
3505 : // move constructors
3506 : RangeFromExpr (RangeFromExpr &&other) = default;
3507 : RangeFromExpr &operator= (RangeFromExpr &&other) = default;
3508 :
3509 : void accept_vis (ASTVisitor &vis) override;
3510 :
3511 : // Invalid if expr is null, so base stripping on that.
3512 0 : void mark_for_strip () override { from = nullptr; }
3513 28 : bool is_marked_for_strip () const override { return from == nullptr; }
3514 :
3515 : // TODO: is this better? Or is a "vis_block" better?
3516 133 : Expr &get_from_expr ()
3517 : {
3518 133 : rust_assert (from != nullptr);
3519 133 : return *from;
3520 : }
3521 :
3522 21 : std::unique_ptr<Expr> &get_from_expr_ptr ()
3523 : {
3524 21 : rust_assert (from != nullptr);
3525 21 : return from;
3526 : }
3527 :
3528 : protected:
3529 : /* Use covariance to implement clone function as returning this object rather
3530 : * than base */
3531 7 : RangeFromExpr *clone_expr_without_block_impl () const override
3532 : {
3533 7 : return new RangeFromExpr (*this);
3534 : }
3535 : };
3536 :
3537 : // Range to (exclusive) expression AST node object
3538 : // constructs a std::ops::RangeTo object
3539 : class RangeToExpr : public RangeExpr
3540 : {
3541 : std::unique_ptr<Expr> to;
3542 :
3543 : public:
3544 : std::string as_string () const override;
3545 :
3546 : // outer attributes not allowed
3547 8 : RangeToExpr (std::unique_ptr<Expr> range_to, location_t locus)
3548 8 : : RangeExpr (locus), to (std::move (range_to))
3549 : {}
3550 :
3551 : // Copy constructor with clone
3552 7 : RangeToExpr (RangeToExpr const &other) : RangeExpr (other)
3553 : {
3554 : // guard to prevent null dereference (only required if error state)
3555 7 : if (other.to != nullptr)
3556 7 : to = other.to->clone_expr ();
3557 7 : }
3558 :
3559 : // Overload assignment operator to clone unique_ptr
3560 : RangeToExpr &operator= (RangeToExpr const &other)
3561 : {
3562 : RangeExpr::operator= (other);
3563 :
3564 : // guard to prevent null dereference (only required if error state)
3565 : if (other.to != nullptr)
3566 : to = other.to->clone_expr ();
3567 : else
3568 : to = nullptr;
3569 :
3570 : return *this;
3571 : }
3572 :
3573 : // move constructors
3574 : RangeToExpr (RangeToExpr &&other) = default;
3575 : RangeToExpr &operator= (RangeToExpr &&other) = default;
3576 :
3577 : void accept_vis (ASTVisitor &vis) override;
3578 :
3579 : // Invalid if expr is null, so base stripping on that.
3580 0 : void mark_for_strip () override { to = nullptr; }
3581 28 : bool is_marked_for_strip () const override { return to == nullptr; }
3582 :
3583 : // TODO: is this better? Or is a "vis_block" better?
3584 133 : Expr &get_to_expr ()
3585 : {
3586 133 : rust_assert (to != nullptr);
3587 133 : return *to;
3588 : }
3589 :
3590 21 : std::unique_ptr<Expr> &get_to_expr_ptr ()
3591 : {
3592 21 : rust_assert (to != nullptr);
3593 21 : return to;
3594 : }
3595 :
3596 : protected:
3597 : /* Use covariance to implement clone function as returning this object rather
3598 : * than base */
3599 7 : RangeToExpr *clone_expr_without_block_impl () const override
3600 : {
3601 7 : return new RangeToExpr (*this);
3602 : }
3603 : };
3604 :
3605 : // Full range expression AST node object
3606 : // constructs a std::ops::RangeFull object
3607 : class RangeFullExpr : public RangeExpr
3608 : {
3609 : // TODO: find another way to store this to save memory?
3610 : bool marked_for_strip = false;
3611 :
3612 : public:
3613 : std::string as_string () const override;
3614 :
3615 1 : RangeFullExpr (location_t locus) : RangeExpr (locus) {}
3616 : // outer attributes not allowed
3617 :
3618 : void accept_vis (ASTVisitor &vis) override;
3619 :
3620 : // Can't think of any invalid invariants, so store boolean.
3621 0 : void mark_for_strip () override { marked_for_strip = true; }
3622 0 : bool is_marked_for_strip () const override { return marked_for_strip; }
3623 :
3624 : protected:
3625 : /* Use covariance to implement clone function as returning this object rather
3626 : * than base */
3627 0 : RangeFullExpr *clone_expr_without_block_impl () const override
3628 : {
3629 0 : return new RangeFullExpr (*this);
3630 : }
3631 : };
3632 :
3633 : // Range from (inclusive) and to (inclusive) expression AST node object
3634 : // aka RangeInclusiveExpr; constructs a std::ops::RangeInclusive object
3635 : class RangeFromToInclExpr : public RangeExpr
3636 : {
3637 : std::unique_ptr<Expr> from;
3638 : std::unique_ptr<Expr> to;
3639 :
3640 : public:
3641 : std::string as_string () const override;
3642 :
3643 7 : RangeFromToInclExpr (std::unique_ptr<Expr> range_from,
3644 : std::unique_ptr<Expr> range_to, location_t locus)
3645 14 : : RangeExpr (locus), from (std::move (range_from)),
3646 7 : to (std::move (range_to))
3647 : {}
3648 : // outer attributes not allowed
3649 :
3650 : // Copy constructor with clone
3651 7 : RangeFromToInclExpr (RangeFromToInclExpr const &other) : RangeExpr (other)
3652 : {
3653 : // guard to prevent null dereference (only required if error state)
3654 7 : if (other.from != nullptr)
3655 7 : from = other.from->clone_expr ();
3656 7 : if (other.to != nullptr)
3657 7 : to = other.to->clone_expr ();
3658 7 : }
3659 :
3660 : // Overload assignment operator to use clone
3661 : RangeFromToInclExpr &operator= (RangeFromToInclExpr const &other)
3662 : {
3663 : RangeExpr::operator= (other);
3664 :
3665 : // guard to prevent null dereference (only required if error state)
3666 : if (other.from != nullptr)
3667 : from = other.from->clone_expr ();
3668 : else
3669 : from = nullptr;
3670 : if (other.to != nullptr)
3671 : to = other.to->clone_expr ();
3672 : else
3673 : to = nullptr;
3674 :
3675 : return *this;
3676 : }
3677 :
3678 : // move constructors
3679 : RangeFromToInclExpr (RangeFromToInclExpr &&other) = default;
3680 : RangeFromToInclExpr &operator= (RangeFromToInclExpr &&other) = default;
3681 :
3682 : void accept_vis (ASTVisitor &vis) override;
3683 :
3684 : // Invalid if either expr is null, so base stripping on that.
3685 0 : void mark_for_strip () override
3686 : {
3687 0 : from = nullptr;
3688 0 : to = nullptr;
3689 0 : }
3690 28 : bool is_marked_for_strip () const override
3691 : {
3692 28 : return from == nullptr && to == nullptr;
3693 : }
3694 :
3695 : // TODO: is this better? Or is a "vis_block" better?
3696 133 : Expr &get_from_expr ()
3697 : {
3698 133 : rust_assert (from != nullptr);
3699 133 : return *from;
3700 : }
3701 :
3702 : // TODO: is this better? Or is a "vis_block" better?
3703 133 : Expr &get_to_expr ()
3704 : {
3705 133 : rust_assert (to != nullptr);
3706 133 : return *to;
3707 : }
3708 :
3709 21 : std::unique_ptr<Expr> &get_from_expr_ptr ()
3710 : {
3711 21 : rust_assert (from != nullptr);
3712 21 : return from;
3713 : }
3714 :
3715 21 : std::unique_ptr<Expr> &get_to_expr_ptr ()
3716 : {
3717 21 : rust_assert (to != nullptr);
3718 21 : return to;
3719 : }
3720 :
3721 : protected:
3722 : /* Use covariance to implement clone function as returning this object rather
3723 : * than base */
3724 7 : RangeFromToInclExpr *clone_expr_without_block_impl () const override
3725 : {
3726 7 : return new RangeFromToInclExpr (*this);
3727 : }
3728 : };
3729 :
3730 : // Range to (inclusive) expression AST node object
3731 : // aka RangeToInclusiveExpr; constructs a std::ops::RangeToInclusive object
3732 : class RangeToInclExpr : public RangeExpr
3733 : {
3734 : std::unique_ptr<Expr> to;
3735 :
3736 : public:
3737 : std::string as_string () const override;
3738 :
3739 0 : RangeToInclExpr (std::unique_ptr<Expr> range_to, location_t locus)
3740 0 : : RangeExpr (locus), to (std::move (range_to))
3741 : {}
3742 : // outer attributes not allowed
3743 :
3744 : // Copy constructor with clone
3745 0 : RangeToInclExpr (RangeToInclExpr const &other) : RangeExpr (other)
3746 : {
3747 : // guard to prevent null dereference (only required if error state)
3748 0 : if (other.to != nullptr)
3749 0 : to = other.to->clone_expr ();
3750 0 : }
3751 :
3752 : // Overload assignment operator to clone pointer
3753 : RangeToInclExpr &operator= (RangeToInclExpr const &other)
3754 : {
3755 : RangeExpr::operator= (other);
3756 :
3757 : // guard to prevent null dereference (only required if error state)
3758 : if (other.to != nullptr)
3759 : to = other.to->clone_expr ();
3760 : else
3761 : to = nullptr;
3762 :
3763 : return *this;
3764 : }
3765 :
3766 : // move constructors
3767 : RangeToInclExpr (RangeToInclExpr &&other) = default;
3768 : RangeToInclExpr &operator= (RangeToInclExpr &&other) = default;
3769 :
3770 : void accept_vis (ASTVisitor &vis) override;
3771 :
3772 : // Invalid if expr is null, so base stripping on that.
3773 0 : void mark_for_strip () override { to = nullptr; }
3774 0 : bool is_marked_for_strip () const override { return to == nullptr; }
3775 :
3776 : // TODO: is this better? Or is a "vis_block" better?
3777 0 : Expr &get_to_expr ()
3778 : {
3779 0 : rust_assert (to != nullptr);
3780 0 : return *to;
3781 : }
3782 :
3783 0 : std::unique_ptr<Expr> &get_to_expr_ptr ()
3784 : {
3785 0 : rust_assert (to != nullptr);
3786 0 : return to;
3787 : }
3788 :
3789 : protected:
3790 : /* Use covariance to implement clone function as returning this object rather
3791 : * than base */
3792 0 : RangeToInclExpr *clone_expr_without_block_impl () const override
3793 : {
3794 0 : return new RangeToInclExpr (*this);
3795 : }
3796 : };
3797 :
3798 : class BoxExpr : public ExprWithoutBlock
3799 : {
3800 : std::unique_ptr<Expr> expr;
3801 : std::vector<Attribute> outer_attrs;
3802 : location_t locus;
3803 :
3804 : public:
3805 2 : BoxExpr (std::unique_ptr<Expr> expr, std::vector<Attribute> outer_attrs,
3806 : location_t locus)
3807 2 : : expr (std::move (expr)), outer_attrs (outer_attrs), locus (locus)
3808 2 : {}
3809 :
3810 : // Copy constructor with clone
3811 1 : BoxExpr (BoxExpr const &other)
3812 1 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
3813 1 : locus (other.locus)
3814 : {
3815 : // guard to protect from null pointer dereference
3816 1 : if (other.expr != nullptr)
3817 1 : expr = other.expr->clone_expr ();
3818 1 : }
3819 :
3820 : BoxExpr &operator= (BoxExpr const &other)
3821 : {
3822 : ExprWithoutBlock::operator= (other);
3823 : locus = other.locus;
3824 : outer_attrs = other.outer_attrs;
3825 :
3826 : // guard to protect from null pointer dereference
3827 : if (other.expr != nullptr)
3828 : expr = other.expr->clone_expr ();
3829 : else
3830 : expr = nullptr;
3831 :
3832 : return *this;
3833 : }
3834 :
3835 : // move constructors
3836 : BoxExpr (BoxExpr &&other) = default;
3837 : BoxExpr &operator= (BoxExpr &&other) = default;
3838 :
3839 1 : location_t get_locus () const override final { return locus; }
3840 :
3841 : void accept_vis (ASTVisitor &vis) override;
3842 :
3843 0 : void mark_for_strip () override { expr = nullptr; }
3844 4 : bool is_marked_for_strip () const override { return expr == nullptr; }
3845 :
3846 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3847 17 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3848 :
3849 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3850 : {
3851 0 : outer_attrs = std::move (new_attrs);
3852 0 : }
3853 :
3854 : std::string as_string () const override;
3855 :
3856 14 : Expr &get_boxed_expr ()
3857 : {
3858 14 : rust_assert (expr != nullptr);
3859 14 : return *expr;
3860 : }
3861 :
3862 3 : std::unique_ptr<Expr> &get_boxed_expr_ptr ()
3863 : {
3864 3 : rust_assert (expr != nullptr);
3865 3 : return expr;
3866 : }
3867 :
3868 1 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Box; }
3869 :
3870 : protected:
3871 : /* Use covariance to implement clone function as returning this object rather
3872 : * than base */
3873 1 : BoxExpr *clone_expr_without_block_impl () const override
3874 : {
3875 1 : return new BoxExpr (*this);
3876 : }
3877 : };
3878 :
3879 : // Return expression AST node representation
3880 : class ReturnExpr : public ExprWithoutBlock
3881 : {
3882 : std::vector<Attribute> outer_attrs;
3883 : tl::optional<std::unique_ptr<Expr>> return_expr;
3884 : location_t locus;
3885 :
3886 : // TODO: find another way to store this to save memory?
3887 : bool marked_for_strip = false;
3888 :
3889 : public:
3890 : std::string as_string () const override;
3891 :
3892 : /* Returns whether the object has an expression returned (i.e. not void return
3893 : * type). */
3894 13792 : bool has_returned_expr () const { return return_expr.has_value (); }
3895 :
3896 : // Constructor for ReturnExpr.
3897 547 : ReturnExpr (tl::optional<std::unique_ptr<Expr>> returned_expr,
3898 : std::vector<Attribute> outer_attribs, location_t locus)
3899 1094 : : outer_attrs (std::move (outer_attribs)),
3900 547 : return_expr (std::move (returned_expr)), locus (locus)
3901 547 : {}
3902 :
3903 : // Copy constructor with clone
3904 606 : ReturnExpr (ReturnExpr const &other)
3905 606 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
3906 606 : locus (other.locus), marked_for_strip (other.marked_for_strip)
3907 : {
3908 : // guard to protect from null pointer dereference
3909 606 : if (other.return_expr)
3910 566 : return_expr = other.return_expr.value ()->clone_expr ();
3911 606 : }
3912 :
3913 : // Overloaded assignment operator to clone return_expr pointer
3914 : ReturnExpr &operator= (ReturnExpr const &other)
3915 : {
3916 : ExprWithoutBlock::operator= (other);
3917 : locus = other.locus;
3918 : marked_for_strip = other.marked_for_strip;
3919 : outer_attrs = other.outer_attrs;
3920 :
3921 : // guard to protect from null pointer dereference
3922 : if (other.return_expr)
3923 : return_expr = other.return_expr.value ()->clone_expr ();
3924 : else
3925 : return_expr = tl::nullopt;
3926 :
3927 : return *this;
3928 : }
3929 :
3930 : // move constructors
3931 : ReturnExpr (ReturnExpr &&other) = default;
3932 : ReturnExpr &operator= (ReturnExpr &&other) = default;
3933 :
3934 1072 : location_t get_locus () const override final { return locus; }
3935 :
3936 : void accept_vis (ASTVisitor &vis) override;
3937 :
3938 : // Can't think of any invalid invariants, so store boolean.
3939 0 : void mark_for_strip () override { marked_for_strip = true; }
3940 3108 : bool is_marked_for_strip () const override { return marked_for_strip; }
3941 :
3942 : // TODO: is this better? Or is a "vis_block" better?
3943 11082 : Expr &get_returned_expr ()
3944 : {
3945 11082 : rust_assert (return_expr);
3946 11082 : return *return_expr.value ();
3947 : }
3948 :
3949 0 : const Expr &get_returned_expr () const
3950 : {
3951 0 : rust_assert (return_expr);
3952 0 : return *return_expr.value ();
3953 : }
3954 :
3955 1523 : std::unique_ptr<Expr> &get_returned_expr_ptr ()
3956 : {
3957 1523 : rust_assert (return_expr);
3958 1523 : return return_expr.value ();
3959 : }
3960 :
3961 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3962 16400 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3963 :
3964 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3965 : {
3966 0 : outer_attrs = std::move (new_attrs);
3967 0 : }
3968 :
3969 542 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Return; }
3970 :
3971 : protected:
3972 : /* Use covariance to implement clone function as returning this object rather
3973 : * than base */
3974 606 : ReturnExpr *clone_expr_without_block_impl () const override
3975 : {
3976 606 : return new ReturnExpr (*this);
3977 : }
3978 : };
3979 :
3980 : // Try expression AST node representation
3981 : class TryExpr : public ExprWithBlock
3982 : {
3983 : std::vector<Attribute> outer_attrs;
3984 : std::unique_ptr<BlockExpr> block_expr;
3985 : location_t locus;
3986 :
3987 : // TODO: find another way to store this to save memory?
3988 : bool marked_for_strip = false;
3989 :
3990 : public:
3991 : std::string as_string () const override;
3992 :
3993 : // Constructor for ReturnExpr.
3994 1 : TryExpr (std::unique_ptr<BlockExpr> block_expr,
3995 : std::vector<Attribute> outer_attribs, location_t locus)
3996 2 : : outer_attrs (std::move (outer_attribs)),
3997 1 : block_expr (std::move (block_expr)), locus (locus)
3998 : {
3999 1 : rust_assert (this->block_expr);
4000 1 : }
4001 :
4002 : // Copy constructor with clone
4003 2 : TryExpr (TryExpr const &other)
4004 2 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4005 2 : block_expr (other.block_expr->clone_block_expr ()), locus (other.locus),
4006 2 : marked_for_strip (other.marked_for_strip)
4007 2 : {}
4008 :
4009 : // Overloaded assignment operator to clone return_expr pointer
4010 : TryExpr &operator= (TryExpr const &other)
4011 : {
4012 : ExprWithBlock::operator= (other);
4013 : locus = other.locus;
4014 : marked_for_strip = other.marked_for_strip;
4015 : outer_attrs = other.outer_attrs;
4016 :
4017 : block_expr = other.block_expr->clone_block_expr ();
4018 :
4019 : return *this;
4020 : }
4021 :
4022 : // move constructors
4023 : TryExpr (TryExpr &&other) = default;
4024 : TryExpr &operator= (TryExpr &&other) = default;
4025 :
4026 1 : location_t get_locus () const override final { return locus; }
4027 :
4028 : void accept_vis (ASTVisitor &vis) override;
4029 :
4030 : // Can't think of any invalid invariants, so store boolean.
4031 0 : void mark_for_strip () override { marked_for_strip = true; }
4032 4 : bool is_marked_for_strip () const override { return marked_for_strip; }
4033 :
4034 : // TODO: is this better? Or is a "vis_block" better?
4035 10 : BlockExpr &get_block_expr () { return *block_expr; }
4036 2 : std::unique_ptr<BlockExpr> &get_block_expr_ptr () { return block_expr; }
4037 :
4038 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4039 11 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4040 :
4041 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4042 : {
4043 0 : outer_attrs = std::move (new_attrs);
4044 0 : }
4045 :
4046 2 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Try; }
4047 :
4048 : protected:
4049 : /* Use covariance to implement clone function as returning this object rather
4050 : * than base */
4051 1 : TryExpr *clone_expr_with_block_impl () const override
4052 : {
4053 1 : return new TryExpr (*this);
4054 : }
4055 : };
4056 :
4057 : // Forward decl - defined in rust-macro.h
4058 : class MacroInvocation;
4059 :
4060 : // An unsafe block AST node
4061 : class UnsafeBlockExpr : public ExprWithBlock
4062 : {
4063 : std::vector<Attribute> outer_attrs;
4064 : // Or just have it extend BlockExpr
4065 : std::unique_ptr<BlockExpr> expr;
4066 : location_t locus;
4067 :
4068 : public:
4069 : std::string as_string () const override;
4070 :
4071 3548 : UnsafeBlockExpr (std::unique_ptr<BlockExpr> block_expr,
4072 : std::vector<Attribute> outer_attribs, location_t locus)
4073 7096 : : outer_attrs (std::move (outer_attribs)), expr (std::move (block_expr)),
4074 3548 : locus (locus)
4075 3548 : {}
4076 :
4077 : // Copy constructor with clone
4078 6255 : UnsafeBlockExpr (UnsafeBlockExpr const &other)
4079 6255 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4080 6255 : locus (other.locus)
4081 : {
4082 : // guard to prevent null dereference (only required if error state)
4083 6255 : if (other.expr != nullptr)
4084 6255 : expr = other.expr->clone_block_expr ();
4085 6255 : }
4086 :
4087 : // Overloaded assignment operator to clone
4088 : UnsafeBlockExpr &operator= (UnsafeBlockExpr const &other)
4089 : {
4090 : ExprWithBlock::operator= (other);
4091 : locus = other.locus;
4092 : outer_attrs = other.outer_attrs;
4093 :
4094 : // guard to prevent null dereference (only required if error state)
4095 : if (other.expr != nullptr)
4096 : expr = other.expr->clone_block_expr ();
4097 : else
4098 : expr = nullptr;
4099 :
4100 : return *this;
4101 : }
4102 :
4103 : // move constructors
4104 : UnsafeBlockExpr (UnsafeBlockExpr &&other) = default;
4105 : UnsafeBlockExpr &operator= (UnsafeBlockExpr &&other) = default;
4106 :
4107 7446 : location_t get_locus () const override final { return locus; }
4108 :
4109 : void accept_vis (ASTVisitor &vis) override;
4110 :
4111 : // Invalid if block is null, so base stripping on that.
4112 7 : void mark_for_strip () override { expr = nullptr; }
4113 16488 : bool is_marked_for_strip () const override { return expr == nullptr; }
4114 :
4115 : // TODO: is this better? Or is a "vis_block" better?
4116 74390 : BlockExpr &get_block_expr ()
4117 : {
4118 74390 : rust_assert (expr != nullptr);
4119 74390 : return *expr;
4120 : }
4121 :
4122 11565 : std::unique_ptr<BlockExpr> &get_block_expr_ptr ()
4123 : {
4124 11565 : rust_assert (expr != nullptr);
4125 11565 : return expr;
4126 : }
4127 :
4128 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4129 107765 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4130 :
4131 3155 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4132 : {
4133 3155 : outer_attrs = std::move (new_attrs);
4134 3155 : }
4135 :
4136 3521 : Expr::Kind get_expr_kind () const override { return Expr::Kind::UnsafeBlock; }
4137 :
4138 : protected:
4139 : /* Use covariance to implement clone function as returning this object rather
4140 : * than base */
4141 6255 : UnsafeBlockExpr *clone_expr_with_block_impl () const override
4142 : {
4143 6255 : return new UnsafeBlockExpr (*this);
4144 : }
4145 : };
4146 :
4147 : // Base loop expression AST node - aka LoopExpr
4148 : class BaseLoopExpr : public ExprWithBlock
4149 : {
4150 : protected:
4151 : // protected to allow subclasses better use of them
4152 : std::vector<Attribute> outer_attrs;
4153 : tl::optional<LoopLabel> loop_label;
4154 : std::unique_ptr<BlockExpr> loop_block;
4155 :
4156 : private:
4157 : location_t locus;
4158 :
4159 : protected:
4160 : // Constructor for BaseLoopExpr
4161 232 : BaseLoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus,
4162 : tl::optional<LoopLabel> loop_label = tl::nullopt,
4163 : std::vector<Attribute> outer_attribs
4164 : = std::vector<Attribute> ())
4165 464 : : outer_attrs (std::move (outer_attribs)),
4166 232 : loop_label (std::move (loop_label)), loop_block (std::move (loop_block)),
4167 232 : locus (locus)
4168 232 : {}
4169 :
4170 : // Copy constructor for BaseLoopExpr with clone
4171 232 : BaseLoopExpr (BaseLoopExpr const &other)
4172 232 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4173 232 : loop_label (other.loop_label), locus (other.locus)
4174 : {
4175 : // guard to prevent null dereference (only required if error state)
4176 232 : if (other.loop_block != nullptr)
4177 232 : loop_block = other.loop_block->clone_block_expr ();
4178 232 : }
4179 :
4180 : // Overloaded assignment operator to clone
4181 : BaseLoopExpr &operator= (BaseLoopExpr const &other)
4182 : {
4183 : ExprWithBlock::operator= (other);
4184 : loop_label = other.loop_label;
4185 : locus = other.locus;
4186 : outer_attrs = other.outer_attrs;
4187 :
4188 : // guard to prevent null dereference (only required if error state)
4189 : if (other.loop_block != nullptr)
4190 : loop_block = other.loop_block->clone_block_expr ();
4191 : else
4192 : loop_block = nullptr;
4193 :
4194 : return *this;
4195 : }
4196 :
4197 : // move constructors
4198 : BaseLoopExpr (BaseLoopExpr &&other) = default;
4199 : BaseLoopExpr &operator= (BaseLoopExpr &&other) = default;
4200 :
4201 : public:
4202 4216 : bool has_loop_label () const { return loop_label.has_value (); }
4203 :
4204 648 : LoopLabel &get_loop_label () { return loop_label.value (); }
4205 0 : const LoopLabel &get_loop_label () const { return loop_label.value (); }
4206 :
4207 455 : location_t get_locus () const override final { return locus; }
4208 :
4209 : // Invalid if loop block is null, so base stripping on that.
4210 0 : void mark_for_strip () override { loop_block = nullptr; }
4211 924 : bool is_marked_for_strip () const override { return loop_block == nullptr; }
4212 :
4213 : // TODO: is this better? Or is a "vis_block" better?
4214 4419 : BlockExpr &get_loop_block ()
4215 : {
4216 4419 : rust_assert (loop_block != nullptr);
4217 4419 : return *loop_block;
4218 : }
4219 :
4220 739 : std::unique_ptr<BlockExpr> &get_loop_block_ptr ()
4221 : {
4222 739 : rust_assert (loop_block != nullptr);
4223 739 : return loop_block;
4224 : }
4225 :
4226 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4227 6225 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4228 :
4229 178 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4230 : {
4231 178 : outer_attrs = std::move (new_attrs);
4232 178 : }
4233 :
4234 243 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Loop; }
4235 :
4236 : enum class Kind
4237 : {
4238 : Loop,
4239 : While,
4240 : WhileLet,
4241 : For
4242 : };
4243 :
4244 : virtual Kind get_loop_kind () const = 0;
4245 : };
4246 :
4247 : // 'Loop' expression (i.e. the infinite loop) AST node
4248 258 : class LoopExpr : public BaseLoopExpr
4249 : {
4250 : public:
4251 : std::string as_string () const override;
4252 :
4253 : // Constructor for LoopExpr
4254 132 : LoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus,
4255 36 : tl::optional<LoopLabel> loop_label = tl::nullopt,
4256 : std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
4257 132 : : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
4258 170 : std::move (outer_attribs))
4259 132 : {}
4260 :
4261 : void accept_vis (ASTVisitor &vis) override;
4262 :
4263 129 : BaseLoopExpr::Kind get_loop_kind () const override
4264 : {
4265 129 : return BaseLoopExpr::Kind::Loop;
4266 : }
4267 :
4268 : protected:
4269 : /* Use covariance to implement clone function as returning this object rather
4270 : * than base */
4271 129 : LoopExpr *clone_expr_with_block_impl () const override
4272 : {
4273 129 : return new LoopExpr (*this);
4274 : }
4275 : };
4276 :
4277 : // While loop expression AST node (predicate loop)
4278 : class WhileLoopExpr : public BaseLoopExpr
4279 : {
4280 : std::unique_ptr<Expr> condition;
4281 :
4282 : public:
4283 : std::string as_string () const override;
4284 :
4285 : // Constructor for while loop with loop label
4286 78 : WhileLoopExpr (std::unique_ptr<Expr> loop_condition,
4287 : std::unique_ptr<BlockExpr> loop_block, location_t locus,
4288 : tl::optional<LoopLabel> loop_label = tl::nullopt,
4289 : std::vector<Attribute> outer_attribs
4290 : = std::vector<Attribute> ())
4291 78 : : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
4292 : std::move (outer_attribs)),
4293 80 : condition (std::move (loop_condition))
4294 78 : {}
4295 :
4296 : // Copy constructor with clone
4297 85 : WhileLoopExpr (WhileLoopExpr const &other)
4298 85 : : BaseLoopExpr (other), condition (other.condition->clone_expr ())
4299 85 : {}
4300 :
4301 : // Overloaded assignment operator to clone
4302 : WhileLoopExpr &operator= (WhileLoopExpr const &other)
4303 : {
4304 : BaseLoopExpr::operator= (other);
4305 : condition = other.condition->clone_expr ();
4306 : // loop_block = other.loop_block->clone_block_expr();
4307 : // loop_label = other.loop_label;
4308 : // outer_attrs = other.outer_attrs;
4309 :
4310 : return *this;
4311 : }
4312 :
4313 : // move constructors
4314 : WhileLoopExpr (WhileLoopExpr &&other) = default;
4315 : WhileLoopExpr &operator= (WhileLoopExpr &&other) = default;
4316 :
4317 : void accept_vis (ASTVisitor &vis) override;
4318 :
4319 : // TODO: is this better? Or is a "vis_block" better?
4320 1932 : Expr &get_predicate_expr ()
4321 : {
4322 1932 : rust_assert (condition != nullptr);
4323 1932 : return *condition;
4324 : }
4325 :
4326 298 : std::unique_ptr<Expr> &get_predicate_expr_ptr ()
4327 : {
4328 298 : rust_assert (condition != nullptr);
4329 298 : return condition;
4330 : }
4331 :
4332 78 : BaseLoopExpr::Kind get_loop_kind () const override
4333 : {
4334 78 : return BaseLoopExpr::Kind::While;
4335 : }
4336 :
4337 : protected:
4338 : /* Use covariance to implement clone function as returning this object rather
4339 : * than base */
4340 85 : WhileLoopExpr *clone_expr_with_block_impl () const override
4341 : {
4342 85 : return new WhileLoopExpr (*this);
4343 : }
4344 : };
4345 :
4346 : // While let loop expression AST node (predicate pattern loop)
4347 : class WhileLetLoopExpr : public BaseLoopExpr
4348 : {
4349 : // MatchArmPatterns patterns;
4350 : std::unique_ptr<Pattern> match_arm_pattern; // inlined
4351 : std::unique_ptr<Expr> scrutinee;
4352 :
4353 : public:
4354 : std::string as_string () const override;
4355 :
4356 : // Constructor with a loop label
4357 3 : WhileLetLoopExpr (std::unique_ptr<Pattern> match_arm_pattern,
4358 : std::unique_ptr<Expr> scrutinee,
4359 : std::unique_ptr<BlockExpr> loop_block, location_t locus,
4360 : tl::optional<LoopLabel> loop_label = tl::nullopt,
4361 : std::vector<Attribute> outer_attribs
4362 : = std::vector<Attribute> ())
4363 3 : : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
4364 : std::move (outer_attribs)),
4365 3 : match_arm_pattern (std::move (match_arm_pattern)),
4366 3 : scrutinee (std::move (scrutinee))
4367 3 : {}
4368 :
4369 : // Copy constructor with clone
4370 2 : WhileLetLoopExpr (WhileLetLoopExpr const &other)
4371 2 : : BaseLoopExpr (other),
4372 2 : /*match_arm_patterns(other.match_arm_patterns),*/ scrutinee (
4373 2 : other.scrutinee->clone_expr ())
4374 : {
4375 2 : match_arm_pattern = other.get_pattern ()->clone_pattern ();
4376 2 : }
4377 :
4378 : // Overloaded assignment operator to clone pointers
4379 : WhileLetLoopExpr &operator= (WhileLetLoopExpr const &other)
4380 : {
4381 : BaseLoopExpr::operator= (other);
4382 : scrutinee = other.scrutinee->clone_expr ();
4383 : match_arm_pattern = other.get_pattern ()->clone_pattern ();
4384 : return *this;
4385 : }
4386 :
4387 : // move constructors
4388 : WhileLetLoopExpr (WhileLetLoopExpr &&other) = default;
4389 : WhileLetLoopExpr &operator= (WhileLetLoopExpr &&other) = default;
4390 :
4391 : void accept_vis (ASTVisitor &vis) override;
4392 :
4393 : // TODO: is this better? Or is a "vis_block" better?
4394 20 : Expr &get_scrutinee_expr ()
4395 : {
4396 20 : rust_assert (scrutinee != nullptr);
4397 20 : return *scrutinee;
4398 : }
4399 :
4400 4 : std::unique_ptr<Expr> &get_scrutinee_expr_ptr ()
4401 : {
4402 4 : rust_assert (scrutinee != nullptr);
4403 4 : return scrutinee;
4404 : }
4405 :
4406 : // TODO: this mutable getter seems really dodgy. Think up better way.
4407 2 : const std::unique_ptr<Pattern> &get_pattern () const
4408 : {
4409 2 : return match_arm_pattern;
4410 : }
4411 24 : std::unique_ptr<Pattern> &get_pattern () { return match_arm_pattern; }
4412 :
4413 4 : BaseLoopExpr::Kind get_loop_kind () const override
4414 : {
4415 4 : return BaseLoopExpr::Kind::WhileLet;
4416 : }
4417 :
4418 : protected:
4419 : /* Use covariance to implement clone function as returning this object rather
4420 : * than base */
4421 2 : WhileLetLoopExpr *clone_expr_with_block_impl () const override
4422 : {
4423 2 : return new WhileLetLoopExpr (*this);
4424 : }
4425 : };
4426 :
4427 : // For loop expression AST node (iterator loop)
4428 : class ForLoopExpr : public BaseLoopExpr
4429 : {
4430 : std::unique_ptr<Pattern> pattern;
4431 : std::unique_ptr<Expr> iterator_expr;
4432 :
4433 : public:
4434 : std::string as_string () const override;
4435 :
4436 : // Constructor with loop label
4437 19 : ForLoopExpr (std::unique_ptr<Pattern> loop_pattern,
4438 : std::unique_ptr<Expr> iterator_expr,
4439 : std::unique_ptr<BlockExpr> loop_body, location_t locus,
4440 : tl::optional<LoopLabel> loop_label = tl::nullopt,
4441 : std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
4442 19 : : BaseLoopExpr (std::move (loop_body), locus, std::move (loop_label),
4443 : std::move (outer_attribs)),
4444 19 : pattern (std::move (loop_pattern)),
4445 19 : iterator_expr (std::move (iterator_expr))
4446 19 : {}
4447 :
4448 : // Copy constructor with clone
4449 16 : ForLoopExpr (ForLoopExpr const &other)
4450 48 : : BaseLoopExpr (other), pattern (other.pattern->clone_pattern ()),
4451 16 : iterator_expr (other.iterator_expr->clone_expr ())
4452 16 : {}
4453 :
4454 : // Overloaded assignment operator to clone
4455 : ForLoopExpr &operator= (ForLoopExpr const &other)
4456 : {
4457 : BaseLoopExpr::operator= (other);
4458 : pattern = other.pattern->clone_pattern ();
4459 : iterator_expr = other.iterator_expr->clone_expr ();
4460 : /*loop_block = other.loop_block->clone_block_expr();
4461 : loop_label = other.loop_label;
4462 : outer_attrs = other.outer_attrs;*/
4463 :
4464 : return *this;
4465 : }
4466 :
4467 : // move constructors
4468 : ForLoopExpr (ForLoopExpr &&other) = default;
4469 : ForLoopExpr &operator= (ForLoopExpr &&other) = default;
4470 :
4471 : void accept_vis (ASTVisitor &vis) override;
4472 :
4473 : // TODO: is this better? Or is a "vis_block" better?
4474 400 : Expr &get_iterator_expr ()
4475 : {
4476 400 : rust_assert (iterator_expr != nullptr);
4477 400 : return *iterator_expr;
4478 : }
4479 :
4480 64 : std::unique_ptr<Expr> &get_iterator_expr_ptr ()
4481 : {
4482 64 : rust_assert (iterator_expr != nullptr);
4483 64 : return iterator_expr;
4484 : }
4485 :
4486 : // TODO: is this better? Or is a "vis_block" better?
4487 400 : Pattern &get_pattern ()
4488 : {
4489 400 : rust_assert (pattern != nullptr);
4490 400 : return *pattern;
4491 : }
4492 :
4493 64 : std::unique_ptr<Pattern> &get_pattern_ptr ()
4494 : {
4495 64 : rust_assert (pattern != nullptr);
4496 64 : return pattern;
4497 : }
4498 :
4499 32 : BaseLoopExpr::Kind get_loop_kind () const override
4500 : {
4501 32 : return BaseLoopExpr::Kind::For;
4502 : }
4503 :
4504 : protected:
4505 : /* Use covariance to implement clone function as returning this object rather
4506 : * than base */
4507 16 : ForLoopExpr *clone_expr_with_block_impl () const override
4508 : {
4509 16 : return new ForLoopExpr (*this);
4510 : }
4511 : };
4512 :
4513 : // forward decl for IfExpr
4514 : class IfLetExpr;
4515 :
4516 : // Base if expression with no "else" or "if let" AST node
4517 : class IfExpr : public ExprWithBlock
4518 : {
4519 : std::vector<Attribute> outer_attrs;
4520 : std::unique_ptr<Expr> condition;
4521 : std::unique_ptr<BlockExpr> if_block;
4522 : location_t locus;
4523 :
4524 : public:
4525 : std::string as_string () const override;
4526 :
4527 1745 : IfExpr (std::unique_ptr<Expr> condition, std::unique_ptr<BlockExpr> if_block,
4528 : std::vector<Attribute> outer_attrs, location_t locus)
4529 3490 : : outer_attrs (std::move (outer_attrs)), condition (std::move (condition)),
4530 1745 : if_block (std::move (if_block)), locus (locus)
4531 1745 : {}
4532 : // outer attributes are never allowed on IfExprs
4533 :
4534 : // Copy constructor with clone
4535 2261 : IfExpr (IfExpr const &other)
4536 2261 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4537 2261 : locus (other.locus)
4538 : {
4539 : // guard to prevent null dereference (only required if error state)
4540 2261 : if (other.condition != nullptr)
4541 2261 : condition = other.condition->clone_expr ();
4542 2261 : if (other.if_block != nullptr)
4543 2261 : if_block = other.if_block->clone_block_expr ();
4544 2261 : }
4545 :
4546 : // Overloaded assignment operator to clone expressions
4547 : IfExpr &operator= (IfExpr const &other)
4548 : {
4549 : ExprWithBlock::operator= (other);
4550 : outer_attrs = other.outer_attrs;
4551 : locus = other.locus;
4552 :
4553 : // guard to prevent null dereference (only required if error state)
4554 : if (other.condition != nullptr)
4555 : condition = other.condition->clone_expr ();
4556 : else
4557 : condition = nullptr;
4558 : if (other.if_block != nullptr)
4559 : if_block = other.if_block->clone_block_expr ();
4560 : else
4561 : if_block = nullptr;
4562 :
4563 : return *this;
4564 : }
4565 :
4566 : // move constructors
4567 : IfExpr (IfExpr &&other) = default;
4568 : IfExpr &operator= (IfExpr &&other) = default;
4569 :
4570 : // Unique pointer custom clone function
4571 : std::unique_ptr<IfExpr> clone_if_expr () const
4572 : {
4573 : return std::unique_ptr<IfExpr> (clone_if_expr_impl ());
4574 : }
4575 :
4576 : /* Note that multiple "else if"s are handled via nested ASTs rather than a
4577 : * vector of else ifs - i.e. not like a switch statement. TODO - is this a
4578 : * better approach? or does it not parse correctly and have downsides? */
4579 :
4580 3372 : location_t get_locus () const override final { return locus; }
4581 :
4582 : void accept_vis (ASTVisitor &vis) override;
4583 :
4584 : void vis_if_condition (ASTVisitor &vis) { condition->accept_vis (vis); }
4585 : void vis_if_block (ASTVisitor &vis) { if_block->accept_vis (vis); }
4586 :
4587 : // TODO: is this better? Or is a "vis_block" better?
4588 43415 : Expr &get_condition_expr ()
4589 : {
4590 43415 : rust_assert (condition != nullptr);
4591 43415 : return *condition;
4592 : }
4593 :
4594 6062 : std::unique_ptr<Expr> &get_condition_expr_ptr ()
4595 : {
4596 6062 : rust_assert (condition != nullptr);
4597 6062 : return condition;
4598 : }
4599 :
4600 : // TODO: is this better? Or is a "vis_block" better?
4601 49477 : BlockExpr &get_if_block ()
4602 : {
4603 49477 : rust_assert (if_block != nullptr);
4604 49477 : return *if_block;
4605 : }
4606 :
4607 : // Invalid if if block or condition is null, so base stripping on that.
4608 0 : void mark_for_strip () override
4609 : {
4610 0 : if_block = nullptr;
4611 0 : condition = nullptr;
4612 0 : }
4613 8301 : bool is_marked_for_strip () const override
4614 : {
4615 8301 : return if_block == nullptr && condition == nullptr;
4616 : }
4617 :
4618 1387 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4619 : {
4620 1387 : outer_attrs = std::move (new_attrs);
4621 1387 : }
4622 :
4623 : // TODO: this mutable getter seems really dodgy. Think up better way.
4624 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4625 59545 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4626 :
4627 1416 : Expr::Kind get_expr_kind () const override { return Expr::Kind::If; }
4628 :
4629 : protected:
4630 : // Base clone function but still concrete as concrete base class
4631 584 : virtual IfExpr *clone_if_expr_impl () const { return new IfExpr (*this); }
4632 :
4633 : /* Use covariance to implement clone function as returning this object rather
4634 : * than base */
4635 2261 : IfExpr *clone_expr_with_block_impl () const final override
4636 : {
4637 2261 : return clone_if_expr_impl ();
4638 : }
4639 : };
4640 :
4641 : // If expression with an ending "else" expression AST node (trailing)
4642 : class IfExprConseqElse : public IfExpr
4643 : {
4644 : std::unique_ptr<ExprWithBlock> else_block;
4645 :
4646 : public:
4647 : std::string as_string () const override;
4648 :
4649 1213 : IfExprConseqElse (std::unique_ptr<Expr> condition,
4650 : std::unique_ptr<BlockExpr> if_block,
4651 : std::unique_ptr<ExprWithBlock> else_block,
4652 : std::vector<Attribute> outer_attrs, location_t locus)
4653 1213 : : IfExpr (std::move (condition), std::move (if_block),
4654 : std::move (outer_attrs), locus),
4655 1213 : else_block (std::move (else_block))
4656 1213 : {}
4657 : // again, outer attributes not allowed
4658 :
4659 : // Copy constructor with clone
4660 1677 : IfExprConseqElse (IfExprConseqElse const &other)
4661 1677 : : IfExpr (other), else_block (other.else_block->clone_expr_with_block ())
4662 1677 : {}
4663 :
4664 : // Overloaded assignment operator with cloning
4665 : IfExprConseqElse &operator= (IfExprConseqElse const &other)
4666 : {
4667 : IfExpr::operator= (other);
4668 : // condition = other.condition->clone_expr();
4669 : // if_block = other.if_block->clone_block_expr();
4670 : else_block = other.else_block->clone_expr_with_block ();
4671 :
4672 : return *this;
4673 : }
4674 :
4675 : // move constructors
4676 : IfExprConseqElse (IfExprConseqElse &&other) = default;
4677 : IfExprConseqElse &operator= (IfExprConseqElse &&other) = default;
4678 :
4679 : void accept_vis (ASTVisitor &vis) override;
4680 :
4681 : void vis_else_block (ASTVisitor &vis) { else_block->accept_vis (vis); }
4682 :
4683 : // TODO: is this better? Or is a "vis_block" better?
4684 30900 : ExprWithBlock &get_else_block ()
4685 : {
4686 30900 : rust_assert (else_block != nullptr);
4687 30900 : return *else_block;
4688 : }
4689 :
4690 : protected:
4691 : /* Use covariance to implement clone function as returning this object rather
4692 : * than base */
4693 1677 : IfExprConseqElse *clone_if_expr_impl () const override
4694 : {
4695 1677 : return new IfExprConseqElse (*this);
4696 : }
4697 : };
4698 :
4699 : // Basic "if let" expression AST node with no else
4700 : class IfLetExpr : public ExprWithBlock
4701 : {
4702 : std::vector<Attribute> outer_attrs;
4703 : std::unique_ptr<Pattern> match_arm_pattern; // inlined
4704 : std::unique_ptr<Expr> value;
4705 : std::unique_ptr<BlockExpr> if_block;
4706 : location_t locus;
4707 :
4708 : public:
4709 : std::string as_string () const override;
4710 :
4711 31 : IfLetExpr (std::unique_ptr<Pattern> match_arm_pattern,
4712 : std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block,
4713 : std::vector<Attribute> outer_attrs, location_t locus)
4714 62 : : outer_attrs (std::move (outer_attrs)),
4715 31 : match_arm_pattern (std::move (match_arm_pattern)),
4716 31 : value (std::move (value)), if_block (std::move (if_block)), locus (locus)
4717 31 : {}
4718 :
4719 : // copy constructor with clone
4720 30 : IfLetExpr (IfLetExpr const &other)
4721 30 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4722 30 : locus (other.locus)
4723 : {
4724 : // guard to prevent null dereference (only required if error state)
4725 30 : if (other.value != nullptr)
4726 30 : value = other.value->clone_expr ();
4727 30 : if (other.if_block != nullptr)
4728 30 : if_block = other.if_block->clone_block_expr ();
4729 30 : match_arm_pattern = other.match_arm_pattern->clone_pattern ();
4730 30 : }
4731 :
4732 : // overload assignment operator to clone
4733 : IfLetExpr &operator= (IfLetExpr const &other)
4734 : {
4735 : ExprWithBlock::operator= (other);
4736 : outer_attrs = other.outer_attrs;
4737 : locus = other.locus;
4738 :
4739 : // guard to prevent null dereference (only required if error state)
4740 : if (other.value != nullptr)
4741 : value = other.value->clone_expr ();
4742 : else
4743 : value = nullptr;
4744 : if (other.if_block != nullptr)
4745 : if_block = other.if_block->clone_block_expr ();
4746 : else
4747 : if_block = nullptr;
4748 :
4749 : if (other.if_block != nullptr)
4750 : if_block = other.if_block->clone_block_expr ();
4751 :
4752 : match_arm_pattern = other.match_arm_pattern->clone_pattern ();
4753 : return *this;
4754 : }
4755 :
4756 : // move constructors
4757 : IfLetExpr (IfLetExpr &&other) = default;
4758 : IfLetExpr &operator= (IfLetExpr &&other) = default;
4759 :
4760 : // Unique pointer custom clone function
4761 : std::unique_ptr<IfLetExpr> clone_if_let_expr () const
4762 : {
4763 : return std::unique_ptr<IfLetExpr> (clone_if_let_expr_impl ());
4764 : }
4765 :
4766 137 : location_t get_locus () const override final { return locus; }
4767 :
4768 : void accept_vis (ASTVisitor &vis) override;
4769 :
4770 : // Invalid if block or value is null, so base stripping on that.
4771 0 : void mark_for_strip () override
4772 : {
4773 0 : if_block = nullptr;
4774 0 : value = nullptr;
4775 0 : }
4776 102 : bool is_marked_for_strip () const override
4777 : {
4778 102 : return if_block == nullptr && value == nullptr;
4779 : }
4780 :
4781 : // TODO: is this better? Or is a "vis_block" better?
4782 566 : Expr &get_value_expr ()
4783 : {
4784 566 : rust_assert (value != nullptr);
4785 566 : return *value;
4786 : }
4787 :
4788 90 : std::unique_ptr<Expr> &get_value_expr_ptr ()
4789 : {
4790 90 : rust_assert (value != nullptr);
4791 90 : return value;
4792 : }
4793 :
4794 : // TODO: is this better? Or is a "vis_block" better?
4795 656 : BlockExpr &get_if_block ()
4796 : {
4797 656 : rust_assert (if_block != nullptr);
4798 656 : return *if_block;
4799 : }
4800 :
4801 : // TODO: this mutable getter seems really dodgy. Think up better way.
4802 : const std::unique_ptr<Pattern> &get_pattern () const
4803 : {
4804 : return match_arm_pattern;
4805 : }
4806 596 : std::unique_ptr<Pattern> &get_pattern () { return match_arm_pattern; }
4807 :
4808 29 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4809 : {
4810 29 : outer_attrs = std::move (new_attrs);
4811 29 : }
4812 :
4813 : // TODO: this mutable getter seems really dodgy. Think up better way.
4814 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4815 714 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4816 :
4817 29 : Expr::Kind get_expr_kind () const override { return Expr::Kind::IfLet; }
4818 :
4819 : protected:
4820 : /* Use covariance to implement clone function as returning this object rather
4821 : * than base (or rather this or any derived object) */
4822 30 : IfLetExpr *clone_expr_with_block_impl () const final override
4823 : {
4824 30 : return clone_if_let_expr_impl ();
4825 : }
4826 :
4827 : // Base clone function but still concrete as concrete base class
4828 18 : virtual IfLetExpr *clone_if_let_expr_impl () const
4829 : {
4830 18 : return new IfLetExpr (*this);
4831 : }
4832 : };
4833 :
4834 : /* AST node representing "if let" expression with an "else" expression at the
4835 : * end */
4836 : class IfLetExprConseqElse : public IfLetExpr
4837 : {
4838 : std::unique_ptr<ExprWithBlock> else_block;
4839 :
4840 : public:
4841 : std::string as_string () const override;
4842 :
4843 12 : IfLetExprConseqElse (std::unique_ptr<Pattern> match_arm_pattern,
4844 : std::unique_ptr<Expr> value,
4845 : std::unique_ptr<BlockExpr> if_block,
4846 : std::unique_ptr<ExprWithBlock> else_block,
4847 : std::vector<Attribute> outer_attrs, location_t locus)
4848 12 : : IfLetExpr (std::move (match_arm_pattern), std::move (value),
4849 : std::move (if_block), std::move (outer_attrs), locus),
4850 12 : else_block (std::move (else_block))
4851 12 : {}
4852 : // outer attributes not allowed
4853 :
4854 : // copy constructor with clone
4855 12 : IfLetExprConseqElse (IfLetExprConseqElse const &other)
4856 12 : : IfLetExpr (other), else_block (other.else_block->clone_expr_with_block ())
4857 12 : {}
4858 :
4859 : // overload assignment operator to clone
4860 : IfLetExprConseqElse &operator= (IfLetExprConseqElse const &other)
4861 : {
4862 : IfLetExpr::operator= (other);
4863 : // match_arm_patterns = other.match_arm_patterns;
4864 : // value = other.value->clone_expr();
4865 : // if_block = other.if_block->clone_block_expr();
4866 : else_block = other.else_block->clone_expr_with_block ();
4867 : // outer_attrs = other.outer_attrs;
4868 :
4869 : return *this;
4870 : }
4871 :
4872 : // move constructors
4873 : IfLetExprConseqElse (IfLetExprConseqElse &&other) = default;
4874 : IfLetExprConseqElse &operator= (IfLetExprConseqElse &&other) = default;
4875 :
4876 : void accept_vis (ASTVisitor &vis) override;
4877 :
4878 : // TODO: is this better? Or is a "vis_block" better?
4879 230 : ExprWithBlock &get_else_block ()
4880 : {
4881 230 : rust_assert (else_block != nullptr);
4882 230 : return *else_block;
4883 : }
4884 :
4885 : protected:
4886 : /* Use covariance to implement clone function as returning this object rather
4887 : * than base */
4888 12 : IfLetExprConseqElse *clone_if_let_expr_impl () const override
4889 : {
4890 12 : return new IfLetExprConseqElse (*this);
4891 : }
4892 : };
4893 :
4894 : // Match arm expression
4895 : struct MatchArm
4896 : {
4897 : private:
4898 : std::vector<Attribute> outer_attrs;
4899 : // MatchArmPatterns patterns;
4900 : std::unique_ptr<Pattern> match_arm_pattern; // inlined
4901 :
4902 : // bool has_match_arm_guard;
4903 : // inlined from MatchArmGuard
4904 : std::unique_ptr<Expr> guard_expr;
4905 :
4906 : location_t locus;
4907 :
4908 : public:
4909 : // Returns whether the MatchArm has a match arm guard expression
4910 57043 : bool has_match_arm_guard () const { return guard_expr != nullptr; }
4911 :
4912 : // Constructor for match arm with a guard expression
4913 2505 : MatchArm (std::unique_ptr<Pattern> match_arm_pattern, location_t locus,
4914 : std::unique_ptr<Expr> guard_expr = nullptr,
4915 : std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
4916 2505 : : outer_attrs (std::move (outer_attrs)),
4917 367 : match_arm_pattern (std::move (match_arm_pattern)),
4918 2505 : guard_expr (std::move (guard_expr)), locus (locus)
4919 : {}
4920 :
4921 : // Copy constructor with clone
4922 2755 : MatchArm (MatchArm const &other) : outer_attrs (other.outer_attrs)
4923 : {
4924 : // guard to protect from null pointer dereference
4925 2755 : if (other.guard_expr != nullptr)
4926 1 : guard_expr = other.guard_expr->clone_expr ();
4927 :
4928 2755 : match_arm_pattern = other.match_arm_pattern->clone_pattern ();
4929 :
4930 2755 : locus = other.locus;
4931 2755 : }
4932 :
4933 11815 : ~MatchArm () = default;
4934 :
4935 : // Overload assignment operator to clone
4936 : MatchArm &operator= (MatchArm const &other)
4937 : {
4938 : outer_attrs = other.outer_attrs;
4939 :
4940 : if (other.guard_expr != nullptr)
4941 : guard_expr = other.guard_expr->clone_expr ();
4942 : else
4943 : guard_expr = nullptr;
4944 :
4945 : match_arm_pattern = other.match_arm_pattern->clone_pattern ();
4946 :
4947 : return *this;
4948 : }
4949 :
4950 : // move constructors
4951 2589 : MatchArm (MatchArm &&other) = default;
4952 0 : MatchArm &operator= (MatchArm &&other) = default;
4953 :
4954 : // Returns whether match arm is in an error state.
4955 64135 : bool is_error () const { return match_arm_pattern == nullptr; }
4956 :
4957 : // Creates a match arm in an error state.
4958 0 : static MatchArm create_error ()
4959 : {
4960 0 : location_t locus = UNDEF_LOCATION;
4961 0 : return MatchArm (nullptr, locus);
4962 : }
4963 :
4964 : std::string as_string () const;
4965 :
4966 : // TODO: is this better? Or is a "vis_block" better?
4967 16 : Expr &get_guard_expr ()
4968 : {
4969 16 : rust_assert (has_match_arm_guard ());
4970 16 : return *guard_expr;
4971 : }
4972 :
4973 3 : std::unique_ptr<Expr> &get_guard_expr_ptr ()
4974 : {
4975 3 : rust_assert (has_match_arm_guard ());
4976 3 : return guard_expr;
4977 : }
4978 :
4979 : // TODO: this mutable getter seems really dodgy. Think up better way.
4980 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4981 57043 : std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
4982 :
4983 : const std::unique_ptr<Pattern> &get_pattern () const
4984 : {
4985 : return match_arm_pattern;
4986 : }
4987 57043 : std::unique_ptr<Pattern> &get_pattern () { return match_arm_pattern; }
4988 :
4989 : location_t get_locus () const { return locus; }
4990 : };
4991 :
4992 : /* A "match case" - a correlated match arm and resulting expression. Not
4993 : * abstract. */
4994 : struct MatchCase
4995 : {
4996 : private:
4997 : MatchArm arm;
4998 : std::unique_ptr<Expr> expr;
4999 : NodeId node_id;
5000 :
5001 : /* TODO: does whether trailing comma exists need to be stored? currently
5002 : * assuming it is only syntactical and has no effect on meaning. */
5003 :
5004 : public:
5005 2503 : MatchCase (MatchArm arm, std::unique_ptr<Expr> expr)
5006 2503 : : arm (std::move (arm)), expr (std::move (expr)),
5007 2503 : node_id (Analysis::Mappings::get ().get_next_node_id ())
5008 2503 : {}
5009 :
5010 2755 : MatchCase (const MatchCase &other)
5011 2755 : : arm (other.arm), expr (other.expr->clone_expr ()), node_id (other.node_id)
5012 2755 : {}
5013 :
5014 : MatchCase &operator= (const MatchCase &other)
5015 : {
5016 : arm = other.arm;
5017 : expr = other.expr->clone_expr ();
5018 : node_id = other.node_id;
5019 :
5020 : return *this;
5021 : }
5022 :
5023 3754 : MatchCase (MatchCase &&other) = default;
5024 0 : MatchCase &operator= (MatchCase &&other) = default;
5025 :
5026 6616 : ~MatchCase () = default;
5027 :
5028 : std::string as_string () const;
5029 :
5030 : // TODO: is this better? Or is a "vis_block" better?
5031 48656 : Expr &get_expr ()
5032 : {
5033 48656 : rust_assert (expr != nullptr);
5034 48656 : return *expr;
5035 : }
5036 :
5037 8387 : std::unique_ptr<Expr> &get_expr_ptr ()
5038 : {
5039 8387 : rust_assert (expr != nullptr);
5040 8387 : return expr;
5041 : }
5042 :
5043 : // TODO: is this better? Or is a "vis_block" better?
5044 61997 : MatchArm &get_arm ()
5045 : {
5046 61997 : rust_assert (!arm.is_error ());
5047 61997 : return arm;
5048 : }
5049 :
5050 16150 : NodeId get_node_id () const { return node_id; }
5051 : };
5052 :
5053 : // Match expression AST node
5054 : class MatchExpr : public ExprWithBlock
5055 : {
5056 : std::vector<Attribute> outer_attrs;
5057 : std::unique_ptr<Expr> branch_value;
5058 : std::vector<Attribute> inner_attrs;
5059 : std::vector<MatchCase> match_arms;
5060 : location_t locus;
5061 :
5062 : public:
5063 : std::string as_string () const override;
5064 :
5065 : // Returns whether the match expression has any match arms.
5066 : bool has_match_arms () const { return !match_arms.empty (); }
5067 :
5068 1080 : MatchExpr (std::unique_ptr<Expr> branch_value,
5069 : std::vector<MatchCase> match_arms,
5070 : std::vector<Attribute> inner_attrs,
5071 : std::vector<Attribute> outer_attrs, location_t locus)
5072 2160 : : outer_attrs (std::move (outer_attrs)),
5073 1080 : branch_value (std::move (branch_value)),
5074 1080 : inner_attrs (std::move (inner_attrs)),
5075 1080 : match_arms (std::move (match_arms)), locus (locus)
5076 1080 : {}
5077 :
5078 : // Copy constructor requires clone due to unique_ptr
5079 1102 : MatchExpr (MatchExpr const &other)
5080 1102 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
5081 1102 : inner_attrs (other.inner_attrs), match_arms (other.match_arms),
5082 1102 : locus (other.locus)
5083 : {
5084 : // guard to prevent null dereference (only required if error state)
5085 1102 : if (other.branch_value != nullptr)
5086 1102 : branch_value = other.branch_value->clone_expr ();
5087 1102 : }
5088 :
5089 : // Overloaded assignment operator to clone due to unique_ptr
5090 : MatchExpr &operator= (MatchExpr const &other)
5091 : {
5092 : ExprWithBlock::operator= (other);
5093 : inner_attrs = other.inner_attrs;
5094 : match_arms = other.match_arms;
5095 : outer_attrs = other.outer_attrs;
5096 : locus = other.locus;
5097 :
5098 : // guard to prevent null dereference (only required if error state)
5099 : if (other.branch_value != nullptr)
5100 : branch_value = other.branch_value->clone_expr ();
5101 : else
5102 : branch_value = nullptr;
5103 :
5104 : return *this;
5105 : }
5106 :
5107 : // move constructors
5108 : MatchExpr (MatchExpr &&other) = default;
5109 : MatchExpr &operator= (MatchExpr &&other) = default;
5110 :
5111 4683 : location_t get_locus () const override final { return locus; }
5112 :
5113 : void accept_vis (ASTVisitor &vis) override;
5114 :
5115 : // Invalid if branch value is null, so base stripping on that.
5116 0 : void mark_for_strip () override { branch_value = nullptr; }
5117 11367 : bool is_marked_for_strip () const override { return branch_value == nullptr; }
5118 :
5119 : // TODO: this mutable getter seems really dodgy. Think up better way.
5120 : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
5121 24627 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
5122 :
5123 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
5124 30653 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
5125 :
5126 842 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
5127 : {
5128 842 : outer_attrs = std::move (new_attrs);
5129 842 : }
5130 :
5131 : // TODO: is this better? Or is a "vis_block" better?
5132 21015 : Expr &get_scrutinee_expr ()
5133 : {
5134 21015 : rust_assert (branch_value != nullptr);
5135 21015 : return *branch_value;
5136 : }
5137 :
5138 3612 : std::unique_ptr<Expr> &get_scrutinee_expr_ptr ()
5139 : {
5140 3612 : rust_assert (branch_value != nullptr);
5141 3612 : return branch_value;
5142 : }
5143 :
5144 : const std::vector<MatchCase> &get_match_cases () const { return match_arms; }
5145 24627 : std::vector<MatchCase> &get_match_cases () { return match_arms; }
5146 :
5147 1072 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Match; }
5148 :
5149 : protected:
5150 : /* Use covariance to implement clone function as returning this object rather
5151 : * than base */
5152 1102 : MatchExpr *clone_expr_with_block_impl () const override
5153 : {
5154 1102 : return new MatchExpr (*this);
5155 : }
5156 : };
5157 :
5158 : // Await expression AST node (pseudo-member variable access)
5159 : class AwaitExpr : public ExprWithoutBlock
5160 : {
5161 : std::vector<Attribute> outer_attrs;
5162 : std::unique_ptr<Expr> awaited_expr;
5163 : location_t locus;
5164 :
5165 : public:
5166 : // TODO: ensure outer attributes are actually allowed
5167 0 : AwaitExpr (std::unique_ptr<Expr> awaited_expr,
5168 : std::vector<Attribute> outer_attrs, location_t locus)
5169 0 : : outer_attrs (std::move (outer_attrs)),
5170 0 : awaited_expr (std::move (awaited_expr)), locus (locus)
5171 0 : {}
5172 :
5173 : // copy constructor with clone
5174 0 : AwaitExpr (AwaitExpr const &other)
5175 0 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
5176 0 : locus (other.locus)
5177 : {
5178 : // guard to prevent null dereference (only required if error state)
5179 0 : if (other.awaited_expr != nullptr)
5180 0 : awaited_expr = other.awaited_expr->clone_expr ();
5181 0 : }
5182 :
5183 : // overloaded assignment operator with clone
5184 : AwaitExpr &operator= (AwaitExpr const &other)
5185 : {
5186 : ExprWithoutBlock::operator= (other);
5187 : outer_attrs = other.outer_attrs;
5188 : locus = other.locus;
5189 :
5190 : // guard to prevent null dereference (only required if error state)
5191 : if (other.awaited_expr != nullptr)
5192 : awaited_expr = other.awaited_expr->clone_expr ();
5193 : else
5194 : awaited_expr = nullptr;
5195 :
5196 : return *this;
5197 : }
5198 :
5199 : // move constructors
5200 : AwaitExpr (AwaitExpr &&other) = default;
5201 : AwaitExpr &operator= (AwaitExpr &&other) = default;
5202 :
5203 : std::string as_string () const override;
5204 :
5205 0 : location_t get_locus () const override final { return locus; }
5206 :
5207 : void accept_vis (ASTVisitor &vis) override;
5208 :
5209 : // Invalid if awaited expr is null, so base stripping on that.
5210 0 : void mark_for_strip () override { awaited_expr = nullptr; }
5211 0 : bool is_marked_for_strip () const override { return awaited_expr == nullptr; }
5212 :
5213 : // TODO: is this better? Or is a "vis_block" better?
5214 0 : std::unique_ptr<Expr> &get_awaited_expr ()
5215 : {
5216 0 : rust_assert (awaited_expr != nullptr);
5217 0 : return awaited_expr;
5218 : }
5219 :
5220 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
5221 0 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
5222 :
5223 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
5224 : {
5225 0 : outer_attrs = std::move (new_attrs);
5226 0 : }
5227 :
5228 0 : Expr::Kind get_expr_kind () const override { return Expr::Kind::Await; }
5229 :
5230 : protected:
5231 : /* Use covariance to implement clone function as returning this object rather
5232 : * than base */
5233 0 : AwaitExpr *clone_expr_without_block_impl () const override
5234 : {
5235 0 : return new AwaitExpr (*this);
5236 : }
5237 : };
5238 :
5239 : // Async block expression AST node (block expr that evaluates to a future)
5240 : class AsyncBlockExpr : public ExprWithBlock
5241 : {
5242 : // TODO: should this extend BlockExpr rather than be a composite of it?
5243 : std::vector<Attribute> outer_attrs;
5244 : bool has_move;
5245 : std::unique_ptr<BlockExpr> block_expr;
5246 : location_t locus;
5247 :
5248 : public:
5249 0 : AsyncBlockExpr (std::unique_ptr<BlockExpr> block_expr, bool has_move,
5250 : std::vector<Attribute> outer_attrs, location_t locus)
5251 0 : : outer_attrs (std::move (outer_attrs)), has_move (has_move),
5252 0 : block_expr (std::move (block_expr)), locus (locus)
5253 0 : {}
5254 :
5255 : // copy constructor with clone
5256 0 : AsyncBlockExpr (AsyncBlockExpr const &other)
5257 0 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
5258 0 : has_move (other.has_move), locus (other.locus)
5259 : {
5260 : // guard to prevent null dereference (only required if error state)
5261 0 : if (other.block_expr != nullptr)
5262 0 : block_expr = other.block_expr->clone_block_expr ();
5263 0 : }
5264 :
5265 : // overloaded assignment operator to clone
5266 : AsyncBlockExpr &operator= (AsyncBlockExpr const &other)
5267 : {
5268 : ExprWithBlock::operator= (other);
5269 : outer_attrs = other.outer_attrs;
5270 : has_move = other.has_move;
5271 : locus = other.locus;
5272 :
5273 : // guard to prevent null dereference (only required if error state)
5274 : if (other.block_expr != nullptr)
5275 : block_expr = other.block_expr->clone_block_expr ();
5276 : else
5277 : block_expr = nullptr;
5278 :
5279 : return *this;
5280 : }
5281 :
5282 : // move constructors
5283 : AsyncBlockExpr (AsyncBlockExpr &&other) = default;
5284 : AsyncBlockExpr &operator= (AsyncBlockExpr &&other) = default;
5285 :
5286 : std::string as_string () const override;
5287 :
5288 0 : bool get_has_move () { return has_move; }
5289 0 : location_t get_locus () const override final { return locus; }
5290 :
5291 : void accept_vis (ASTVisitor &vis) override;
5292 :
5293 : // Invalid if block is null, so base stripping on that.
5294 0 : void mark_for_strip () override { block_expr = nullptr; }
5295 0 : bool is_marked_for_strip () const override { return block_expr == nullptr; }
5296 :
5297 : // TODO: is this better? Or is a "vis_block" better?
5298 0 : std::unique_ptr<BlockExpr> &get_block_expr ()
5299 : {
5300 0 : rust_assert (block_expr != nullptr);
5301 0 : return block_expr;
5302 : }
5303 :
5304 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
5305 0 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
5306 :
5307 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
5308 : {
5309 0 : outer_attrs = std::move (new_attrs);
5310 0 : }
5311 :
5312 0 : Expr::Kind get_expr_kind () const override { return Expr::Kind::AsyncBlock; }
5313 :
5314 : protected:
5315 : /* Use covariance to implement clone function as returning this object rather
5316 : * than base */
5317 0 : AsyncBlockExpr *clone_expr_with_block_impl () const override
5318 : {
5319 0 : return new AsyncBlockExpr (*this);
5320 : }
5321 : };
5322 :
5323 : // Inline-assembly specific options
5324 : enum class InlineAsmOption
5325 : {
5326 : PURE = 1 << 0,
5327 : NOMEM = 1 << 1,
5328 : READONLY = 1 << 2,
5329 : PRESERVES_FLAGS = 1 << 3,
5330 : NORETURN = 1 << 4,
5331 : NOSTACK = 1 << 5,
5332 : ATT_SYNTAX = 1 << 6,
5333 : RAW = 1 << 7,
5334 : MAY_UNWIND = 1 << 8,
5335 : };
5336 :
5337 : struct InlineAsmRegOrRegClass
5338 : {
5339 : enum Type
5340 : {
5341 : Reg,
5342 : RegClass,
5343 : };
5344 :
5345 : struct Reg
5346 : {
5347 : std::string Symbol;
5348 : };
5349 :
5350 : struct RegClass
5351 : {
5352 : std::string Symbol;
5353 : };
5354 :
5355 : Type type;
5356 : struct Reg reg;
5357 : struct RegClass reg_class;
5358 :
5359 : Identifier name;
5360 : location_t locus;
5361 : };
5362 :
5363 18 : struct LlvmOperand
5364 : {
5365 : std::string constraint;
5366 : std::unique_ptr<Expr> expr;
5367 :
5368 2 : LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr)
5369 4 : : constraint (constraint), expr (std::move (expr))
5370 : {}
5371 :
5372 18 : LlvmOperand (const LlvmOperand &other)
5373 36 : : constraint (other.constraint), expr (other.expr->clone_expr ())
5374 18 : {}
5375 : LlvmOperand &operator= (const LlvmOperand &other)
5376 : {
5377 : constraint = other.constraint;
5378 : expr = other.expr->clone_expr ();
5379 :
5380 : return *this;
5381 : }
5382 : };
5383 :
5384 618 : class InlineAsmOperand
5385 : {
5386 : public:
5387 : enum class RegisterType
5388 : {
5389 : In,
5390 : Out,
5391 : InOut,
5392 : SplitInOut,
5393 : Const,
5394 : Sym,
5395 : Label,
5396 : };
5397 :
5398 0 : class Register
5399 : {
5400 : public:
5401 734 : Register () {}
5402 0 : virtual ~Register () = default;
5403 :
5404 615 : std::unique_ptr<Register> clone () const
5405 : {
5406 615 : return std::unique_ptr<Register> (clone_impl ());
5407 : }
5408 :
5409 : protected:
5410 : virtual Register *clone_impl () const = 0;
5411 : };
5412 :
5413 : class In : public Register
5414 : {
5415 : public:
5416 : tl::optional<InlineAsmRegOrRegClass> reg;
5417 : std::unique_ptr<Expr> expr;
5418 :
5419 12 : In (tl::optional<struct InlineAsmRegOrRegClass> ®,
5420 : std::unique_ptr<Expr> expr)
5421 12 : : reg (reg), expr (std::move (expr))
5422 : {
5423 12 : rust_assert (this->expr != nullptr);
5424 12 : }
5425 :
5426 241 : In (const In &other)
5427 241 : {
5428 241 : reg = other.reg;
5429 :
5430 241 : expr = other.expr->clone_expr ();
5431 241 : }
5432 :
5433 : In operator= (const In &other)
5434 : {
5435 : reg = other.reg;
5436 : expr = other.expr->clone_expr ();
5437 :
5438 : return *this;
5439 : }
5440 :
5441 : private:
5442 219 : In *clone_impl () const { return new In (*this); }
5443 : };
5444 :
5445 : class Out : public Register
5446 : {
5447 : public:
5448 : tl::optional<InlineAsmRegOrRegClass> reg;
5449 : bool late;
5450 : std::unique_ptr<Expr> expr; // can be null
5451 :
5452 17 : Out (tl::optional<struct InlineAsmRegOrRegClass> ®, bool late,
5453 : std::unique_ptr<Expr> expr)
5454 17 : : reg (reg), late (late), expr (std::move (expr))
5455 : {
5456 17 : rust_assert (this->expr != nullptr);
5457 17 : }
5458 :
5459 388 : Out (const Out &other)
5460 388 : {
5461 388 : reg = other.reg;
5462 388 : late = other.late;
5463 388 : expr = other.expr->clone_expr ();
5464 388 : }
5465 :
5466 : Out operator= (const Out &other)
5467 : {
5468 : reg = other.reg;
5469 : late = other.late;
5470 : expr = other.expr->clone_expr ();
5471 : return *this;
5472 : }
5473 :
5474 : private:
5475 354 : Out *clone_impl () const { return new Out (*this); }
5476 : };
5477 :
5478 : class InOut : public Register
5479 : {
5480 : public:
5481 : tl::optional<InlineAsmRegOrRegClass> reg;
5482 : bool late;
5483 : std::unique_ptr<Expr> expr; // this can't be null
5484 :
5485 1 : InOut (tl::optional<struct InlineAsmRegOrRegClass> ®, bool late,
5486 : std::unique_ptr<Expr> expr)
5487 1 : : reg (reg), late (late), expr (std::move (expr))
5488 : {
5489 1 : rust_assert (this->expr != nullptr);
5490 1 : }
5491 :
5492 1 : InOut (const InOut &other)
5493 1 : {
5494 1 : reg = other.reg;
5495 1 : late = other.late;
5496 1 : expr = other.expr->clone_expr ();
5497 1 : }
5498 :
5499 : InOut operator= (const InOut &other)
5500 : {
5501 : reg = other.reg;
5502 : late = other.late;
5503 : expr = other.expr->clone_expr ();
5504 :
5505 : return *this;
5506 : }
5507 :
5508 : private:
5509 0 : InOut *clone_impl () const { return new InOut (*this); }
5510 : };
5511 :
5512 : class SplitInOut : public Register
5513 : {
5514 : public:
5515 : tl::optional<InlineAsmRegOrRegClass> reg;
5516 : bool late;
5517 : std::unique_ptr<Expr> in_expr;
5518 : std::unique_ptr<Expr> out_expr; // could be null
5519 :
5520 2 : SplitInOut (tl::optional<struct InlineAsmRegOrRegClass> ®, bool late,
5521 : std::unique_ptr<Expr> in_expr, std::unique_ptr<Expr> out_expr)
5522 2 : : reg (reg), late (late), in_expr (std::move (in_expr)),
5523 2 : out_expr (std::move (out_expr))
5524 : {
5525 2 : rust_assert (this->in_expr != nullptr);
5526 2 : rust_assert (this->out_expr != nullptr);
5527 2 : }
5528 :
5529 72 : SplitInOut (const SplitInOut &other)
5530 72 : {
5531 72 : reg = other.reg;
5532 72 : late = other.late;
5533 72 : in_expr = other.in_expr->clone_expr ();
5534 72 : out_expr = other.out_expr->clone_expr ();
5535 72 : }
5536 :
5537 : SplitInOut operator= (const SplitInOut &other)
5538 : {
5539 : reg = other.reg;
5540 : late = other.late;
5541 : in_expr = other.in_expr->clone_expr ();
5542 : out_expr = other.out_expr->clone_expr ();
5543 :
5544 : return *this;
5545 : }
5546 :
5547 : private:
5548 42 : SplitInOut *clone_impl () const { return new SplitInOut (*this); }
5549 : };
5550 :
5551 0 : class Const : public Register
5552 : {
5553 : public:
5554 : AnonConst anon_const;
5555 :
5556 : private:
5557 0 : Const *clone_impl () const { return new Const (*this); }
5558 : };
5559 :
5560 0 : class Sym : public Register
5561 : {
5562 : public:
5563 : std::unique_ptr<Expr> expr;
5564 :
5565 : Sym (std::unique_ptr<Expr> expr) : expr (std::move (expr))
5566 : {
5567 : rust_assert (this->expr != nullptr);
5568 : }
5569 0 : Sym (const Sym &other)
5570 0 : {
5571 0 : expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
5572 0 : }
5573 :
5574 : Sym operator= (const Sym &other)
5575 : {
5576 : expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
5577 : return *this;
5578 : }
5579 :
5580 : private:
5581 0 : Sym *clone_impl () const { return new Sym (*this); }
5582 : };
5583 :
5584 : class Label : public Register
5585 : {
5586 : public:
5587 : std::string label_name;
5588 : std::unique_ptr<Expr> expr;
5589 :
5590 : Label (tl::optional<std::string> label_name, std::unique_ptr<Expr> expr)
5591 : : expr (std::move (expr))
5592 : {
5593 : rust_assert (this->expr != nullptr);
5594 : if (label_name.has_value ())
5595 : this->label_name = label_name.value ();
5596 : }
5597 0 : Label (const Label &other)
5598 0 : {
5599 0 : expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
5600 0 : }
5601 :
5602 : Label operator= (const Label &other)
5603 : {
5604 : expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
5605 : return *this;
5606 : }
5607 :
5608 : private:
5609 0 : Label *clone_impl () const { return new Label (*this); }
5610 : };
5611 :
5612 615 : InlineAsmOperand (const InlineAsmOperand &other)
5613 615 : : register_type (other.register_type), locus (other.locus),
5614 615 : reg (other.reg->clone ())
5615 615 : {}
5616 :
5617 12 : InlineAsmOperand (const In ®, location_t locus)
5618 12 : : register_type (RegisterType::In), locus (locus), reg (new In (reg))
5619 12 : {}
5620 17 : InlineAsmOperand (const Out ®, location_t locus)
5621 17 : : register_type (RegisterType::Out), locus (locus), reg (new Out (reg))
5622 17 : {}
5623 1 : InlineAsmOperand (const InOut ®, location_t locus)
5624 1 : : register_type (RegisterType::InOut), locus (locus), reg (new InOut (reg))
5625 1 : {}
5626 2 : InlineAsmOperand (const SplitInOut ®, location_t locus)
5627 2 : : register_type (RegisterType::SplitInOut), locus (locus),
5628 2 : reg (new SplitInOut (reg))
5629 2 : {}
5630 : InlineAsmOperand (const Const ®, location_t locus)
5631 : : register_type (RegisterType::Const), locus (locus), reg (new Const (reg))
5632 : {}
5633 : InlineAsmOperand (const Sym ®, location_t locus)
5634 : : register_type (RegisterType::Sym), locus (locus), reg (new Sym (reg))
5635 : {}
5636 : InlineAsmOperand (const Label ®, location_t locus)
5637 : : register_type (RegisterType::Label), locus (locus), reg (new Label (reg))
5638 : {}
5639 :
5640 : location_t get_locus () const { return locus; }
5641 402 : RegisterType get_register_type () const { return register_type; }
5642 :
5643 : // Potentially fail immediately if you don't use get_register_type() to
5644 : // inspect the RegisterType first before calling the following functions Check
5645 : // first
5646 130 : In &get_in ()
5647 : {
5648 130 : rust_assert (register_type == RegisterType::In);
5649 130 : return static_cast<In &> (*reg);
5650 : }
5651 10 : const In &get_in () const
5652 : {
5653 10 : rust_assert (register_type == RegisterType::In);
5654 10 : return static_cast<const In &> (*reg);
5655 : }
5656 :
5657 217 : Out &get_out ()
5658 : {
5659 217 : rust_assert (register_type == RegisterType::Out);
5660 217 : return static_cast<Out &> (*reg);
5661 : }
5662 17 : const Out &get_out () const
5663 : {
5664 17 : rust_assert (register_type == RegisterType::Out);
5665 17 : return static_cast<const Out &> (*reg);
5666 : }
5667 :
5668 0 : InOut &get_in_out ()
5669 : {
5670 0 : rust_assert (register_type == RegisterType::InOut);
5671 0 : return static_cast<InOut &> (*reg);
5672 : }
5673 0 : const InOut &get_in_out () const
5674 : {
5675 0 : rust_assert (register_type == RegisterType::InOut);
5676 0 : return static_cast<const InOut &> (*reg);
5677 : }
5678 :
5679 26 : SplitInOut &get_split_in_out ()
5680 : {
5681 26 : rust_assert (register_type == RegisterType::SplitInOut);
5682 26 : return static_cast<SplitInOut &> (*reg);
5683 : }
5684 2 : const SplitInOut &get_split_in_out () const
5685 : {
5686 2 : rust_assert (register_type == RegisterType::SplitInOut);
5687 2 : return static_cast<const SplitInOut &> (*reg);
5688 : }
5689 :
5690 0 : Const &get_const ()
5691 : {
5692 0 : rust_assert (register_type == RegisterType::Const);
5693 0 : return static_cast<Const &> (*reg);
5694 : }
5695 0 : const Const &get_const () const
5696 : {
5697 0 : rust_assert (register_type == RegisterType::Const);
5698 0 : return static_cast<Const &> (*reg);
5699 : }
5700 :
5701 0 : Sym &get_sym ()
5702 : {
5703 0 : rust_assert (register_type == RegisterType::Sym);
5704 0 : return static_cast<Sym &> (*reg);
5705 : }
5706 0 : const Sym &get_sym () const
5707 : {
5708 0 : rust_assert (register_type == RegisterType::Sym);
5709 0 : return static_cast<const Sym &> (*reg);
5710 : }
5711 :
5712 0 : Label &get_label ()
5713 : {
5714 0 : rust_assert (register_type == RegisterType::Label);
5715 0 : return static_cast<Label &> (*reg);
5716 : }
5717 0 : const Label &get_label () const
5718 : {
5719 0 : rust_assert (register_type == RegisterType::Label);
5720 0 : return static_cast<const Label &> (*reg);
5721 : }
5722 :
5723 : private:
5724 : RegisterType register_type;
5725 :
5726 : location_t locus;
5727 : std::unique_ptr<Register> reg;
5728 : };
5729 :
5730 : struct InlineAsmPlaceHolder
5731 : {
5732 : size_t operand_idx;
5733 : char modifier; // can be null
5734 : location_t locus;
5735 : };
5736 :
5737 0 : struct InlineAsmTemplatePiece
5738 : {
5739 : bool is_placeholder;
5740 : std::string string;
5741 : InlineAsmPlaceHolder placeholder;
5742 : };
5743 :
5744 20 : struct TupleClobber
5745 : {
5746 4 : TupleClobber (std::string symbol, location_t loc) : symbol (symbol), loc (loc)
5747 : {}
5748 : // as gccrs still doesn't contain a symbol class I have put them as strings
5749 : std::string symbol;
5750 : location_t loc;
5751 : };
5752 :
5753 322 : struct TupleTemplateStr
5754 : {
5755 : // as gccrs still doesn't contain a symbol class I have put them as strings
5756 : location_t loc;
5757 : std::string symbol;
5758 :
5759 2 : location_t get_locus () { return loc; }
5760 40 : TupleTemplateStr (location_t loc, const std::string &symbol)
5761 80 : : loc (loc), symbol (symbol)
5762 : {}
5763 : };
5764 :
5765 : // Inline Assembly Node
5766 : class InlineAsm : public ExprWithoutBlock
5767 : {
5768 : public:
5769 : enum class Option
5770 : {
5771 : PURE = 1 << 0,
5772 : NOMEM = 1 << 1,
5773 : READONLY = 1 << 2,
5774 : PRESERVES_FLAGS = 1 << 3,
5775 : NORETURN = 1 << 4,
5776 : NOSTACK = 1 << 5,
5777 : ATT_SYNTAX = 1 << 6,
5778 : RAW = 1 << 7,
5779 : MAY_UNWIND = 1 << 8,
5780 : };
5781 :
5782 : private:
5783 : location_t locus;
5784 : // TODO: Not sure how outer_attrs plays with InlineAsm, I put it here in order
5785 : // to override, very hacky.
5786 : std::vector<Attribute> outer_attrs;
5787 :
5788 : public:
5789 : // https://github.com/rust-lang/rust/blob/55cac26a9ef17da1c9c77c0816e88e178b7cc5dd/compiler/rustc_builtin_macros/src/asm.rs#L56C1-L64C7
5790 : // let mut args = AsmArgs {
5791 : // templates: vec![first_template],
5792 : // operands: vec![],
5793 : // named_args: Default::default(),
5794 : // reg_args: Default::default(),
5795 : // clobber_abis: Vec::new(),
5796 : // options: ast::InlineAsmOptions::empty(),
5797 : // options_spans: vec![],
5798 : // };
5799 : std::vector<InlineAsmTemplatePiece> template_;
5800 : std::vector<TupleTemplateStr> template_strs;
5801 : std::vector<InlineAsmOperand> operands;
5802 : std::map<std::string, int> named_args;
5803 : std::set<int> reg_args;
5804 : std::vector<TupleClobber> clobber_abi;
5805 : std::set<InlineAsm::Option> options;
5806 :
5807 : std::vector<location_t> line_spans;
5808 :
5809 : bool is_global_asm;
5810 :
5811 39 : InlineAsm (location_t locus, bool is_global_asm)
5812 39 : : locus (locus), is_global_asm (is_global_asm)
5813 39 : {}
5814 :
5815 : void accept_vis (ASTVisitor &vis) override;
5816 0 : std::string as_string () const override { return "InlineAsm AST Node"; }
5817 :
5818 54 : location_t get_locus () const override { return locus; }
5819 :
5820 0 : void mark_for_strip () override {}
5821 :
5822 92 : bool is_marked_for_strip () const override { return false; }
5823 :
5824 343 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
5825 :
5826 0 : void set_outer_attrs (std::vector<Attribute> v) override { outer_attrs = v; }
5827 :
5828 27 : std::vector<InlineAsmTemplatePiece> get_template_ () { return template_; }
5829 :
5830 56 : std::vector<TupleTemplateStr> get_template_strs () { return template_strs; }
5831 :
5832 370 : std::vector<InlineAsmOperand> get_operands () { return operands; }
5833 :
5834 27 : std::vector<TupleClobber> get_clobber_abi () { return clobber_abi; }
5835 :
5836 27 : std::set<InlineAsm::Option> get_options () { return options; }
5837 :
5838 203 : InlineAsm *clone_expr_without_block_impl () const override
5839 : {
5840 203 : return new InlineAsm (*this);
5841 : }
5842 :
5843 27 : Expr::Kind get_expr_kind () const override { return Expr::Kind::InlineAsm; }
5844 :
5845 2 : static std::string option_to_string (Option option)
5846 : {
5847 2 : switch (option)
5848 : {
5849 0 : case Option::PURE:
5850 0 : return "pure";
5851 1 : case Option::NOMEM:
5852 1 : return "nomem";
5853 0 : case Option::READONLY:
5854 0 : return "readonly";
5855 0 : case Option::PRESERVES_FLAGS:
5856 0 : return "preserves_flags";
5857 1 : case Option::NORETURN:
5858 1 : return "noreturn";
5859 0 : case Option::NOSTACK:
5860 0 : return "nostack";
5861 0 : case Option::ATT_SYNTAX:
5862 0 : return "att_syntax";
5863 0 : case Option::RAW:
5864 0 : return "raw";
5865 0 : case Option::MAY_UNWIND:
5866 0 : return "may_unwind";
5867 0 : default:
5868 0 : rust_unreachable ();
5869 : }
5870 : }
5871 : };
5872 :
5873 : class LlvmInlineAsm : public ExprWithoutBlock
5874 : {
5875 : // llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
5876 : // Asm, Outputs, Inputs, Clobbers, Options,
5877 :
5878 : public:
5879 : enum class Dialect
5880 : {
5881 : Att,
5882 : Intel,
5883 : };
5884 :
5885 : private:
5886 : location_t locus;
5887 : std::vector<Attribute> outer_attrs;
5888 : std::vector<LlvmOperand> inputs;
5889 : std::vector<LlvmOperand> outputs;
5890 : std::vector<TupleTemplateStr> templates;
5891 : std::vector<TupleClobber> clobbers;
5892 : bool volatility;
5893 : bool align_stack;
5894 : Dialect dialect;
5895 :
5896 : public:
5897 2 : LlvmInlineAsm (location_t locus) : locus (locus) {}
5898 :
5899 2 : Dialect get_dialect () { return dialect; }
5900 :
5901 28 : location_t get_locus () const override { return locus; }
5902 :
5903 0 : void mark_for_strip () override {}
5904 :
5905 8 : bool is_marked_for_strip () const override { return false; }
5906 :
5907 2 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
5908 :
5909 : void accept_vis (ASTVisitor &vis) override;
5910 :
5911 0 : std::string as_string () const override { return "InlineAsm AST Node"; }
5912 :
5913 0 : void set_outer_attrs (std::vector<Attribute> v) override { outer_attrs = v; }
5914 :
5915 14 : LlvmInlineAsm *clone_expr_without_block_impl () const override
5916 : {
5917 14 : return new LlvmInlineAsm (*this);
5918 : }
5919 :
5920 6 : std::vector<TupleTemplateStr> &get_templates () { return templates; }
5921 : const std::vector<TupleTemplateStr> &get_templates () const
5922 : {
5923 : return templates;
5924 : }
5925 :
5926 2 : Expr::Kind get_expr_kind () const override
5927 : {
5928 2 : return Expr::Kind::LlvmInlineAsm;
5929 : }
5930 :
5931 0 : void set_align_stack (bool align_stack) { this->align_stack = align_stack; }
5932 2 : bool is_stack_aligned () { return align_stack; }
5933 :
5934 2 : void set_volatile (bool volatility) { this->volatility = volatility; }
5935 2 : bool is_volatile () { return volatility; }
5936 :
5937 0 : void set_dialect (Dialect dialect) { this->dialect = dialect; }
5938 :
5939 : void set_inputs (std::vector<LlvmOperand> operands) { inputs = operands; }
5940 : void set_outputs (std::vector<LlvmOperand> operands) { outputs = operands; }
5941 :
5942 32 : std::vector<LlvmOperand> &get_inputs () { return inputs; }
5943 : const std::vector<LlvmOperand> &get_inputs () const { return inputs; }
5944 32 : std::vector<LlvmOperand> &get_outputs () { return outputs; }
5945 : const std::vector<LlvmOperand> &get_outputs () const { return outputs; }
5946 :
5947 6 : std::vector<TupleClobber> &get_clobbers () { return clobbers; }
5948 : const std::vector<TupleClobber> &get_clobbers () const { return clobbers; }
5949 : };
5950 :
5951 : } // namespace AST
5952 : } // namespace Rust
5953 :
5954 : #endif
|