[PR testsuite/116860] Testsuite adjustment for recently added tests
[official-gcc.git] / gcc / rust / ast / rust-expr.h
blobd3dc197ea558d99e9ddee8a5aa70fccb584319c9
1 #ifndef RUST_AST_EXPR_H
2 #define RUST_AST_EXPR_H
4 #include "rust-ast.h"
5 #include "rust-path.h"
6 #include "rust-macro.h"
7 #include "rust-operators.h"
9 namespace Rust {
10 namespace AST {
11 /* TODO: if GCC moves to C++17 or allows boost, replace some boolean
12 * "has_whatever" pairs with
13 * optional types (std::optional or boost::optional)? */
15 // Loop label expression AST node used with break and continue expressions
16 // TODO: inline?
17 class LoopLabel /*: public Node*/
19 Lifetime label; // or type LIFETIME_OR_LABEL
20 location_t locus;
22 NodeId node_id;
24 public:
25 std::string as_string () const;
27 LoopLabel (Lifetime loop_label, location_t locus = UNDEF_LOCATION)
28 : label (std::move (loop_label)), locus (locus),
29 node_id (Analysis::Mappings::get ()->get_next_node_id ())
32 // Returns whether the LoopLabel is in an error state.
33 bool is_error () const { return label.is_error (); }
35 // Creates an error state LoopLabel.
36 static LoopLabel error () { return LoopLabel (Lifetime::error ()); }
38 location_t get_locus () const { return locus; }
40 Lifetime &get_lifetime () { return label; }
42 NodeId get_node_id () const { return node_id; }
45 // AST node for an expression with an accompanying block - abstract
46 class ExprWithBlock : public Expr
48 protected:
49 // pure virtual clone implementation
50 virtual ExprWithBlock *clone_expr_with_block_impl () const = 0;
52 // prevent having to define multiple clone expressions
53 ExprWithBlock *clone_expr_impl () const final override
55 return clone_expr_with_block_impl ();
58 bool is_expr_without_block () const final override { return false; };
60 public:
61 // Unique pointer custom clone function
62 std::unique_ptr<ExprWithBlock> clone_expr_with_block () const
64 return std::unique_ptr<ExprWithBlock> (clone_expr_with_block_impl ());
68 // Literals? Or literal base?
69 class LiteralExpr : public ExprWithoutBlock
71 std::vector<Attribute> outer_attrs;
72 Literal literal;
73 location_t locus;
75 public:
76 std::string as_string () const override { return literal.as_string (); }
78 Literal::LitType get_lit_type () const { return literal.get_lit_type (); }
80 LiteralExpr (std::string value_as_string, Literal::LitType type,
81 PrimitiveCoreType type_hint, std::vector<Attribute> outer_attrs,
82 location_t locus)
83 : outer_attrs (std::move (outer_attrs)),
84 literal (std::move (value_as_string), type, type_hint), locus (locus)
87 LiteralExpr (Literal literal, std::vector<Attribute> outer_attrs,
88 location_t locus)
89 : outer_attrs (std::move (outer_attrs)), literal (std::move (literal)),
90 locus (locus)
93 // Unique pointer custom clone function
94 std::unique_ptr<LiteralExpr> clone_literal_expr () const
96 return std::unique_ptr<LiteralExpr> (clone_literal_expr_impl ());
99 location_t get_locus () const override final { return locus; }
101 bool is_literal () const override final { return true; }
103 Literal get_literal () const { return literal; }
105 void accept_vis (ASTVisitor &vis) override;
107 // Invalid if literal is in error state, so base stripping on that.
108 void mark_for_strip () override { literal = Literal::create_error (); }
109 bool is_marked_for_strip () const override { return literal.is_error (); }
111 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
112 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
114 void set_outer_attrs (std::vector<Attribute> new_attrs) override
116 outer_attrs = std::move (new_attrs);
119 protected:
120 /* Use covariance to implement clone function as returning this object rather
121 * than base */
122 LiteralExpr *clone_expr_without_block_impl () const final override
124 return clone_literal_expr_impl ();
127 /* not virtual as currently no subclasses of LiteralExpr, but could be in
128 * future */
129 /*virtual*/ LiteralExpr *clone_literal_expr_impl () const
131 return new LiteralExpr (*this);
135 // Literal expression attribute body (non-macro attribute)
136 class AttrInputLiteral : public AttrInput
138 LiteralExpr literal_expr;
140 public:
141 AttrInputLiteral (LiteralExpr lit_expr) : literal_expr (std::move (lit_expr))
144 std::string as_string () const override
146 return " = " + literal_expr.as_string ();
149 void accept_vis (ASTVisitor &vis) override;
151 /* this can never be a cfg predicate - cfg and cfg_attr require a token-tree
152 * cfg */
153 bool check_cfg_predicate (const Session &) const override { return false; }
155 bool is_meta_item () const override { return false; }
157 LiteralExpr &get_literal () { return literal_expr; }
159 AttrInputType get_attr_input_type () const final override
161 return AttrInput::AttrInputType::LITERAL;
164 protected:
165 /* Use covariance to implement clone function as returning this object rather
166 * than base */
167 AttrInputLiteral *clone_attr_input_impl () const override
169 return new AttrInputLiteral (*this);
173 // Like an AttrInputLiteral, but stores a MacroInvocation
174 class AttrInputMacro : public AttrInput
176 std::unique_ptr<MacroInvocation> macro;
178 public:
179 AttrInputMacro (std::unique_ptr<MacroInvocation> macro)
180 : macro (std::move (macro))
183 AttrInputMacro (const AttrInputMacro &oth);
185 AttrInputMacro (AttrInputMacro &&oth) : macro (std::move (oth.macro)) {}
187 void operator= (const AttrInputMacro &oth);
189 void operator= (AttrInputMacro &&oth) { macro = std::move (oth.macro); }
191 std::string as_string () const override;
193 void accept_vis (ASTVisitor &vis) override;
195 // assuming this can't be a cfg predicate
196 bool check_cfg_predicate (const Session &) const override { return false; }
198 // assuming this is like AttrInputLiteral
199 bool is_meta_item () const override { return false; }
201 std::unique_ptr<MacroInvocation> &get_macro () { return macro; }
203 AttrInputType get_attr_input_type () const final override
205 return AttrInput::AttrInputType::MACRO;
208 protected:
209 AttrInputMacro *clone_attr_input_impl () const override
211 return new AttrInputMacro (*this);
215 /* literal expr only meta item inner - TODO possibly replace with inheritance of
216 * LiteralExpr itself? */
217 class MetaItemLitExpr : public MetaItemInner
219 LiteralExpr lit_expr;
221 public:
222 MetaItemLitExpr (LiteralExpr lit_expr) : lit_expr (std::move (lit_expr)) {}
224 std::string as_string () const override { return lit_expr.as_string (); }
226 location_t get_locus () const override { return lit_expr.get_locus (); }
228 LiteralExpr get_literal () const { return lit_expr; }
230 LiteralExpr &get_literal () { return lit_expr; }
232 void accept_vis (ASTVisitor &vis) override;
234 bool check_cfg_predicate (const Session &session) const override;
236 MetaItemInner::Kind get_kind () override
238 return MetaItemInner::Kind::LitExpr;
241 protected:
242 // Use covariance to implement clone function as returning this type
243 MetaItemLitExpr *clone_meta_item_inner_impl () const override
245 return new MetaItemLitExpr (*this);
249 // more generic meta item "path = lit" form
250 class MetaItemPathLit : public MetaItem
252 SimplePath path;
253 LiteralExpr lit;
255 public:
256 MetaItemPathLit (SimplePath path, LiteralExpr lit_expr)
257 : path (std::move (path)), lit (std::move (lit_expr))
260 SimplePath get_path () const { return path; }
262 SimplePath &get_path () { return path; }
264 LiteralExpr get_literal () const { return lit; }
266 LiteralExpr &get_literal () { return lit; }
268 std::string as_string () const override
270 return path.as_string () + " = " + lit.as_string ();
273 MetaItem::ItemKind get_item_kind () const override
275 return MetaItem::ItemKind::PathLit;
278 // There are two Locations in MetaItemPathLit (path and lit_expr),
279 // we have no idea use which of them, just simply return UNKNOWN_LOCATION
280 // now.
281 // Maybe we will figure out when we really need the location in the future.
282 location_t get_locus () const override { return UNKNOWN_LOCATION; }
284 void accept_vis (ASTVisitor &vis) override;
286 bool check_cfg_predicate (const Session &session) const override;
287 /* TODO: return true if "ident" is defined and value of it is "lit", return
288 * false otherwise */
290 Attribute to_attribute () const override;
292 protected:
293 // Use covariance to implement clone function as returning this type
294 MetaItemPathLit *clone_meta_item_inner_impl () const override
296 return new MetaItemPathLit (*this);
300 /* Represents an expression using unary or binary operators as AST node. Can be
301 * overloaded. */
302 class OperatorExpr : public ExprWithoutBlock
304 // TODO: create binary and unary operator subclasses?
305 public:
306 location_t locus;
308 protected:
309 /* Variables must be protected to allow derived classes to use them as first
310 * class citizens */
311 std::vector<Attribute> outer_attrs;
312 std::unique_ptr<Expr> main_or_left_expr;
314 // Constructor (only for initialisation of expr purposes)
315 OperatorExpr (std::unique_ptr<Expr> main_or_left_expr,
316 std::vector<Attribute> outer_attribs, location_t locus)
317 : locus (locus), outer_attrs (std::move (outer_attribs)),
318 main_or_left_expr (std::move (main_or_left_expr))
321 // Copy constructor (only for initialisation of expr purposes)
322 OperatorExpr (OperatorExpr const &other)
323 : locus (other.locus), outer_attrs (other.outer_attrs)
325 // guard to prevent null dereference (only required if error state)
326 if (other.main_or_left_expr != nullptr)
327 main_or_left_expr = other.main_or_left_expr->clone_expr ();
330 // Overload assignment operator to deep copy expr
331 OperatorExpr &operator= (OperatorExpr const &other)
333 ExprWithoutBlock::operator= (other);
334 locus = other.locus;
335 outer_attrs = other.outer_attrs;
337 // guard to prevent null dereference (only required if error state)
338 if (other.main_or_left_expr != nullptr)
339 main_or_left_expr = other.main_or_left_expr->clone_expr ();
340 else
341 main_or_left_expr = nullptr;
343 return *this;
346 // move constructors
347 OperatorExpr (OperatorExpr &&other) = default;
348 OperatorExpr &operator= (OperatorExpr &&other) = default;
350 public:
351 location_t get_locus () const override final { return locus; }
353 // Invalid if expr is null, so base stripping on that.
354 void mark_for_strip () override { main_or_left_expr = nullptr; }
355 bool is_marked_for_strip () const override
357 return main_or_left_expr == nullptr;
360 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
361 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
363 void set_outer_attrs (std::vector<Attribute> new_attrs) override
365 outer_attrs = std::move (new_attrs);
369 /* Unary prefix & or &mut (or && and &&mut) borrow operator. Cannot be
370 * overloaded. */
371 class BorrowExpr : public OperatorExpr
373 bool is_mut;
374 bool double_borrow;
376 public:
377 std::string as_string () const override;
379 BorrowExpr (std::unique_ptr<Expr> borrow_lvalue, bool is_mut_borrow,
380 bool is_double_borrow, std::vector<Attribute> outer_attribs,
381 location_t locus)
382 : OperatorExpr (std::move (borrow_lvalue), std::move (outer_attribs),
383 locus),
384 is_mut (is_mut_borrow), double_borrow (is_double_borrow)
387 void accept_vis (ASTVisitor &vis) override;
389 // TODO: is this better? Or is a "vis_block" better?
390 Expr &get_borrowed_expr ()
392 rust_assert (main_or_left_expr != nullptr);
393 return *main_or_left_expr;
396 bool get_is_mut () const { return is_mut; }
398 bool get_is_double_borrow () const { return double_borrow; }
400 protected:
401 /* Use covariance to implement clone function as returning this object rather
402 * than base */
403 BorrowExpr *clone_expr_without_block_impl () const override
405 return new BorrowExpr (*this);
409 // Unary prefix * deference operator
410 class DereferenceExpr : public OperatorExpr
412 public:
413 std::string as_string () const override;
415 // Constructor calls OperatorExpr's protected constructor
416 DereferenceExpr (std::unique_ptr<Expr> deref_lvalue,
417 std::vector<Attribute> outer_attribs, location_t locus)
418 : OperatorExpr (std::move (deref_lvalue), std::move (outer_attribs), locus)
421 void accept_vis (ASTVisitor &vis) override;
423 // TODO: is this better? Or is a "vis_block" better?
424 Expr &get_dereferenced_expr ()
426 rust_assert (main_or_left_expr != nullptr);
427 return *main_or_left_expr;
430 protected:
431 /* Use covariance to implement clone function as returning this object rather
432 * than base */
433 DereferenceExpr *clone_expr_without_block_impl () const override
435 return new DereferenceExpr (*this);
439 // Unary postfix ? error propogation operator. Cannot be overloaded.
440 class ErrorPropagationExpr : public OperatorExpr
442 public:
443 std::string as_string () const override;
445 // Constructor calls OperatorExpr's protected constructor
446 ErrorPropagationExpr (std::unique_ptr<Expr> potential_error_value,
447 std::vector<Attribute> outer_attribs, location_t locus)
448 : OperatorExpr (std::move (potential_error_value),
449 std::move (outer_attribs), locus)
452 void accept_vis (ASTVisitor &vis) override;
454 // TODO: is this better? Or is a "vis_block" better?
455 Expr &get_propagating_expr ()
457 rust_assert (main_or_left_expr != nullptr);
458 return *main_or_left_expr;
461 protected:
462 /* Use covariance to implement clone function as returning this object rather
463 * than base */
464 ErrorPropagationExpr *clone_expr_without_block_impl () const override
466 return new ErrorPropagationExpr (*this);
470 // Unary prefix - or ! negation or NOT operators.
471 class NegationExpr : public OperatorExpr
473 public:
474 using ExprType = NegationOperator;
476 private:
477 /* Note: overload negation via std::ops::Neg and not via std::ops::Not
478 * Negation only works for signed integer and floating-point types, NOT only
479 * works for boolean and integer types (via bitwise NOT) */
480 ExprType expr_type;
482 public:
483 std::string as_string () const override;
485 ExprType get_expr_type () const { return expr_type; }
487 // Constructor calls OperatorExpr's protected constructor
488 NegationExpr (std::unique_ptr<Expr> negated_value, ExprType expr_kind,
489 std::vector<Attribute> outer_attribs, location_t locus)
490 : OperatorExpr (std::move (negated_value), std::move (outer_attribs),
491 locus),
492 expr_type (expr_kind)
495 void accept_vis (ASTVisitor &vis) override;
497 // TODO: is this better? Or is a "vis_block" better?
498 Expr &get_negated_expr ()
500 rust_assert (main_or_left_expr != nullptr);
501 return *main_or_left_expr;
504 protected:
505 /* Use covariance to implement clone function as returning this object rather
506 * than base */
507 NegationExpr *clone_expr_without_block_impl () const override
509 return new NegationExpr (*this);
513 // Infix binary operators. +, -, *, /, %, &, |, ^, <<, >>
514 class ArithmeticOrLogicalExpr : public OperatorExpr
516 public:
517 using ExprType = ArithmeticOrLogicalOperator;
519 private:
520 // Note: overloading trait specified in comments
521 ExprType expr_type;
523 std::unique_ptr<Expr> right_expr;
525 public:
526 std::string as_string () const override;
528 ExprType get_expr_type () const { return expr_type; }
530 // Constructor calls OperatorExpr's protected constructor
531 ArithmeticOrLogicalExpr (std::unique_ptr<Expr> left_value,
532 std::unique_ptr<Expr> right_value,
533 ExprType expr_kind, location_t locus)
534 : OperatorExpr (std::move (left_value), std::vector<Attribute> (), locus),
535 expr_type (expr_kind), right_expr (std::move (right_value))
537 // outer attributes not allowed
539 // Copy constructor - probably required due to unique pointer
540 ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr const &other)
541 : OperatorExpr (other), expr_type (other.expr_type),
542 right_expr (other.right_expr->clone_expr ())
545 // Overload assignment operator
546 ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr const &other)
548 OperatorExpr::operator= (other);
549 // main_or_left_expr = other.main_or_left_expr->clone_expr();
550 right_expr = other.right_expr->clone_expr ();
551 expr_type = other.expr_type;
553 return *this;
556 // move constructors
557 ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr &&other) = default;
558 ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr &&other)
559 = default;
561 void accept_vis (ASTVisitor &vis) override;
563 // TODO: is this better? Or is a "vis_block" better?
564 Expr &get_left_expr ()
566 rust_assert (main_or_left_expr != nullptr);
567 return *main_or_left_expr;
570 std::unique_ptr<Expr> &get_left_expr_ptr ()
572 rust_assert (main_or_left_expr != nullptr);
573 return main_or_left_expr;
576 // TODO: is this better? Or is a "vis_block" better?
577 Expr &get_right_expr ()
579 rust_assert (right_expr != nullptr);
580 return *right_expr;
583 std::unique_ptr<Expr> &get_right_expr_ptr ()
585 rust_assert (right_expr != nullptr);
586 return right_expr;
589 void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); }
590 void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); }
592 protected:
593 /* Use covariance to implement clone function as returning this object rather
594 * than base */
595 ArithmeticOrLogicalExpr *clone_expr_without_block_impl () const override
597 return new ArithmeticOrLogicalExpr (*this);
601 // Infix binary comparison operators. ==, !=, <, <=, >, >=
602 class ComparisonExpr : public OperatorExpr
604 public:
605 using ExprType = ComparisonOperator;
607 private:
608 // Note: overloading trait specified in comments
609 ExprType expr_type;
611 std::unique_ptr<Expr> right_expr;
613 public:
614 std::string as_string () const override;
616 ExprType get_expr_type () const { return expr_type; }
618 // Constructor requires pointers for polymorphism
619 ComparisonExpr (std::unique_ptr<Expr> left_value,
620 std::unique_ptr<Expr> right_value, ExprType comparison_kind,
621 location_t locus)
622 : OperatorExpr (std::move (left_value), std::vector<Attribute> (), locus),
623 expr_type (comparison_kind), right_expr (std::move (right_value))
625 // outer attributes not allowed
627 // Copy constructor also calls OperatorExpr's protected constructor
628 ComparisonExpr (ComparisonExpr const &other)
629 : OperatorExpr (other), expr_type (other.expr_type),
630 right_expr (other.right_expr->clone_expr ())
633 // Overload assignment operator to deep copy
634 ComparisonExpr &operator= (ComparisonExpr const &other)
636 OperatorExpr::operator= (other);
637 // main_or_left_expr = other.main_or_left_expr->clone_expr();
638 right_expr = other.right_expr->clone_expr ();
639 expr_type = other.expr_type;
640 // outer_attrs = other.outer_attrs;
642 return *this;
645 // move constructors
646 ComparisonExpr (ComparisonExpr &&other) = default;
647 ComparisonExpr &operator= (ComparisonExpr &&other) = default;
649 void accept_vis (ASTVisitor &vis) override;
651 // TODO: is this better? Or is a "vis_block" better?
652 Expr &get_left_expr ()
654 rust_assert (main_or_left_expr != nullptr);
655 return *main_or_left_expr;
658 std::unique_ptr<Expr> &get_left_expr_ptr ()
660 rust_assert (main_or_left_expr != nullptr);
661 return main_or_left_expr;
664 // TODO: is this better? Or is a "vis_block" better?
665 Expr &get_right_expr ()
667 rust_assert (right_expr != nullptr);
668 return *right_expr;
671 std::unique_ptr<Expr> &get_right_expr_ptr ()
673 rust_assert (right_expr != nullptr);
674 return right_expr;
677 ExprType get_kind () { return expr_type; }
679 /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2)
680 * maybe? */
681 protected:
682 /* Use covariance to implement clone function as returning this object rather
683 * than base */
684 ComparisonExpr *clone_expr_without_block_impl () const override
686 return new ComparisonExpr (*this);
690 // Infix binary lazy boolean logical operators && and ||.
691 class LazyBooleanExpr : public OperatorExpr
693 public:
694 using ExprType = LazyBooleanOperator;
696 private:
697 ExprType expr_type;
699 std::unique_ptr<Expr> right_expr;
701 public:
702 // Constructor calls OperatorExpr's protected constructor
703 LazyBooleanExpr (std::unique_ptr<Expr> left_bool_expr,
704 std::unique_ptr<Expr> right_bool_expr, ExprType expr_kind,
705 location_t locus)
706 : OperatorExpr (std::move (left_bool_expr), std::vector<Attribute> (),
707 locus),
708 expr_type (expr_kind), right_expr (std::move (right_bool_expr))
710 // outer attributes not allowed
712 // Copy constructor also calls OperatorExpr's protected constructor
713 LazyBooleanExpr (LazyBooleanExpr const &other)
714 : OperatorExpr (other), expr_type (other.expr_type),
715 right_expr (other.right_expr->clone_expr ())
718 // Overload assignment operator to deep copy
719 LazyBooleanExpr &operator= (LazyBooleanExpr const &other)
721 OperatorExpr::operator= (other);
722 // main_or_left_expr = other.main_or_left_expr->clone_expr();
723 right_expr = other.right_expr->clone_expr ();
724 expr_type = other.expr_type;
726 return *this;
729 // move constructors
730 LazyBooleanExpr (LazyBooleanExpr &&other) = default;
731 LazyBooleanExpr &operator= (LazyBooleanExpr &&other) = default;
733 std::string as_string () const override;
735 ExprType get_expr_type () const { return expr_type; }
737 void accept_vis (ASTVisitor &vis) override;
739 // TODO: is this better? Or is a "vis_block" better?
740 Expr &get_left_expr ()
742 rust_assert (main_or_left_expr != nullptr);
743 return *main_or_left_expr;
746 std::unique_ptr<Expr> &get_left_expr_ptr ()
748 rust_assert (main_or_left_expr != nullptr);
749 return main_or_left_expr;
752 // TODO: is this better? Or is a "vis_block" better?
753 Expr &get_right_expr ()
755 rust_assert (right_expr != nullptr);
756 return *right_expr;
759 std::unique_ptr<Expr> &get_right_expr_ptr ()
761 rust_assert (right_expr != nullptr);
762 return right_expr;
765 ExprType get_kind () { return expr_type; }
767 protected:
768 /* Use covariance to implement clone function as returning this object rather
769 * than base */
770 LazyBooleanExpr *clone_expr_without_block_impl () const override
772 return new LazyBooleanExpr (*this);
776 // Binary infix "as" cast expression.
777 class TypeCastExpr : public OperatorExpr
779 std::unique_ptr<TypeNoBounds> type_to_convert_to;
781 // Note: only certain type casts allowed, outlined in reference
782 public:
783 std::string as_string () const override;
785 // Constructor requires calling protected constructor of OperatorExpr
786 TypeCastExpr (std::unique_ptr<Expr> expr_to_cast,
787 std::unique_ptr<TypeNoBounds> type_to_cast_to, location_t locus)
788 : OperatorExpr (std::move (expr_to_cast), std::vector<Attribute> (), locus),
789 type_to_convert_to (std::move (type_to_cast_to))
791 // outer attributes not allowed
793 // Copy constructor also requires calling protected constructor
794 TypeCastExpr (TypeCastExpr const &other)
795 : OperatorExpr (other),
796 type_to_convert_to (other.type_to_convert_to->clone_type_no_bounds ())
799 // Overload assignment operator to deep copy
800 TypeCastExpr &operator= (TypeCastExpr const &other)
802 OperatorExpr::operator= (other);
803 // main_or_left_expr = other.main_or_left_expr->clone_expr();
804 type_to_convert_to = other.type_to_convert_to->clone_type_no_bounds ();
806 return *this;
809 // move constructors
810 TypeCastExpr (TypeCastExpr &&other) = default;
811 TypeCastExpr &operator= (TypeCastExpr &&other) = default;
813 void accept_vis (ASTVisitor &vis) override;
815 // TODO: is this better? Or is a "vis_block" better?
816 Expr &get_casted_expr ()
818 rust_assert (main_or_left_expr != nullptr);
819 return *main_or_left_expr;
822 // TODO: is this better? Or is a "vis_block" better?
823 TypeNoBounds &get_type_to_cast_to ()
825 rust_assert (type_to_convert_to != nullptr);
826 return *type_to_convert_to;
829 protected:
830 /* Use covariance to implement clone function as returning this object rather
831 * than base */
832 TypeCastExpr *clone_expr_without_block_impl () const override
834 return new TypeCastExpr (*this);
838 // Binary assignment expression.
839 class AssignmentExpr : public OperatorExpr
841 std::unique_ptr<Expr> right_expr;
843 public:
844 std::string as_string () const override;
846 // Call OperatorExpr constructor to initialise left_expr
847 AssignmentExpr (std::unique_ptr<Expr> value_to_assign_to,
848 std::unique_ptr<Expr> value_to_assign,
849 std::vector<Attribute> outer_attribs, location_t locus)
850 : OperatorExpr (std::move (value_to_assign_to), std::move (outer_attribs),
851 locus),
852 right_expr (std::move (value_to_assign))
854 // outer attributes not allowed
856 // Call OperatorExpr constructor in copy constructor, as well as clone
857 AssignmentExpr (AssignmentExpr const &other)
858 : OperatorExpr (other), right_expr (other.right_expr->clone_expr ())
861 // Overload assignment operator to clone unique_ptr right_expr
862 AssignmentExpr &operator= (AssignmentExpr const &other)
864 OperatorExpr::operator= (other);
865 // main_or_left_expr = other.main_or_left_expr->clone_expr();
866 right_expr = other.right_expr->clone_expr ();
867 // outer_attrs = other.outer_attrs;
869 return *this;
872 // move constructors
873 AssignmentExpr (AssignmentExpr &&other) = default;
874 AssignmentExpr &operator= (AssignmentExpr &&other) = default;
876 void accept_vis (ASTVisitor &vis) override;
878 void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); }
879 void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); }
881 // TODO: is this better? Or is a "vis_block" better?
882 Expr &get_left_expr ()
884 rust_assert (main_or_left_expr != nullptr);
885 return *main_or_left_expr;
888 std::unique_ptr<Expr> &get_left_expr_ptr ()
890 rust_assert (main_or_left_expr != nullptr);
891 return main_or_left_expr;
894 std::unique_ptr<Expr> &get_right_expr_ptr ()
896 rust_assert (right_expr != nullptr);
897 return right_expr;
900 // TODO: is this better? Or is a "vis_block" better?
901 Expr &get_right_expr ()
903 rust_assert (right_expr != nullptr);
904 return *right_expr;
907 protected:
908 /* Use covariance to implement clone function as returning this object rather
909 * than base */
910 AssignmentExpr *clone_expr_without_block_impl () const override
912 return new AssignmentExpr (*this);
916 /* Binary infix compound assignment (arithmetic or logic then assignment)
917 * expressions. */
918 class CompoundAssignmentExpr : public OperatorExpr
920 public:
921 using ExprType = CompoundAssignmentOperator;
923 private:
924 // Note: overloading trait specified in comments
925 ExprType expr_type;
926 std::unique_ptr<Expr> right_expr;
928 public:
929 std::string as_string () const override;
931 ExprType get_expr_type () const { return expr_type; }
933 // Use pointers in constructor to enable polymorphism
934 CompoundAssignmentExpr (std::unique_ptr<Expr> value_to_assign_to,
935 std::unique_ptr<Expr> value_to_assign,
936 ExprType expr_kind, location_t locus)
937 : OperatorExpr (std::move (value_to_assign_to), std::vector<Attribute> (),
938 locus),
939 expr_type (expr_kind), right_expr (std::move (value_to_assign))
941 // outer attributes not allowed
943 // Have clone in copy constructor
944 CompoundAssignmentExpr (CompoundAssignmentExpr const &other)
945 : OperatorExpr (other), expr_type (other.expr_type),
946 right_expr (other.right_expr->clone_expr ())
949 // Overload assignment operator to clone
950 CompoundAssignmentExpr &operator= (CompoundAssignmentExpr const &other)
952 OperatorExpr::operator= (other);
953 // main_or_left_expr = other.main_or_left_expr->clone_expr();
954 right_expr = other.right_expr->clone_expr ();
955 expr_type = other.expr_type;
956 // outer_attrs = other.outer_attrs;
958 return *this;
961 // move constructors
962 CompoundAssignmentExpr (CompoundAssignmentExpr &&other) = default;
963 CompoundAssignmentExpr &operator= (CompoundAssignmentExpr &&other) = default;
965 void accept_vis (ASTVisitor &vis) override;
967 // TODO: is this better? Or is a "vis_block" better?
968 Expr &get_left_expr ()
970 rust_assert (main_or_left_expr != nullptr);
971 return *main_or_left_expr;
974 std::unique_ptr<Expr> &get_left_expr_ptr ()
976 rust_assert (main_or_left_expr != nullptr);
977 return main_or_left_expr;
980 // TODO: is this better? Or is a "vis_block" better?
981 Expr &get_right_expr ()
983 rust_assert (right_expr != nullptr);
984 return *right_expr;
987 std::unique_ptr<Expr> &get_right_expr_ptr ()
989 rust_assert (right_expr != nullptr);
990 return right_expr;
993 protected:
994 /* Use covariance to implement clone function as returning this object rather
995 * than base */
996 CompoundAssignmentExpr *clone_expr_without_block_impl () const override
998 return new CompoundAssignmentExpr (*this);
1002 // Expression in parentheses (i.e. like literally just any 3 + (2 * 6))
1003 class GroupedExpr : public ExprWithoutBlock
1005 std::vector<Attribute> outer_attrs;
1006 std::vector<Attribute> inner_attrs;
1007 std::unique_ptr<Expr> expr_in_parens;
1008 location_t locus;
1010 public:
1011 std::string as_string () const override;
1013 const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1014 std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1016 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1017 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1019 void set_outer_attrs (std::vector<Attribute> new_attrs) override
1021 outer_attrs = std::move (new_attrs);
1024 GroupedExpr (std::unique_ptr<Expr> parenthesised_expr,
1025 std::vector<Attribute> inner_attribs,
1026 std::vector<Attribute> outer_attribs, location_t locus)
1027 : outer_attrs (std::move (outer_attribs)),
1028 inner_attrs (std::move (inner_attribs)),
1029 expr_in_parens (std::move (parenthesised_expr)), locus (locus)
1032 // Copy constructor includes clone for expr_in_parens
1033 GroupedExpr (GroupedExpr const &other)
1034 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1035 inner_attrs (other.inner_attrs), locus (other.locus)
1037 // guard to prevent null dereference (only required if error state)
1038 if (other.expr_in_parens != nullptr)
1039 expr_in_parens = other.expr_in_parens->clone_expr ();
1042 // Overloaded assignment operator to clone expr_in_parens
1043 GroupedExpr &operator= (GroupedExpr const &other)
1045 ExprWithoutBlock::operator= (other);
1046 inner_attrs = other.inner_attrs;
1047 locus = other.locus;
1048 outer_attrs = other.outer_attrs;
1050 // guard to prevent null dereference (only required if error state)
1051 if (other.expr_in_parens != nullptr)
1052 expr_in_parens = other.expr_in_parens->clone_expr ();
1053 else
1054 expr_in_parens = nullptr;
1056 return *this;
1059 // move constructors
1060 GroupedExpr (GroupedExpr &&other) = default;
1061 GroupedExpr &operator= (GroupedExpr &&other) = default;
1063 location_t get_locus () const override final { return locus; }
1065 void accept_vis (ASTVisitor &vis) override;
1067 // Invalid if inner expr is null, so base stripping on that.
1068 void mark_for_strip () override { expr_in_parens = nullptr; }
1069 bool is_marked_for_strip () const override
1071 return expr_in_parens == nullptr;
1074 // TODO: is this better? Or is a "vis_block" better?
1075 Expr &get_expr_in_parens ()
1077 rust_assert (expr_in_parens != nullptr);
1078 return *expr_in_parens;
1081 std::unique_ptr<Expr> &get_expr_in_parens_ptr ()
1083 rust_assert (expr_in_parens != nullptr);
1084 return expr_in_parens;
1087 protected:
1088 /* Use covariance to implement clone function as returning this object rather
1089 * than base */
1090 GroupedExpr *clone_expr_without_block_impl () const override
1092 return new GroupedExpr (*this);
1096 // Base array initialisation internal element representation thing (abstract)
1097 // aka ArrayElements
1098 class ArrayElems
1100 public:
1101 virtual ~ArrayElems () {}
1103 // Unique pointer custom clone ArrayElems function
1104 std::unique_ptr<ArrayElems> clone_array_elems () const
1106 return std::unique_ptr<ArrayElems> (clone_array_elems_impl ());
1109 virtual std::string as_string () const = 0;
1111 virtual void accept_vis (ASTVisitor &vis) = 0;
1113 NodeId get_node_id () const { return node_id; }
1115 protected:
1116 ArrayElems () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {}
1118 // pure virtual clone implementation
1119 virtual ArrayElems *clone_array_elems_impl () const = 0;
1121 NodeId node_id;
1124 // Value array elements
1125 class ArrayElemsValues : public ArrayElems
1127 std::vector<std::unique_ptr<Expr> > values;
1128 location_t locus;
1130 public:
1131 ArrayElemsValues (std::vector<std::unique_ptr<Expr> > elems, location_t locus)
1132 : ArrayElems (), values (std::move (elems)), locus (locus)
1135 // copy constructor with vector clone
1136 ArrayElemsValues (ArrayElemsValues const &other)
1138 values.reserve (other.values.size ());
1139 for (const auto &e : other.values)
1140 values.push_back (e->clone_expr ());
1143 // overloaded assignment operator with vector clone
1144 ArrayElemsValues &operator= (ArrayElemsValues const &other)
1146 values.reserve (other.values.size ());
1147 for (const auto &e : other.values)
1148 values.push_back (e->clone_expr ());
1150 return *this;
1153 // move constructors
1154 ArrayElemsValues (ArrayElemsValues &&other) = default;
1155 ArrayElemsValues &operator= (ArrayElemsValues &&other) = default;
1157 std::string as_string () const override;
1159 void accept_vis (ASTVisitor &vis) override;
1161 // TODO: this mutable getter seems really dodgy. Think up better way.
1162 const std::vector<std::unique_ptr<Expr> > &get_values () const
1164 return values;
1166 std::vector<std::unique_ptr<Expr> > &get_values () { return values; }
1168 size_t get_num_values () const { return values.size (); }
1170 protected:
1171 ArrayElemsValues *clone_array_elems_impl () const override
1173 return new ArrayElemsValues (*this);
1177 // Copied array element and number of copies
1178 class ArrayElemsCopied : public ArrayElems
1180 std::unique_ptr<Expr> elem_to_copy;
1181 std::unique_ptr<Expr> num_copies;
1182 location_t locus;
1184 public:
1185 // Constructor requires pointers for polymorphism
1186 ArrayElemsCopied (std::unique_ptr<Expr> copied_elem,
1187 std::unique_ptr<Expr> copy_amount, location_t locus)
1188 : ArrayElems (), elem_to_copy (std::move (copied_elem)),
1189 num_copies (std::move (copy_amount)), locus (locus)
1192 // Copy constructor required due to unique_ptr - uses custom clone
1193 ArrayElemsCopied (ArrayElemsCopied const &other)
1194 : elem_to_copy (other.elem_to_copy->clone_expr ()),
1195 num_copies (other.num_copies->clone_expr ())
1198 // Overloaded assignment operator for deep copying
1199 ArrayElemsCopied &operator= (ArrayElemsCopied const &other)
1201 elem_to_copy = other.elem_to_copy->clone_expr ();
1202 num_copies = other.num_copies->clone_expr ();
1204 return *this;
1207 // move constructors
1208 ArrayElemsCopied (ArrayElemsCopied &&other) = default;
1209 ArrayElemsCopied &operator= (ArrayElemsCopied &&other) = default;
1211 std::string as_string () const override;
1213 void accept_vis (ASTVisitor &vis) override;
1215 // TODO: is this better? Or is a "vis_block" better?
1216 Expr &get_elem_to_copy ()
1218 rust_assert (elem_to_copy != nullptr);
1219 return *elem_to_copy;
1222 // TODO: is this better? Or is a "vis_block" better?
1223 Expr &get_num_copies ()
1225 rust_assert (num_copies != nullptr);
1226 return *num_copies;
1229 protected:
1230 ArrayElemsCopied *clone_array_elems_impl () const override
1232 return new ArrayElemsCopied (*this);
1236 // Array definition-ish expression
1237 class ArrayExpr : public ExprWithoutBlock
1239 std::vector<Attribute> outer_attrs;
1240 std::vector<Attribute> inner_attrs;
1241 std::unique_ptr<ArrayElems> internal_elements;
1242 location_t locus;
1244 // TODO: find another way to store this to save memory?
1245 bool marked_for_strip = false;
1247 public:
1248 std::string as_string () const override;
1250 const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1251 std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1253 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1254 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1256 void set_outer_attrs (std::vector<Attribute> new_attrs) override
1258 outer_attrs = std::move (new_attrs);
1261 // Constructor requires ArrayElems pointer
1262 ArrayExpr (std::unique_ptr<ArrayElems> array_elems,
1263 std::vector<Attribute> inner_attribs,
1264 std::vector<Attribute> outer_attribs, location_t locus)
1265 : outer_attrs (std::move (outer_attribs)),
1266 inner_attrs (std::move (inner_attribs)),
1267 internal_elements (std::move (array_elems)), locus (locus)
1269 rust_assert (internal_elements != nullptr);
1272 // Copy constructor requires cloning ArrayElems for polymorphism to hold
1273 ArrayExpr (ArrayExpr const &other)
1274 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1275 inner_attrs (other.inner_attrs), locus (other.locus),
1276 marked_for_strip (other.marked_for_strip)
1278 internal_elements = other.internal_elements->clone_array_elems ();
1279 rust_assert (internal_elements != nullptr);
1282 // Overload assignment operator to clone internal_elements
1283 ArrayExpr &operator= (ArrayExpr const &other)
1285 ExprWithoutBlock::operator= (other);
1286 inner_attrs = other.inner_attrs;
1287 locus = other.locus;
1288 marked_for_strip = other.marked_for_strip;
1289 outer_attrs = other.outer_attrs;
1291 internal_elements = other.internal_elements->clone_array_elems ();
1293 rust_assert (internal_elements != nullptr);
1294 return *this;
1297 // move constructors
1298 ArrayExpr (ArrayExpr &&other) = default;
1299 ArrayExpr &operator= (ArrayExpr &&other) = default;
1301 location_t get_locus () const override final { return locus; }
1303 void accept_vis (ASTVisitor &vis) override;
1305 // Can't think of any invalid invariants, so store boolean.
1306 void mark_for_strip () override { marked_for_strip = true; }
1307 bool is_marked_for_strip () const override { return marked_for_strip; }
1309 // TODO: is this better? Or is a "vis_block" better?
1310 std::unique_ptr<ArrayElems> &get_array_elems ()
1312 rust_assert (internal_elements != nullptr);
1313 return internal_elements;
1316 protected:
1317 /* Use covariance to implement clone function as returning this object rather
1318 * than base */
1319 ArrayExpr *clone_expr_without_block_impl () const override
1321 return new ArrayExpr (*this);
1325 // Aka IndexExpr (also applies to slices)
1326 /* Apparently a[b] is equivalent to *std::ops::Index::index(&a, b) or
1327 * *std::ops::Index::index_mut(&mut a, b) */
1328 /* Also apparently deref operations on a will be repeatedly applied to find an
1329 * implementation */
1330 class ArrayIndexExpr : public ExprWithoutBlock
1332 std::vector<Attribute> outer_attrs;
1333 std::unique_ptr<Expr> array_expr;
1334 std::unique_ptr<Expr> index_expr;
1335 location_t locus;
1337 public:
1338 std::string as_string () const override;
1340 ArrayIndexExpr (std::unique_ptr<Expr> array_expr,
1341 std::unique_ptr<Expr> array_index_expr,
1342 std::vector<Attribute> outer_attribs, location_t locus)
1343 : outer_attrs (std::move (outer_attribs)),
1344 array_expr (std::move (array_expr)),
1345 index_expr (std::move (array_index_expr)), locus (locus)
1348 // Copy constructor requires special cloning due to unique_ptr
1349 ArrayIndexExpr (ArrayIndexExpr const &other)
1350 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1351 locus (other.locus)
1353 // guard to prevent null dereference (only required if error state)
1354 if (other.array_expr != nullptr)
1355 array_expr = other.array_expr->clone_expr ();
1356 if (other.index_expr != nullptr)
1357 index_expr = other.index_expr->clone_expr ();
1360 // Overload assignment operator to clone unique_ptrs
1361 ArrayIndexExpr &operator= (ArrayIndexExpr const &other)
1363 ExprWithoutBlock::operator= (other);
1364 outer_attrs = other.outer_attrs;
1365 locus = other.locus;
1367 // guard to prevent null dereference (only required if error state)
1368 if (other.array_expr != nullptr)
1369 array_expr = other.array_expr->clone_expr ();
1370 else
1371 array_expr = nullptr;
1372 if (other.index_expr != nullptr)
1373 index_expr = other.index_expr->clone_expr ();
1374 else
1375 index_expr = nullptr;
1377 return *this;
1380 // move constructors
1381 ArrayIndexExpr (ArrayIndexExpr &&other) = default;
1382 ArrayIndexExpr &operator= (ArrayIndexExpr &&other) = default;
1384 location_t get_locus () const override final { return locus; }
1386 void accept_vis (ASTVisitor &vis) override;
1388 // Invalid if either expr is null, so base stripping on that.
1389 void mark_for_strip () override
1391 array_expr = nullptr;
1392 index_expr = nullptr;
1394 bool is_marked_for_strip () const override
1396 return array_expr == nullptr && index_expr == nullptr;
1399 // TODO: is this better? Or is a "vis_block" better?
1400 Expr &get_array_expr ()
1402 rust_assert (array_expr != nullptr);
1403 return *array_expr;
1406 // TODO: is this better? Or is a "vis_block" better?
1407 Expr &get_index_expr ()
1409 rust_assert (index_expr != nullptr);
1410 return *index_expr;
1413 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1414 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1416 void set_outer_attrs (std::vector<Attribute> new_attrs) override
1418 outer_attrs = std::move (new_attrs);
1421 protected:
1422 /* Use covariance to implement clone function as returning this object rather
1423 * than base */
1424 ArrayIndexExpr *clone_expr_without_block_impl () const override
1426 return new ArrayIndexExpr (*this);
1430 // AST representation of a tuple
1431 class TupleExpr : public ExprWithoutBlock
1433 std::vector<Attribute> outer_attrs;
1434 std::vector<Attribute> inner_attrs;
1435 std::vector<std::unique_ptr<Expr> > tuple_elems;
1436 location_t locus;
1438 // TODO: find another way to store this to save memory?
1439 bool marked_for_strip = false;
1441 public:
1442 std::string as_string () const override;
1444 const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1445 std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1447 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1448 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1450 void set_outer_attrs (std::vector<Attribute> new_attrs) override
1452 outer_attrs = std::move (new_attrs);
1455 TupleExpr (std::vector<std::unique_ptr<Expr> > tuple_elements,
1456 std::vector<Attribute> inner_attribs,
1457 std::vector<Attribute> outer_attribs, location_t locus)
1458 : outer_attrs (std::move (outer_attribs)),
1459 inner_attrs (std::move (inner_attribs)),
1460 tuple_elems (std::move (tuple_elements)), locus (locus)
1463 // copy constructor with vector clone
1464 TupleExpr (TupleExpr const &other)
1465 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1466 inner_attrs (other.inner_attrs), locus (other.locus),
1467 marked_for_strip (other.marked_for_strip)
1469 tuple_elems.reserve (other.tuple_elems.size ());
1470 for (const auto &e : other.tuple_elems)
1471 tuple_elems.push_back (e->clone_expr ());
1474 // overloaded assignment operator to vector clone
1475 TupleExpr &operator= (TupleExpr const &other)
1477 ExprWithoutBlock::operator= (other);
1478 outer_attrs = other.outer_attrs;
1479 inner_attrs = other.inner_attrs;
1480 locus = other.locus;
1481 marked_for_strip = other.marked_for_strip;
1483 tuple_elems.reserve (other.tuple_elems.size ());
1484 for (const auto &e : other.tuple_elems)
1485 tuple_elems.push_back (e->clone_expr ());
1487 return *this;
1490 // move constructors
1491 TupleExpr (TupleExpr &&other) = default;
1492 TupleExpr &operator= (TupleExpr &&other) = default;
1494 /* Note: syntactically, can disambiguate single-element tuple from parens with
1495 * comma, i.e. (0,) rather than (0) */
1497 location_t get_locus () const override final { return locus; }
1499 void accept_vis (ASTVisitor &vis) override;
1501 // Can't think of any invalid invariants, so store boolean.
1502 void mark_for_strip () override { marked_for_strip = true; }
1503 bool is_marked_for_strip () const override { return marked_for_strip; }
1505 // TODO: this mutable getter seems really dodgy. Think up better way.
1506 const std::vector<std::unique_ptr<Expr> > &get_tuple_elems () const
1508 return tuple_elems;
1510 std::vector<std::unique_ptr<Expr> > &get_tuple_elems ()
1512 return tuple_elems;
1515 bool is_unit () const { return tuple_elems.size () == 0; }
1517 protected:
1518 /* Use covariance to implement clone function as returning this object rather
1519 * than base */
1520 TupleExpr *clone_expr_without_block_impl () const override
1522 return new TupleExpr (*this);
1526 // aka TupleIndexingExpr
1527 // AST representation of a tuple indexing expression
1528 class TupleIndexExpr : public ExprWithoutBlock
1530 std::vector<Attribute> outer_attrs;
1531 std::unique_ptr<Expr> tuple_expr;
1532 // TupleIndex is a decimal int literal with no underscores or suffix
1533 TupleIndex tuple_index;
1535 location_t locus;
1537 // i.e. pair.0
1539 public:
1540 std::string as_string () const override;
1542 TupleIndex get_tuple_index () const { return tuple_index; }
1544 TupleIndexExpr (std::unique_ptr<Expr> tuple_expr, TupleIndex index,
1545 std::vector<Attribute> outer_attribs, location_t locus)
1546 : outer_attrs (std::move (outer_attribs)),
1547 tuple_expr (std::move (tuple_expr)), tuple_index (index), locus (locus)
1550 // Copy constructor requires a clone for tuple_expr
1551 TupleIndexExpr (TupleIndexExpr const &other)
1552 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1553 tuple_index (other.tuple_index), locus (other.locus)
1555 // guard to prevent null dereference (only required if error state)
1556 if (other.tuple_expr != nullptr)
1557 tuple_expr = other.tuple_expr->clone_expr ();
1560 // Overload assignment operator in order to clone
1561 TupleIndexExpr &operator= (TupleIndexExpr const &other)
1563 ExprWithoutBlock::operator= (other);
1564 tuple_index = other.tuple_index;
1565 locus = other.locus;
1566 outer_attrs = other.outer_attrs;
1568 // guard to prevent null dereference (only required if error state)
1569 if (other.tuple_expr != nullptr)
1570 tuple_expr = other.tuple_expr->clone_expr ();
1571 else
1572 tuple_expr = nullptr;
1574 return *this;
1577 // move constructors
1578 TupleIndexExpr (TupleIndexExpr &&other) = default;
1579 TupleIndexExpr &operator= (TupleIndexExpr &&other) = default;
1581 location_t get_locus () const override final { return locus; }
1583 void accept_vis (ASTVisitor &vis) override;
1585 // Invalid if tuple expr is null, so base stripping on that.
1586 void mark_for_strip () override { tuple_expr = nullptr; }
1587 bool is_marked_for_strip () const override { return tuple_expr == nullptr; }
1589 // TODO: is this better? Or is a "vis_block" better?
1590 Expr &get_tuple_expr ()
1592 rust_assert (tuple_expr != nullptr);
1593 return *tuple_expr;
1596 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1597 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1599 void set_outer_attrs (std::vector<Attribute> new_attrs) override
1601 outer_attrs = std::move (new_attrs);
1604 protected:
1605 /* Use covariance to implement clone function as returning this object rather
1606 * than base */
1607 TupleIndexExpr *clone_expr_without_block_impl () const override
1609 return new TupleIndexExpr (*this);
1613 // Base struct/tuple/union value creator AST node (abstract)
1614 class StructExpr : public ExprWithoutBlock
1616 std::vector<Attribute> outer_attrs;
1617 PathInExpression struct_name;
1619 protected:
1620 // Protected constructor to allow initialising struct_name
1621 StructExpr (PathInExpression struct_path,
1622 std::vector<Attribute> outer_attribs)
1623 : outer_attrs (std::move (outer_attribs)),
1624 struct_name (std::move (struct_path))
1627 public:
1628 const PathInExpression &get_struct_name () const { return struct_name; }
1629 PathInExpression &get_struct_name () { return struct_name; }
1631 std::string as_string () const override;
1633 // Invalid if path is empty, so base stripping on that.
1634 void mark_for_strip () override
1636 struct_name = PathInExpression::create_error ();
1638 bool is_marked_for_strip () const override { return struct_name.is_error (); }
1640 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1641 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1643 void set_outer_attrs (std::vector<Attribute> new_attrs) override
1645 outer_attrs = std::move (new_attrs);
1649 // Actual AST node of the struct creator (with no fields). Not abstract!
1650 class StructExprStruct : public StructExpr
1652 std::vector<Attribute> inner_attrs;
1654 location_t locus;
1656 public:
1657 std::string as_string () const override;
1659 const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1660 std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1662 // Constructor has to call protected constructor of base class
1663 StructExprStruct (PathInExpression struct_path,
1664 std::vector<Attribute> inner_attribs,
1665 std::vector<Attribute> outer_attribs, location_t locus)
1666 : StructExpr (std::move (struct_path), std::move (outer_attribs)),
1667 inner_attrs (std::move (inner_attribs)), locus (locus)
1670 location_t get_locus () const override final { return locus; }
1672 void accept_vis (ASTVisitor &vis) override;
1674 protected:
1675 /* Use covariance to implement clone function as returning this object rather
1676 * than base */
1677 StructExprStruct *clone_expr_without_block_impl () const override
1679 return new StructExprStruct (*this);
1683 /* AST node representing expression used to fill a struct's fields from another
1684 * struct */
1685 struct StructBase
1687 private:
1688 std::unique_ptr<Expr> base_struct;
1689 location_t locus;
1691 public:
1692 StructBase (std::unique_ptr<Expr> base_struct_ptr, location_t locus)
1693 : base_struct (std::move (base_struct_ptr)), locus (locus)
1696 // Copy constructor requires clone
1697 StructBase (StructBase const &other)
1699 /* HACK: gets around base_struct pointer being null (e.g. if no struct base
1700 * exists) */
1701 if (other.base_struct != nullptr)
1702 base_struct = other.base_struct->clone_expr ();
1705 // Destructor
1706 ~StructBase () = default;
1708 // Overload assignment operator to clone base_struct
1709 StructBase &operator= (StructBase const &other)
1711 // prevent null pointer dereference
1712 if (other.base_struct != nullptr)
1713 base_struct = other.base_struct->clone_expr ();
1714 else
1715 base_struct = nullptr;
1717 return *this;
1720 // move constructors
1721 StructBase (StructBase &&other) = default;
1722 StructBase &operator= (StructBase &&other) = default;
1724 // Returns a null expr-ed StructBase - error state
1725 static StructBase error () { return StructBase (nullptr, UNDEF_LOCATION); }
1727 // Returns whether StructBase is in error state
1728 bool is_invalid () const { return base_struct == nullptr; }
1730 std::string as_string () const;
1732 // TODO: is this better? Or is a "vis_block" better?
1733 Expr &get_base_struct ()
1735 rust_assert (base_struct != nullptr);
1736 return *base_struct;
1740 /* Base AST node for a single struct expression field (in struct instance
1741 * creation) - abstract */
1742 class StructExprField
1744 public:
1745 virtual ~StructExprField () {}
1747 // Unique pointer custom clone function
1748 std::unique_ptr<StructExprField> clone_struct_expr_field () const
1750 return std::unique_ptr<StructExprField> (clone_struct_expr_field_impl ());
1753 virtual std::string as_string () const = 0;
1755 virtual void accept_vis (ASTVisitor &vis) = 0;
1757 virtual location_t get_locus () const = 0;
1759 NodeId get_node_id () const { return node_id; }
1761 protected:
1762 // pure virtual clone implementation
1763 virtual StructExprField *clone_struct_expr_field_impl () const = 0;
1765 StructExprField () : node_id (Analysis::Mappings::get ()->get_next_node_id ())
1768 NodeId node_id;
1771 // Identifier-only variant of StructExprField AST node
1772 class StructExprFieldIdentifier : public StructExprField
1774 Identifier field_name;
1775 location_t locus;
1777 public:
1778 StructExprFieldIdentifier (Identifier field_identifier, location_t locus)
1779 : StructExprField (), field_name (std::move (field_identifier)),
1780 locus (locus)
1783 std::string as_string () const override { return field_name.as_string (); }
1785 location_t get_locus () const override final { return locus; }
1787 void accept_vis (ASTVisitor &vis) override;
1789 Identifier get_field_name () const { return field_name; }
1791 protected:
1792 /* Use covariance to implement clone function as returning this object rather
1793 * than base */
1794 StructExprFieldIdentifier *clone_struct_expr_field_impl () const override
1796 return new StructExprFieldIdentifier (*this);
1800 /* Base AST node for a single struct expression field with an assigned value -
1801 * abstract */
1802 class StructExprFieldWithVal : public StructExprField
1804 std::unique_ptr<Expr> value;
1806 protected:
1807 StructExprFieldWithVal (std::unique_ptr<Expr> field_value)
1808 : StructExprField (), value (std::move (field_value))
1811 // Copy constructor requires clone
1812 StructExprFieldWithVal (StructExprFieldWithVal const &other)
1813 : value (other.value->clone_expr ())
1816 // Overload assignment operator to clone unique_ptr
1817 StructExprFieldWithVal &operator= (StructExprFieldWithVal const &other)
1819 value = other.value->clone_expr ();
1821 return *this;
1824 // move constructors
1825 StructExprFieldWithVal (StructExprFieldWithVal &&other) = default;
1826 StructExprFieldWithVal &operator= (StructExprFieldWithVal &&other) = default;
1828 public:
1829 std::string as_string () const override;
1831 // TODO: is this better? Or is a "vis_block" better?
1832 Expr &get_value ()
1834 rust_assert (value != nullptr);
1835 return *value;
1839 // Identifier and value variant of StructExprField AST node
1840 class StructExprFieldIdentifierValue : public StructExprFieldWithVal
1842 Identifier field_name;
1843 location_t locus;
1845 public:
1846 StructExprFieldIdentifierValue (Identifier field_identifier,
1847 std::unique_ptr<Expr> field_value,
1848 location_t locus)
1849 : StructExprFieldWithVal (std::move (field_value)),
1850 field_name (std::move (field_identifier)), locus (locus)
1853 std::string as_string () const override;
1855 void accept_vis (ASTVisitor &vis) override;
1857 std::string get_field_name () const { return field_name.as_string (); }
1859 location_t get_locus () const override final { return locus; }
1861 protected:
1862 /* Use covariance to implement clone function as returning this object rather
1863 * than base */
1864 StructExprFieldIdentifierValue *clone_struct_expr_field_impl () const override
1866 return new StructExprFieldIdentifierValue (*this);
1870 // Tuple index and value variant of StructExprField AST node
1871 class StructExprFieldIndexValue : public StructExprFieldWithVal
1873 TupleIndex index;
1874 location_t locus;
1876 public:
1877 StructExprFieldIndexValue (TupleIndex tuple_index,
1878 std::unique_ptr<Expr> field_value,
1879 location_t locus)
1880 : StructExprFieldWithVal (std::move (field_value)), index (tuple_index),
1881 locus (locus)
1884 std::string as_string () const override;
1886 void accept_vis (ASTVisitor &vis) override;
1888 TupleIndex get_index () const { return index; }
1890 location_t get_locus () const override final { return locus; }
1892 protected:
1893 /* Use covariance to implement clone function as returning this object rather
1894 * than base */
1895 StructExprFieldIndexValue *clone_struct_expr_field_impl () const override
1897 return new StructExprFieldIndexValue (*this);
1901 // AST node of a struct creator with fields
1902 class StructExprStructFields : public StructExprStruct
1904 // std::vector<StructExprField> fields;
1905 std::vector<std::unique_ptr<StructExprField> > fields;
1907 // bool has_struct_base;
1908 StructBase struct_base;
1910 public:
1911 std::string as_string () const override;
1913 bool has_struct_base () const { return !struct_base.is_invalid (); }
1915 // Constructor for StructExprStructFields when no struct base is used
1916 StructExprStructFields (
1917 PathInExpression struct_path,
1918 std::vector<std::unique_ptr<StructExprField> > expr_fields,
1919 location_t locus, StructBase base_struct = StructBase::error (),
1920 std::vector<Attribute> inner_attribs = std::vector<Attribute> (),
1921 std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
1922 : StructExprStruct (std::move (struct_path), std::move (inner_attribs),
1923 std::move (outer_attribs), locus),
1924 fields (std::move (expr_fields)), struct_base (std::move (base_struct))
1927 // copy constructor with vector clone
1928 StructExprStructFields (StructExprStructFields const &other)
1929 : StructExprStruct (other), struct_base (other.struct_base)
1931 fields.reserve (other.fields.size ());
1932 for (const auto &e : other.fields)
1933 fields.push_back (e->clone_struct_expr_field ());
1936 // overloaded assignment operator with vector clone
1937 StructExprStructFields &operator= (StructExprStructFields const &other)
1939 StructExprStruct::operator= (other);
1940 struct_base = other.struct_base;
1942 fields.reserve (other.fields.size ());
1943 for (const auto &e : other.fields)
1944 fields.push_back (e->clone_struct_expr_field ());
1946 return *this;
1949 // move constructors
1950 StructExprStructFields (StructExprStructFields &&other) = default;
1951 StructExprStructFields &operator= (StructExprStructFields &&other) = default;
1953 void accept_vis (ASTVisitor &vis) override;
1955 // TODO: this mutable getter seems really dodgy. Think up better way.
1956 std::vector<std::unique_ptr<StructExprField> > &get_fields ()
1958 return fields;
1960 const std::vector<std::unique_ptr<StructExprField> > &get_fields () const
1962 return fields;
1965 StructBase &get_struct_base () { return struct_base; }
1966 const StructBase &get_struct_base () const { return struct_base; }
1968 protected:
1969 /* Use covariance to implement clone function as returning this object rather
1970 * than base */
1971 StructExprStructFields *clone_expr_without_block_impl () const override
1973 return new StructExprStructFields (*this);
1977 // AST node of the functional update struct creator
1978 /* TODO: remove and replace with StructExprStructFields, except with empty
1979 * vector of fields? */
1980 class StructExprStructBase : public StructExprStruct
1982 StructBase struct_base;
1984 public:
1985 std::string as_string () const override;
1987 StructExprStructBase (PathInExpression struct_path, StructBase base_struct,
1988 std::vector<Attribute> inner_attribs,
1989 std::vector<Attribute> outer_attribs, location_t locus)
1990 : StructExprStruct (std::move (struct_path), std::move (inner_attribs),
1991 std::move (outer_attribs), locus),
1992 struct_base (std::move (base_struct))
1995 void accept_vis (ASTVisitor &vis) override;
1997 StructBase &get_struct_base () { return struct_base; }
1998 const StructBase &get_struct_base () const { return struct_base; }
2000 protected:
2001 /* Use covariance to implement clone function as returning this object rather
2002 * than base */
2003 StructExprStructBase *clone_expr_without_block_impl () const override
2005 return new StructExprStructBase (*this);
2009 // Forward decl for Function - used in CallExpr
2010 class Function;
2012 // Function call expression AST node
2013 class CallExpr : public ExprWithoutBlock
2015 std::vector<Attribute> outer_attrs;
2016 std::unique_ptr<Expr> function;
2017 std::vector<std::unique_ptr<Expr> > params;
2018 location_t locus;
2020 public:
2021 Function *fndeclRef;
2023 std::string as_string () const override;
2025 CallExpr (std::unique_ptr<Expr> function_expr,
2026 std::vector<std::unique_ptr<Expr> > function_params,
2027 std::vector<Attribute> outer_attribs, location_t locus)
2028 : outer_attrs (std::move (outer_attribs)),
2029 function (std::move (function_expr)),
2030 params (std::move (function_params)), locus (locus)
2033 // copy constructor requires clone
2034 CallExpr (CallExpr const &other)
2035 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2036 locus (other.locus)
2038 // guard to prevent null dereference (only required if error state)
2039 if (other.function != nullptr)
2040 function = other.function->clone_expr ();
2042 params.reserve (other.params.size ());
2043 for (const auto &e : other.params)
2044 params.push_back (e->clone_expr ());
2047 // Overload assignment operator to clone
2048 CallExpr &operator= (CallExpr const &other)
2050 ExprWithoutBlock::operator= (other);
2051 locus = other.locus;
2052 outer_attrs = other.outer_attrs;
2054 // guard to prevent null dereference (only required if error state)
2055 if (other.function != nullptr)
2056 function = other.function->clone_expr ();
2057 else
2058 function = nullptr;
2060 params.reserve (other.params.size ());
2061 for (const auto &e : other.params)
2062 params.push_back (e->clone_expr ());
2064 return *this;
2067 // move constructors
2068 CallExpr (CallExpr &&other) = default;
2069 CallExpr &operator= (CallExpr &&other) = default;
2071 // Returns whether function call has parameters.
2072 bool has_params () const { return !params.empty (); }
2074 location_t get_locus () const override final { return locus; }
2076 void accept_vis (ASTVisitor &vis) override;
2078 // Invalid if function expr is null, so base stripping on that.
2079 void mark_for_strip () override { function = nullptr; }
2080 bool is_marked_for_strip () const override { return function == nullptr; }
2082 // TODO: this mutable getter seems really dodgy. Think up better way.
2083 const std::vector<std::unique_ptr<Expr> > &get_params () const
2085 return params;
2087 std::vector<std::unique_ptr<Expr> > &get_params () { return params; }
2089 // TODO: is this better? Or is a "vis_block" better?
2090 Expr &get_function_expr ()
2092 rust_assert (function != nullptr);
2093 return *function;
2096 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2097 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2099 void set_outer_attrs (std::vector<Attribute> new_attrs) override
2101 outer_attrs = std::move (new_attrs);
2104 protected:
2105 /* Use covariance to implement clone function as returning this object rather
2106 * than base */
2107 CallExpr *clone_expr_without_block_impl () const override
2109 return new CallExpr (*this);
2113 // Method call expression AST node
2114 class MethodCallExpr : public ExprWithoutBlock
2116 std::vector<Attribute> outer_attrs;
2117 std::unique_ptr<Expr> receiver;
2118 PathExprSegment method_name;
2119 std::vector<std::unique_ptr<Expr> > params;
2120 location_t locus;
2122 public:
2123 std::string as_string () const override;
2125 MethodCallExpr (std::unique_ptr<Expr> call_receiver,
2126 PathExprSegment method_path,
2127 std::vector<std::unique_ptr<Expr> > method_params,
2128 std::vector<Attribute> outer_attribs, location_t locus)
2129 : outer_attrs (std::move (outer_attribs)),
2130 receiver (std::move (call_receiver)),
2131 method_name (std::move (method_path)), params (std::move (method_params)),
2132 locus (locus)
2135 // copy constructor required due to cloning
2136 MethodCallExpr (MethodCallExpr const &other)
2137 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2138 method_name (other.method_name), locus (other.locus)
2140 // guard to prevent null dereference (only required if error state)
2141 if (other.receiver != nullptr)
2142 receiver = other.receiver->clone_expr ();
2144 params.reserve (other.params.size ());
2145 for (const auto &e : other.params)
2146 params.push_back (e->clone_expr ());
2149 // Overload assignment operator to clone receiver object
2150 MethodCallExpr &operator= (MethodCallExpr const &other)
2152 ExprWithoutBlock::operator= (other);
2153 method_name = other.method_name;
2154 locus = other.locus;
2155 outer_attrs = other.outer_attrs;
2157 // guard to prevent null dereference (only required if error state)
2158 if (other.receiver != nullptr)
2159 receiver = other.receiver->clone_expr ();
2160 else
2161 receiver = nullptr;
2163 params.reserve (other.params.size ());
2164 for (const auto &e : other.params)
2165 params.push_back (e->clone_expr ());
2167 return *this;
2170 // move constructors
2171 MethodCallExpr (MethodCallExpr &&other) = default;
2172 MethodCallExpr &operator= (MethodCallExpr &&other) = default;
2174 location_t get_locus () const override final { return locus; }
2176 void accept_vis (ASTVisitor &vis) override;
2178 // Invalid if receiver expr is null, so base stripping on that.
2179 void mark_for_strip () override { receiver = nullptr; }
2180 bool is_marked_for_strip () const override { return receiver == nullptr; }
2182 // TODO: this mutable getter seems really dodgy. Think up better way.
2183 const std::vector<std::unique_ptr<Expr> > &get_params () const
2185 return params;
2187 std::vector<std::unique_ptr<Expr> > &get_params () { return params; }
2189 // TODO: is this better? Or is a "vis_block" better?
2190 Expr &get_receiver_expr ()
2192 rust_assert (receiver != nullptr);
2193 return *receiver;
2196 const PathExprSegment &get_method_name () const { return method_name; }
2197 PathExprSegment &get_method_name () { return method_name; }
2199 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2200 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2202 void set_outer_attrs (std::vector<Attribute> new_attrs) override
2204 outer_attrs = std::move (new_attrs);
2207 protected:
2208 /* Use covariance to implement clone function as returning this object rather
2209 * than base */
2210 MethodCallExpr *clone_expr_without_block_impl () const override
2212 return new MethodCallExpr (*this);
2216 // aka FieldExpression
2217 // Struct or union field access expression AST node
2218 class FieldAccessExpr : public ExprWithoutBlock
2220 std::vector<Attribute> outer_attrs;
2221 std::unique_ptr<Expr> receiver;
2222 Identifier field;
2223 location_t locus;
2225 public:
2226 std::string as_string () const override;
2228 FieldAccessExpr (std::unique_ptr<Expr> field_access_receiver,
2229 Identifier field_name, std::vector<Attribute> outer_attribs,
2230 location_t locus)
2231 : outer_attrs (std::move (outer_attribs)),
2232 receiver (std::move (field_access_receiver)),
2233 field (std::move (field_name)), locus (locus)
2236 // Copy constructor required due to unique_ptr cloning
2237 FieldAccessExpr (FieldAccessExpr const &other)
2238 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2239 field (other.field), locus (other.locus)
2241 // guard to prevent null dereference (only required if error state)
2242 if (other.receiver != nullptr)
2243 receiver = other.receiver->clone_expr ();
2246 // Overload assignment operator to clone unique_ptr
2247 FieldAccessExpr &operator= (FieldAccessExpr const &other)
2249 ExprWithoutBlock::operator= (other);
2250 field = other.field;
2251 locus = other.locus;
2252 outer_attrs = other.outer_attrs;
2254 // guard to prevent null dereference (only required if error state)
2255 if (other.receiver != nullptr)
2256 receiver = other.receiver->clone_expr ();
2257 else
2258 receiver = nullptr;
2260 return *this;
2263 // move constructors
2264 FieldAccessExpr (FieldAccessExpr &&other) = default;
2265 FieldAccessExpr &operator= (FieldAccessExpr &&other) = default;
2267 location_t get_locus () const override final { return locus; }
2269 void accept_vis (ASTVisitor &vis) override;
2271 // Invalid if receiver expr is null, so base stripping on that.
2272 void mark_for_strip () override { receiver = nullptr; }
2273 bool is_marked_for_strip () const override { return receiver == nullptr; }
2275 // TODO: is this better? Or is a "vis_block" better?
2276 Expr &get_receiver_expr ()
2278 rust_assert (receiver != nullptr);
2279 return *receiver;
2282 Identifier get_field_name () const { return field; }
2284 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2285 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2287 void set_outer_attrs (std::vector<Attribute> new_attrs) override
2289 outer_attrs = std::move (new_attrs);
2292 protected:
2293 /* Use covariance to implement clone function as returning this object rather
2294 * than base */
2295 FieldAccessExpr *clone_expr_without_block_impl () const override
2297 return new FieldAccessExpr (*this);
2301 // Closure parameter data structure
2302 struct ClosureParam
2304 private:
2305 std::vector<Attribute> outer_attrs;
2306 std::unique_ptr<Pattern> pattern;
2307 std::unique_ptr<Type> type;
2308 location_t locus;
2310 public:
2311 // Returns whether the type of the parameter has been given.
2312 bool has_type_given () const { return type != nullptr; }
2314 bool has_outer_attrs () const { return !outer_attrs.empty (); }
2316 // Constructor for closure parameter
2317 ClosureParam (std::unique_ptr<Pattern> param_pattern, location_t locus,
2318 std::unique_ptr<Type> param_type = nullptr,
2319 std::vector<Attribute> outer_attrs = {})
2320 : outer_attrs (std::move (outer_attrs)),
2321 pattern (std::move (param_pattern)), type (std::move (param_type)),
2322 locus (locus)
2325 // Copy constructor required due to cloning as a result of unique_ptrs
2326 ClosureParam (ClosureParam const &other) : outer_attrs (other.outer_attrs)
2328 // guard to protect from null pointer dereference
2329 if (other.pattern != nullptr)
2330 pattern = other.pattern->clone_pattern ();
2331 if (other.type != nullptr)
2332 type = other.type->clone_type ();
2335 ~ClosureParam () = default;
2337 // Assignment operator must be overloaded to clone as well
2338 ClosureParam &operator= (ClosureParam const &other)
2340 outer_attrs = other.outer_attrs;
2342 // guard to protect from null pointer dereference
2343 if (other.pattern != nullptr)
2344 pattern = other.pattern->clone_pattern ();
2345 else
2346 pattern = nullptr;
2347 if (other.type != nullptr)
2348 type = other.type->clone_type ();
2349 else
2350 type = nullptr;
2352 return *this;
2355 // move constructors
2356 ClosureParam (ClosureParam &&other) = default;
2357 ClosureParam &operator= (ClosureParam &&other) = default;
2359 // Returns whether closure parameter is in an error state.
2360 bool is_error () const { return pattern == nullptr; }
2362 // Creates an error state closure parameter.
2363 static ClosureParam create_error ()
2365 return ClosureParam (nullptr, UNDEF_LOCATION);
2368 std::string as_string () const;
2370 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2371 std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
2373 Pattern &get_pattern ()
2375 rust_assert (pattern != nullptr);
2376 return *pattern;
2379 Type &get_type ()
2381 rust_assert (has_type_given ());
2382 return *type;
2385 std::unique_ptr<Type> &get_type_ptr ()
2387 rust_assert (has_type_given ());
2388 return type;
2391 location_t get_locus () const { return locus; }
2394 // Base closure definition expression AST node - abstract
2395 class ClosureExpr : public ExprWithoutBlock
2397 std::vector<Attribute> outer_attrs;
2398 bool has_move;
2399 std::vector<ClosureParam> params; // may be empty
2400 location_t locus;
2402 protected:
2403 ClosureExpr (std::vector<ClosureParam> closure_params, bool has_move,
2404 std::vector<Attribute> outer_attribs, location_t locus)
2405 : outer_attrs (std::move (outer_attribs)), has_move (has_move),
2406 params (std::move (closure_params)), locus (locus)
2409 public:
2410 std::string as_string () const override;
2412 location_t get_locus () const override final { return locus; }
2414 // TODO: this mutable getter seems really dodgy. Think up better way.
2415 const std::vector<ClosureParam> &get_params () const { return params; }
2416 std::vector<ClosureParam> &get_params () { return params; }
2418 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2419 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2421 void set_outer_attrs (std::vector<Attribute> new_attrs) override
2423 outer_attrs = std::move (new_attrs);
2426 bool get_has_move () const { return has_move; }
2429 // Represents a non-type-specified closure expression AST node
2430 class ClosureExprInner : public ClosureExpr
2432 std::unique_ptr<Expr> closure_inner;
2434 public:
2435 std::string as_string () const override;
2437 // Constructor for a ClosureExprInner
2438 ClosureExprInner (std::unique_ptr<Expr> closure_inner_expr,
2439 std::vector<ClosureParam> closure_params, location_t locus,
2440 bool is_move = false,
2441 std::vector<Attribute> outer_attribs
2442 = std::vector<Attribute> ())
2443 : ClosureExpr (std::move (closure_params), is_move,
2444 std::move (outer_attribs), locus),
2445 closure_inner (std::move (closure_inner_expr))
2448 // Copy constructor must be defined to allow copying via cloning of unique_ptr
2449 ClosureExprInner (ClosureExprInner const &other) : ClosureExpr (other)
2451 // guard to prevent null dereference (only required if error state)
2452 if (other.closure_inner != nullptr)
2453 closure_inner = other.closure_inner->clone_expr ();
2456 // Overload assignment operator to clone closure_inner
2457 ClosureExprInner &operator= (ClosureExprInner const &other)
2459 ClosureExpr::operator= (other);
2460 // params = other.params;
2461 // has_move = other.has_move;
2462 // outer_attrs = other.outer_attrs;
2464 // guard to prevent null dereference (only required if error state)
2465 if (other.closure_inner != nullptr)
2466 closure_inner = other.closure_inner->clone_expr ();
2467 else
2468 closure_inner = nullptr;
2470 return *this;
2473 // move constructors
2474 ClosureExprInner (ClosureExprInner &&other) = default;
2475 ClosureExprInner &operator= (ClosureExprInner &&other) = default;
2477 void accept_vis (ASTVisitor &vis) override;
2479 // Invalid if inner expr is null, so base stripping on that.
2480 void mark_for_strip () override { closure_inner = nullptr; }
2481 bool is_marked_for_strip () const override
2483 return closure_inner == nullptr;
2486 Expr &get_definition_expr ()
2488 rust_assert (closure_inner != nullptr);
2489 return *closure_inner;
2492 protected:
2493 /* Use covariance to implement clone function as returning this object rather
2494 * than base */
2495 ClosureExprInner *clone_expr_without_block_impl () const override
2497 return new ClosureExprInner (*this);
2501 // A block AST node
2502 class BlockExpr : public ExprWithBlock
2504 std::vector<Attribute> outer_attrs;
2505 std::vector<Attribute> inner_attrs;
2506 std::vector<std::unique_ptr<Stmt> > statements;
2507 std::unique_ptr<Expr> expr;
2508 LoopLabel label;
2509 location_t start_locus;
2510 location_t end_locus;
2511 bool marked_for_strip = false;
2513 public:
2514 std::string as_string () const override;
2516 // Returns whether the block contains statements.
2517 bool has_statements () const { return !statements.empty (); }
2519 // Returns whether the block contains a final expression.
2520 bool has_tail_expr () const { return expr != nullptr; }
2522 BlockExpr (std::vector<std::unique_ptr<Stmt> > block_statements,
2523 std::unique_ptr<Expr> block_expr,
2524 std::vector<Attribute> inner_attribs,
2525 std::vector<Attribute> outer_attribs, LoopLabel label,
2526 location_t start_locus, location_t end_locus)
2527 : outer_attrs (std::move (outer_attribs)),
2528 inner_attrs (std::move (inner_attribs)),
2529 statements (std::move (block_statements)), expr (std::move (block_expr)),
2530 label (std::move (label)), start_locus (start_locus),
2531 end_locus (end_locus)
2534 // Copy constructor with clone
2535 BlockExpr (BlockExpr const &other)
2536 : ExprWithBlock (other), outer_attrs (other.outer_attrs),
2537 inner_attrs (other.inner_attrs), label (other.label),
2538 start_locus (other.start_locus), end_locus (other.end_locus),
2539 marked_for_strip (other.marked_for_strip)
2541 // guard to protect from null pointer dereference
2542 if (other.expr != nullptr)
2543 expr = other.expr->clone_expr ();
2545 statements.reserve (other.statements.size ());
2546 for (const auto &e : other.statements)
2547 statements.push_back (e->clone_stmt ());
2550 // Overloaded assignment operator to clone pointer
2551 BlockExpr &operator= (BlockExpr const &other)
2553 ExprWithBlock::operator= (other);
2554 inner_attrs = other.inner_attrs;
2555 start_locus = other.start_locus;
2556 end_locus = other.end_locus;
2557 marked_for_strip = other.marked_for_strip;
2558 outer_attrs = other.outer_attrs;
2560 // guard to protect from null pointer dereference
2561 if (other.expr != nullptr)
2562 expr = other.expr->clone_expr ();
2563 else
2564 expr = nullptr;
2566 statements.reserve (other.statements.size ());
2567 for (const auto &e : other.statements)
2568 statements.push_back (e->clone_stmt ());
2570 return *this;
2573 // move constructors
2574 BlockExpr (BlockExpr &&other) = default;
2575 BlockExpr &operator= (BlockExpr &&other) = default;
2577 // Unique pointer custom clone function
2578 std::unique_ptr<BlockExpr> clone_block_expr () const
2580 return std::unique_ptr<BlockExpr> (clone_block_expr_impl ());
2583 location_t get_locus () const override final { return start_locus; }
2585 location_t get_start_locus () const { return start_locus; }
2586 location_t get_end_locus () const { return end_locus; }
2588 void accept_vis (ASTVisitor &vis) override;
2590 // Can be completely empty, so have to have a separate flag.
2591 void mark_for_strip () override { marked_for_strip = true; }
2592 bool is_marked_for_strip () const override { return marked_for_strip; }
2594 size_t num_statements () const { return statements.size (); }
2596 // TODO: this mutable getter seems really dodgy. Think up better way.
2597 const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
2598 std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
2600 const std::vector<std::unique_ptr<Stmt> > &get_statements () const
2602 return statements;
2604 std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; }
2606 // TODO: is this better? Or is a "vis_block" better?
2607 Expr &get_tail_expr ()
2609 rust_assert (has_tail_expr ());
2610 return *expr;
2613 std::unique_ptr<Expr> &get_tail_expr_ptr ()
2615 rust_assert (has_tail_expr ());
2616 return expr;
2619 std::unique_ptr<Expr> take_tail_expr ()
2621 rust_assert (has_tail_expr ());
2622 return std::move (expr);
2625 void set_tail_expr (std::unique_ptr<Expr> expr)
2627 this->expr = std::move (expr);
2630 // Removes the tail expression from the block.
2631 void strip_tail_expr () { expr = nullptr; }
2632 // Normalizes a trailing statement without a semicolon to a tail expression.
2633 void normalize_tail_expr ();
2635 void try_convert_last_stmt ();
2637 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2638 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2640 void set_outer_attrs (std::vector<Attribute> new_attrs) override
2642 outer_attrs = std::move (new_attrs);
2645 bool has_label () { return !label.is_error (); }
2646 LoopLabel &get_label () { return label; }
2648 protected:
2649 /* Use covariance to implement clone function as returning this object rather
2650 * than base */
2651 BlockExpr *clone_expr_with_block_impl () const final override
2653 return clone_block_expr_impl ();
2656 /* This is the base method as not an abstract class - not virtual but could be
2657 * in future if required. */
2658 /*virtual*/ BlockExpr *clone_block_expr_impl () const
2660 return new BlockExpr (*this);
2664 // Represents a type-specified closure expression AST node
2665 class ClosureExprInnerTyped : public ClosureExpr
2667 // TODO: spec says typenobounds
2668 std::unique_ptr<Type> return_type;
2669 std::unique_ptr<BlockExpr>
2670 expr; // only used because may be polymorphic in future
2672 public:
2673 std::string as_string () const override;
2675 // Constructor potentially with a move
2676 ClosureExprInnerTyped (std::unique_ptr<Type> closure_return_type,
2677 std::unique_ptr<BlockExpr> closure_expr,
2678 std::vector<ClosureParam> closure_params,
2679 location_t locus, bool is_move = false,
2680 std::vector<Attribute> outer_attribs
2681 = std::vector<Attribute> ())
2682 : ClosureExpr (std::move (closure_params), is_move,
2683 std::move (outer_attribs), locus),
2684 return_type (std::move (closure_return_type)),
2685 expr (std::move (closure_expr))
2688 // Copy constructor requires cloning
2689 ClosureExprInnerTyped (ClosureExprInnerTyped const &other)
2690 : ClosureExpr (other)
2692 // guard to prevent null dereference (only required if error state)
2693 if (other.expr != nullptr)
2694 expr = other.expr->clone_block_expr ();
2695 if (other.return_type != nullptr)
2696 return_type = other.return_type->clone_type ();
2699 // Overload assignment operator to clone unique_ptrs
2700 ClosureExprInnerTyped &operator= (ClosureExprInnerTyped const &other)
2702 ClosureExpr::operator= (other);
2703 // params = other.params;
2704 // has_move = other.has_move;
2705 // outer_attrs = other.outer_attrs;
2707 // guard to prevent null dereference (only required if error state)
2708 if (other.expr != nullptr)
2709 expr = other.expr->clone_block_expr ();
2710 else
2711 expr = nullptr;
2712 if (other.return_type != nullptr)
2713 return_type = other.return_type->clone_type ();
2714 else
2715 return_type = nullptr;
2717 return *this;
2720 // move constructors
2721 ClosureExprInnerTyped (ClosureExprInnerTyped &&other) = default;
2722 ClosureExprInnerTyped &operator= (ClosureExprInnerTyped &&other) = default;
2724 void accept_vis (ASTVisitor &vis) override;
2726 /* Invalid if inner expr is null, so base stripping on that. Technically,
2727 * type should also not be null. */
2728 void mark_for_strip () override { expr = nullptr; }
2729 bool is_marked_for_strip () const override { return expr == nullptr; }
2731 // TODO: is this better? Or is a "vis_block" better?
2732 BlockExpr &get_definition_block ()
2734 rust_assert (expr != nullptr);
2735 return *expr;
2738 // TODO: is this better? Or is a "vis_block" better?
2739 Type &get_return_type ()
2741 rust_assert (return_type != nullptr);
2742 return *return_type;
2745 std::unique_ptr<Type> &get_return_type_ptr ()
2747 rust_assert (return_type != nullptr);
2748 return return_type;
2751 protected:
2752 /* Use covariance to implement clone function as returning this object rather
2753 * than base */
2754 ClosureExprInnerTyped *clone_expr_without_block_impl () const override
2756 return new ClosureExprInnerTyped (*this);
2760 // AST node representing continue expression within loops
2761 class ContinueExpr : public ExprWithoutBlock
2763 std::vector<Attribute> outer_attrs;
2764 Lifetime label;
2765 location_t locus;
2767 // TODO: find another way to store this to save memory?
2768 bool marked_for_strip = false;
2770 public:
2771 std::string as_string () const override;
2773 // Returns true if the continue expr has a label.
2774 bool has_label () const { return !label.is_error (); }
2776 // Constructor for a ContinueExpr with a label.
2777 ContinueExpr (Lifetime label, std::vector<Attribute> outer_attribs,
2778 location_t locus)
2779 : outer_attrs (std::move (outer_attribs)), label (std::move (label)),
2780 locus (locus)
2783 location_t get_locus () const override final { return locus; }
2785 void accept_vis (ASTVisitor &vis) override;
2787 // Can't think of any invalid invariants, so store boolean.
2788 void mark_for_strip () override { marked_for_strip = true; }
2789 bool is_marked_for_strip () const override { return marked_for_strip; }
2791 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2792 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2794 void set_outer_attrs (std::vector<Attribute> new_attrs) override
2796 outer_attrs = std::move (new_attrs);
2799 Lifetime &get_label () { return label; }
2801 protected:
2802 /* Use covariance to implement clone function as returning this object rather
2803 * than base */
2804 ContinueExpr *clone_expr_without_block_impl () const override
2806 return new ContinueExpr (*this);
2809 // TODO: merge "break" and "continue"? Or even merge in "return"?
2811 // AST node representing break expression within loops
2812 class BreakExpr : public ExprWithoutBlock
2814 std::vector<Attribute> outer_attrs;
2815 LoopLabel label;
2816 std::unique_ptr<Expr> break_expr;
2817 location_t locus;
2819 // TODO: find another way to store this to save memory?
2820 bool marked_for_strip = false;
2822 public:
2823 std::string as_string () const override;
2825 // Returns whether the break expression has a label or not.
2826 bool has_label () const { return !label.is_error (); }
2828 /* Returns whether the break expression has an expression used in the break or
2829 * not. */
2830 bool has_break_expr () const { return break_expr != nullptr; }
2832 // Constructor for a break expression
2833 BreakExpr (LoopLabel break_label, std::unique_ptr<Expr> expr_in_break,
2834 std::vector<Attribute> outer_attribs, location_t locus)
2835 : outer_attrs (std::move (outer_attribs)), label (std::move (break_label)),
2836 break_expr (std::move (expr_in_break)), locus (locus)
2839 // Copy constructor defined to use clone for unique pointer
2840 BreakExpr (BreakExpr const &other)
2841 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2842 label (other.label), locus (other.locus),
2843 marked_for_strip (other.marked_for_strip)
2845 // guard to protect from null pointer dereference
2846 if (other.break_expr != nullptr)
2847 break_expr = other.break_expr->clone_expr ();
2850 // Overload assignment operator to clone unique pointer
2851 BreakExpr &operator= (BreakExpr const &other)
2853 ExprWithoutBlock::operator= (other);
2854 label = other.label;
2855 locus = other.locus;
2856 marked_for_strip = other.marked_for_strip;
2857 outer_attrs = other.outer_attrs;
2859 // guard to protect from null pointer dereference
2860 if (other.break_expr != nullptr)
2861 break_expr = other.break_expr->clone_expr ();
2862 else
2863 break_expr = nullptr;
2865 return *this;
2868 // move constructors
2869 BreakExpr (BreakExpr &&other) = default;
2870 BreakExpr &operator= (BreakExpr &&other) = default;
2872 location_t get_locus () const override final { return locus; }
2874 void accept_vis (ASTVisitor &vis) override;
2876 // Can't think of any invalid invariants, so store boolean.
2877 void mark_for_strip () override { marked_for_strip = true; }
2878 bool is_marked_for_strip () const override { return marked_for_strip; }
2880 // TODO: is this better? Or is a "vis_block" better?
2881 Expr &get_break_expr ()
2883 rust_assert (has_break_expr ());
2884 return *break_expr;
2887 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2888 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2890 void set_outer_attrs (std::vector<Attribute> new_attrs) override
2892 outer_attrs = std::move (new_attrs);
2895 LoopLabel &get_label () { return label; }
2897 protected:
2898 /* Use covariance to implement clone function as returning this object rather
2899 * than base */
2900 BreakExpr *clone_expr_without_block_impl () const override
2902 return new BreakExpr (*this);
2906 // Base range expression AST node object - abstract
2907 class RangeExpr : public ExprWithoutBlock
2909 location_t locus;
2911 protected:
2912 // outer attributes not allowed before range expressions
2913 RangeExpr (location_t locus) : locus (locus) {}
2915 public:
2916 location_t get_locus () const override final { return locus; }
2918 std::vector<Attribute> &get_outer_attrs () override final
2920 // RangeExpr cannot have any outer attributes
2921 rust_assert (false);
2924 // should never be called - error if called
2925 void set_outer_attrs (std::vector<Attribute> /* new_attrs */) override
2927 rust_assert (false);
2931 // Range from (inclusive) and to (exclusive) expression AST node object
2932 // aka RangeExpr; constructs a std::ops::Range object
2933 class RangeFromToExpr : public RangeExpr
2935 std::unique_ptr<Expr> from;
2936 std::unique_ptr<Expr> to;
2938 public:
2939 std::string as_string () const override;
2941 RangeFromToExpr (std::unique_ptr<Expr> range_from,
2942 std::unique_ptr<Expr> range_to, location_t locus)
2943 : RangeExpr (locus), from (std::move (range_from)),
2944 to (std::move (range_to))
2947 // Copy constructor with cloning
2948 RangeFromToExpr (RangeFromToExpr const &other) : RangeExpr (other)
2950 // guard to prevent null dereference (only required if error state)
2951 if (other.from != nullptr)
2952 from = other.from->clone_expr ();
2953 if (other.to != nullptr)
2954 to = other.to->clone_expr ();
2957 // Overload assignment operator to clone unique pointers
2958 RangeFromToExpr &operator= (RangeFromToExpr const &other)
2960 RangeExpr::operator= (other);
2962 // guard to prevent null dereference (only required if error state)
2963 if (other.from != nullptr)
2964 from = other.from->clone_expr ();
2965 else
2966 from = nullptr;
2967 if (other.to != nullptr)
2968 to = other.to->clone_expr ();
2969 else
2970 to = nullptr;
2972 return *this;
2975 // move constructors
2976 RangeFromToExpr (RangeFromToExpr &&other) = default;
2977 RangeFromToExpr &operator= (RangeFromToExpr &&other) = default;
2979 void accept_vis (ASTVisitor &vis) override;
2981 // Invalid if either expr is null, so base stripping on that.
2982 void mark_for_strip () override
2984 from = nullptr;
2985 to = nullptr;
2987 bool is_marked_for_strip () const override
2989 return from == nullptr && to == nullptr;
2992 // TODO: is this better? Or is a "vis_block" better?
2993 Expr &get_from_expr ()
2995 rust_assert (from != nullptr);
2996 return *from;
2999 // TODO: is this better? Or is a "vis_block" better?
3000 Expr &get_to_expr ()
3002 rust_assert (to != nullptr);
3003 return *to;
3006 protected:
3007 /* Use covariance to implement clone function as returning this object rather
3008 * than base */
3009 RangeFromToExpr *clone_expr_without_block_impl () const override
3011 return new RangeFromToExpr (*this);
3015 // Range from (inclusive) expression AST node object
3016 // constructs a std::ops::RangeFrom object
3017 class RangeFromExpr : public RangeExpr
3019 std::unique_ptr<Expr> from;
3021 public:
3022 std::string as_string () const override;
3024 RangeFromExpr (std::unique_ptr<Expr> range_from, location_t locus)
3025 : RangeExpr (locus), from (std::move (range_from))
3028 // Copy constructor with clone
3029 RangeFromExpr (RangeFromExpr const &other) : RangeExpr (other)
3031 // guard to prevent null dereference (only required if error state)
3032 if (other.from != nullptr)
3033 from = other.from->clone_expr ();
3036 // Overload assignment operator to clone unique_ptr
3037 RangeFromExpr &operator= (RangeFromExpr const &other)
3039 RangeExpr::operator= (other);
3041 // guard to prevent null dereference (only required if error state)
3042 if (other.from != nullptr)
3043 from = other.from->clone_expr ();
3044 else
3045 from = nullptr;
3047 return *this;
3050 // move constructors
3051 RangeFromExpr (RangeFromExpr &&other) = default;
3052 RangeFromExpr &operator= (RangeFromExpr &&other) = default;
3054 void accept_vis (ASTVisitor &vis) override;
3056 // Invalid if expr is null, so base stripping on that.
3057 void mark_for_strip () override { from = nullptr; }
3058 bool is_marked_for_strip () const override { return from == nullptr; }
3060 // TODO: is this better? Or is a "vis_block" better?
3061 Expr &get_from_expr ()
3063 rust_assert (from != nullptr);
3064 return *from;
3067 protected:
3068 /* Use covariance to implement clone function as returning this object rather
3069 * than base */
3070 RangeFromExpr *clone_expr_without_block_impl () const override
3072 return new RangeFromExpr (*this);
3076 // Range to (exclusive) expression AST node object
3077 // constructs a std::ops::RangeTo object
3078 class RangeToExpr : public RangeExpr
3080 std::unique_ptr<Expr> to;
3082 public:
3083 std::string as_string () const override;
3085 // outer attributes not allowed
3086 RangeToExpr (std::unique_ptr<Expr> range_to, location_t locus)
3087 : RangeExpr (locus), to (std::move (range_to))
3090 // Copy constructor with clone
3091 RangeToExpr (RangeToExpr const &other) : RangeExpr (other)
3093 // guard to prevent null dereference (only required if error state)
3094 if (other.to != nullptr)
3095 to = other.to->clone_expr ();
3098 // Overload assignment operator to clone unique_ptr
3099 RangeToExpr &operator= (RangeToExpr const &other)
3101 RangeExpr::operator= (other);
3103 // guard to prevent null dereference (only required if error state)
3104 if (other.to != nullptr)
3105 to = other.to->clone_expr ();
3106 else
3107 to = nullptr;
3109 return *this;
3112 // move constructors
3113 RangeToExpr (RangeToExpr &&other) = default;
3114 RangeToExpr &operator= (RangeToExpr &&other) = default;
3116 void accept_vis (ASTVisitor &vis) override;
3118 // Invalid if expr is null, so base stripping on that.
3119 void mark_for_strip () override { to = nullptr; }
3120 bool is_marked_for_strip () const override { return to == nullptr; }
3122 // TODO: is this better? Or is a "vis_block" better?
3123 Expr &get_to_expr ()
3125 rust_assert (to != nullptr);
3126 return *to;
3129 protected:
3130 /* Use covariance to implement clone function as returning this object rather
3131 * than base */
3132 RangeToExpr *clone_expr_without_block_impl () const override
3134 return new RangeToExpr (*this);
3138 // Full range expression AST node object
3139 // constructs a std::ops::RangeFull object
3140 class RangeFullExpr : public RangeExpr
3142 // TODO: find another way to store this to save memory?
3143 bool marked_for_strip = false;
3145 public:
3146 std::string as_string () const override;
3148 RangeFullExpr (location_t locus) : RangeExpr (locus) {}
3149 // outer attributes not allowed
3151 void accept_vis (ASTVisitor &vis) override;
3153 // Can't think of any invalid invariants, so store boolean.
3154 void mark_for_strip () override { marked_for_strip = true; }
3155 bool is_marked_for_strip () const override { return marked_for_strip; }
3157 protected:
3158 /* Use covariance to implement clone function as returning this object rather
3159 * than base */
3160 RangeFullExpr *clone_expr_without_block_impl () const override
3162 return new RangeFullExpr (*this);
3166 // Range from (inclusive) and to (inclusive) expression AST node object
3167 // aka RangeInclusiveExpr; constructs a std::ops::RangeInclusive object
3168 class RangeFromToInclExpr : public RangeExpr
3170 std::unique_ptr<Expr> from;
3171 std::unique_ptr<Expr> to;
3173 public:
3174 std::string as_string () const override;
3176 RangeFromToInclExpr (std::unique_ptr<Expr> range_from,
3177 std::unique_ptr<Expr> range_to, location_t locus)
3178 : RangeExpr (locus), from (std::move (range_from)),
3179 to (std::move (range_to))
3181 // outer attributes not allowed
3183 // Copy constructor with clone
3184 RangeFromToInclExpr (RangeFromToInclExpr const &other) : RangeExpr (other)
3186 // guard to prevent null dereference (only required if error state)
3187 if (other.from != nullptr)
3188 from = other.from->clone_expr ();
3189 if (other.to != nullptr)
3190 to = other.to->clone_expr ();
3193 // Overload assignment operator to use clone
3194 RangeFromToInclExpr &operator= (RangeFromToInclExpr const &other)
3196 RangeExpr::operator= (other);
3198 // guard to prevent null dereference (only required if error state)
3199 if (other.from != nullptr)
3200 from = other.from->clone_expr ();
3201 else
3202 from = nullptr;
3203 if (other.to != nullptr)
3204 to = other.to->clone_expr ();
3205 else
3206 to = nullptr;
3208 return *this;
3211 // move constructors
3212 RangeFromToInclExpr (RangeFromToInclExpr &&other) = default;
3213 RangeFromToInclExpr &operator= (RangeFromToInclExpr &&other) = default;
3215 void accept_vis (ASTVisitor &vis) override;
3217 // Invalid if either expr is null, so base stripping on that.
3218 void mark_for_strip () override
3220 from = nullptr;
3221 to = nullptr;
3223 bool is_marked_for_strip () const override
3225 return from == nullptr && to == nullptr;
3228 // TODO: is this better? Or is a "vis_block" better?
3229 Expr &get_from_expr ()
3231 rust_assert (from != nullptr);
3232 return *from;
3235 // TODO: is this better? Or is a "vis_block" better?
3236 Expr &get_to_expr ()
3238 rust_assert (to != nullptr);
3239 return *to;
3242 protected:
3243 /* Use covariance to implement clone function as returning this object rather
3244 * than base */
3245 RangeFromToInclExpr *clone_expr_without_block_impl () const override
3247 return new RangeFromToInclExpr (*this);
3251 // Range to (inclusive) expression AST node object
3252 // aka RangeToInclusiveExpr; constructs a std::ops::RangeToInclusive object
3253 class RangeToInclExpr : public RangeExpr
3255 std::unique_ptr<Expr> to;
3257 public:
3258 std::string as_string () const override;
3260 RangeToInclExpr (std::unique_ptr<Expr> range_to, location_t locus)
3261 : RangeExpr (locus), to (std::move (range_to))
3263 // outer attributes not allowed
3265 // Copy constructor with clone
3266 RangeToInclExpr (RangeToInclExpr const &other) : RangeExpr (other)
3268 // guard to prevent null dereference (only required if error state)
3269 if (other.to != nullptr)
3270 to = other.to->clone_expr ();
3273 // Overload assignment operator to clone pointer
3274 RangeToInclExpr &operator= (RangeToInclExpr const &other)
3276 RangeExpr::operator= (other);
3278 // guard to prevent null dereference (only required if error state)
3279 if (other.to != nullptr)
3280 to = other.to->clone_expr ();
3281 else
3282 to = nullptr;
3284 return *this;
3287 // move constructors
3288 RangeToInclExpr (RangeToInclExpr &&other) = default;
3289 RangeToInclExpr &operator= (RangeToInclExpr &&other) = default;
3291 void accept_vis (ASTVisitor &vis) override;
3293 // Invalid if expr is null, so base stripping on that.
3294 void mark_for_strip () override { to = nullptr; }
3295 bool is_marked_for_strip () const override { return to == nullptr; }
3297 // TODO: is this better? Or is a "vis_block" better?
3298 Expr &get_to_expr ()
3300 rust_assert (to != nullptr);
3301 return *to;
3304 protected:
3305 /* Use covariance to implement clone function as returning this object rather
3306 * than base */
3307 RangeToInclExpr *clone_expr_without_block_impl () const override
3309 return new RangeToInclExpr (*this);
3313 // Return expression AST node representation
3314 class ReturnExpr : public ExprWithoutBlock
3316 std::vector<Attribute> outer_attrs;
3317 std::unique_ptr<Expr> return_expr;
3318 location_t locus;
3320 // TODO: find another way to store this to save memory?
3321 bool marked_for_strip = false;
3323 public:
3324 std::string as_string () const override;
3326 /* Returns whether the object has an expression returned (i.e. not void return
3327 * type). */
3328 bool has_returned_expr () const { return return_expr != nullptr; }
3330 // Constructor for ReturnExpr.
3331 ReturnExpr (std::unique_ptr<Expr> returned_expr,
3332 std::vector<Attribute> outer_attribs, location_t locus)
3333 : outer_attrs (std::move (outer_attribs)),
3334 return_expr (std::move (returned_expr)), locus (locus)
3337 // Copy constructor with clone
3338 ReturnExpr (ReturnExpr const &other)
3339 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
3340 locus (other.locus), marked_for_strip (other.marked_for_strip)
3342 // guard to protect from null pointer dereference
3343 if (other.return_expr != nullptr)
3344 return_expr = other.return_expr->clone_expr ();
3347 // Overloaded assignment operator to clone return_expr pointer
3348 ReturnExpr &operator= (ReturnExpr const &other)
3350 ExprWithoutBlock::operator= (other);
3351 locus = other.locus;
3352 marked_for_strip = other.marked_for_strip;
3353 outer_attrs = other.outer_attrs;
3355 // guard to protect from null pointer dereference
3356 if (other.return_expr != nullptr)
3357 return_expr = other.return_expr->clone_expr ();
3358 else
3359 return_expr = nullptr;
3361 return *this;
3364 // move constructors
3365 ReturnExpr (ReturnExpr &&other) = default;
3366 ReturnExpr &operator= (ReturnExpr &&other) = default;
3368 location_t get_locus () const override final { return locus; }
3370 void accept_vis (ASTVisitor &vis) override;
3372 // Can't think of any invalid invariants, so store boolean.
3373 void mark_for_strip () override { marked_for_strip = true; }
3374 bool is_marked_for_strip () const override { return marked_for_strip; }
3376 // TODO: is this better? Or is a "vis_block" better?
3377 Expr &get_returned_expr ()
3379 rust_assert (return_expr != nullptr);
3380 return *return_expr;
3383 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3384 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3386 void set_outer_attrs (std::vector<Attribute> new_attrs) override
3388 outer_attrs = std::move (new_attrs);
3391 protected:
3392 /* Use covariance to implement clone function as returning this object rather
3393 * than base */
3394 ReturnExpr *clone_expr_without_block_impl () const override
3396 return new ReturnExpr (*this);
3400 // Forward decl - defined in rust-macro.h
3401 class MacroInvocation;
3403 // An unsafe block AST node
3404 class UnsafeBlockExpr : public ExprWithBlock
3406 std::vector<Attribute> outer_attrs;
3407 // Or just have it extend BlockExpr
3408 std::unique_ptr<BlockExpr> expr;
3409 location_t locus;
3411 public:
3412 std::string as_string () const override;
3414 UnsafeBlockExpr (std::unique_ptr<BlockExpr> block_expr,
3415 std::vector<Attribute> outer_attribs, location_t locus)
3416 : outer_attrs (std::move (outer_attribs)), expr (std::move (block_expr)),
3417 locus (locus)
3420 // Copy constructor with clone
3421 UnsafeBlockExpr (UnsafeBlockExpr const &other)
3422 : ExprWithBlock (other), outer_attrs (other.outer_attrs),
3423 locus (other.locus)
3425 // guard to prevent null dereference (only required if error state)
3426 if (other.expr != nullptr)
3427 expr = other.expr->clone_block_expr ();
3430 // Overloaded assignment operator to clone
3431 UnsafeBlockExpr &operator= (UnsafeBlockExpr const &other)
3433 ExprWithBlock::operator= (other);
3434 locus = other.locus;
3435 outer_attrs = other.outer_attrs;
3437 // guard to prevent null dereference (only required if error state)
3438 if (other.expr != nullptr)
3439 expr = other.expr->clone_block_expr ();
3440 else
3441 expr = nullptr;
3443 return *this;
3446 // move constructors
3447 UnsafeBlockExpr (UnsafeBlockExpr &&other) = default;
3448 UnsafeBlockExpr &operator= (UnsafeBlockExpr &&other) = default;
3450 location_t get_locus () const override final { return locus; }
3452 void accept_vis (ASTVisitor &vis) override;
3454 // Invalid if block is null, so base stripping on that.
3455 void mark_for_strip () override { expr = nullptr; }
3456 bool is_marked_for_strip () const override { return expr == nullptr; }
3458 // TODO: is this better? Or is a "vis_block" better?
3459 BlockExpr &get_block_expr ()
3461 rust_assert (expr != nullptr);
3462 return *expr;
3465 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3466 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3468 void set_outer_attrs (std::vector<Attribute> new_attrs) override
3470 outer_attrs = std::move (new_attrs);
3473 protected:
3474 /* Use covariance to implement clone function as returning this object rather
3475 * than base */
3476 UnsafeBlockExpr *clone_expr_with_block_impl () const override
3478 return new UnsafeBlockExpr (*this);
3482 // Base loop expression AST node - aka LoopExpr
3483 class BaseLoopExpr : public ExprWithBlock
3485 protected:
3486 // protected to allow subclasses better use of them
3487 std::vector<Attribute> outer_attrs;
3488 LoopLabel loop_label;
3489 std::unique_ptr<BlockExpr> loop_block;
3491 private:
3492 location_t locus;
3494 protected:
3495 // Constructor for BaseLoopExpr
3496 BaseLoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus,
3497 LoopLabel loop_label = LoopLabel::error (),
3498 std::vector<Attribute> outer_attribs
3499 = std::vector<Attribute> ())
3500 : outer_attrs (std::move (outer_attribs)),
3501 loop_label (std::move (loop_label)), loop_block (std::move (loop_block)),
3502 locus (locus)
3505 // Copy constructor for BaseLoopExpr with clone
3506 BaseLoopExpr (BaseLoopExpr const &other)
3507 : ExprWithBlock (other), outer_attrs (other.outer_attrs),
3508 loop_label (other.loop_label), locus (other.locus)
3510 // guard to prevent null dereference (only required if error state)
3511 if (other.loop_block != nullptr)
3512 loop_block = other.loop_block->clone_block_expr ();
3515 // Overloaded assignment operator to clone
3516 BaseLoopExpr &operator= (BaseLoopExpr const &other)
3518 ExprWithBlock::operator= (other);
3519 loop_label = other.loop_label;
3520 locus = other.locus;
3521 outer_attrs = other.outer_attrs;
3523 // guard to prevent null dereference (only required if error state)
3524 if (other.loop_block != nullptr)
3525 loop_block = other.loop_block->clone_block_expr ();
3526 else
3527 loop_block = nullptr;
3529 return *this;
3532 // move constructors
3533 BaseLoopExpr (BaseLoopExpr &&other) = default;
3534 BaseLoopExpr &operator= (BaseLoopExpr &&other) = default;
3536 public:
3537 bool has_loop_label () const { return !loop_label.is_error (); }
3539 LoopLabel &get_loop_label () { return loop_label; }
3541 location_t get_locus () const override final { return locus; }
3543 // Invalid if loop block is null, so base stripping on that.
3544 void mark_for_strip () override { loop_block = nullptr; }
3545 bool is_marked_for_strip () const override { return loop_block == nullptr; }
3547 // TODO: is this better? Or is a "vis_block" better?
3548 BlockExpr &get_loop_block ()
3550 rust_assert (loop_block != nullptr);
3551 return *loop_block;
3554 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3555 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3557 void set_outer_attrs (std::vector<Attribute> new_attrs) override
3559 outer_attrs = std::move (new_attrs);
3563 // 'Loop' expression (i.e. the infinite loop) AST node
3564 class LoopExpr : public BaseLoopExpr
3566 public:
3567 std::string as_string () const override;
3569 // Constructor for LoopExpr
3570 LoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus,
3571 LoopLabel loop_label = LoopLabel::error (),
3572 std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
3573 : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
3574 std::move (outer_attribs))
3577 void accept_vis (ASTVisitor &vis) override;
3579 protected:
3580 /* Use covariance to implement clone function as returning this object rather
3581 * than base */
3582 LoopExpr *clone_expr_with_block_impl () const override
3584 return new LoopExpr (*this);
3588 // While loop expression AST node (predicate loop)
3589 class WhileLoopExpr : public BaseLoopExpr
3591 std::unique_ptr<Expr> condition;
3593 public:
3594 std::string as_string () const override;
3596 // Constructor for while loop with loop label
3597 WhileLoopExpr (std::unique_ptr<Expr> loop_condition,
3598 std::unique_ptr<BlockExpr> loop_block, location_t locus,
3599 LoopLabel loop_label = LoopLabel::error (),
3600 std::vector<Attribute> outer_attribs
3601 = std::vector<Attribute> ())
3602 : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
3603 std::move (outer_attribs)),
3604 condition (std::move (loop_condition))
3607 // Copy constructor with clone
3608 WhileLoopExpr (WhileLoopExpr const &other)
3609 : BaseLoopExpr (other), condition (other.condition->clone_expr ())
3612 // Overloaded assignment operator to clone
3613 WhileLoopExpr &operator= (WhileLoopExpr const &other)
3615 BaseLoopExpr::operator= (other);
3616 condition = other.condition->clone_expr ();
3617 // loop_block = other.loop_block->clone_block_expr();
3618 // loop_label = other.loop_label;
3619 // outer_attrs = other.outer_attrs;
3621 return *this;
3624 // move constructors
3625 WhileLoopExpr (WhileLoopExpr &&other) = default;
3626 WhileLoopExpr &operator= (WhileLoopExpr &&other) = default;
3628 void accept_vis (ASTVisitor &vis) override;
3630 // TODO: is this better? Or is a "vis_block" better?
3631 Expr &get_predicate_expr ()
3633 rust_assert (condition != nullptr);
3634 return *condition;
3637 protected:
3638 /* Use covariance to implement clone function as returning this object rather
3639 * than base */
3640 WhileLoopExpr *clone_expr_with_block_impl () const override
3642 return new WhileLoopExpr (*this);
3646 // While let loop expression AST node (predicate pattern loop)
3647 class WhileLetLoopExpr : public BaseLoopExpr
3649 // MatchArmPatterns patterns;
3650 std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined
3651 std::unique_ptr<Expr> scrutinee;
3653 public:
3654 std::string as_string () const override;
3656 // Constructor with a loop label
3657 WhileLetLoopExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
3658 std::unique_ptr<Expr> scrutinee,
3659 std::unique_ptr<BlockExpr> loop_block, location_t locus,
3660 LoopLabel loop_label = LoopLabel::error (),
3661 std::vector<Attribute> outer_attribs
3662 = std::vector<Attribute> ())
3663 : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
3664 std::move (outer_attribs)),
3665 match_arm_patterns (std::move (match_arm_patterns)),
3666 scrutinee (std::move (scrutinee))
3669 // Copy constructor with clone
3670 WhileLetLoopExpr (WhileLetLoopExpr const &other)
3671 : BaseLoopExpr (other),
3672 /*match_arm_patterns(other.match_arm_patterns),*/ scrutinee (
3673 other.scrutinee->clone_expr ())
3675 match_arm_patterns.reserve (other.match_arm_patterns.size ());
3676 for (const auto &e : other.match_arm_patterns)
3677 match_arm_patterns.push_back (e->clone_pattern ());
3680 // Overloaded assignment operator to clone pointers
3681 WhileLetLoopExpr &operator= (WhileLetLoopExpr const &other)
3683 BaseLoopExpr::operator= (other);
3684 // match_arm_patterns = other.match_arm_patterns;
3685 scrutinee = other.scrutinee->clone_expr ();
3686 // loop_block = other.loop_block->clone_block_expr();
3687 // loop_label = other.loop_label;
3688 // outer_attrs = other.outer_attrs;
3690 match_arm_patterns.reserve (other.match_arm_patterns.size ());
3691 for (const auto &e : other.match_arm_patterns)
3692 match_arm_patterns.push_back (e->clone_pattern ());
3694 return *this;
3697 // move constructors
3698 WhileLetLoopExpr (WhileLetLoopExpr &&other) = default;
3699 WhileLetLoopExpr &operator= (WhileLetLoopExpr &&other) = default;
3701 void accept_vis (ASTVisitor &vis) override;
3703 // TODO: is this better? Or is a "vis_block" better?
3704 Expr &get_scrutinee_expr ()
3706 rust_assert (scrutinee != nullptr);
3707 return *scrutinee;
3710 // TODO: this mutable getter seems really dodgy. Think up better way.
3711 const std::vector<std::unique_ptr<Pattern> > &get_patterns () const
3713 return match_arm_patterns;
3715 std::vector<std::unique_ptr<Pattern> > &get_patterns ()
3717 return match_arm_patterns;
3720 protected:
3721 /* Use covariance to implement clone function as returning this object rather
3722 * than base */
3723 WhileLetLoopExpr *clone_expr_with_block_impl () const override
3725 return new WhileLetLoopExpr (*this);
3729 // For loop expression AST node (iterator loop)
3730 class ForLoopExpr : public BaseLoopExpr
3732 std::unique_ptr<Pattern> pattern;
3733 std::unique_ptr<Expr> iterator_expr;
3735 public:
3736 std::string as_string () const override;
3738 // Constructor with loop label
3739 ForLoopExpr (std::unique_ptr<Pattern> loop_pattern,
3740 std::unique_ptr<Expr> iterator_expr,
3741 std::unique_ptr<BlockExpr> loop_body, location_t locus,
3742 LoopLabel loop_label = LoopLabel::error (),
3743 std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
3744 : BaseLoopExpr (std::move (loop_body), locus, std::move (loop_label),
3745 std::move (outer_attribs)),
3746 pattern (std::move (loop_pattern)),
3747 iterator_expr (std::move (iterator_expr))
3750 // Copy constructor with clone
3751 ForLoopExpr (ForLoopExpr const &other)
3752 : BaseLoopExpr (other), pattern (other.pattern->clone_pattern ()),
3753 iterator_expr (other.iterator_expr->clone_expr ())
3756 // Overloaded assignment operator to clone
3757 ForLoopExpr &operator= (ForLoopExpr const &other)
3759 BaseLoopExpr::operator= (other);
3760 pattern = other.pattern->clone_pattern ();
3761 iterator_expr = other.iterator_expr->clone_expr ();
3762 /*loop_block = other.loop_block->clone_block_expr();
3763 loop_label = other.loop_label;
3764 outer_attrs = other.outer_attrs;*/
3766 return *this;
3769 // move constructors
3770 ForLoopExpr (ForLoopExpr &&other) = default;
3771 ForLoopExpr &operator= (ForLoopExpr &&other) = default;
3773 void accept_vis (ASTVisitor &vis) override;
3775 // TODO: is this better? Or is a "vis_block" better?
3776 Expr &get_iterator_expr ()
3778 rust_assert (iterator_expr != nullptr);
3779 return *iterator_expr;
3782 // TODO: is this better? Or is a "vis_block" better?
3783 Pattern &get_pattern ()
3785 rust_assert (pattern != nullptr);
3786 return *pattern;
3789 protected:
3790 /* Use covariance to implement clone function as returning this object rather
3791 * than base */
3792 ForLoopExpr *clone_expr_with_block_impl () const override
3794 return new ForLoopExpr (*this);
3798 // forward decl for IfExpr
3799 class IfLetExpr;
3801 // Base if expression with no "else" or "if let" AST node
3802 class IfExpr : public ExprWithBlock
3804 std::vector<Attribute> outer_attrs;
3805 std::unique_ptr<Expr> condition;
3806 std::unique_ptr<BlockExpr> if_block;
3807 location_t locus;
3809 public:
3810 std::string as_string () const override;
3812 IfExpr (std::unique_ptr<Expr> condition, std::unique_ptr<BlockExpr> if_block,
3813 std::vector<Attribute> outer_attrs, location_t locus)
3814 : outer_attrs (std::move (outer_attrs)), condition (std::move (condition)),
3815 if_block (std::move (if_block)), locus (locus)
3817 // outer attributes are never allowed on IfExprs
3819 // Copy constructor with clone
3820 IfExpr (IfExpr const &other)
3821 : ExprWithBlock (other), outer_attrs (other.outer_attrs),
3822 locus (other.locus)
3824 // guard to prevent null dereference (only required if error state)
3825 if (other.condition != nullptr)
3826 condition = other.condition->clone_expr ();
3827 if (other.if_block != nullptr)
3828 if_block = other.if_block->clone_block_expr ();
3831 // Overloaded assignment operator to clone expressions
3832 IfExpr &operator= (IfExpr const &other)
3834 ExprWithBlock::operator= (other);
3835 outer_attrs = other.outer_attrs;
3836 locus = other.locus;
3838 // guard to prevent null dereference (only required if error state)
3839 if (other.condition != nullptr)
3840 condition = other.condition->clone_expr ();
3841 else
3842 condition = nullptr;
3843 if (other.if_block != nullptr)
3844 if_block = other.if_block->clone_block_expr ();
3845 else
3846 if_block = nullptr;
3848 return *this;
3851 // move constructors
3852 IfExpr (IfExpr &&other) = default;
3853 IfExpr &operator= (IfExpr &&other) = default;
3855 // Unique pointer custom clone function
3856 std::unique_ptr<IfExpr> clone_if_expr () const
3858 return std::unique_ptr<IfExpr> (clone_if_expr_impl ());
3861 /* Note that multiple "else if"s are handled via nested ASTs rather than a
3862 * vector of else ifs - i.e. not like a switch statement. TODO - is this a
3863 * better approach? or does it not parse correctly and have downsides? */
3865 location_t get_locus () const override final { return locus; }
3867 void accept_vis (ASTVisitor &vis) override;
3869 void vis_if_condition (ASTVisitor &vis) { condition->accept_vis (vis); }
3870 void vis_if_block (ASTVisitor &vis) { if_block->accept_vis (vis); }
3872 // TODO: is this better? Or is a "vis_block" better?
3873 Expr &get_condition_expr ()
3875 rust_assert (condition != nullptr);
3876 return *condition;
3879 std::unique_ptr<Expr> &get_condition_expr_ptr ()
3881 rust_assert (condition != nullptr);
3882 return condition;
3885 // TODO: is this better? Or is a "vis_block" better?
3886 BlockExpr &get_if_block ()
3888 rust_assert (if_block != nullptr);
3889 return *if_block;
3892 // Invalid if if block or condition is null, so base stripping on that.
3893 void mark_for_strip () override
3895 if_block = nullptr;
3896 condition = nullptr;
3898 bool is_marked_for_strip () const override
3900 return if_block == nullptr && condition == nullptr;
3903 void set_outer_attrs (std::vector<Attribute> new_attrs) override
3905 outer_attrs = std::move (new_attrs);
3908 // TODO: this mutable getter seems really dodgy. Think up better way.
3909 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3910 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3912 protected:
3913 // Base clone function but still concrete as concrete base class
3914 virtual IfExpr *clone_if_expr_impl () const { return new IfExpr (*this); }
3916 /* Use covariance to implement clone function as returning this object rather
3917 * than base */
3918 IfExpr *clone_expr_with_block_impl () const final override
3920 return clone_if_expr_impl ();
3924 // If expression with an ending "else" expression AST node (trailing)
3925 class IfExprConseqElse : public IfExpr
3927 std::unique_ptr<ExprWithBlock> else_block;
3929 public:
3930 std::string as_string () const override;
3932 IfExprConseqElse (std::unique_ptr<Expr> condition,
3933 std::unique_ptr<BlockExpr> if_block,
3934 std::unique_ptr<ExprWithBlock> else_block,
3935 std::vector<Attribute> outer_attrs, location_t locus)
3936 : IfExpr (std::move (condition), std::move (if_block),
3937 std::move (outer_attrs), locus),
3938 else_block (std::move (else_block))
3940 // again, outer attributes not allowed
3942 // Copy constructor with clone
3943 IfExprConseqElse (IfExprConseqElse const &other)
3944 : IfExpr (other), else_block (other.else_block->clone_expr_with_block ())
3947 // Overloaded assignment operator with cloning
3948 IfExprConseqElse &operator= (IfExprConseqElse const &other)
3950 IfExpr::operator= (other);
3951 // condition = other.condition->clone_expr();
3952 // if_block = other.if_block->clone_block_expr();
3953 else_block = other.else_block->clone_expr_with_block ();
3955 return *this;
3958 // move constructors
3959 IfExprConseqElse (IfExprConseqElse &&other) = default;
3960 IfExprConseqElse &operator= (IfExprConseqElse &&other) = default;
3962 void accept_vis (ASTVisitor &vis) override;
3964 void vis_else_block (ASTVisitor &vis) { else_block->accept_vis (vis); }
3966 // TODO: is this better? Or is a "vis_block" better?
3967 ExprWithBlock &get_else_block ()
3969 rust_assert (else_block != nullptr);
3970 return *else_block;
3973 protected:
3974 /* Use covariance to implement clone function as returning this object rather
3975 * than base */
3976 IfExprConseqElse *clone_if_expr_impl () const override
3978 return new IfExprConseqElse (*this);
3982 // Basic "if let" expression AST node with no else
3983 class IfLetExpr : public ExprWithBlock
3985 std::vector<Attribute> outer_attrs;
3986 std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined
3987 std::unique_ptr<Expr> value;
3988 std::unique_ptr<BlockExpr> if_block;
3989 location_t locus;
3991 public:
3992 std::string as_string () const override;
3994 IfLetExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
3995 std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block,
3996 std::vector<Attribute> outer_attrs, location_t locus)
3997 : outer_attrs (std::move (outer_attrs)),
3998 match_arm_patterns (std::move (match_arm_patterns)),
3999 value (std::move (value)), if_block (std::move (if_block)), locus (locus)
4002 // copy constructor with clone
4003 IfLetExpr (IfLetExpr const &other)
4004 : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4005 locus (other.locus)
4007 // guard to prevent null dereference (only required if error state)
4008 if (other.value != nullptr)
4009 value = other.value->clone_expr ();
4010 if (other.if_block != nullptr)
4011 if_block = other.if_block->clone_block_expr ();
4013 match_arm_patterns.reserve (other.match_arm_patterns.size ());
4014 for (const auto &e : other.match_arm_patterns)
4015 match_arm_patterns.push_back (e->clone_pattern ());
4018 // overload assignment operator to clone
4019 IfLetExpr &operator= (IfLetExpr const &other)
4021 ExprWithBlock::operator= (other);
4022 outer_attrs = other.outer_attrs;
4023 locus = other.locus;
4025 // guard to prevent null dereference (only required if error state)
4026 if (other.value != nullptr)
4027 value = other.value->clone_expr ();
4028 else
4029 value = nullptr;
4030 if (other.if_block != nullptr)
4031 if_block = other.if_block->clone_block_expr ();
4032 else
4033 if_block = nullptr;
4035 match_arm_patterns.reserve (other.match_arm_patterns.size ());
4036 for (const auto &e : other.match_arm_patterns)
4037 match_arm_patterns.push_back (e->clone_pattern ());
4039 return *this;
4042 // move constructors
4043 IfLetExpr (IfLetExpr &&other) = default;
4044 IfLetExpr &operator= (IfLetExpr &&other) = default;
4046 // Unique pointer custom clone function
4047 std::unique_ptr<IfLetExpr> clone_if_let_expr () const
4049 return std::unique_ptr<IfLetExpr> (clone_if_let_expr_impl ());
4052 location_t get_locus () const override final { return locus; }
4054 void accept_vis (ASTVisitor &vis) override;
4056 // Invalid if block or value is null, so base stripping on that.
4057 void mark_for_strip () override
4059 if_block = nullptr;
4060 value = nullptr;
4062 bool is_marked_for_strip () const override
4064 return if_block == nullptr && value == nullptr;
4067 // TODO: is this better? Or is a "vis_block" better?
4068 Expr &get_value_expr ()
4070 rust_assert (value != nullptr);
4071 return *value;
4074 std::unique_ptr<Expr> &get_value_expr_ptr ()
4076 rust_assert (value != nullptr);
4077 return value;
4080 // TODO: is this better? Or is a "vis_block" better?
4081 BlockExpr &get_if_block ()
4083 rust_assert (if_block != nullptr);
4084 return *if_block;
4087 // TODO: this mutable getter seems really dodgy. Think up better way.
4088 const std::vector<std::unique_ptr<Pattern> > &get_patterns () const
4090 return match_arm_patterns;
4092 std::vector<std::unique_ptr<Pattern> > &get_patterns ()
4094 return match_arm_patterns;
4097 void set_outer_attrs (std::vector<Attribute> new_attrs) override
4099 outer_attrs = std::move (new_attrs);
4102 // TODO: this mutable getter seems really dodgy. Think up better way.
4103 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4104 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4106 protected:
4107 /* Use covariance to implement clone function as returning this object rather
4108 * than base (or rather this or any derived object) */
4109 IfLetExpr *clone_expr_with_block_impl () const final override
4111 return clone_if_let_expr_impl ();
4114 // Base clone function but still concrete as concrete base class
4115 virtual IfLetExpr *clone_if_let_expr_impl () const
4117 return new IfLetExpr (*this);
4121 /* AST node representing "if let" expression with an "else" expression at the
4122 * end */
4123 class IfLetExprConseqElse : public IfLetExpr
4125 std::unique_ptr<ExprWithBlock> else_block;
4127 public:
4128 std::string as_string () const override;
4130 IfLetExprConseqElse (
4131 std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
4132 std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block,
4133 std::unique_ptr<ExprWithBlock> else_block,
4134 std::vector<Attribute> outer_attrs, location_t locus)
4135 : IfLetExpr (std::move (match_arm_patterns), std::move (value),
4136 std::move (if_block), std::move (outer_attrs), locus),
4137 else_block (std::move (else_block))
4139 // outer attributes not allowed
4141 // copy constructor with clone
4142 IfLetExprConseqElse (IfLetExprConseqElse const &other)
4143 : IfLetExpr (other), else_block (other.else_block->clone_expr_with_block ())
4146 // overload assignment operator to clone
4147 IfLetExprConseqElse &operator= (IfLetExprConseqElse const &other)
4149 IfLetExpr::operator= (other);
4150 // match_arm_patterns = other.match_arm_patterns;
4151 // value = other.value->clone_expr();
4152 // if_block = other.if_block->clone_block_expr();
4153 else_block = other.else_block->clone_expr_with_block ();
4154 // outer_attrs = other.outer_attrs;
4156 return *this;
4159 // move constructors
4160 IfLetExprConseqElse (IfLetExprConseqElse &&other) = default;
4161 IfLetExprConseqElse &operator= (IfLetExprConseqElse &&other) = default;
4163 void accept_vis (ASTVisitor &vis) override;
4165 // TODO: is this better? Or is a "vis_block" better?
4166 ExprWithBlock &get_else_block ()
4168 rust_assert (else_block != nullptr);
4169 return *else_block;
4172 protected:
4173 /* Use covariance to implement clone function as returning this object rather
4174 * than base */
4175 IfLetExprConseqElse *clone_if_let_expr_impl () const override
4177 return new IfLetExprConseqElse (*this);
4181 // Match arm expression
4182 struct MatchArm
4184 private:
4185 std::vector<Attribute> outer_attrs;
4186 // MatchArmPatterns patterns;
4187 std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined
4189 // bool has_match_arm_guard;
4190 // inlined from MatchArmGuard
4191 std::unique_ptr<Expr> guard_expr;
4193 location_t locus;
4195 public:
4196 // Returns whether the MatchArm has a match arm guard expression
4197 bool has_match_arm_guard () const { return guard_expr != nullptr; }
4199 // Constructor for match arm with a guard expression
4200 MatchArm (std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
4201 location_t locus, std::unique_ptr<Expr> guard_expr = nullptr,
4202 std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
4203 : outer_attrs (std::move (outer_attrs)),
4204 match_arm_patterns (std::move (match_arm_patterns)),
4205 guard_expr (std::move (guard_expr)), locus (locus)
4208 // Copy constructor with clone
4209 MatchArm (MatchArm const &other) : outer_attrs (other.outer_attrs)
4211 // guard to protect from null pointer dereference
4212 if (other.guard_expr != nullptr)
4213 guard_expr = other.guard_expr->clone_expr ();
4215 match_arm_patterns.reserve (other.match_arm_patterns.size ());
4216 for (const auto &e : other.match_arm_patterns)
4217 match_arm_patterns.push_back (e->clone_pattern ());
4219 locus = other.locus;
4222 ~MatchArm () = default;
4224 // Overload assignment operator to clone
4225 MatchArm &operator= (MatchArm const &other)
4227 outer_attrs = other.outer_attrs;
4229 if (other.guard_expr != nullptr)
4230 guard_expr = other.guard_expr->clone_expr ();
4231 else
4232 guard_expr = nullptr;
4234 match_arm_patterns.reserve (other.match_arm_patterns.size ());
4235 for (const auto &e : other.match_arm_patterns)
4236 match_arm_patterns.push_back (e->clone_pattern ());
4238 return *this;
4241 // move constructors
4242 MatchArm (MatchArm &&other) = default;
4243 MatchArm &operator= (MatchArm &&other) = default;
4245 // Returns whether match arm is in an error state.
4246 bool is_error () const { return match_arm_patterns.empty (); }
4248 // Creates a match arm in an error state.
4249 static MatchArm create_error ()
4251 location_t locus = UNDEF_LOCATION;
4252 return MatchArm (std::vector<std::unique_ptr<Pattern> > (), locus);
4255 std::string as_string () const;
4257 // TODO: is this better? Or is a "vis_block" better?
4258 Expr &get_guard_expr ()
4260 rust_assert (has_match_arm_guard ());
4261 return *guard_expr;
4264 std::unique_ptr<Expr> &get_guard_expr_ptr ()
4266 rust_assert (has_match_arm_guard ());
4267 return guard_expr;
4270 // TODO: this mutable getter seems really dodgy. Think up better way.
4271 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4272 std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
4274 const std::vector<std::unique_ptr<Pattern> > &get_patterns () const
4276 return match_arm_patterns;
4278 std::vector<std::unique_ptr<Pattern> > &get_patterns ()
4280 return match_arm_patterns;
4283 location_t get_locus () const { return locus; }
4286 /* A "match case" - a correlated match arm and resulting expression. Not
4287 * abstract. */
4288 struct MatchCase
4290 private:
4291 MatchArm arm;
4292 std::unique_ptr<Expr> expr;
4293 NodeId node_id;
4295 /* TODO: does whether trailing comma exists need to be stored? currently
4296 * assuming it is only syntactical and has no effect on meaning. */
4298 public:
4299 MatchCase (MatchArm arm, std::unique_ptr<Expr> expr)
4300 : arm (std::move (arm)), expr (std::move (expr)),
4301 node_id (Analysis::Mappings::get ()->get_next_node_id ())
4304 MatchCase (const MatchCase &other)
4305 : arm (other.arm), expr (other.expr->clone_expr ()), node_id (other.node_id)
4308 MatchCase &operator= (const MatchCase &other)
4310 arm = other.arm;
4311 expr = other.expr->clone_expr ();
4312 node_id = other.node_id;
4314 return *this;
4317 MatchCase (MatchCase &&other) = default;
4318 MatchCase &operator= (MatchCase &&other) = default;
4320 ~MatchCase () = default;
4322 std::string as_string () const;
4324 // TODO: is this better? Or is a "vis_block" better?
4325 Expr &get_expr ()
4327 rust_assert (expr != nullptr);
4328 return *expr;
4331 std::unique_ptr<Expr> &get_expr_ptr ()
4333 rust_assert (expr != nullptr);
4334 return expr;
4337 // TODO: is this better? Or is a "vis_block" better?
4338 MatchArm &get_arm ()
4340 rust_assert (!arm.is_error ());
4341 return arm;
4344 NodeId get_node_id () const { return node_id; }
4347 // Match expression AST node
4348 class MatchExpr : public ExprWithBlock
4350 std::vector<Attribute> outer_attrs;
4351 std::unique_ptr<Expr> branch_value;
4352 std::vector<Attribute> inner_attrs;
4353 std::vector<MatchCase> match_arms;
4354 location_t locus;
4356 public:
4357 std::string as_string () const override;
4359 // Returns whether the match expression has any match arms.
4360 bool has_match_arms () const { return !match_arms.empty (); }
4362 MatchExpr (std::unique_ptr<Expr> branch_value,
4363 std::vector<MatchCase> match_arms,
4364 std::vector<Attribute> inner_attrs,
4365 std::vector<Attribute> outer_attrs, location_t locus)
4366 : outer_attrs (std::move (outer_attrs)),
4367 branch_value (std::move (branch_value)),
4368 inner_attrs (std::move (inner_attrs)),
4369 match_arms (std::move (match_arms)), locus (locus)
4372 // Copy constructor requires clone due to unique_ptr
4373 MatchExpr (MatchExpr const &other)
4374 : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4375 inner_attrs (other.inner_attrs), match_arms (other.match_arms),
4376 locus (other.locus)
4378 // guard to prevent null dereference (only required if error state)
4379 if (other.branch_value != nullptr)
4380 branch_value = other.branch_value->clone_expr ();
4383 // Overloaded assignment operator to clone due to unique_ptr
4384 MatchExpr &operator= (MatchExpr const &other)
4386 ExprWithBlock::operator= (other);
4387 inner_attrs = other.inner_attrs;
4388 match_arms = other.match_arms;
4389 outer_attrs = other.outer_attrs;
4390 locus = other.locus;
4392 // guard to prevent null dereference (only required if error state)
4393 if (other.branch_value != nullptr)
4394 branch_value = other.branch_value->clone_expr ();
4395 else
4396 branch_value = nullptr;
4398 return *this;
4401 // move constructors
4402 MatchExpr (MatchExpr &&other) = default;
4403 MatchExpr &operator= (MatchExpr &&other) = default;
4405 location_t get_locus () const override final { return locus; }
4407 void accept_vis (ASTVisitor &vis) override;
4409 // Invalid if branch value is null, so base stripping on that.
4410 void mark_for_strip () override { branch_value = nullptr; }
4411 bool is_marked_for_strip () const override { return branch_value == nullptr; }
4413 // TODO: this mutable getter seems really dodgy. Think up better way.
4414 const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
4415 std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
4417 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4418 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4420 void set_outer_attrs (std::vector<Attribute> new_attrs) override
4422 outer_attrs = std::move (new_attrs);
4425 // TODO: is this better? Or is a "vis_block" better?
4426 Expr &get_scrutinee_expr ()
4428 rust_assert (branch_value != nullptr);
4429 return *branch_value;
4432 const std::vector<MatchCase> &get_match_cases () const { return match_arms; }
4433 std::vector<MatchCase> &get_match_cases () { return match_arms; }
4435 protected:
4436 /* Use covariance to implement clone function as returning this object rather
4437 * than base */
4438 MatchExpr *clone_expr_with_block_impl () const override
4440 return new MatchExpr (*this);
4444 // Await expression AST node (pseudo-member variable access)
4445 class AwaitExpr : public ExprWithoutBlock
4447 std::vector<Attribute> outer_attrs;
4448 std::unique_ptr<Expr> awaited_expr;
4449 location_t locus;
4451 public:
4452 // TODO: ensure outer attributes are actually allowed
4453 AwaitExpr (std::unique_ptr<Expr> awaited_expr,
4454 std::vector<Attribute> outer_attrs, location_t locus)
4455 : outer_attrs (std::move (outer_attrs)),
4456 awaited_expr (std::move (awaited_expr)), locus (locus)
4459 // copy constructor with clone
4460 AwaitExpr (AwaitExpr const &other)
4461 : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
4462 locus (other.locus)
4464 // guard to prevent null dereference (only required if error state)
4465 if (other.awaited_expr != nullptr)
4466 awaited_expr = other.awaited_expr->clone_expr ();
4469 // overloaded assignment operator with clone
4470 AwaitExpr &operator= (AwaitExpr const &other)
4472 ExprWithoutBlock::operator= (other);
4473 outer_attrs = other.outer_attrs;
4474 locus = other.locus;
4476 // guard to prevent null dereference (only required if error state)
4477 if (other.awaited_expr != nullptr)
4478 awaited_expr = other.awaited_expr->clone_expr ();
4479 else
4480 awaited_expr = nullptr;
4482 return *this;
4485 // move constructors
4486 AwaitExpr (AwaitExpr &&other) = default;
4487 AwaitExpr &operator= (AwaitExpr &&other) = default;
4489 std::string as_string () const override;
4491 location_t get_locus () const override final { return locus; }
4493 void accept_vis (ASTVisitor &vis) override;
4495 // Invalid if awaited expr is null, so base stripping on that.
4496 void mark_for_strip () override { awaited_expr = nullptr; }
4497 bool is_marked_for_strip () const override { return awaited_expr == nullptr; }
4499 // TODO: is this better? Or is a "vis_block" better?
4500 std::unique_ptr<Expr> &get_awaited_expr ()
4502 rust_assert (awaited_expr != nullptr);
4503 return awaited_expr;
4506 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4507 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4509 void set_outer_attrs (std::vector<Attribute> new_attrs) override
4511 outer_attrs = std::move (new_attrs);
4514 protected:
4515 /* Use covariance to implement clone function as returning this object rather
4516 * than base */
4517 AwaitExpr *clone_expr_without_block_impl () const override
4519 return new AwaitExpr (*this);
4523 // Async block expression AST node (block expr that evaluates to a future)
4524 class AsyncBlockExpr : public ExprWithBlock
4526 // TODO: should this extend BlockExpr rather than be a composite of it?
4527 std::vector<Attribute> outer_attrs;
4528 bool has_move;
4529 std::unique_ptr<BlockExpr> block_expr;
4530 location_t locus;
4532 public:
4533 AsyncBlockExpr (std::unique_ptr<BlockExpr> block_expr, bool has_move,
4534 std::vector<Attribute> outer_attrs, location_t locus)
4535 : outer_attrs (std::move (outer_attrs)), has_move (has_move),
4536 block_expr (std::move (block_expr)), locus (locus)
4539 // copy constructor with clone
4540 AsyncBlockExpr (AsyncBlockExpr const &other)
4541 : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4542 has_move (other.has_move), locus (other.locus)
4544 // guard to prevent null dereference (only required if error state)
4545 if (other.block_expr != nullptr)
4546 block_expr = other.block_expr->clone_block_expr ();
4549 // overloaded assignment operator to clone
4550 AsyncBlockExpr &operator= (AsyncBlockExpr const &other)
4552 ExprWithBlock::operator= (other);
4553 outer_attrs = other.outer_attrs;
4554 has_move = other.has_move;
4555 locus = other.locus;
4557 // guard to prevent null dereference (only required if error state)
4558 if (other.block_expr != nullptr)
4559 block_expr = other.block_expr->clone_block_expr ();
4560 else
4561 block_expr = nullptr;
4563 return *this;
4566 // move constructors
4567 AsyncBlockExpr (AsyncBlockExpr &&other) = default;
4568 AsyncBlockExpr &operator= (AsyncBlockExpr &&other) = default;
4570 std::string as_string () const override;
4572 bool get_has_move () { return has_move; }
4573 location_t get_locus () const override final { return locus; }
4575 void accept_vis (ASTVisitor &vis) override;
4577 // Invalid if block is null, so base stripping on that.
4578 void mark_for_strip () override { block_expr = nullptr; }
4579 bool is_marked_for_strip () const override { return block_expr == nullptr; }
4581 // TODO: is this better? Or is a "vis_block" better?
4582 std::unique_ptr<BlockExpr> &get_block_expr ()
4584 rust_assert (block_expr != nullptr);
4585 return block_expr;
4588 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4589 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4591 void set_outer_attrs (std::vector<Attribute> new_attrs) override
4593 outer_attrs = std::move (new_attrs);
4596 protected:
4597 /* Use covariance to implement clone function as returning this object rather
4598 * than base */
4599 AsyncBlockExpr *clone_expr_with_block_impl () const override
4601 return new AsyncBlockExpr (*this);
4605 // Inline-assembly specific options
4606 enum class InlineAsmOptions
4608 PURE = 1 << 0,
4609 NOMEM = 1 << 1,
4610 READONLY = 1 << 2,
4611 PRESERVES_FLAGS = 1 << 3,
4612 NORETURN = 1 << 4,
4613 NOSTACK = 1 << 5,
4614 ATT_SYNTAX = 1 << 6,
4615 RAW = 1 << 7,
4616 MAY_UNWIND = 1 << 8,
4619 struct AnonConst
4621 NodeId id;
4622 std::unique_ptr<Expr> value;
4625 struct InlineAsmRegOrRegClass
4627 enum Type
4629 Reg,
4630 RegClass,
4633 struct Reg
4635 std::string Symbol;
4638 struct RegClass
4640 std::string Symbol;
4643 Identifier name;
4644 location_t locus;
4647 struct InlineAsmOperand
4649 enum RegisterType
4652 Out,
4653 InOut,
4654 SplitInOut,
4655 Const,
4656 Sym,
4659 struct In
4661 InlineAsmRegOrRegClass reg;
4662 std::unique_ptr<Expr> expr;
4665 struct Out
4667 InlineAsmRegOrRegClass reg;
4668 bool late;
4669 std::unique_ptr<Expr> expr; // can be null
4672 struct InOut
4674 InlineAsmRegOrRegClass reg;
4675 bool late;
4676 std::unique_ptr<Expr> expr; // this can't be null
4679 struct SplitInOut
4681 InlineAsmRegOrRegClass reg;
4682 bool late;
4683 std::unique_ptr<Expr> in_expr;
4684 std::unique_ptr<Expr> out_expr; // could be null
4687 struct Const
4689 AnonConst anon_const;
4692 struct Sym
4694 std::unique_ptr<Expr> sym;
4696 location_t locus;
4699 struct InlineAsmPlaceHolder
4701 size_t operand_idx;
4702 char modifier; // can be null
4703 location_t locus;
4706 struct InlineAsmTemplatePiece
4708 bool is_placeholder;
4709 union
4711 std::string string;
4712 InlineAsmPlaceHolder placeholder;
4716 struct TupleClobber
4718 // as gccrs still doesn't contain a symbol class I have put them as strings
4719 std::string symbol;
4720 location_t loc;
4723 struct TupleTemplateStr
4725 // as gccrs still doesn't contain a symbol class I have put them as strings
4726 std::string symbol;
4727 std::string optional_symbol;
4728 location_t loc;
4731 // Inline Assembly Node
4732 class InlineAsm : public ExprWithoutBlock
4734 public:
4735 std::vector<InlineAsmTemplatePiece> template_;
4736 std::vector<TupleTemplateStr> template_strs;
4737 std::vector<InlineAsmOperand> operands;
4738 TupleClobber clobber_abi;
4739 InlineAsmOptions options;
4740 std::vector<location_t> line_spans;
4743 } // namespace AST
4744 } // namespace Rust
4746 #endif