1 #ifndef RUST_AST_EXPR_H
2 #define RUST_AST_EXPR_H
6 #include "rust-macro.h"
7 #include "rust-operators.h"
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
17 class LoopLabel
/*: public Node*/
19 Lifetime label
; // or type LIFETIME_OR_LABEL
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
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; };
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
;
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
,
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
,
89 : outer_attrs (std::move (outer_attrs
)), literal (std::move (literal
)),
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
);
120 /* Use covariance to implement clone function as returning this object rather
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
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
;
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
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
;
165 /* Use covariance to implement clone function as returning this object rather
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
;
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
;
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
;
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
;
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
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
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
290 Attribute
to_attribute () const override
;
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
302 class OperatorExpr
: public ExprWithoutBlock
304 // TODO: create binary and unary operator subclasses?
309 /* Variables must be protected to allow derived classes to use them as first
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
);
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 ();
341 main_or_left_expr
= nullptr;
347 OperatorExpr (OperatorExpr
&&other
) = default;
348 OperatorExpr
&operator= (OperatorExpr
&&other
) = default;
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
371 class BorrowExpr
: public OperatorExpr
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
,
382 : OperatorExpr (std::move (borrow_lvalue
), std::move (outer_attribs
),
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
; }
401 /* Use covariance to implement clone function as returning this object rather
403 BorrowExpr
*clone_expr_without_block_impl () const override
405 return new BorrowExpr (*this);
409 // Unary prefix * deference operator
410 class DereferenceExpr
: public OperatorExpr
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
;
431 /* Use covariance to implement clone function as returning this object rather
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
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
;
462 /* Use covariance to implement clone function as returning this object rather
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
474 using ExprType
= NegationOperator
;
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) */
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
),
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
;
505 /* Use covariance to implement clone function as returning this object rather
507 NegationExpr
*clone_expr_without_block_impl () const override
509 return new NegationExpr (*this);
513 // Infix binary operators. +, -, *, /, %, &, |, ^, <<, >>
514 class ArithmeticOrLogicalExpr
: public OperatorExpr
517 using ExprType
= ArithmeticOrLogicalOperator
;
520 // Note: overloading trait specified in comments
523 std::unique_ptr
<Expr
> right_expr
;
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
;
557 ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr
&&other
) = default;
558 ArithmeticOrLogicalExpr
&operator= (ArithmeticOrLogicalExpr
&&other
)
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);
583 std::unique_ptr
<Expr
> &get_right_expr_ptr ()
585 rust_assert (right_expr
!= nullptr);
589 void visit_lhs (ASTVisitor
&vis
) { main_or_left_expr
->accept_vis (vis
); }
590 void visit_rhs (ASTVisitor
&vis
) { right_expr
->accept_vis (vis
); }
593 /* Use covariance to implement clone function as returning this object rather
595 ArithmeticOrLogicalExpr
*clone_expr_without_block_impl () const override
597 return new ArithmeticOrLogicalExpr (*this);
601 // Infix binary comparison operators. ==, !=, <, <=, >, >=
602 class ComparisonExpr
: public OperatorExpr
605 using ExprType
= ComparisonOperator
;
608 // Note: overloading trait specified in comments
611 std::unique_ptr
<Expr
> right_expr
;
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
,
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;
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);
671 std::unique_ptr
<Expr
> &get_right_expr_ptr ()
673 rust_assert (right_expr
!= nullptr);
677 ExprType
get_kind () { return expr_type
; }
679 /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2)
682 /* Use covariance to implement clone function as returning this object rather
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
694 using ExprType
= LazyBooleanOperator
;
699 std::unique_ptr
<Expr
> right_expr
;
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
,
706 : OperatorExpr (std::move (left_bool_expr
), std::vector
<Attribute
> (),
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
;
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);
759 std::unique_ptr
<Expr
> &get_right_expr_ptr ()
761 rust_assert (right_expr
!= nullptr);
765 ExprType
get_kind () { return expr_type
; }
768 /* Use covariance to implement clone function as returning this object rather
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
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 ();
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
;
830 /* Use covariance to implement clone function as returning this object rather
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
;
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
),
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;
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);
900 // TODO: is this better? Or is a "vis_block" better?
901 Expr
&get_right_expr ()
903 rust_assert (right_expr
!= nullptr);
908 /* Use covariance to implement clone function as returning this object rather
910 AssignmentExpr
*clone_expr_without_block_impl () const override
912 return new AssignmentExpr (*this);
916 /* Binary infix compound assignment (arithmetic or logic then assignment)
918 class CompoundAssignmentExpr
: public OperatorExpr
921 using ExprType
= CompoundAssignmentOperator
;
924 // Note: overloading trait specified in comments
926 std::unique_ptr
<Expr
> right_expr
;
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
> (),
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;
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);
987 std::unique_ptr
<Expr
> &get_right_expr_ptr ()
989 rust_assert (right_expr
!= nullptr);
994 /* Use covariance to implement clone function as returning this object rather
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
;
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 ();
1054 expr_in_parens
= nullptr;
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
;
1088 /* Use covariance to implement clone function as returning this object rather
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
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
; }
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;
1124 // Value array elements
1125 class ArrayElemsValues
: public ArrayElems
1127 std::vector
<std::unique_ptr
<Expr
> > values
;
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 ());
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
1166 std::vector
<std::unique_ptr
<Expr
> > &get_values () { return values
; }
1168 size_t get_num_values () const { return values
.size (); }
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
;
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 ();
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);
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
;
1244 // TODO: find another way to store this to save memory?
1245 bool marked_for_strip
= false;
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);
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
;
1317 /* Use covariance to implement clone function as returning this object rather
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
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
;
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
),
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 ();
1371 array_expr
= nullptr;
1372 if (other
.index_expr
!= nullptr)
1373 index_expr
= other
.index_expr
->clone_expr ();
1375 index_expr
= nullptr;
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);
1406 // TODO: is this better? Or is a "vis_block" better?
1407 Expr
&get_index_expr ()
1409 rust_assert (index_expr
!= nullptr);
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
);
1422 /* Use covariance to implement clone function as returning this object rather
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
;
1438 // TODO: find another way to store this to save memory?
1439 bool marked_for_strip
= false;
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 ());
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
1510 std::vector
<std::unique_ptr
<Expr
> > &get_tuple_elems ()
1515 bool is_unit () const { return tuple_elems
.size () == 0; }
1518 /* Use covariance to implement clone function as returning this object rather
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
;
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 ();
1572 tuple_expr
= nullptr;
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);
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
);
1605 /* Use covariance to implement clone function as returning this object rather
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
;
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
))
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
;
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
;
1675 /* Use covariance to implement clone function as returning this object rather
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
1688 std::unique_ptr
<Expr
> base_struct
;
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
1701 if (other
.base_struct
!= nullptr)
1702 base_struct
= other
.base_struct
->clone_expr ();
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 ();
1715 base_struct
= nullptr;
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
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
; }
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 ())
1771 // Identifier-only variant of StructExprField AST node
1772 class StructExprFieldIdentifier
: public StructExprField
1774 Identifier field_name
;
1778 StructExprFieldIdentifier (Identifier field_identifier
, location_t locus
)
1779 : StructExprField (), field_name (std::move (field_identifier
)),
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
; }
1792 /* Use covariance to implement clone function as returning this object rather
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 -
1802 class StructExprFieldWithVal
: public StructExprField
1804 std::unique_ptr
<Expr
> value
;
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 ();
1824 // move constructors
1825 StructExprFieldWithVal (StructExprFieldWithVal
&&other
) = default;
1826 StructExprFieldWithVal
&operator= (StructExprFieldWithVal
&&other
) = default;
1829 std::string
as_string () const override
;
1831 // TODO: is this better? Or is a "vis_block" better?
1834 rust_assert (value
!= nullptr);
1839 // Identifier and value variant of StructExprField AST node
1840 class StructExprFieldIdentifierValue
: public StructExprFieldWithVal
1842 Identifier field_name
;
1846 StructExprFieldIdentifierValue (Identifier field_identifier
,
1847 std::unique_ptr
<Expr
> field_value
,
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
; }
1862 /* Use covariance to implement clone function as returning this object rather
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
1877 StructExprFieldIndexValue (TupleIndex tuple_index
,
1878 std::unique_ptr
<Expr
> field_value
,
1880 : StructExprFieldWithVal (std::move (field_value
)), index (tuple_index
),
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
; }
1893 /* Use covariance to implement clone function as returning this object rather
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
;
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 ());
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 ()
1960 const std::vector
<std::unique_ptr
<StructExprField
> > &get_fields () const
1965 StructBase
&get_struct_base () { return struct_base
; }
1966 const StructBase
&get_struct_base () const { return struct_base
; }
1969 /* Use covariance to implement clone function as returning this object rather
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
;
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
; }
2001 /* Use covariance to implement clone function as returning this object rather
2003 StructExprStructBase
*clone_expr_without_block_impl () const override
2005 return new StructExprStructBase (*this);
2009 // Forward decl for Function - used in CallExpr
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
;
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
),
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 ();
2060 params
.reserve (other
.params
.size ());
2061 for (const auto &e
: other
.params
)
2062 params
.push_back (e
->clone_expr ());
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
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);
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
);
2105 /* Use covariance to implement clone function as returning this object rather
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
;
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
)),
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 ();
2163 params
.reserve (other
.params
.size ());
2164 for (const auto &e
: other
.params
)
2165 params
.push_back (e
->clone_expr ());
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
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);
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
);
2208 /* Use covariance to implement clone function as returning this object rather
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
;
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
,
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 ();
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);
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
);
2293 /* Use covariance to implement clone function as returning this object rather
2295 FieldAccessExpr
*clone_expr_without_block_impl () const override
2297 return new FieldAccessExpr (*this);
2301 // Closure parameter data structure
2305 std::vector
<Attribute
> outer_attrs
;
2306 std::unique_ptr
<Pattern
> pattern
;
2307 std::unique_ptr
<Type
> type
;
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
)),
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 ();
2347 if (other
.type
!= nullptr)
2348 type
= other
.type
->clone_type ();
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);
2381 rust_assert (has_type_given ());
2385 std::unique_ptr
<Type
> &get_type_ptr ()
2387 rust_assert (has_type_given ());
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
;
2399 std::vector
<ClosureParam
> params
; // may be empty
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
)
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
;
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 ();
2468 closure_inner
= nullptr;
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
;
2493 /* Use covariance to implement clone function as returning this object rather
2495 ClosureExprInner
*clone_expr_without_block_impl () const override
2497 return new ClosureExprInner (*this);
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
;
2509 location_t start_locus
;
2510 location_t end_locus
;
2511 bool marked_for_strip
= false;
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 ();
2566 statements
.reserve (other
.statements
.size ());
2567 for (const auto &e
: other
.statements
)
2568 statements
.push_back (e
->clone_stmt ());
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
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 ());
2613 std::unique_ptr
<Expr
> &get_tail_expr_ptr ()
2615 rust_assert (has_tail_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
; }
2649 /* Use covariance to implement clone function as returning this object rather
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
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 ();
2712 if (other
.return_type
!= nullptr)
2713 return_type
= other
.return_type
->clone_type ();
2715 return_type
= nullptr;
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);
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);
2752 /* Use covariance to implement clone function as returning this object rather
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
;
2767 // TODO: find another way to store this to save memory?
2768 bool marked_for_strip
= false;
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
,
2779 : outer_attrs (std::move (outer_attribs
)), label (std::move (label
)),
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
; }
2802 /* Use covariance to implement clone function as returning this object rather
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
;
2816 std::unique_ptr
<Expr
> break_expr
;
2819 // TODO: find another way to store this to save memory?
2820 bool marked_for_strip
= false;
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
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 ();
2863 break_expr
= nullptr;
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 ());
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
; }
2898 /* Use covariance to implement clone function as returning this object rather
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
2912 // outer attributes not allowed before range expressions
2913 RangeExpr (location_t locus
) : locus (locus
) {}
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
;
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 ();
2967 if (other
.to
!= nullptr)
2968 to
= other
.to
->clone_expr ();
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
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);
2999 // TODO: is this better? Or is a "vis_block" better?
3000 Expr
&get_to_expr ()
3002 rust_assert (to
!= nullptr);
3007 /* Use covariance to implement clone function as returning this object rather
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
;
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 ();
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);
3068 /* Use covariance to implement clone function as returning this object rather
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
;
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 ();
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);
3130 /* Use covariance to implement clone function as returning this object rather
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;
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
; }
3158 /* Use covariance to implement clone function as returning this object rather
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
;
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 ();
3203 if (other
.to
!= nullptr)
3204 to
= other
.to
->clone_expr ();
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
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);
3235 // TODO: is this better? Or is a "vis_block" better?
3236 Expr
&get_to_expr ()
3238 rust_assert (to
!= nullptr);
3243 /* Use covariance to implement clone function as returning this object rather
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
;
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 ();
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);
3305 /* Use covariance to implement clone function as returning this object rather
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
;
3320 // TODO: find another way to store this to save memory?
3321 bool marked_for_strip
= false;
3324 std::string
as_string () const override
;
3326 /* Returns whether the object has an expression returned (i.e. not void return
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 ();
3359 return_expr
= nullptr;
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
);
3392 /* Use covariance to implement clone function as returning this object rather
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
;
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
)),
3420 // Copy constructor with clone
3421 UnsafeBlockExpr (UnsafeBlockExpr
const &other
)
3422 : ExprWithBlock (other
), outer_attrs (other
.outer_attrs
),
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 ();
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);
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
);
3474 /* Use covariance to implement clone function as returning this object rather
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
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
;
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
)),
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 ();
3527 loop_block
= nullptr;
3532 // move constructors
3533 BaseLoopExpr (BaseLoopExpr
&&other
) = default;
3534 BaseLoopExpr
&operator= (BaseLoopExpr
&&other
) = default;
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);
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
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
;
3580 /* Use covariance to implement clone function as returning this object rather
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
;
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;
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);
3638 /* Use covariance to implement clone function as returning this object rather
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
;
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 ());
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);
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
;
3721 /* Use covariance to implement clone function as returning this object rather
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
;
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;*/
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);
3790 /* Use covariance to implement clone function as returning this object rather
3792 ForLoopExpr
*clone_expr_with_block_impl () const override
3794 return new ForLoopExpr (*this);
3798 // forward decl for IfExpr
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
;
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
),
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 ();
3842 condition
= nullptr;
3843 if (other
.if_block
!= nullptr)
3844 if_block
= other
.if_block
->clone_block_expr ();
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);
3879 std::unique_ptr
<Expr
> &get_condition_expr_ptr ()
3881 rust_assert (condition
!= nullptr);
3885 // TODO: is this better? Or is a "vis_block" better?
3886 BlockExpr
&get_if_block ()
3888 rust_assert (if_block
!= nullptr);
3892 // Invalid if if block or condition is null, so base stripping on that.
3893 void mark_for_strip () override
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
; }
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
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
;
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 ();
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);
3974 /* Use covariance to implement clone function as returning this object rather
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
;
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
),
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 ();
4030 if (other
.if_block
!= nullptr)
4031 if_block
= other
.if_block
->clone_block_expr ();
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 ());
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
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);
4074 std::unique_ptr
<Expr
> &get_value_expr_ptr ()
4076 rust_assert (value
!= nullptr);
4080 // TODO: is this better? Or is a "vis_block" better?
4081 BlockExpr
&get_if_block ()
4083 rust_assert (if_block
!= nullptr);
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
; }
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
4123 class IfLetExprConseqElse
: public IfLetExpr
4125 std::unique_ptr
<ExprWithBlock
> else_block
;
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;
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);
4173 /* Use covariance to implement clone function as returning this object rather
4175 IfLetExprConseqElse
*clone_if_let_expr_impl () const override
4177 return new IfLetExprConseqElse (*this);
4181 // Match arm expression
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
;
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 ();
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 ());
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 ());
4264 std::unique_ptr
<Expr
> &get_guard_expr_ptr ()
4266 rust_assert (has_match_arm_guard ());
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
4292 std::unique_ptr
<Expr
> expr
;
4295 /* TODO: does whether trailing comma exists need to be stored? currently
4296 * assuming it is only syntactical and has no effect on meaning. */
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
)
4311 expr
= other
.expr
->clone_expr ();
4312 node_id
= other
.node_id
;
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?
4327 rust_assert (expr
!= nullptr);
4331 std::unique_ptr
<Expr
> &get_expr_ptr ()
4333 rust_assert (expr
!= nullptr);
4337 // TODO: is this better? Or is a "vis_block" better?
4338 MatchArm
&get_arm ()
4340 rust_assert (!arm
.is_error ());
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
;
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
),
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 ();
4396 branch_value
= nullptr;
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
; }
4436 /* Use covariance to implement clone function as returning this object rather
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
;
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
),
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 ();
4480 awaited_expr
= nullptr;
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
);
4515 /* Use covariance to implement clone function as returning this object rather
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
;
4529 std::unique_ptr
<BlockExpr
> block_expr
;
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 ();
4561 block_expr
= nullptr;
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);
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
);
4597 /* Use covariance to implement clone function as returning this object rather
4599 AsyncBlockExpr
*clone_expr_with_block_impl () const override
4601 return new AsyncBlockExpr (*this);
4605 // Inline-assembly specific options
4606 enum class InlineAsmOptions
4611 PRESERVES_FLAGS
= 1 << 3,
4614 ATT_SYNTAX
= 1 << 6,
4616 MAY_UNWIND
= 1 << 8,
4622 std::unique_ptr
<Expr
> value
;
4625 struct InlineAsmRegOrRegClass
4647 struct InlineAsmOperand
4661 InlineAsmRegOrRegClass reg
;
4662 std::unique_ptr
<Expr
> expr
;
4667 InlineAsmRegOrRegClass reg
;
4669 std::unique_ptr
<Expr
> expr
; // can be null
4674 InlineAsmRegOrRegClass reg
;
4676 std::unique_ptr
<Expr
> expr
; // this can't be null
4681 InlineAsmRegOrRegClass reg
;
4683 std::unique_ptr
<Expr
> in_expr
;
4684 std::unique_ptr
<Expr
> out_expr
; // could be null
4689 AnonConst anon_const
;
4694 std::unique_ptr
<Expr
> sym
;
4699 struct InlineAsmPlaceHolder
4702 char modifier
; // can be null
4706 struct InlineAsmTemplatePiece
4708 bool is_placeholder
;
4712 InlineAsmPlaceHolder placeholder
;
4718 // as gccrs still doesn't contain a symbol class I have put them as strings
4723 struct TupleTemplateStr
4725 // as gccrs still doesn't contain a symbol class I have put them as strings
4727 std::string optional_symbol
;
4731 // Inline Assembly Node
4732 class InlineAsm
: public ExprWithoutBlock
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
;