Branch data Line data Source code
1 : : #ifndef RUST_AST_EXPR_H
2 : : #define RUST_AST_EXPR_H
3 : :
4 : : #include "rust-ast.h"
5 : : #include "rust-path.h"
6 : : #include "rust-macro.h"
7 : : #include "rust-operators.h"
8 : :
9 : : namespace Rust {
10 : : namespace AST {
11 : : /* TODO: if GCC moves to C++17 or allows boost, replace some boolean
12 : : * "has_whatever" pairs with
13 : : * optional types (std::optional or boost::optional)? */
14 : :
15 : : // Loop label expression AST node used with break and continue expressions
16 : : // TODO: inline?
17 : 40416 : class LoopLabel /*: public Node*/
18 : : {
19 : : Lifetime label; // or type LIFETIME_OR_LABEL
20 : : location_t locus;
21 : :
22 : : NodeId node_id;
23 : :
24 : : public:
25 : : std::string as_string () const;
26 : :
27 : 13440 : LoopLabel (Lifetime loop_label, location_t locus = UNDEF_LOCATION)
28 : 13440 : : label (std::move (loop_label)), locus (locus),
29 : 13440 : node_id (Analysis::Mappings::get ()->get_next_node_id ())
30 : 13440 : {}
31 : :
32 : : // Returns whether the LoopLabel is in an error state.
33 : 27671 : bool is_error () const { return label.is_error (); }
34 : :
35 : : // Creates an error state LoopLabel.
36 : 13341 : static LoopLabel error () { return LoopLabel (Lifetime::error ()); }
37 : :
38 : 12968 : location_t get_locus () const { return locus; }
39 : :
40 : 13794 : Lifetime &get_lifetime () { return label; }
41 : :
42 : 12908 : NodeId get_node_id () const { return node_id; }
43 : : };
44 : :
45 : : // AST node for an expression with an accompanying block - abstract
46 : 30601 : class ExprWithBlock : public Expr
47 : : {
48 : : protected:
49 : : // pure virtual clone implementation
50 : : virtual ExprWithBlock *clone_expr_with_block_impl () const = 0;
51 : :
52 : : // prevent having to define multiple clone expressions
53 : 3411 : ExprWithBlock *clone_expr_impl () const final override
54 : : {
55 : 3411 : return clone_expr_with_block_impl ();
56 : : }
57 : :
58 : 7287 : bool is_expr_without_block () const final override { return false; };
59 : :
60 : : public:
61 : : // Unique pointer custom clone function
62 : 270 : std::unique_ptr<ExprWithBlock> clone_expr_with_block () const
63 : : {
64 : 270 : return std::unique_ptr<ExprWithBlock> (clone_expr_with_block_impl ());
65 : : }
66 : : };
67 : :
68 : : // Literals? Or literal base?
69 : : class LiteralExpr : public ExprWithoutBlock
70 : : {
71 : : std::vector<Attribute> outer_attrs;
72 : : Literal literal;
73 : : location_t locus;
74 : :
75 : : public:
76 : 1983 : std::string as_string () const override { return literal.as_string (); }
77 : :
78 : 159 : Literal::LitType get_lit_type () const { return literal.get_lit_type (); }
79 : :
80 : 21987 : LiteralExpr (std::string value_as_string, Literal::LitType type,
81 : : PrimitiveCoreType type_hint, std::vector<Attribute> outer_attrs,
82 : : location_t locus)
83 : 43974 : : outer_attrs (std::move (outer_attrs)),
84 : 21987 : literal (std::move (value_as_string), type, type_hint), locus (locus)
85 : 21987 : {}
86 : :
87 : 27 : LiteralExpr (Literal literal, std::vector<Attribute> outer_attrs,
88 : : location_t locus)
89 : 81 : : outer_attrs (std::move (outer_attrs)), literal (std::move (literal)),
90 : 27 : locus (locus)
91 : 27 : {}
92 : :
93 : : // Unique pointer custom clone function
94 : : std::unique_ptr<LiteralExpr> clone_literal_expr () const
95 : : {
96 : : return std::unique_ptr<LiteralExpr> (clone_literal_expr_impl ());
97 : : }
98 : :
99 : 29282 : location_t get_locus () const override final { return locus; }
100 : :
101 : 179 : bool is_literal () const override final { return true; }
102 : :
103 : 14495 : Literal get_literal () const { return literal; }
104 : :
105 : : void accept_vis (ASTVisitor &vis) override;
106 : :
107 : : // Invalid if literal is in error state, so base stripping on that.
108 : 0 : void mark_for_strip () override { literal = Literal::create_error (); }
109 : 555866 : bool is_marked_for_strip () const override { return literal.is_error (); }
110 : :
111 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
112 : 1155069 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
113 : :
114 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
115 : : {
116 : 0 : outer_attrs = std::move (new_attrs);
117 : 0 : }
118 : :
119 : : protected:
120 : : /* Use covariance to implement clone function as returning this object rather
121 : : * than base */
122 : 18820 : LiteralExpr *clone_expr_without_block_impl () const final override
123 : : {
124 : 18820 : return clone_literal_expr_impl ();
125 : : }
126 : :
127 : : /* not virtual as currently no subclasses of LiteralExpr, but could be in
128 : : * future */
129 : 18820 : /*virtual*/ LiteralExpr *clone_literal_expr_impl () const
130 : : {
131 : 18820 : return new LiteralExpr (*this);
132 : : }
133 : : };
134 : :
135 : : // Literal expression attribute body (non-macro attribute)
136 : 4962 : class AttrInputLiteral : public AttrInput
137 : : {
138 : : LiteralExpr literal_expr;
139 : :
140 : : public:
141 : 2308 : AttrInputLiteral (LiteralExpr lit_expr) : literal_expr (std::move (lit_expr))
142 : : {}
143 : :
144 : 42 : std::string as_string () const override
145 : : {
146 : 42 : return " = " + literal_expr.as_string ();
147 : : }
148 : :
149 : : void accept_vis (ASTVisitor &vis) override;
150 : :
151 : : /* this can never be a cfg predicate - cfg and cfg_attr require a token-tree
152 : : * cfg */
153 : 0 : bool check_cfg_predicate (const Session &) const override { return false; }
154 : :
155 : 0 : bool is_meta_item () const override { return false; }
156 : :
157 : 3241 : LiteralExpr &get_literal () { return literal_expr; }
158 : :
159 : 3488 : AttrInputType get_attr_input_type () const final override
160 : : {
161 : 3488 : return AttrInput::AttrInputType::LITERAL;
162 : : }
163 : :
164 : : protected:
165 : : /* Use covariance to implement clone function as returning this object rather
166 : : * than base */
167 : 4962 : AttrInputLiteral *clone_attr_input_impl () const override
168 : : {
169 : 4962 : return new AttrInputLiteral (*this);
170 : : }
171 : : };
172 : :
173 : : // Like an AttrInputLiteral, but stores a MacroInvocation
174 : : class AttrInputMacro : public AttrInput
175 : : {
176 : : std::unique_ptr<MacroInvocation> macro;
177 : :
178 : : public:
179 : 1 : AttrInputMacro (std::unique_ptr<MacroInvocation> macro)
180 : 1 : : macro (std::move (macro))
181 : : {}
182 : :
183 : : AttrInputMacro (const AttrInputMacro &oth);
184 : :
185 : : AttrInputMacro (AttrInputMacro &&oth) : macro (std::move (oth.macro)) {}
186 : :
187 : : void operator= (const AttrInputMacro &oth);
188 : :
189 : : void operator= (AttrInputMacro &&oth) { macro = std::move (oth.macro); }
190 : :
191 : : std::string as_string () const override;
192 : :
193 : : void accept_vis (ASTVisitor &vis) override;
194 : :
195 : : // assuming this can't be a cfg predicate
196 : 0 : bool check_cfg_predicate (const Session &) const override { return false; }
197 : :
198 : : // assuming this is like AttrInputLiteral
199 : 0 : bool is_meta_item () const override { return false; }
200 : :
201 : 0 : std::unique_ptr<MacroInvocation> &get_macro () { return macro; }
202 : :
203 : 1 : AttrInputType get_attr_input_type () const final override
204 : : {
205 : 1 : return AttrInput::AttrInputType::MACRO;
206 : : }
207 : :
208 : : protected:
209 : 1 : AttrInputMacro *clone_attr_input_impl () const override
210 : : {
211 : 1 : return new AttrInputMacro (*this);
212 : : }
213 : : };
214 : :
215 : : /* literal expr only meta item inner - TODO possibly replace with inheritance of
216 : : * LiteralExpr itself? */
217 : 0 : class MetaItemLitExpr : public MetaItemInner
218 : : {
219 : : LiteralExpr lit_expr;
220 : :
221 : : public:
222 : 27 : MetaItemLitExpr (LiteralExpr lit_expr) : lit_expr (std::move (lit_expr)) {}
223 : :
224 : 6 : std::string as_string () const override { return lit_expr.as_string (); }
225 : :
226 : 0 : location_t get_locus () const override { return lit_expr.get_locus (); }
227 : :
228 : : LiteralExpr get_literal () const { return lit_expr; }
229 : :
230 : 0 : LiteralExpr &get_literal () { return lit_expr; }
231 : :
232 : : void accept_vis (ASTVisitor &vis) override;
233 : :
234 : : bool check_cfg_predicate (const Session &session) const override;
235 : :
236 : 0 : MetaItemInner::Kind get_kind () override
237 : : {
238 : 0 : return MetaItemInner::Kind::LitExpr;
239 : : }
240 : :
241 : : protected:
242 : : // Use covariance to implement clone function as returning this type
243 : 0 : MetaItemLitExpr *clone_meta_item_inner_impl () const override
244 : : {
245 : 0 : return new MetaItemLitExpr (*this);
246 : : }
247 : : };
248 : :
249 : : // more generic meta item "path = lit" form
250 : : class MetaItemPathLit : public MetaItem
251 : : {
252 : : SimplePath path;
253 : : LiteralExpr lit;
254 : :
255 : : public:
256 : 0 : MetaItemPathLit (SimplePath path, LiteralExpr lit_expr)
257 : 0 : : path (std::move (path)), lit (std::move (lit_expr))
258 : 0 : {}
259 : :
260 : : SimplePath get_path () const { return path; }
261 : :
262 : 0 : SimplePath &get_path () { return path; }
263 : :
264 : : LiteralExpr get_literal () const { return lit; }
265 : :
266 : 0 : LiteralExpr &get_literal () { return lit; }
267 : :
268 : 0 : std::string as_string () const override
269 : : {
270 : 0 : return path.as_string () + " = " + lit.as_string ();
271 : : }
272 : :
273 : 0 : MetaItem::ItemKind get_item_kind () const override
274 : : {
275 : 0 : return MetaItem::ItemKind::PathLit;
276 : : }
277 : :
278 : : // There are two Locations in MetaItemPathLit (path and lit_expr),
279 : : // we have no idea use which of them, just simply return UNKNOWN_LOCATION
280 : : // now.
281 : : // Maybe we will figure out when we really need the location in the future.
282 : 0 : location_t get_locus () const override { return UNKNOWN_LOCATION; }
283 : :
284 : : void accept_vis (ASTVisitor &vis) override;
285 : :
286 : : bool check_cfg_predicate (const Session &session) const override;
287 : : /* TODO: return true if "ident" is defined and value of it is "lit", return
288 : : * false otherwise */
289 : :
290 : : Attribute to_attribute () const override;
291 : :
292 : : protected:
293 : : // Use covariance to implement clone function as returning this type
294 : 0 : MetaItemPathLit *clone_meta_item_inner_impl () const override
295 : : {
296 : 0 : return new MetaItemPathLit (*this);
297 : : }
298 : : };
299 : :
300 : : /* Represents an expression using unary or binary operators as AST node. Can be
301 : : * overloaded. */
302 : : class OperatorExpr : public ExprWithoutBlock
303 : : {
304 : : // TODO: create binary and unary operator subclasses?
305 : : public:
306 : : location_t locus;
307 : :
308 : : protected:
309 : : /* Variables must be protected to allow derived classes to use them as first
310 : : * class citizens */
311 : : std::vector<Attribute> outer_attrs;
312 : : std::unique_ptr<Expr> main_or_left_expr;
313 : :
314 : : // Constructor (only for initialisation of expr purposes)
315 : 12580 : OperatorExpr (std::unique_ptr<Expr> main_or_left_expr,
316 : : std::vector<Attribute> outer_attribs, location_t locus)
317 : 25160 : : locus (locus), outer_attrs (std::move (outer_attribs)),
318 : 12580 : main_or_left_expr (std::move (main_or_left_expr))
319 : 12580 : {}
320 : :
321 : : // Copy constructor (only for initialisation of expr purposes)
322 : 13421 : OperatorExpr (OperatorExpr const &other)
323 : 13421 : : locus (other.locus), outer_attrs (other.outer_attrs)
324 : : {
325 : : // guard to prevent null dereference (only required if error state)
326 : 13421 : if (other.main_or_left_expr != nullptr)
327 : 13421 : main_or_left_expr = other.main_or_left_expr->clone_expr ();
328 : 13421 : }
329 : :
330 : : // Overload assignment operator to deep copy expr
331 : : OperatorExpr &operator= (OperatorExpr const &other)
332 : : {
333 : : ExprWithoutBlock::operator= (other);
334 : : locus = other.locus;
335 : : outer_attrs = other.outer_attrs;
336 : :
337 : : // guard to prevent null dereference (only required if error state)
338 : : if (other.main_or_left_expr != nullptr)
339 : : main_or_left_expr = other.main_or_left_expr->clone_expr ();
340 : : else
341 : : main_or_left_expr = nullptr;
342 : :
343 : : return *this;
344 : : }
345 : :
346 : : // move constructors
347 : : OperatorExpr (OperatorExpr &&other) = default;
348 : : OperatorExpr &operator= (OperatorExpr &&other) = default;
349 : :
350 : : public:
351 : 20064 : location_t get_locus () const override final { return locus; }
352 : :
353 : : // Invalid if expr is null, so base stripping on that.
354 : 14 : void mark_for_strip () override { main_or_left_expr = nullptr; }
355 : 559184 : bool is_marked_for_strip () const override
356 : : {
357 : 559184 : return main_or_left_expr == nullptr;
358 : : }
359 : :
360 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
361 : 1149079 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
362 : :
363 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
364 : : {
365 : 0 : outer_attrs = std::move (new_attrs);
366 : 0 : }
367 : : };
368 : :
369 : : /* Unary prefix & or &mut (or && and &&mut) borrow operator. Cannot be
370 : : * overloaded. */
371 : 130 : class BorrowExpr : public OperatorExpr
372 : : {
373 : : bool is_mut;
374 : : bool double_borrow;
375 : :
376 : : public:
377 : : std::string as_string () const override;
378 : :
379 : 918 : BorrowExpr (std::unique_ptr<Expr> borrow_lvalue, bool is_mut_borrow,
380 : : bool is_double_borrow, std::vector<Attribute> outer_attribs,
381 : : location_t locus)
382 : 918 : : OperatorExpr (std::move (borrow_lvalue), std::move (outer_attribs),
383 : : locus),
384 : 918 : is_mut (is_mut_borrow), double_borrow (is_double_borrow)
385 : 918 : {}
386 : :
387 : : void accept_vis (ASTVisitor &vis) override;
388 : :
389 : : // TODO: is this better? Or is a "vis_block" better?
390 : 12702 : std::unique_ptr<Expr> &get_borrowed_expr ()
391 : : {
392 : 12702 : rust_assert (main_or_left_expr != nullptr);
393 : 12702 : return main_or_left_expr;
394 : : }
395 : :
396 : 952 : bool get_is_mut () const { return is_mut; }
397 : :
398 : 929 : bool get_is_double_borrow () const { return double_borrow; }
399 : :
400 : : protected:
401 : : /* Use covariance to implement clone function as returning this object rather
402 : : * than base */
403 : 65 : BorrowExpr *clone_expr_without_block_impl () const override
404 : : {
405 : 65 : return new BorrowExpr (*this);
406 : : }
407 : : };
408 : :
409 : : // Unary prefix * deference operator
410 : 7680 : class DereferenceExpr : public OperatorExpr
411 : : {
412 : : public:
413 : : std::string as_string () const override;
414 : :
415 : : // Constructor calls OperatorExpr's protected constructor
416 : 1290 : DereferenceExpr (std::unique_ptr<Expr> deref_lvalue,
417 : : std::vector<Attribute> outer_attribs, location_t locus)
418 : 1290 : : OperatorExpr (std::move (deref_lvalue), std::move (outer_attribs), locus)
419 : 1290 : {}
420 : :
421 : : void accept_vis (ASTVisitor &vis) override;
422 : :
423 : : // TODO: is this better? Or is a "vis_block" better?
424 : 10391 : std::unique_ptr<Expr> &get_dereferenced_expr ()
425 : : {
426 : 10391 : rust_assert (main_or_left_expr != nullptr);
427 : 10391 : return main_or_left_expr;
428 : : }
429 : :
430 : : protected:
431 : : /* Use covariance to implement clone function as returning this object rather
432 : : * than base */
433 : 3840 : DereferenceExpr *clone_expr_without_block_impl () const override
434 : : {
435 : 3840 : return new DereferenceExpr (*this);
436 : : }
437 : : };
438 : :
439 : : // Unary postfix ? error propogation operator. Cannot be overloaded.
440 : 0 : class ErrorPropagationExpr : public OperatorExpr
441 : : {
442 : : public:
443 : : std::string as_string () const override;
444 : :
445 : : // Constructor calls OperatorExpr's protected constructor
446 : 0 : ErrorPropagationExpr (std::unique_ptr<Expr> potential_error_value,
447 : : std::vector<Attribute> outer_attribs, location_t locus)
448 : 0 : : OperatorExpr (std::move (potential_error_value),
449 : 0 : std::move (outer_attribs), locus)
450 : 0 : {}
451 : :
452 : : void accept_vis (ASTVisitor &vis) override;
453 : :
454 : : // TODO: is this better? Or is a "vis_block" better?
455 : 0 : std::unique_ptr<Expr> &get_propagating_expr ()
456 : : {
457 : 0 : rust_assert (main_or_left_expr != nullptr);
458 : 0 : return main_or_left_expr;
459 : : }
460 : :
461 : : protected:
462 : : /* Use covariance to implement clone function as returning this object rather
463 : : * than base */
464 : 0 : ErrorPropagationExpr *clone_expr_without_block_impl () const override
465 : : {
466 : 0 : return new ErrorPropagationExpr (*this);
467 : : }
468 : : };
469 : :
470 : : // Unary prefix - or ! negation or NOT operators.
471 : 0 : class NegationExpr : public OperatorExpr
472 : : {
473 : : public:
474 : : using ExprType = NegationOperator;
475 : :
476 : : private:
477 : : /* Note: overload negation via std::ops::Neg and not via std::ops::Not
478 : : * Negation only works for signed integer and floating-point types, NOT only
479 : : * works for boolean and integer types (via bitwise NOT) */
480 : : ExprType expr_type;
481 : :
482 : : public:
483 : : std::string as_string () const override;
484 : :
485 : 290 : ExprType get_expr_type () const { return expr_type; }
486 : :
487 : : // Constructor calls OperatorExpr's protected constructor
488 : 290 : NegationExpr (std::unique_ptr<Expr> negated_value, ExprType expr_kind,
489 : : std::vector<Attribute> outer_attribs, location_t locus)
490 : 290 : : OperatorExpr (std::move (negated_value), std::move (outer_attribs),
491 : : locus),
492 : 290 : expr_type (expr_kind)
493 : 290 : {}
494 : :
495 : : void accept_vis (ASTVisitor &vis) override;
496 : :
497 : : // TODO: is this better? Or is a "vis_block" better?
498 : 2760 : std::unique_ptr<Expr> &get_negated_expr ()
499 : : {
500 : 2760 : rust_assert (main_or_left_expr != nullptr);
501 : 2760 : return main_or_left_expr;
502 : : }
503 : :
504 : : protected:
505 : : /* Use covariance to implement clone function as returning this object rather
506 : : * than base */
507 : 0 : NegationExpr *clone_expr_without_block_impl () const override
508 : : {
509 : 0 : return new NegationExpr (*this);
510 : : }
511 : : };
512 : :
513 : : // Infix binary operators. +, -, *, /, %, &, |, ^, <<, >>
514 : : class ArithmeticOrLogicalExpr : public OperatorExpr
515 : : {
516 : : public:
517 : : using ExprType = ArithmeticOrLogicalOperator;
518 : :
519 : : private:
520 : : // Note: overloading trait specified in comments
521 : : ExprType expr_type;
522 : :
523 : : std::unique_ptr<Expr> right_expr;
524 : :
525 : : public:
526 : : std::string as_string () const override;
527 : :
528 : 2447 : ExprType get_expr_type () const { return expr_type; }
529 : :
530 : : // Constructor calls OperatorExpr's protected constructor
531 : 3641 : ArithmeticOrLogicalExpr (std::unique_ptr<Expr> left_value,
532 : : std::unique_ptr<Expr> right_value,
533 : : ExprType expr_kind, location_t locus)
534 : 10923 : : OperatorExpr (std::move (left_value), std::vector<Attribute> (), locus),
535 : 3641 : expr_type (expr_kind), right_expr (std::move (right_value))
536 : 3641 : {}
537 : : // outer attributes not allowed
538 : :
539 : : // Copy constructor - probably required due to unique pointer
540 : 7716 : ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr const &other)
541 : 15432 : : OperatorExpr (other), expr_type (other.expr_type),
542 : 7716 : right_expr (other.right_expr->clone_expr ())
543 : 7716 : {}
544 : :
545 : : // Overload assignment operator
546 : : ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr const &other)
547 : : {
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;
552 : :
553 : : return *this;
554 : : }
555 : :
556 : : // move constructors
557 : : ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr &&other) = default;
558 : : ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr &&other)
559 : : = default;
560 : :
561 : : void accept_vis (ASTVisitor &vis) override;
562 : :
563 : : // TODO: is this better? Or is a "vis_block" better?
564 : 2123406 : std::unique_ptr<Expr> &get_left_expr ()
565 : : {
566 : 2123406 : rust_assert (main_or_left_expr != nullptr);
567 : 2123406 : return main_or_left_expr;
568 : : }
569 : :
570 : : // TODO: is this better? Or is a "vis_block" better?
571 : 2123406 : std::unique_ptr<Expr> &get_right_expr ()
572 : : {
573 : 2123406 : rust_assert (right_expr != nullptr);
574 : 2123406 : return right_expr;
575 : : }
576 : :
577 : : void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); }
578 : : void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); }
579 : :
580 : : protected:
581 : : /* Use covariance to implement clone function as returning this object rather
582 : : * than base */
583 : 7716 : ArithmeticOrLogicalExpr *clone_expr_without_block_impl () const override
584 : : {
585 : 7716 : return new ArithmeticOrLogicalExpr (*this);
586 : : }
587 : : };
588 : :
589 : : // Infix binary comparison operators. ==, !=, <, <=, >, >=
590 : : class ComparisonExpr : public OperatorExpr
591 : : {
592 : : public:
593 : : using ExprType = ComparisonOperator;
594 : :
595 : : private:
596 : : // Note: overloading trait specified in comments
597 : : ExprType expr_type;
598 : :
599 : : std::unique_ptr<Expr> right_expr;
600 : :
601 : : public:
602 : : std::string as_string () const override;
603 : :
604 : 900 : ExprType get_expr_type () const { return expr_type; }
605 : :
606 : : // Constructor requires pointers for polymorphism
607 : 909 : ComparisonExpr (std::unique_ptr<Expr> left_value,
608 : : std::unique_ptr<Expr> right_value, ExprType comparison_kind,
609 : : location_t locus)
610 : 2727 : : OperatorExpr (std::move (left_value), std::vector<Attribute> (), locus),
611 : 909 : expr_type (comparison_kind), right_expr (std::move (right_value))
612 : 909 : {}
613 : : // outer attributes not allowed
614 : :
615 : : // Copy constructor also calls OperatorExpr's protected constructor
616 : 70 : ComparisonExpr (ComparisonExpr const &other)
617 : 140 : : OperatorExpr (other), expr_type (other.expr_type),
618 : 70 : right_expr (other.right_expr->clone_expr ())
619 : 70 : {}
620 : :
621 : : // Overload assignment operator to deep copy
622 : : ComparisonExpr &operator= (ComparisonExpr const &other)
623 : : {
624 : : OperatorExpr::operator= (other);
625 : : // main_or_left_expr = other.main_or_left_expr->clone_expr();
626 : : right_expr = other.right_expr->clone_expr ();
627 : : expr_type = other.expr_type;
628 : : // outer_attrs = other.outer_attrs;
629 : :
630 : : return *this;
631 : : }
632 : :
633 : : // move constructors
634 : : ComparisonExpr (ComparisonExpr &&other) = default;
635 : : ComparisonExpr &operator= (ComparisonExpr &&other) = default;
636 : :
637 : : void accept_vis (ASTVisitor &vis) override;
638 : :
639 : : // TODO: is this better? Or is a "vis_block" better?
640 : 9048 : std::unique_ptr<Expr> &get_left_expr ()
641 : : {
642 : 9048 : rust_assert (main_or_left_expr != nullptr);
643 : 9048 : return main_or_left_expr;
644 : : }
645 : :
646 : : // TODO: is this better? Or is a "vis_block" better?
647 : 9048 : std::unique_ptr<Expr> &get_right_expr ()
648 : : {
649 : 9048 : rust_assert (right_expr != nullptr);
650 : 9048 : return right_expr;
651 : : }
652 : :
653 : : ExprType get_kind () { return expr_type; }
654 : :
655 : : /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2)
656 : : * maybe? */
657 : : protected:
658 : : /* Use covariance to implement clone function as returning this object rather
659 : : * than base */
660 : 70 : ComparisonExpr *clone_expr_without_block_impl () const override
661 : : {
662 : 70 : return new ComparisonExpr (*this);
663 : : }
664 : : };
665 : :
666 : : // Infix binary lazy boolean logical operators && and ||.
667 : : class LazyBooleanExpr : public OperatorExpr
668 : : {
669 : : public:
670 : : using ExprType = LazyBooleanOperator;
671 : :
672 : : private:
673 : : ExprType expr_type;
674 : :
675 : : std::unique_ptr<Expr> right_expr;
676 : :
677 : : public:
678 : : // Constructor calls OperatorExpr's protected constructor
679 : 378 : LazyBooleanExpr (std::unique_ptr<Expr> left_bool_expr,
680 : : std::unique_ptr<Expr> right_bool_expr, ExprType expr_kind,
681 : : location_t locus)
682 : 1134 : : OperatorExpr (std::move (left_bool_expr), std::vector<Attribute> (),
683 : : locus),
684 : 378 : expr_type (expr_kind), right_expr (std::move (right_bool_expr))
685 : 378 : {}
686 : : // outer attributes not allowed
687 : :
688 : : // Copy constructor also calls OperatorExpr's protected constructor
689 : 0 : LazyBooleanExpr (LazyBooleanExpr const &other)
690 : 0 : : OperatorExpr (other), expr_type (other.expr_type),
691 : 0 : right_expr (other.right_expr->clone_expr ())
692 : 0 : {}
693 : :
694 : : // Overload assignment operator to deep copy
695 : : LazyBooleanExpr &operator= (LazyBooleanExpr const &other)
696 : : {
697 : : OperatorExpr::operator= (other);
698 : : // main_or_left_expr = other.main_or_left_expr->clone_expr();
699 : : right_expr = other.right_expr->clone_expr ();
700 : : expr_type = other.expr_type;
701 : :
702 : : return *this;
703 : : }
704 : :
705 : : // move constructors
706 : : LazyBooleanExpr (LazyBooleanExpr &&other) = default;
707 : : LazyBooleanExpr &operator= (LazyBooleanExpr &&other) = default;
708 : :
709 : : std::string as_string () const override;
710 : :
711 : 378 : ExprType get_expr_type () const { return expr_type; }
712 : :
713 : : void accept_vis (ASTVisitor &vis) override;
714 : :
715 : : // TODO: is this better? Or is a "vis_block" better?
716 : 4102 : std::unique_ptr<Expr> &get_left_expr ()
717 : : {
718 : 4102 : rust_assert (main_or_left_expr != nullptr);
719 : 4102 : return main_or_left_expr;
720 : : }
721 : :
722 : : // TODO: is this better? Or is a "vis_block" better?
723 : 4102 : std::unique_ptr<Expr> &get_right_expr ()
724 : : {
725 : 4102 : rust_assert (right_expr != nullptr);
726 : 4102 : return right_expr;
727 : : }
728 : :
729 : : ExprType get_kind () { return expr_type; }
730 : :
731 : : protected:
732 : : /* Use covariance to implement clone function as returning this object rather
733 : : * than base */
734 : 0 : LazyBooleanExpr *clone_expr_without_block_impl () const override
735 : : {
736 : 0 : return new LazyBooleanExpr (*this);
737 : : }
738 : : };
739 : :
740 : : // Binary infix "as" cast expression.
741 : : class TypeCastExpr : public OperatorExpr
742 : : {
743 : : std::unique_ptr<TypeNoBounds> type_to_convert_to;
744 : :
745 : : // Note: only certain type casts allowed, outlined in reference
746 : : public:
747 : : std::string as_string () const override;
748 : :
749 : : // Constructor requires calling protected constructor of OperatorExpr
750 : 3330 : TypeCastExpr (std::unique_ptr<Expr> expr_to_cast,
751 : : std::unique_ptr<TypeNoBounds> type_to_cast_to, location_t locus)
752 : 9990 : : OperatorExpr (std::move (expr_to_cast), std::vector<Attribute> (), locus),
753 : 3330 : type_to_convert_to (std::move (type_to_cast_to))
754 : 3330 : {}
755 : : // outer attributes not allowed
756 : :
757 : : // Copy constructor also requires calling protected constructor
758 : 1660 : TypeCastExpr (TypeCastExpr const &other)
759 : 1660 : : OperatorExpr (other),
760 : 1660 : type_to_convert_to (other.type_to_convert_to->clone_type_no_bounds ())
761 : 1660 : {}
762 : :
763 : : // Overload assignment operator to deep copy
764 : : TypeCastExpr &operator= (TypeCastExpr const &other)
765 : : {
766 : : OperatorExpr::operator= (other);
767 : : // main_or_left_expr = other.main_or_left_expr->clone_expr();
768 : : type_to_convert_to = other.type_to_convert_to->clone_type_no_bounds ();
769 : :
770 : : return *this;
771 : : }
772 : :
773 : : // move constructors
774 : : TypeCastExpr (TypeCastExpr &&other) = default;
775 : : TypeCastExpr &operator= (TypeCastExpr &&other) = default;
776 : :
777 : : void accept_vis (ASTVisitor &vis) override;
778 : :
779 : : // TODO: is this better? Or is a "vis_block" better?
780 : 51938 : std::unique_ptr<Expr> &get_casted_expr ()
781 : : {
782 : 51938 : rust_assert (main_or_left_expr != nullptr);
783 : 51938 : return main_or_left_expr;
784 : : }
785 : :
786 : : // TODO: is this better? Or is a "vis_block" better?
787 : 51938 : std::unique_ptr<TypeNoBounds> &get_type_to_cast_to ()
788 : : {
789 : 51938 : rust_assert (type_to_convert_to != nullptr);
790 : 51938 : return type_to_convert_to;
791 : : }
792 : :
793 : : protected:
794 : : /* Use covariance to implement clone function as returning this object rather
795 : : * than base */
796 : 1660 : TypeCastExpr *clone_expr_without_block_impl () const override
797 : : {
798 : 1660 : return new TypeCastExpr (*this);
799 : : }
800 : : };
801 : :
802 : : // Binary assignment expression.
803 : : class AssignmentExpr : public OperatorExpr
804 : : {
805 : : std::unique_ptr<Expr> right_expr;
806 : :
807 : : public:
808 : : std::string as_string () const override;
809 : :
810 : : // Call OperatorExpr constructor to initialise left_expr
811 : 1664 : AssignmentExpr (std::unique_ptr<Expr> value_to_assign_to,
812 : : std::unique_ptr<Expr> value_to_assign,
813 : : std::vector<Attribute> outer_attribs, location_t locus)
814 : 1664 : : OperatorExpr (std::move (value_to_assign_to), std::move (outer_attribs),
815 : : locus),
816 : 1664 : right_expr (std::move (value_to_assign))
817 : 1664 : {}
818 : : // outer attributes not allowed
819 : :
820 : : // Call OperatorExpr constructor in copy constructor, as well as clone
821 : 70 : AssignmentExpr (AssignmentExpr const &other)
822 : 70 : : OperatorExpr (other), right_expr (other.right_expr->clone_expr ())
823 : 70 : {}
824 : :
825 : : // Overload assignment operator to clone unique_ptr right_expr
826 : : AssignmentExpr &operator= (AssignmentExpr const &other)
827 : : {
828 : : OperatorExpr::operator= (other);
829 : : // main_or_left_expr = other.main_or_left_expr->clone_expr();
830 : : right_expr = other.right_expr->clone_expr ();
831 : : // outer_attrs = other.outer_attrs;
832 : :
833 : : return *this;
834 : : }
835 : :
836 : : // move constructors
837 : : AssignmentExpr (AssignmentExpr &&other) = default;
838 : : AssignmentExpr &operator= (AssignmentExpr &&other) = default;
839 : :
840 : : void accept_vis (ASTVisitor &vis) override;
841 : :
842 : 37 : void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); }
843 : 37 : void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); }
844 : :
845 : : // TODO: is this better? Or is a "vis_block" better?
846 : 17699 : std::unique_ptr<Expr> &get_left_expr ()
847 : : {
848 : 17699 : rust_assert (main_or_left_expr != nullptr);
849 : 17699 : return main_or_left_expr;
850 : : }
851 : :
852 : : // TODO: is this better? Or is a "vis_block" better?
853 : 17699 : std::unique_ptr<Expr> &get_right_expr ()
854 : : {
855 : 17699 : rust_assert (right_expr != nullptr);
856 : 17699 : return right_expr;
857 : : }
858 : :
859 : : protected:
860 : : /* Use covariance to implement clone function as returning this object rather
861 : : * than base */
862 : 70 : AssignmentExpr *clone_expr_without_block_impl () const override
863 : : {
864 : 70 : return new AssignmentExpr (*this);
865 : : }
866 : : };
867 : :
868 : : /* Binary infix compound assignment (arithmetic or logic then assignment)
869 : : * expressions. */
870 : : class CompoundAssignmentExpr : public OperatorExpr
871 : : {
872 : : public:
873 : : using ExprType = CompoundAssignmentOperator;
874 : :
875 : : private:
876 : : // Note: overloading trait specified in comments
877 : : ExprType expr_type;
878 : : std::unique_ptr<Expr> right_expr;
879 : :
880 : : public:
881 : : std::string as_string () const override;
882 : :
883 : 160 : ExprType get_expr_type () const { return expr_type; }
884 : :
885 : : // Use pointers in constructor to enable polymorphism
886 : 160 : CompoundAssignmentExpr (std::unique_ptr<Expr> value_to_assign_to,
887 : : std::unique_ptr<Expr> value_to_assign,
888 : : ExprType expr_kind, location_t locus)
889 : 480 : : OperatorExpr (std::move (value_to_assign_to), std::vector<Attribute> (),
890 : : locus),
891 : 160 : expr_type (expr_kind), right_expr (std::move (value_to_assign))
892 : 160 : {}
893 : : // outer attributes not allowed
894 : :
895 : : // Have clone in copy constructor
896 : 0 : CompoundAssignmentExpr (CompoundAssignmentExpr const &other)
897 : 0 : : OperatorExpr (other), expr_type (other.expr_type),
898 : 0 : right_expr (other.right_expr->clone_expr ())
899 : 0 : {}
900 : :
901 : : // Overload assignment operator to clone
902 : : CompoundAssignmentExpr &operator= (CompoundAssignmentExpr const &other)
903 : : {
904 : : OperatorExpr::operator= (other);
905 : : // main_or_left_expr = other.main_or_left_expr->clone_expr();
906 : : right_expr = other.right_expr->clone_expr ();
907 : : expr_type = other.expr_type;
908 : : // outer_attrs = other.outer_attrs;
909 : :
910 : : return *this;
911 : : }
912 : :
913 : : // move constructors
914 : : CompoundAssignmentExpr (CompoundAssignmentExpr &&other) = default;
915 : : CompoundAssignmentExpr &operator= (CompoundAssignmentExpr &&other) = default;
916 : :
917 : : void accept_vis (ASTVisitor &vis) override;
918 : :
919 : : // TODO: is this better? Or is a "vis_block" better?
920 : 2008 : std::unique_ptr<Expr> &get_left_expr ()
921 : : {
922 : 2008 : rust_assert (main_or_left_expr != nullptr);
923 : 2008 : return main_or_left_expr;
924 : : }
925 : :
926 : : // TODO: is this better? Or is a "vis_block" better?
927 : 2008 : std::unique_ptr<Expr> &get_right_expr ()
928 : : {
929 : 2008 : rust_assert (right_expr != nullptr);
930 : 2008 : return right_expr;
931 : : }
932 : :
933 : : protected:
934 : : /* Use covariance to implement clone function as returning this object rather
935 : : * than base */
936 : 0 : CompoundAssignmentExpr *clone_expr_without_block_impl () const override
937 : : {
938 : 0 : return new CompoundAssignmentExpr (*this);
939 : : }
940 : : };
941 : :
942 : : // Expression in parentheses (i.e. like literally just any 3 + (2 * 6))
943 : : class GroupedExpr : public ExprWithoutBlock
944 : : {
945 : : std::vector<Attribute> outer_attrs;
946 : : std::vector<Attribute> inner_attrs;
947 : : std::unique_ptr<Expr> expr_in_parens;
948 : : location_t locus;
949 : :
950 : : public:
951 : : std::string as_string () const override;
952 : :
953 : : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
954 : 1285 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
955 : :
956 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
957 : 1677 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
958 : :
959 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
960 : : {
961 : 0 : outer_attrs = std::move (new_attrs);
962 : 0 : }
963 : :
964 : 162 : GroupedExpr (std::unique_ptr<Expr> parenthesised_expr,
965 : : std::vector<Attribute> inner_attribs,
966 : : std::vector<Attribute> outer_attribs, location_t locus)
967 : 324 : : outer_attrs (std::move (outer_attribs)),
968 : 162 : inner_attrs (std::move (inner_attribs)),
969 : 162 : expr_in_parens (std::move (parenthesised_expr)), locus (locus)
970 : 162 : {}
971 : :
972 : : // Copy constructor includes clone for expr_in_parens
973 : 75 : GroupedExpr (GroupedExpr const &other)
974 : 75 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
975 : 75 : inner_attrs (other.inner_attrs), locus (other.locus)
976 : : {
977 : : // guard to prevent null dereference (only required if error state)
978 : 75 : if (other.expr_in_parens != nullptr)
979 : 75 : expr_in_parens = other.expr_in_parens->clone_expr ();
980 : 75 : }
981 : :
982 : : // Overloaded assignment operator to clone expr_in_parens
983 : : GroupedExpr &operator= (GroupedExpr const &other)
984 : : {
985 : : ExprWithoutBlock::operator= (other);
986 : : inner_attrs = other.inner_attrs;
987 : : locus = other.locus;
988 : : outer_attrs = other.outer_attrs;
989 : :
990 : : // guard to prevent null dereference (only required if error state)
991 : : if (other.expr_in_parens != nullptr)
992 : : expr_in_parens = other.expr_in_parens->clone_expr ();
993 : : else
994 : : expr_in_parens = nullptr;
995 : :
996 : : return *this;
997 : : }
998 : :
999 : : // move constructors
1000 : : GroupedExpr (GroupedExpr &&other) = default;
1001 : : GroupedExpr &operator= (GroupedExpr &&other) = default;
1002 : :
1003 : 421 : location_t get_locus () const override final { return locus; }
1004 : :
1005 : : void accept_vis (ASTVisitor &vis) override;
1006 : :
1007 : : // Invalid if inner expr is null, so base stripping on that.
1008 : 0 : void mark_for_strip () override { expr_in_parens = nullptr; }
1009 : 388 : bool is_marked_for_strip () const override
1010 : : {
1011 : 388 : return expr_in_parens == nullptr;
1012 : : }
1013 : :
1014 : : // TODO: is this better? Or is a "vis_block" better?
1015 : 1643 : std::unique_ptr<Expr> &get_expr_in_parens ()
1016 : : {
1017 : 1643 : rust_assert (expr_in_parens != nullptr);
1018 : 1643 : return expr_in_parens;
1019 : : }
1020 : :
1021 : : protected:
1022 : : /* Use covariance to implement clone function as returning this object rather
1023 : : * than base */
1024 : 75 : GroupedExpr *clone_expr_without_block_impl () const override
1025 : : {
1026 : 75 : return new GroupedExpr (*this);
1027 : : }
1028 : : };
1029 : :
1030 : : // Base array initialisation internal element representation thing (abstract)
1031 : : // aka ArrayElements
1032 : : class ArrayElems
1033 : : {
1034 : : public:
1035 : : virtual ~ArrayElems () {}
1036 : :
1037 : : // Unique pointer custom clone ArrayElems function
1038 : 65 : std::unique_ptr<ArrayElems> clone_array_elems () const
1039 : : {
1040 : 65 : return std::unique_ptr<ArrayElems> (clone_array_elems_impl ());
1041 : : }
1042 : :
1043 : : virtual std::string as_string () const = 0;
1044 : :
1045 : : virtual void accept_vis (ASTVisitor &vis) = 0;
1046 : :
1047 : 295 : NodeId get_node_id () const { return node_id; }
1048 : :
1049 : : protected:
1050 : 375 : ArrayElems () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {}
1051 : :
1052 : : // pure virtual clone implementation
1053 : : virtual ArrayElems *clone_array_elems_impl () const = 0;
1054 : :
1055 : : NodeId node_id;
1056 : : };
1057 : :
1058 : : // Value array elements
1059 : : class ArrayElemsValues : public ArrayElems
1060 : : {
1061 : : std::vector<std::unique_ptr<Expr> > values;
1062 : : location_t locus;
1063 : :
1064 : : public:
1065 : 201 : ArrayElemsValues (std::vector<std::unique_ptr<Expr> > elems, location_t locus)
1066 : 201 : : ArrayElems (), values (std::move (elems)), locus (locus)
1067 : 201 : {}
1068 : :
1069 : : // copy constructor with vector clone
1070 : 65 : ArrayElemsValues (ArrayElemsValues const &other)
1071 : 65 : {
1072 : 65 : values.reserve (other.values.size ());
1073 : 8881 : for (const auto &e : other.values)
1074 : 8816 : values.push_back (e->clone_expr ());
1075 : 65 : }
1076 : :
1077 : : // overloaded assignment operator with vector clone
1078 : : ArrayElemsValues &operator= (ArrayElemsValues const &other)
1079 : : {
1080 : : values.reserve (other.values.size ());
1081 : : for (const auto &e : other.values)
1082 : : values.push_back (e->clone_expr ());
1083 : :
1084 : : return *this;
1085 : : }
1086 : :
1087 : : // move constructors
1088 : : ArrayElemsValues (ArrayElemsValues &&other) = default;
1089 : : ArrayElemsValues &operator= (ArrayElemsValues &&other) = default;
1090 : :
1091 : : std::string as_string () const override;
1092 : :
1093 : : void accept_vis (ASTVisitor &vis) override;
1094 : :
1095 : : // TODO: this mutable getter seems really dodgy. Think up better way.
1096 : : const std::vector<std::unique_ptr<Expr> > &get_values () const
1097 : : {
1098 : : return values;
1099 : : }
1100 : 1361 : std::vector<std::unique_ptr<Expr> > &get_values () { return values; }
1101 : :
1102 : : size_t get_num_values () const { return values.size (); }
1103 : :
1104 : : protected:
1105 : 65 : ArrayElemsValues *clone_array_elems_impl () const override
1106 : : {
1107 : 65 : return new ArrayElemsValues (*this);
1108 : : }
1109 : : };
1110 : :
1111 : : // Copied array element and number of copies
1112 : : class ArrayElemsCopied : public ArrayElems
1113 : : {
1114 : : std::unique_ptr<Expr> elem_to_copy;
1115 : : std::unique_ptr<Expr> num_copies;
1116 : : location_t locus;
1117 : :
1118 : : public:
1119 : : // Constructor requires pointers for polymorphism
1120 : 109 : ArrayElemsCopied (std::unique_ptr<Expr> copied_elem,
1121 : : std::unique_ptr<Expr> copy_amount, location_t locus)
1122 : 218 : : ArrayElems (), elem_to_copy (std::move (copied_elem)),
1123 : 109 : num_copies (std::move (copy_amount)), locus (locus)
1124 : : {}
1125 : :
1126 : : // Copy constructor required due to unique_ptr - uses custom clone
1127 : 0 : ArrayElemsCopied (ArrayElemsCopied const &other)
1128 : 0 : : elem_to_copy (other.elem_to_copy->clone_expr ()),
1129 : 0 : num_copies (other.num_copies->clone_expr ())
1130 : 0 : {}
1131 : :
1132 : : // Overloaded assignment operator for deep copying
1133 : : ArrayElemsCopied &operator= (ArrayElemsCopied const &other)
1134 : : {
1135 : : elem_to_copy = other.elem_to_copy->clone_expr ();
1136 : : num_copies = other.num_copies->clone_expr ();
1137 : :
1138 : : return *this;
1139 : : }
1140 : :
1141 : : // move constructors
1142 : : ArrayElemsCopied (ArrayElemsCopied &&other) = default;
1143 : : ArrayElemsCopied &operator= (ArrayElemsCopied &&other) = default;
1144 : :
1145 : : std::string as_string () const override;
1146 : :
1147 : : void accept_vis (ASTVisitor &vis) override;
1148 : :
1149 : : // TODO: is this better? Or is a "vis_block" better?
1150 : 944 : std::unique_ptr<Expr> &get_elem_to_copy ()
1151 : : {
1152 : 944 : rust_assert (elem_to_copy != nullptr);
1153 : 944 : return elem_to_copy;
1154 : : }
1155 : :
1156 : : // TODO: is this better? Or is a "vis_block" better?
1157 : 944 : std::unique_ptr<Expr> &get_num_copies ()
1158 : : {
1159 : 944 : rust_assert (num_copies != nullptr);
1160 : 944 : return num_copies;
1161 : : }
1162 : :
1163 : : protected:
1164 : 0 : ArrayElemsCopied *clone_array_elems_impl () const override
1165 : : {
1166 : 0 : return new ArrayElemsCopied (*this);
1167 : : }
1168 : : };
1169 : :
1170 : : // Array definition-ish expression
1171 : : class ArrayExpr : public ExprWithoutBlock
1172 : : {
1173 : : std::vector<Attribute> outer_attrs;
1174 : : std::vector<Attribute> inner_attrs;
1175 : : std::unique_ptr<ArrayElems> internal_elements;
1176 : : location_t locus;
1177 : :
1178 : : // TODO: find another way to store this to save memory?
1179 : : bool marked_for_strip = false;
1180 : :
1181 : : public:
1182 : : std::string as_string () const override;
1183 : :
1184 : : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1185 : 2375 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1186 : :
1187 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1188 : 2970 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1189 : :
1190 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1191 : : {
1192 : 0 : outer_attrs = std::move (new_attrs);
1193 : 0 : }
1194 : :
1195 : : // Constructor requires ArrayElems pointer
1196 : 310 : ArrayExpr (std::unique_ptr<ArrayElems> array_elems,
1197 : : std::vector<Attribute> inner_attribs,
1198 : : std::vector<Attribute> outer_attribs, location_t locus)
1199 : 620 : : outer_attrs (std::move (outer_attribs)),
1200 : 310 : inner_attrs (std::move (inner_attribs)),
1201 : 310 : internal_elements (std::move (array_elems)), locus (locus)
1202 : : {
1203 : 310 : rust_assert (internal_elements != nullptr);
1204 : 310 : }
1205 : :
1206 : : // Copy constructor requires cloning ArrayElems for polymorphism to hold
1207 : 65 : ArrayExpr (ArrayExpr const &other)
1208 : 65 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1209 : 65 : inner_attrs (other.inner_attrs), locus (other.locus),
1210 : 130 : marked_for_strip (other.marked_for_strip)
1211 : : {
1212 : 65 : internal_elements = other.internal_elements->clone_array_elems ();
1213 : 65 : rust_assert (internal_elements != nullptr);
1214 : 65 : }
1215 : :
1216 : : // Overload assignment operator to clone internal_elements
1217 : : ArrayExpr &operator= (ArrayExpr const &other)
1218 : : {
1219 : : ExprWithoutBlock::operator= (other);
1220 : : inner_attrs = other.inner_attrs;
1221 : : locus = other.locus;
1222 : : marked_for_strip = other.marked_for_strip;
1223 : : outer_attrs = other.outer_attrs;
1224 : :
1225 : : internal_elements = other.internal_elements->clone_array_elems ();
1226 : :
1227 : : rust_assert (internal_elements != nullptr);
1228 : : return *this;
1229 : : }
1230 : :
1231 : : // move constructors
1232 : : ArrayExpr (ArrayExpr &&other) = default;
1233 : : ArrayExpr &operator= (ArrayExpr &&other) = default;
1234 : :
1235 : 601 : location_t get_locus () const override final { return locus; }
1236 : :
1237 : : void accept_vis (ASTVisitor &vis) override;
1238 : :
1239 : : // Can't think of any invalid invariants, so store boolean.
1240 : 0 : void mark_for_strip () override { marked_for_strip = true; }
1241 : 581 : bool is_marked_for_strip () const override { return marked_for_strip; }
1242 : :
1243 : : // TODO: is this better? Or is a "vis_block" better?
1244 : 2103 : std::unique_ptr<ArrayElems> &get_array_elems ()
1245 : : {
1246 : 2103 : rust_assert (internal_elements != nullptr);
1247 : 2103 : return internal_elements;
1248 : : }
1249 : :
1250 : : protected:
1251 : : /* Use covariance to implement clone function as returning this object rather
1252 : : * than base */
1253 : 65 : ArrayExpr *clone_expr_without_block_impl () const override
1254 : : {
1255 : 65 : return new ArrayExpr (*this);
1256 : : }
1257 : : };
1258 : :
1259 : : // Aka IndexExpr (also applies to slices)
1260 : : /* Apparently a[b] is equivalent to *std::ops::Index::index(&a, b) or
1261 : : * *std::ops::Index::index_mut(&mut a, b) */
1262 : : /* Also apparently deref operations on a will be repeatedly applied to find an
1263 : : * implementation */
1264 : : class ArrayIndexExpr : public ExprWithoutBlock
1265 : : {
1266 : : std::vector<Attribute> outer_attrs;
1267 : : std::unique_ptr<Expr> array_expr;
1268 : : std::unique_ptr<Expr> index_expr;
1269 : : location_t locus;
1270 : :
1271 : : public:
1272 : : std::string as_string () const override;
1273 : :
1274 : 437 : ArrayIndexExpr (std::unique_ptr<Expr> array_expr,
1275 : : std::unique_ptr<Expr> array_index_expr,
1276 : : std::vector<Attribute> outer_attribs, location_t locus)
1277 : 874 : : outer_attrs (std::move (outer_attribs)),
1278 : 437 : array_expr (std::move (array_expr)),
1279 : 437 : index_expr (std::move (array_index_expr)), locus (locus)
1280 : 437 : {}
1281 : :
1282 : : // Copy constructor requires special cloning due to unique_ptr
1283 : 0 : ArrayIndexExpr (ArrayIndexExpr const &other)
1284 : 0 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1285 : 0 : locus (other.locus)
1286 : : {
1287 : : // guard to prevent null dereference (only required if error state)
1288 : 0 : if (other.array_expr != nullptr)
1289 : 0 : array_expr = other.array_expr->clone_expr ();
1290 : 0 : if (other.index_expr != nullptr)
1291 : 0 : index_expr = other.index_expr->clone_expr ();
1292 : 0 : }
1293 : :
1294 : : // Overload assignment operator to clone unique_ptrs
1295 : : ArrayIndexExpr &operator= (ArrayIndexExpr const &other)
1296 : : {
1297 : : ExprWithoutBlock::operator= (other);
1298 : : outer_attrs = other.outer_attrs;
1299 : : locus = other.locus;
1300 : :
1301 : : // guard to prevent null dereference (only required if error state)
1302 : : if (other.array_expr != nullptr)
1303 : : array_expr = other.array_expr->clone_expr ();
1304 : : else
1305 : : array_expr = nullptr;
1306 : : if (other.index_expr != nullptr)
1307 : : index_expr = other.index_expr->clone_expr ();
1308 : : else
1309 : : index_expr = nullptr;
1310 : :
1311 : : return *this;
1312 : : }
1313 : :
1314 : : // move constructors
1315 : : ArrayIndexExpr (ArrayIndexExpr &&other) = default;
1316 : : ArrayIndexExpr &operator= (ArrayIndexExpr &&other) = default;
1317 : :
1318 : 1014 : location_t get_locus () const override final { return locus; }
1319 : :
1320 : : void accept_vis (ASTVisitor &vis) override;
1321 : :
1322 : : // Invalid if either expr is null, so base stripping on that.
1323 : 0 : void mark_for_strip () override
1324 : : {
1325 : 0 : array_expr = nullptr;
1326 : 0 : index_expr = nullptr;
1327 : 0 : }
1328 : 1425 : bool is_marked_for_strip () const override
1329 : : {
1330 : 1425 : return array_expr == nullptr && index_expr == nullptr;
1331 : : }
1332 : :
1333 : : // TODO: is this better? Or is a "vis_block" better?
1334 : 5491 : std::unique_ptr<Expr> &get_array_expr ()
1335 : : {
1336 : 5491 : rust_assert (array_expr != nullptr);
1337 : 5491 : return array_expr;
1338 : : }
1339 : :
1340 : : // TODO: is this better? Or is a "vis_block" better?
1341 : 5491 : std::unique_ptr<Expr> &get_index_expr ()
1342 : : {
1343 : 5491 : rust_assert (index_expr != nullptr);
1344 : 5491 : return index_expr;
1345 : : }
1346 : :
1347 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1348 : 6483 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1349 : :
1350 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1351 : : {
1352 : 0 : outer_attrs = std::move (new_attrs);
1353 : 0 : }
1354 : :
1355 : : protected:
1356 : : /* Use covariance to implement clone function as returning this object rather
1357 : : * than base */
1358 : 0 : ArrayIndexExpr *clone_expr_without_block_impl () const override
1359 : : {
1360 : 0 : return new ArrayIndexExpr (*this);
1361 : : }
1362 : : };
1363 : :
1364 : : // AST representation of a tuple
1365 : : class TupleExpr : public ExprWithoutBlock
1366 : : {
1367 : : std::vector<Attribute> outer_attrs;
1368 : : std::vector<Attribute> inner_attrs;
1369 : : std::vector<std::unique_ptr<Expr> > tuple_elems;
1370 : : location_t locus;
1371 : :
1372 : : // TODO: find another way to store this to save memory?
1373 : : bool marked_for_strip = false;
1374 : :
1375 : : public:
1376 : : std::string as_string () const override;
1377 : :
1378 : : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1379 : 2175 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1380 : :
1381 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1382 : 3106 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1383 : :
1384 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1385 : : {
1386 : 0 : outer_attrs = std::move (new_attrs);
1387 : 0 : }
1388 : :
1389 : 335 : TupleExpr (std::vector<std::unique_ptr<Expr> > tuple_elements,
1390 : : std::vector<Attribute> inner_attribs,
1391 : : std::vector<Attribute> outer_attribs, location_t locus)
1392 : 670 : : outer_attrs (std::move (outer_attribs)),
1393 : 335 : inner_attrs (std::move (inner_attribs)),
1394 : 335 : tuple_elems (std::move (tuple_elements)), locus (locus)
1395 : 335 : {}
1396 : :
1397 : : // copy constructor with vector clone
1398 : 315 : TupleExpr (TupleExpr const &other)
1399 : 315 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1400 : 315 : inner_attrs (other.inner_attrs), locus (other.locus),
1401 : 630 : marked_for_strip (other.marked_for_strip)
1402 : : {
1403 : 315 : tuple_elems.reserve (other.tuple_elems.size ());
1404 : 925 : for (const auto &e : other.tuple_elems)
1405 : 610 : tuple_elems.push_back (e->clone_expr ());
1406 : 315 : }
1407 : :
1408 : : // overloaded assignment operator to vector clone
1409 : : TupleExpr &operator= (TupleExpr const &other)
1410 : : {
1411 : : ExprWithoutBlock::operator= (other);
1412 : : outer_attrs = other.outer_attrs;
1413 : : inner_attrs = other.inner_attrs;
1414 : : locus = other.locus;
1415 : : marked_for_strip = other.marked_for_strip;
1416 : :
1417 : : tuple_elems.reserve (other.tuple_elems.size ());
1418 : : for (const auto &e : other.tuple_elems)
1419 : : tuple_elems.push_back (e->clone_expr ());
1420 : :
1421 : : return *this;
1422 : : }
1423 : :
1424 : : // move constructors
1425 : : TupleExpr (TupleExpr &&other) = default;
1426 : : TupleExpr &operator= (TupleExpr &&other) = default;
1427 : :
1428 : : /* Note: syntactically, can disambiguate single-element tuple from parens with
1429 : : * comma, i.e. (0,) rather than (0) */
1430 : :
1431 : 657 : location_t get_locus () const override final { return locus; }
1432 : :
1433 : : void accept_vis (ASTVisitor &vis) override;
1434 : :
1435 : : // Can't think of any invalid invariants, so store boolean.
1436 : 0 : void mark_for_strip () override { marked_for_strip = true; }
1437 : 712 : bool is_marked_for_strip () const override { return marked_for_strip; }
1438 : :
1439 : : // TODO: this mutable getter seems really dodgy. Think up better way.
1440 : : const std::vector<std::unique_ptr<Expr> > &get_tuple_elems () const
1441 : : {
1442 : : return tuple_elems;
1443 : : }
1444 : 790 : std::vector<std::unique_ptr<Expr> > &get_tuple_elems ()
1445 : : {
1446 : 2182 : return tuple_elems;
1447 : : }
1448 : :
1449 : 328 : bool is_unit () const { return tuple_elems.size () == 0; }
1450 : :
1451 : : protected:
1452 : : /* Use covariance to implement clone function as returning this object rather
1453 : : * than base */
1454 : 315 : TupleExpr *clone_expr_without_block_impl () const override
1455 : : {
1456 : 315 : return new TupleExpr (*this);
1457 : : }
1458 : : };
1459 : :
1460 : : // aka TupleIndexingExpr
1461 : : // AST representation of a tuple indexing expression
1462 : : class TupleIndexExpr : public ExprWithoutBlock
1463 : : {
1464 : : std::vector<Attribute> outer_attrs;
1465 : : std::unique_ptr<Expr> tuple_expr;
1466 : : // TupleIndex is a decimal int literal with no underscores or suffix
1467 : : TupleIndex tuple_index;
1468 : :
1469 : : location_t locus;
1470 : :
1471 : : // i.e. pair.0
1472 : :
1473 : : public:
1474 : : std::string as_string () const override;
1475 : :
1476 : 726 : TupleIndex get_tuple_index () const { return tuple_index; }
1477 : :
1478 : 787 : TupleIndexExpr (std::unique_ptr<Expr> tuple_expr, TupleIndex index,
1479 : : std::vector<Attribute> outer_attribs, location_t locus)
1480 : 1574 : : outer_attrs (std::move (outer_attribs)),
1481 : 787 : tuple_expr (std::move (tuple_expr)), tuple_index (index), locus (locus)
1482 : 787 : {}
1483 : :
1484 : : // Copy constructor requires a clone for tuple_expr
1485 : 60 : TupleIndexExpr (TupleIndexExpr const &other)
1486 : 60 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1487 : 60 : tuple_index (other.tuple_index), locus (other.locus)
1488 : : {
1489 : : // guard to prevent null dereference (only required if error state)
1490 : 60 : if (other.tuple_expr != nullptr)
1491 : 60 : tuple_expr = other.tuple_expr->clone_expr ();
1492 : 60 : }
1493 : :
1494 : : // Overload assignment operator in order to clone
1495 : : TupleIndexExpr &operator= (TupleIndexExpr const &other)
1496 : : {
1497 : : ExprWithoutBlock::operator= (other);
1498 : : tuple_index = other.tuple_index;
1499 : : locus = other.locus;
1500 : : outer_attrs = other.outer_attrs;
1501 : :
1502 : : // guard to prevent null dereference (only required if error state)
1503 : : if (other.tuple_expr != nullptr)
1504 : : tuple_expr = other.tuple_expr->clone_expr ();
1505 : : else
1506 : : tuple_expr = nullptr;
1507 : :
1508 : : return *this;
1509 : : }
1510 : :
1511 : : // move constructors
1512 : : TupleIndexExpr (TupleIndexExpr &&other) = default;
1513 : : TupleIndexExpr &operator= (TupleIndexExpr &&other) = default;
1514 : :
1515 : 1565 : location_t get_locus () const override final { return locus; }
1516 : :
1517 : : void accept_vis (ASTVisitor &vis) override;
1518 : :
1519 : : // Invalid if tuple expr is null, so base stripping on that.
1520 : 0 : void mark_for_strip () override { tuple_expr = nullptr; }
1521 : 1979 : bool is_marked_for_strip () const override { return tuple_expr == nullptr; }
1522 : :
1523 : : // TODO: is this better? Or is a "vis_block" better?
1524 : 8635 : std::unique_ptr<Expr> &get_tuple_expr ()
1525 : : {
1526 : 8635 : rust_assert (tuple_expr != nullptr);
1527 : 8635 : return tuple_expr;
1528 : : }
1529 : :
1530 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1531 : 10439 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1532 : :
1533 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1534 : : {
1535 : 0 : outer_attrs = std::move (new_attrs);
1536 : 0 : }
1537 : :
1538 : : protected:
1539 : : /* Use covariance to implement clone function as returning this object rather
1540 : : * than base */
1541 : 60 : TupleIndexExpr *clone_expr_without_block_impl () const override
1542 : : {
1543 : 60 : return new TupleIndexExpr (*this);
1544 : : }
1545 : : };
1546 : :
1547 : : // Base struct/tuple/union value creator AST node (abstract)
1548 : : class StructExpr : public ExprWithoutBlock
1549 : : {
1550 : : std::vector<Attribute> outer_attrs;
1551 : : PathInExpression struct_name;
1552 : :
1553 : : protected:
1554 : : // Protected constructor to allow initialising struct_name
1555 : 872 : StructExpr (PathInExpression struct_path,
1556 : : std::vector<Attribute> outer_attribs)
1557 : 1744 : : outer_attrs (std::move (outer_attribs)),
1558 : 872 : struct_name (std::move (struct_path))
1559 : 872 : {}
1560 : :
1561 : : public:
1562 : 0 : const PathInExpression &get_struct_name () const { return struct_name; }
1563 : 2559 : PathInExpression &get_struct_name () { return struct_name; }
1564 : :
1565 : : std::string as_string () const override;
1566 : :
1567 : : // Invalid if path is empty, so base stripping on that.
1568 : 0 : void mark_for_strip () override
1569 : : {
1570 : 0 : struct_name = PathInExpression::create_error ();
1571 : 0 : }
1572 : 1646 : bool is_marked_for_strip () const override { return struct_name.is_error (); }
1573 : :
1574 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1575 : 8381 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1576 : :
1577 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1578 : : {
1579 : 0 : outer_attrs = std::move (new_attrs);
1580 : 0 : }
1581 : : };
1582 : :
1583 : : // Actual AST node of the struct creator (with no fields). Not abstract!
1584 : : class StructExprStruct : public StructExpr
1585 : : {
1586 : : std::vector<Attribute> inner_attrs;
1587 : :
1588 : : location_t locus;
1589 : :
1590 : : public:
1591 : : std::string as_string () const override;
1592 : :
1593 : : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
1594 : 6566 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
1595 : :
1596 : : // Constructor has to call protected constructor of base class
1597 : 872 : StructExprStruct (PathInExpression struct_path,
1598 : : std::vector<Attribute> inner_attribs,
1599 : : std::vector<Attribute> outer_attribs, location_t locus)
1600 : 872 : : StructExpr (std::move (struct_path), std::move (outer_attribs)),
1601 : 872 : inner_attrs (std::move (inner_attribs)), locus (locus)
1602 : 872 : {}
1603 : :
1604 : 1838 : location_t get_locus () const override final { return locus; }
1605 : :
1606 : : void accept_vis (ASTVisitor &vis) override;
1607 : :
1608 : : protected:
1609 : : /* Use covariance to implement clone function as returning this object rather
1610 : : * than base */
1611 : 0 : StructExprStruct *clone_expr_without_block_impl () const override
1612 : : {
1613 : 0 : return new StructExprStruct (*this);
1614 : : }
1615 : : };
1616 : :
1617 : : /* AST node representing expression used to fill a struct's fields from another
1618 : : * struct */
1619 : : struct StructBase
1620 : : {
1621 : : private:
1622 : : std::unique_ptr<Expr> base_struct;
1623 : : location_t locus;
1624 : :
1625 : : public:
1626 : 884 : StructBase (std::unique_ptr<Expr> base_struct_ptr, location_t locus)
1627 : 821 : : base_struct (std::move (base_struct_ptr)), locus (locus)
1628 : : {}
1629 : :
1630 : : // Copy constructor requires clone
1631 : 0 : StructBase (StructBase const &other)
1632 : 0 : {
1633 : : /* HACK: gets around base_struct pointer being null (e.g. if no struct base
1634 : : * exists) */
1635 : 0 : if (other.base_struct != nullptr)
1636 : 0 : base_struct = other.base_struct->clone_expr ();
1637 : 0 : }
1638 : :
1639 : : // Destructor
1640 : 1691 : ~StructBase () = default;
1641 : :
1642 : : // Overload assignment operator to clone base_struct
1643 : : StructBase &operator= (StructBase const &other)
1644 : : {
1645 : : // prevent null pointer dereference
1646 : : if (other.base_struct != nullptr)
1647 : : base_struct = other.base_struct->clone_expr ();
1648 : : else
1649 : : base_struct = nullptr;
1650 : :
1651 : : return *this;
1652 : : }
1653 : :
1654 : : // move constructors
1655 : 821 : StructBase (StructBase &&other) = default;
1656 : 63 : StructBase &operator= (StructBase &&other) = default;
1657 : :
1658 : : // Returns a null expr-ed StructBase - error state
1659 : 821 : static StructBase error () { return StructBase (nullptr, UNDEF_LOCATION); }
1660 : :
1661 : : // Returns whether StructBase is in error state
1662 : 7186 : bool is_invalid () const { return base_struct == nullptr; }
1663 : :
1664 : : std::string as_string () const;
1665 : :
1666 : : // TODO: is this better? Or is a "vis_block" better?
1667 : 567 : std::unique_ptr<Expr> &get_base_struct ()
1668 : : {
1669 : 567 : rust_assert (base_struct != nullptr);
1670 : 567 : return base_struct;
1671 : : }
1672 : : };
1673 : :
1674 : : /* Base AST node for a single struct expression field (in struct instance
1675 : : * creation) - abstract */
1676 : : class StructExprField
1677 : : {
1678 : : public:
1679 : : virtual ~StructExprField () {}
1680 : :
1681 : : // Unique pointer custom clone function
1682 : 0 : std::unique_ptr<StructExprField> clone_struct_expr_field () const
1683 : : {
1684 : 0 : return std::unique_ptr<StructExprField> (clone_struct_expr_field_impl ());
1685 : : }
1686 : :
1687 : : virtual std::string as_string () const = 0;
1688 : :
1689 : : virtual void accept_vis (ASTVisitor &vis) = 0;
1690 : :
1691 : : virtual location_t get_locus () const = 0;
1692 : :
1693 : 1745 : NodeId get_node_id () const { return node_id; }
1694 : :
1695 : : protected:
1696 : : // pure virtual clone implementation
1697 : : virtual StructExprField *clone_struct_expr_field_impl () const = 0;
1698 : :
1699 : 1547 : StructExprField () : node_id (Analysis::Mappings::get ()->get_next_node_id ())
1700 : 1547 : {}
1701 : :
1702 : : NodeId node_id;
1703 : : };
1704 : :
1705 : : // Identifier-only variant of StructExprField AST node
1706 : : class StructExprFieldIdentifier : public StructExprField
1707 : : {
1708 : : Identifier field_name;
1709 : : location_t locus;
1710 : :
1711 : : public:
1712 : 211 : StructExprFieldIdentifier (Identifier field_identifier, location_t locus)
1713 : 633 : : StructExprField (), field_name (std::move (field_identifier)),
1714 : 211 : locus (locus)
1715 : 211 : {}
1716 : :
1717 : 0 : std::string as_string () const override { return field_name.as_string (); }
1718 : :
1719 : 633 : location_t get_locus () const override final { return locus; }
1720 : :
1721 : : void accept_vis (ASTVisitor &vis) override;
1722 : :
1723 : 422 : Identifier get_field_name () const { return field_name; }
1724 : :
1725 : : protected:
1726 : : /* Use covariance to implement clone function as returning this object rather
1727 : : * than base */
1728 : 0 : StructExprFieldIdentifier *clone_struct_expr_field_impl () const override
1729 : : {
1730 : 0 : return new StructExprFieldIdentifier (*this);
1731 : : }
1732 : : };
1733 : :
1734 : : /* Base AST node for a single struct expression field with an assigned value -
1735 : : * abstract */
1736 : : class StructExprFieldWithVal : public StructExprField
1737 : : {
1738 : : std::unique_ptr<Expr> value;
1739 : :
1740 : : protected:
1741 : 1336 : StructExprFieldWithVal (std::unique_ptr<Expr> field_value)
1742 : 1336 : : StructExprField (), value (std::move (field_value))
1743 : : {}
1744 : :
1745 : : // Copy constructor requires clone
1746 : 0 : StructExprFieldWithVal (StructExprFieldWithVal const &other)
1747 : 0 : : value (other.value->clone_expr ())
1748 : 0 : {}
1749 : :
1750 : : // Overload assignment operator to clone unique_ptr
1751 : : StructExprFieldWithVal &operator= (StructExprFieldWithVal const &other)
1752 : : {
1753 : : value = other.value->clone_expr ();
1754 : :
1755 : : return *this;
1756 : : }
1757 : :
1758 : : // move constructors
1759 : : StructExprFieldWithVal (StructExprFieldWithVal &&other) = default;
1760 : : StructExprFieldWithVal &operator= (StructExprFieldWithVal &&other) = default;
1761 : :
1762 : : public:
1763 : : std::string as_string () const override;
1764 : :
1765 : : // TODO: is this better? Or is a "vis_block" better?
1766 : 12030 : std::unique_ptr<Expr> &get_value ()
1767 : : {
1768 : 12030 : rust_assert (value != nullptr);
1769 : 12030 : return value;
1770 : : }
1771 : : };
1772 : :
1773 : : // Identifier and value variant of StructExprField AST node
1774 : : class StructExprFieldIdentifierValue : public StructExprFieldWithVal
1775 : : {
1776 : : Identifier field_name;
1777 : : location_t locus;
1778 : :
1779 : : public:
1780 : 1292 : StructExprFieldIdentifierValue (Identifier field_identifier,
1781 : : std::unique_ptr<Expr> field_value,
1782 : : location_t locus)
1783 : 1292 : : StructExprFieldWithVal (std::move (field_value)),
1784 : 1292 : field_name (std::move (field_identifier)), locus (locus)
1785 : 1292 : {}
1786 : :
1787 : : std::string as_string () const override;
1788 : :
1789 : : void accept_vis (ASTVisitor &vis) override;
1790 : :
1791 : 1283 : std::string get_field_name () const { return field_name.as_string (); }
1792 : :
1793 : 2562 : location_t get_locus () const override final { return locus; }
1794 : :
1795 : : protected:
1796 : : /* Use covariance to implement clone function as returning this object rather
1797 : : * than base */
1798 : 0 : StructExprFieldIdentifierValue *clone_struct_expr_field_impl () const override
1799 : : {
1800 : 0 : return new StructExprFieldIdentifierValue (*this);
1801 : : }
1802 : : };
1803 : :
1804 : : // Tuple index and value variant of StructExprField AST node
1805 : 0 : class StructExprFieldIndexValue : public StructExprFieldWithVal
1806 : : {
1807 : : TupleIndex index;
1808 : : location_t locus;
1809 : :
1810 : : public:
1811 : 44 : StructExprFieldIndexValue (TupleIndex tuple_index,
1812 : : std::unique_ptr<Expr> field_value,
1813 : : location_t locus)
1814 : 88 : : StructExprFieldWithVal (std::move (field_value)), index (tuple_index),
1815 : 44 : locus (locus)
1816 : 44 : {}
1817 : :
1818 : : std::string as_string () const override;
1819 : :
1820 : : void accept_vis (ASTVisitor &vis) override;
1821 : :
1822 : 44 : TupleIndex get_index () const { return index; }
1823 : :
1824 : 88 : location_t get_locus () const override final { return locus; }
1825 : :
1826 : : protected:
1827 : : /* Use covariance to implement clone function as returning this object rather
1828 : : * than base */
1829 : 0 : StructExprFieldIndexValue *clone_struct_expr_field_impl () const override
1830 : : {
1831 : 0 : return new StructExprFieldIndexValue (*this);
1832 : : }
1833 : : };
1834 : :
1835 : : // AST node of a struct creator with fields
1836 : : class StructExprStructFields : public StructExprStruct
1837 : : {
1838 : : // std::vector<StructExprField> fields;
1839 : : std::vector<std::unique_ptr<StructExprField> > fields;
1840 : :
1841 : : // bool has_struct_base;
1842 : : StructBase struct_base;
1843 : :
1844 : : public:
1845 : : std::string as_string () const override;
1846 : :
1847 : 7186 : bool has_struct_base () const { return !struct_base.is_invalid (); }
1848 : :
1849 : : // Constructor for StructExprStructFields when no struct base is used
1850 : 821 : StructExprStructFields (
1851 : : PathInExpression struct_path,
1852 : : std::vector<std::unique_ptr<StructExprField> > expr_fields,
1853 : : location_t locus, StructBase base_struct = StructBase::error (),
1854 : : std::vector<Attribute> inner_attribs = std::vector<Attribute> (),
1855 : : std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
1856 : 821 : : StructExprStruct (std::move (struct_path), std::move (inner_attribs),
1857 : : std::move (outer_attribs), locus),
1858 : 821 : fields (std::move (expr_fields)), struct_base (std::move (base_struct))
1859 : 821 : {}
1860 : :
1861 : : // copy constructor with vector clone
1862 : 0 : StructExprStructFields (StructExprStructFields const &other)
1863 : 0 : : StructExprStruct (other), struct_base (other.struct_base)
1864 : : {
1865 : 0 : fields.reserve (other.fields.size ());
1866 : 0 : for (const auto &e : other.fields)
1867 : 0 : fields.push_back (e->clone_struct_expr_field ());
1868 : 0 : }
1869 : :
1870 : : // overloaded assignment operator with vector clone
1871 : : StructExprStructFields &operator= (StructExprStructFields const &other)
1872 : : {
1873 : : StructExprStruct::operator= (other);
1874 : : struct_base = other.struct_base;
1875 : :
1876 : : fields.reserve (other.fields.size ());
1877 : : for (const auto &e : other.fields)
1878 : : fields.push_back (e->clone_struct_expr_field ());
1879 : :
1880 : : return *this;
1881 : : }
1882 : :
1883 : : // move constructors
1884 : : StructExprStructFields (StructExprStructFields &&other) = default;
1885 : : StructExprStructFields &operator= (StructExprStructFields &&other) = default;
1886 : :
1887 : : void accept_vis (ASTVisitor &vis) override;
1888 : :
1889 : : // TODO: this mutable getter seems really dodgy. Think up better way.
1890 : 2 : std::vector<std::unique_ptr<StructExprField> > &get_fields ()
1891 : : {
1892 : 5640 : return fields;
1893 : : }
1894 : : const std::vector<std::unique_ptr<StructExprField> > &get_fields () const
1895 : : {
1896 : : return fields;
1897 : : }
1898 : :
1899 : 567 : StructBase &get_struct_base () { return struct_base; }
1900 : : const StructBase &get_struct_base () const { return struct_base; }
1901 : :
1902 : : protected:
1903 : : /* Use covariance to implement clone function as returning this object rather
1904 : : * than base */
1905 : 0 : StructExprStructFields *clone_expr_without_block_impl () const override
1906 : : {
1907 : 0 : return new StructExprStructFields (*this);
1908 : : }
1909 : : };
1910 : :
1911 : : // AST node of the functional update struct creator
1912 : : /* TODO: remove and replace with StructExprStructFields, except with empty
1913 : : * vector of fields? */
1914 : : class StructExprStructBase : public StructExprStruct
1915 : : {
1916 : : StructBase struct_base;
1917 : :
1918 : : public:
1919 : : std::string as_string () const override;
1920 : :
1921 : : StructExprStructBase (PathInExpression struct_path, StructBase base_struct,
1922 : : std::vector<Attribute> inner_attribs,
1923 : : std::vector<Attribute> outer_attribs, location_t locus)
1924 : : : StructExprStruct (std::move (struct_path), std::move (inner_attribs),
1925 : : std::move (outer_attribs), locus),
1926 : : struct_base (std::move (base_struct))
1927 : : {}
1928 : :
1929 : : void accept_vis (ASTVisitor &vis) override;
1930 : :
1931 : 0 : StructBase &get_struct_base () { return struct_base; }
1932 : : const StructBase &get_struct_base () const { return struct_base; }
1933 : :
1934 : : protected:
1935 : : /* Use covariance to implement clone function as returning this object rather
1936 : : * than base */
1937 : 0 : StructExprStructBase *clone_expr_without_block_impl () const override
1938 : : {
1939 : 0 : return new StructExprStructBase (*this);
1940 : : }
1941 : : };
1942 : :
1943 : : // Forward decl for Function - used in CallExpr
1944 : : class Function;
1945 : :
1946 : : // Function call expression AST node
1947 : : class CallExpr : public ExprWithoutBlock
1948 : : {
1949 : : std::vector<Attribute> outer_attrs;
1950 : : std::unique_ptr<Expr> function;
1951 : : std::vector<std::unique_ptr<Expr> > params;
1952 : : location_t locus;
1953 : :
1954 : : public:
1955 : : Function *fndeclRef;
1956 : :
1957 : : std::string as_string () const override;
1958 : :
1959 : 6961 : CallExpr (std::unique_ptr<Expr> function_expr,
1960 : : std::vector<std::unique_ptr<Expr> > function_params,
1961 : : std::vector<Attribute> outer_attribs, location_t locus)
1962 : 13922 : : outer_attrs (std::move (outer_attribs)),
1963 : 6961 : function (std::move (function_expr)),
1964 : 6961 : params (std::move (function_params)), locus (locus)
1965 : 6961 : {}
1966 : :
1967 : : // copy constructor requires clone
1968 : 5311 : CallExpr (CallExpr const &other)
1969 : 5311 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
1970 : 5311 : locus (other.locus)
1971 : : {
1972 : : // guard to prevent null dereference (only required if error state)
1973 : 5311 : if (other.function != nullptr)
1974 : 5311 : function = other.function->clone_expr ();
1975 : :
1976 : 5311 : params.reserve (other.params.size ());
1977 : 11131 : for (const auto &e : other.params)
1978 : 5820 : params.push_back (e->clone_expr ());
1979 : 5311 : }
1980 : :
1981 : : // Overload assignment operator to clone
1982 : : CallExpr &operator= (CallExpr const &other)
1983 : : {
1984 : : ExprWithoutBlock::operator= (other);
1985 : : locus = other.locus;
1986 : : outer_attrs = other.outer_attrs;
1987 : :
1988 : : // guard to prevent null dereference (only required if error state)
1989 : : if (other.function != nullptr)
1990 : : function = other.function->clone_expr ();
1991 : : else
1992 : : function = nullptr;
1993 : :
1994 : : params.reserve (other.params.size ());
1995 : : for (const auto &e : other.params)
1996 : : params.push_back (e->clone_expr ());
1997 : :
1998 : : return *this;
1999 : : }
2000 : :
2001 : : // move constructors
2002 : : CallExpr (CallExpr &&other) = default;
2003 : : CallExpr &operator= (CallExpr &&other) = default;
2004 : :
2005 : : // Returns whether function call has parameters.
2006 : 0 : bool has_params () const { return !params.empty (); }
2007 : :
2008 : 13784 : location_t get_locus () const override final { return locus; }
2009 : :
2010 : : void accept_vis (ASTVisitor &vis) override;
2011 : :
2012 : : // Invalid if function expr is null, so base stripping on that.
2013 : 0 : void mark_for_strip () override { function = nullptr; }
2014 : 21086 : bool is_marked_for_strip () const override { return function == nullptr; }
2015 : :
2016 : : // TODO: this mutable getter seems really dodgy. Think up better way.
2017 : : const std::vector<std::unique_ptr<Expr> > &get_params () const
2018 : : {
2019 : : return params;
2020 : : }
2021 : 79941 : std::vector<std::unique_ptr<Expr> > &get_params () { return params; }
2022 : :
2023 : : // TODO: is this better? Or is a "vis_block" better?
2024 : 79941 : std::unique_ptr<Expr> &get_function_expr ()
2025 : : {
2026 : 79941 : rust_assert (function != nullptr);
2027 : 79941 : return function;
2028 : : }
2029 : :
2030 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2031 : 88007 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2032 : :
2033 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2034 : : {
2035 : 0 : outer_attrs = std::move (new_attrs);
2036 : 0 : }
2037 : :
2038 : : protected:
2039 : : /* Use covariance to implement clone function as returning this object rather
2040 : : * than base */
2041 : 5311 : CallExpr *clone_expr_without_block_impl () const override
2042 : : {
2043 : 5311 : return new CallExpr (*this);
2044 : : }
2045 : : };
2046 : :
2047 : : // Method call expression AST node
2048 : : class MethodCallExpr : public ExprWithoutBlock
2049 : : {
2050 : : std::vector<Attribute> outer_attrs;
2051 : : std::unique_ptr<Expr> receiver;
2052 : : PathExprSegment method_name;
2053 : : std::vector<std::unique_ptr<Expr> > params;
2054 : : location_t locus;
2055 : :
2056 : : public:
2057 : : std::string as_string () const override;
2058 : :
2059 : 1038 : MethodCallExpr (std::unique_ptr<Expr> call_receiver,
2060 : : PathExprSegment method_path,
2061 : : std::vector<std::unique_ptr<Expr> > method_params,
2062 : : std::vector<Attribute> outer_attribs, location_t locus)
2063 : 2076 : : outer_attrs (std::move (outer_attribs)),
2064 : 1038 : receiver (std::move (call_receiver)),
2065 : 1038 : method_name (std::move (method_path)), params (std::move (method_params)),
2066 : 1038 : locus (locus)
2067 : 1038 : {}
2068 : :
2069 : : // copy constructor required due to cloning
2070 : 240 : MethodCallExpr (MethodCallExpr const &other)
2071 : 240 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2072 : 240 : method_name (other.method_name), locus (other.locus)
2073 : : {
2074 : : // guard to prevent null dereference (only required if error state)
2075 : 240 : if (other.receiver != nullptr)
2076 : 240 : receiver = other.receiver->clone_expr ();
2077 : :
2078 : 240 : params.reserve (other.params.size ());
2079 : 480 : for (const auto &e : other.params)
2080 : 240 : params.push_back (e->clone_expr ());
2081 : 240 : }
2082 : :
2083 : : // Overload assignment operator to clone receiver object
2084 : : MethodCallExpr &operator= (MethodCallExpr const &other)
2085 : : {
2086 : : ExprWithoutBlock::operator= (other);
2087 : : method_name = other.method_name;
2088 : : locus = other.locus;
2089 : : outer_attrs = other.outer_attrs;
2090 : :
2091 : : // guard to prevent null dereference (only required if error state)
2092 : : if (other.receiver != nullptr)
2093 : : receiver = other.receiver->clone_expr ();
2094 : : else
2095 : : receiver = nullptr;
2096 : :
2097 : : params.reserve (other.params.size ());
2098 : : for (const auto &e : other.params)
2099 : : params.push_back (e->clone_expr ());
2100 : :
2101 : : return *this;
2102 : : }
2103 : :
2104 : : // move constructors
2105 : : MethodCallExpr (MethodCallExpr &&other) = default;
2106 : : MethodCallExpr &operator= (MethodCallExpr &&other) = default;
2107 : :
2108 : 2152 : location_t get_locus () const override final { return locus; }
2109 : :
2110 : : void accept_vis (ASTVisitor &vis) override;
2111 : :
2112 : : // Invalid if receiver expr is null, so base stripping on that.
2113 : 0 : void mark_for_strip () override { receiver = nullptr; }
2114 : 3132 : bool is_marked_for_strip () const override { return receiver == nullptr; }
2115 : :
2116 : : // TODO: this mutable getter seems really dodgy. Think up better way.
2117 : : const std::vector<std::unique_ptr<Expr> > &get_params () const
2118 : : {
2119 : : return params;
2120 : : }
2121 : 11951 : std::vector<std::unique_ptr<Expr> > &get_params () { return params; }
2122 : :
2123 : : // TODO: is this better? Or is a "vis_block" better?
2124 : 11951 : std::unique_ptr<Expr> &get_receiver_expr ()
2125 : : {
2126 : 11951 : rust_assert (receiver != nullptr);
2127 : 11951 : return receiver;
2128 : : }
2129 : :
2130 : : const PathExprSegment &get_method_name () const { return method_name; }
2131 : 10706 : PathExprSegment &get_method_name () { return method_name; }
2132 : :
2133 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2134 : 12922 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2135 : :
2136 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2137 : : {
2138 : 0 : outer_attrs = std::move (new_attrs);
2139 : 0 : }
2140 : :
2141 : : protected:
2142 : : /* Use covariance to implement clone function as returning this object rather
2143 : : * than base */
2144 : 240 : MethodCallExpr *clone_expr_without_block_impl () const override
2145 : : {
2146 : 240 : return new MethodCallExpr (*this);
2147 : : }
2148 : : };
2149 : :
2150 : : // aka FieldExpression
2151 : : // Struct or union field access expression AST node
2152 : : class FieldAccessExpr : public ExprWithoutBlock
2153 : : {
2154 : : std::vector<Attribute> outer_attrs;
2155 : : std::unique_ptr<Expr> receiver;
2156 : : Identifier field;
2157 : : location_t locus;
2158 : :
2159 : : public:
2160 : : std::string as_string () const override;
2161 : :
2162 : 1407 : FieldAccessExpr (std::unique_ptr<Expr> field_access_receiver,
2163 : : Identifier field_name, std::vector<Attribute> outer_attribs,
2164 : : location_t locus)
2165 : 2814 : : outer_attrs (std::move (outer_attribs)),
2166 : 1407 : receiver (std::move (field_access_receiver)),
2167 : 1407 : field (std::move (field_name)), locus (locus)
2168 : 1407 : {}
2169 : :
2170 : : // Copy constructor required due to unique_ptr cloning
2171 : 0 : FieldAccessExpr (FieldAccessExpr const &other)
2172 : 0 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2173 : 0 : field (other.field), locus (other.locus)
2174 : : {
2175 : : // guard to prevent null dereference (only required if error state)
2176 : 0 : if (other.receiver != nullptr)
2177 : 0 : receiver = other.receiver->clone_expr ();
2178 : 0 : }
2179 : :
2180 : : // Overload assignment operator to clone unique_ptr
2181 : : FieldAccessExpr &operator= (FieldAccessExpr const &other)
2182 : : {
2183 : : ExprWithoutBlock::operator= (other);
2184 : : field = other.field;
2185 : : locus = other.locus;
2186 : : outer_attrs = other.outer_attrs;
2187 : :
2188 : : // guard to prevent null dereference (only required if error state)
2189 : : if (other.receiver != nullptr)
2190 : : receiver = other.receiver->clone_expr ();
2191 : : else
2192 : : receiver = nullptr;
2193 : :
2194 : : return *this;
2195 : : }
2196 : :
2197 : : // move constructors
2198 : : FieldAccessExpr (FieldAccessExpr &&other) = default;
2199 : : FieldAccessExpr &operator= (FieldAccessExpr &&other) = default;
2200 : :
2201 : 3320 : location_t get_locus () const override final { return locus; }
2202 : :
2203 : : void accept_vis (ASTVisitor &vis) override;
2204 : :
2205 : : // Invalid if receiver expr is null, so base stripping on that.
2206 : 0 : void mark_for_strip () override { receiver = nullptr; }
2207 : 3437 : bool is_marked_for_strip () const override { return receiver == nullptr; }
2208 : :
2209 : : // TODO: is this better? Or is a "vis_block" better?
2210 : 14479 : std::unique_ptr<Expr> &get_receiver_expr ()
2211 : : {
2212 : 14479 : rust_assert (receiver != nullptr);
2213 : 14479 : return receiver;
2214 : : }
2215 : :
2216 : 1408 : Identifier get_field_name () const { return field; }
2217 : :
2218 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2219 : 16969 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2220 : :
2221 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2222 : : {
2223 : 0 : outer_attrs = std::move (new_attrs);
2224 : 0 : }
2225 : :
2226 : : protected:
2227 : : /* Use covariance to implement clone function as returning this object rather
2228 : : * than base */
2229 : 0 : FieldAccessExpr *clone_expr_without_block_impl () const override
2230 : : {
2231 : 0 : return new FieldAccessExpr (*this);
2232 : : }
2233 : : };
2234 : :
2235 : : // Closure parameter data structure
2236 : : struct ClosureParam
2237 : : {
2238 : : private:
2239 : : std::vector<Attribute> outer_attrs;
2240 : : std::unique_ptr<Pattern> pattern;
2241 : : std::unique_ptr<Type> type;
2242 : : location_t locus;
2243 : :
2244 : : public:
2245 : : // Returns whether the type of the parameter has been given.
2246 : 546 : bool has_type_given () const { return type != nullptr; }
2247 : :
2248 : : bool has_outer_attrs () const { return !outer_attrs.empty (); }
2249 : :
2250 : : // Constructor for closure parameter
2251 : 64 : ClosureParam (std::unique_ptr<Pattern> param_pattern, location_t locus,
2252 : : std::unique_ptr<Type> param_type = nullptr,
2253 : : std::vector<Attribute> outer_attrs = {})
2254 : 0 : : outer_attrs (std::move (outer_attrs)),
2255 : 0 : pattern (std::move (param_pattern)), type (std::move (param_type)),
2256 : 64 : locus (locus)
2257 : : {}
2258 : :
2259 : : // Copy constructor required due to cloning as a result of unique_ptrs
2260 : 0 : ClosureParam (ClosureParam const &other) : outer_attrs (other.outer_attrs)
2261 : : {
2262 : : // guard to protect from null pointer dereference
2263 : 0 : if (other.pattern != nullptr)
2264 : 0 : pattern = other.pattern->clone_pattern ();
2265 : 0 : if (other.type != nullptr)
2266 : 0 : type = other.type->clone_type ();
2267 : 0 : }
2268 : :
2269 : 75 : ~ClosureParam () = default;
2270 : :
2271 : : // Assignment operator must be overloaded to clone as well
2272 : : ClosureParam &operator= (ClosureParam const &other)
2273 : : {
2274 : : outer_attrs = other.outer_attrs;
2275 : :
2276 : : // guard to protect from null pointer dereference
2277 : : if (other.pattern != nullptr)
2278 : : pattern = other.pattern->clone_pattern ();
2279 : : else
2280 : : pattern = nullptr;
2281 : : if (other.type != nullptr)
2282 : : type = other.type->clone_type ();
2283 : : else
2284 : : type = nullptr;
2285 : :
2286 : : return *this;
2287 : : }
2288 : :
2289 : : // move constructors
2290 : 75 : ClosureParam (ClosureParam &&other) = default;
2291 : 0 : ClosureParam &operator= (ClosureParam &&other) = default;
2292 : :
2293 : : // Returns whether closure parameter is in an error state.
2294 : 64 : bool is_error () const { return pattern == nullptr; }
2295 : :
2296 : : // Creates an error state closure parameter.
2297 : 0 : static ClosureParam create_error ()
2298 : : {
2299 : 0 : return ClosureParam (nullptr, UNDEF_LOCATION);
2300 : : }
2301 : :
2302 : : std::string as_string () const;
2303 : :
2304 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2305 : 383 : std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
2306 : :
2307 : 438 : std::unique_ptr<Pattern> &get_pattern ()
2308 : : {
2309 : 438 : rust_assert (pattern != nullptr);
2310 : 438 : return pattern;
2311 : : }
2312 : :
2313 : 459 : std::unique_ptr<Type> &get_type ()
2314 : : {
2315 : 459 : rust_assert (has_type_given ());
2316 : 459 : return type;
2317 : : }
2318 : :
2319 : 53 : location_t get_locus () const { return locus; }
2320 : : };
2321 : :
2322 : : // Base closure definition expression AST node - abstract
2323 : : class ClosureExpr : public ExprWithoutBlock
2324 : : {
2325 : : std::vector<Attribute> outer_attrs;
2326 : : bool has_move;
2327 : : std::vector<ClosureParam> params; // may be empty
2328 : : location_t locus;
2329 : :
2330 : : protected:
2331 : 61 : ClosureExpr (std::vector<ClosureParam> closure_params, bool has_move,
2332 : : std::vector<Attribute> outer_attribs, location_t locus)
2333 : 122 : : outer_attrs (std::move (outer_attribs)), has_move (has_move),
2334 : 61 : params (std::move (closure_params)), locus (locus)
2335 : 61 : {}
2336 : :
2337 : : public:
2338 : : std::string as_string () const override;
2339 : :
2340 : 106 : location_t get_locus () const override final { return locus; }
2341 : :
2342 : : // TODO: this mutable getter seems really dodgy. Think up better way.
2343 : : const std::vector<ClosureParam> &get_params () const { return params; }
2344 : 477 : std::vector<ClosureParam> &get_params () { return params; }
2345 : :
2346 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2347 : 471 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2348 : :
2349 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2350 : : {
2351 : 0 : outer_attrs = std::move (new_attrs);
2352 : 0 : }
2353 : :
2354 : 53 : bool get_has_move () const { return has_move; }
2355 : : };
2356 : :
2357 : : // Represents a non-type-specified closure expression AST node
2358 : : class ClosureExprInner : public ClosureExpr
2359 : : {
2360 : : std::unique_ptr<Expr> closure_inner;
2361 : :
2362 : : public:
2363 : : std::string as_string () const override;
2364 : :
2365 : : // Constructor for a ClosureExprInner
2366 : 30 : ClosureExprInner (std::unique_ptr<Expr> closure_inner_expr,
2367 : : std::vector<ClosureParam> closure_params, location_t locus,
2368 : : bool is_move = false,
2369 : : std::vector<Attribute> outer_attribs
2370 : : = std::vector<Attribute> ())
2371 : 30 : : ClosureExpr (std::move (closure_params), is_move,
2372 : : std::move (outer_attribs), locus),
2373 : 30 : closure_inner (std::move (closure_inner_expr))
2374 : 30 : {}
2375 : :
2376 : : // Copy constructor must be defined to allow copying via cloning of unique_ptr
2377 : 0 : ClosureExprInner (ClosureExprInner const &other) : ClosureExpr (other)
2378 : : {
2379 : : // guard to prevent null dereference (only required if error state)
2380 : 0 : if (other.closure_inner != nullptr)
2381 : 0 : closure_inner = other.closure_inner->clone_expr ();
2382 : 0 : }
2383 : :
2384 : : // Overload assignment operator to clone closure_inner
2385 : : ClosureExprInner &operator= (ClosureExprInner const &other)
2386 : : {
2387 : : ClosureExpr::operator= (other);
2388 : : // params = other.params;
2389 : : // has_move = other.has_move;
2390 : : // outer_attrs = other.outer_attrs;
2391 : :
2392 : : // guard to prevent null dereference (only required if error state)
2393 : : if (other.closure_inner != nullptr)
2394 : : closure_inner = other.closure_inner->clone_expr ();
2395 : : else
2396 : : closure_inner = nullptr;
2397 : :
2398 : : return *this;
2399 : : }
2400 : :
2401 : : // move constructors
2402 : : ClosureExprInner (ClosureExprInner &&other) = default;
2403 : : ClosureExprInner &operator= (ClosureExprInner &&other) = default;
2404 : :
2405 : : void accept_vis (ASTVisitor &vis) override;
2406 : :
2407 : : // Invalid if inner expr is null, so base stripping on that.
2408 : 0 : void mark_for_strip () override { closure_inner = nullptr; }
2409 : 43 : bool is_marked_for_strip () const override
2410 : : {
2411 : 43 : return closure_inner == nullptr;
2412 : : }
2413 : :
2414 : 207 : std::unique_ptr<Expr> &get_definition_expr ()
2415 : : {
2416 : 207 : rust_assert (closure_inner != nullptr);
2417 : 207 : return closure_inner;
2418 : : }
2419 : :
2420 : : protected:
2421 : : /* Use covariance to implement clone function as returning this object rather
2422 : : * than base */
2423 : 0 : ClosureExprInner *clone_expr_without_block_impl () const override
2424 : : {
2425 : 0 : return new ClosureExprInner (*this);
2426 : : }
2427 : : };
2428 : :
2429 : : // A block AST node
2430 : : class BlockExpr : public ExprWithBlock
2431 : : {
2432 : : std::vector<Attribute> outer_attrs;
2433 : : std::vector<Attribute> inner_attrs;
2434 : : std::vector<std::unique_ptr<Stmt> > statements;
2435 : : std::unique_ptr<Expr> expr;
2436 : : LoopLabel label;
2437 : : location_t start_locus;
2438 : : location_t end_locus;
2439 : : bool marked_for_strip = false;
2440 : :
2441 : : public:
2442 : : std::string as_string () const override;
2443 : :
2444 : : // Returns whether the block contains statements.
2445 : : bool has_statements () const { return !statements.empty (); }
2446 : :
2447 : : // Returns whether the block contains a final expression.
2448 : 174420 : bool has_tail_expr () const { return expr != nullptr; }
2449 : :
2450 : 13218 : BlockExpr (std::vector<std::unique_ptr<Stmt> > block_statements,
2451 : : std::unique_ptr<Expr> block_expr,
2452 : : std::vector<Attribute> inner_attribs,
2453 : : std::vector<Attribute> outer_attribs, LoopLabel label,
2454 : : location_t start_locus, location_t end_locus)
2455 : 26436 : : outer_attrs (std::move (outer_attribs)),
2456 : 13218 : inner_attrs (std::move (inner_attribs)),
2457 : 13218 : statements (std::move (block_statements)), expr (std::move (block_expr)),
2458 : 13218 : label (std::move (label)), start_locus (start_locus),
2459 : 13218 : end_locus (end_locus)
2460 : 13218 : {}
2461 : :
2462 : : // Copy constructor with clone
2463 : 11585 : BlockExpr (BlockExpr const &other)
2464 : 11585 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
2465 : 11585 : inner_attrs (other.inner_attrs), label (other.label),
2466 : 11585 : start_locus (other.start_locus), end_locus (other.end_locus),
2467 : 23170 : marked_for_strip (other.marked_for_strip)
2468 : : {
2469 : : // guard to protect from null pointer dereference
2470 : 11585 : if (other.expr != nullptr)
2471 : 11431 : expr = other.expr->clone_expr ();
2472 : :
2473 : 11585 : statements.reserve (other.statements.size ());
2474 : 12116 : for (const auto &e : other.statements)
2475 : 531 : statements.push_back (e->clone_stmt ());
2476 : 11585 : }
2477 : :
2478 : : // Overloaded assignment operator to clone pointer
2479 : : BlockExpr &operator= (BlockExpr const &other)
2480 : : {
2481 : : ExprWithBlock::operator= (other);
2482 : : inner_attrs = other.inner_attrs;
2483 : : start_locus = other.start_locus;
2484 : : end_locus = other.end_locus;
2485 : : marked_for_strip = other.marked_for_strip;
2486 : : outer_attrs = other.outer_attrs;
2487 : :
2488 : : // guard to protect from null pointer dereference
2489 : : if (other.expr != nullptr)
2490 : : expr = other.expr->clone_expr ();
2491 : : else
2492 : : expr = nullptr;
2493 : :
2494 : : statements.reserve (other.statements.size ());
2495 : : for (const auto &e : other.statements)
2496 : : statements.push_back (e->clone_stmt ());
2497 : :
2498 : : return *this;
2499 : : }
2500 : :
2501 : : // move constructors
2502 : : BlockExpr (BlockExpr &&other) = default;
2503 : : BlockExpr &operator= (BlockExpr &&other) = default;
2504 : :
2505 : : // Unique pointer custom clone function
2506 : 10209 : std::unique_ptr<BlockExpr> clone_block_expr () const
2507 : : {
2508 : 10209 : return std::unique_ptr<BlockExpr> (clone_block_expr_impl ());
2509 : : }
2510 : :
2511 : 887 : location_t get_locus () const override final { return start_locus; }
2512 : :
2513 : 12784 : location_t get_start_locus () const { return start_locus; }
2514 : 12784 : location_t get_end_locus () const { return end_locus; }
2515 : :
2516 : : void accept_vis (ASTVisitor &vis) override;
2517 : :
2518 : : // Can be completely empty, so have to have a separate flag.
2519 : 11 : void mark_for_strip () override { marked_for_strip = true; }
2520 : 26544 : bool is_marked_for_strip () const override { return marked_for_strip; }
2521 : :
2522 : : size_t num_statements () const { return statements.size (); }
2523 : :
2524 : : // TODO: this mutable getter seems really dodgy. Think up better way.
2525 : : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
2526 : 97214 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
2527 : :
2528 : : const std::vector<std::unique_ptr<Stmt> > &get_statements () const
2529 : : {
2530 : : return statements;
2531 : : }
2532 : 152899 : std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; }
2533 : :
2534 : : // TODO: is this better? Or is a "vis_block" better?
2535 : 92118 : std::unique_ptr<Expr> &get_tail_expr ()
2536 : : {
2537 : 92118 : rust_assert (has_tail_expr ());
2538 : 92118 : return expr;
2539 : : }
2540 : :
2541 : 11917 : std::unique_ptr<Expr> take_tail_expr ()
2542 : : {
2543 : 11917 : rust_assert (has_tail_expr ());
2544 : 11917 : return std::move (expr);
2545 : : }
2546 : :
2547 : 11917 : void set_tail_expr (std::unique_ptr<Expr> expr)
2548 : : {
2549 : 11917 : this->expr = std::move (expr);
2550 : : }
2551 : :
2552 : : // Removes the tail expression from the block.
2553 : 15 : void strip_tail_expr () { expr = nullptr; }
2554 : : // Normalizes a trailing statement without a semicolon to a tail expression.
2555 : : void normalize_tail_expr ();
2556 : :
2557 : : void try_convert_last_stmt ();
2558 : :
2559 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2560 : 111655 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2561 : :
2562 : 583 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2563 : : {
2564 : 583 : outer_attrs = std::move (new_attrs);
2565 : 583 : }
2566 : :
2567 : 25734 : bool has_label () { return !label.is_error (); }
2568 : 12784 : LoopLabel &get_label () { return label; }
2569 : :
2570 : : protected:
2571 : : /* Use covariance to implement clone function as returning this object rather
2572 : : * than base */
2573 : 1376 : BlockExpr *clone_expr_with_block_impl () const final override
2574 : : {
2575 : 1376 : return clone_block_expr_impl ();
2576 : : }
2577 : :
2578 : : /* This is the base method as not an abstract class - not virtual but could be
2579 : : * in future if required. */
2580 : 11585 : /*virtual*/ BlockExpr *clone_block_expr_impl () const
2581 : : {
2582 : 11585 : return new BlockExpr (*this);
2583 : : }
2584 : : };
2585 : :
2586 : : // Represents a type-specified closure expression AST node
2587 : : class ClosureExprInnerTyped : public ClosureExpr
2588 : : {
2589 : : // TODO: spec says typenobounds
2590 : : std::unique_ptr<Type> return_type;
2591 : : std::unique_ptr<BlockExpr>
2592 : : expr; // only used because may be polymorphic in future
2593 : :
2594 : : public:
2595 : : std::string as_string () const override;
2596 : :
2597 : : // Constructor potentially with a move
2598 : 31 : ClosureExprInnerTyped (std::unique_ptr<Type> closure_return_type,
2599 : : std::unique_ptr<BlockExpr> closure_expr,
2600 : : std::vector<ClosureParam> closure_params,
2601 : : location_t locus, bool is_move = false,
2602 : : std::vector<Attribute> outer_attribs
2603 : : = std::vector<Attribute> ())
2604 : 31 : : ClosureExpr (std::move (closure_params), is_move,
2605 : : std::move (outer_attribs), locus),
2606 : 31 : return_type (std::move (closure_return_type)),
2607 : 31 : expr (std::move (closure_expr))
2608 : 31 : {}
2609 : :
2610 : : // Copy constructor requires cloning
2611 : 0 : ClosureExprInnerTyped (ClosureExprInnerTyped const &other)
2612 : 0 : : ClosureExpr (other)
2613 : : {
2614 : : // guard to prevent null dereference (only required if error state)
2615 : 0 : if (other.expr != nullptr)
2616 : 0 : expr = other.expr->clone_block_expr ();
2617 : 0 : if (other.return_type != nullptr)
2618 : 0 : return_type = other.return_type->clone_type ();
2619 : 0 : }
2620 : :
2621 : : // Overload assignment operator to clone unique_ptrs
2622 : : ClosureExprInnerTyped &operator= (ClosureExprInnerTyped const &other)
2623 : : {
2624 : : ClosureExpr::operator= (other);
2625 : : // params = other.params;
2626 : : // has_move = other.has_move;
2627 : : // outer_attrs = other.outer_attrs;
2628 : :
2629 : : // guard to prevent null dereference (only required if error state)
2630 : : if (other.expr != nullptr)
2631 : : expr = other.expr->clone_block_expr ();
2632 : : else
2633 : : expr = nullptr;
2634 : : if (other.return_type != nullptr)
2635 : : return_type = other.return_type->clone_type ();
2636 : : else
2637 : : return_type = nullptr;
2638 : :
2639 : : return *this;
2640 : : }
2641 : :
2642 : : // move constructors
2643 : : ClosureExprInnerTyped (ClosureExprInnerTyped &&other) = default;
2644 : : ClosureExprInnerTyped &operator= (ClosureExprInnerTyped &&other) = default;
2645 : :
2646 : : void accept_vis (ASTVisitor &vis) override;
2647 : :
2648 : : /* Invalid if inner expr is null, so base stripping on that. Technically,
2649 : : * type should also not be null. */
2650 : 0 : void mark_for_strip () override { expr = nullptr; }
2651 : 60 : bool is_marked_for_strip () const override { return expr == nullptr; }
2652 : :
2653 : : // TODO: is this better? Or is a "vis_block" better?
2654 : 270 : std::unique_ptr<BlockExpr> &get_definition_block ()
2655 : : {
2656 : 270 : rust_assert (expr != nullptr);
2657 : 270 : return expr;
2658 : : }
2659 : :
2660 : : // TODO: is this better? Or is a "vis_block" better?
2661 : 240 : std::unique_ptr<Type> &get_return_type ()
2662 : : {
2663 : 240 : rust_assert (return_type != nullptr);
2664 : 240 : return return_type;
2665 : : }
2666 : :
2667 : : protected:
2668 : : /* Use covariance to implement clone function as returning this object rather
2669 : : * than base */
2670 : 0 : ClosureExprInnerTyped *clone_expr_without_block_impl () const override
2671 : : {
2672 : 0 : return new ClosureExprInnerTyped (*this);
2673 : : }
2674 : : };
2675 : :
2676 : : // AST node representing continue expression within loops
2677 : : class ContinueExpr : public ExprWithoutBlock
2678 : : {
2679 : : std::vector<Attribute> outer_attrs;
2680 : : Lifetime label;
2681 : : location_t locus;
2682 : :
2683 : : // TODO: find another way to store this to save memory?
2684 : : bool marked_for_strip = false;
2685 : :
2686 : : public:
2687 : : std::string as_string () const override;
2688 : :
2689 : : // Returns true if the continue expr has a label.
2690 : 11 : bool has_label () const { return !label.is_error (); }
2691 : :
2692 : : // Constructor for a ContinueExpr with a label.
2693 : 10 : ContinueExpr (Lifetime label, std::vector<Attribute> outer_attribs,
2694 : : location_t locus)
2695 : 20 : : outer_attrs (std::move (outer_attribs)), label (std::move (label)),
2696 : 10 : locus (locus)
2697 : 10 : {}
2698 : :
2699 : 18 : location_t get_locus () const override final { return locus; }
2700 : :
2701 : : void accept_vis (ASTVisitor &vis) override;
2702 : :
2703 : : // Can't think of any invalid invariants, so store boolean.
2704 : 0 : void mark_for_strip () override { marked_for_strip = true; }
2705 : 64 : bool is_marked_for_strip () const override { return marked_for_strip; }
2706 : :
2707 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2708 : 147 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2709 : :
2710 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2711 : : {
2712 : 0 : outer_attrs = std::move (new_attrs);
2713 : 0 : }
2714 : :
2715 : 21 : Lifetime &get_label () { return label; }
2716 : :
2717 : : protected:
2718 : : /* Use covariance to implement clone function as returning this object rather
2719 : : * than base */
2720 : 0 : ContinueExpr *clone_expr_without_block_impl () const override
2721 : : {
2722 : 0 : return new ContinueExpr (*this);
2723 : : }
2724 : : };
2725 : : // TODO: merge "break" and "continue"? Or even merge in "return"?
2726 : :
2727 : : // AST node representing break expression within loops
2728 : : class BreakExpr : public ExprWithoutBlock
2729 : : {
2730 : : std::vector<Attribute> outer_attrs;
2731 : : LoopLabel label;
2732 : : std::unique_ptr<Expr> break_expr;
2733 : : location_t locus;
2734 : :
2735 : : // TODO: find another way to store this to save memory?
2736 : : bool marked_for_strip = false;
2737 : :
2738 : : public:
2739 : : std::string as_string () const override;
2740 : :
2741 : : // Returns whether the break expression has a label or not.
2742 : 1183 : bool has_label () const { return !label.is_error (); }
2743 : :
2744 : : /* Returns whether the break expression has an expression used in the break or
2745 : : * not. */
2746 : 940 : bool has_break_expr () const { return break_expr != nullptr; }
2747 : :
2748 : : // Constructor for a break expression
2749 : 66 : BreakExpr (LoopLabel break_label, std::unique_ptr<Expr> expr_in_break,
2750 : : std::vector<Attribute> outer_attribs, location_t locus)
2751 : 198 : : outer_attrs (std::move (outer_attribs)), label (std::move (break_label)),
2752 : 66 : break_expr (std::move (expr_in_break)), locus (locus)
2753 : 66 : {}
2754 : :
2755 : : // Copy constructor defined to use clone for unique pointer
2756 : 0 : BreakExpr (BreakExpr const &other)
2757 : 0 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
2758 : 0 : label (other.label), locus (other.locus),
2759 : 0 : marked_for_strip (other.marked_for_strip)
2760 : : {
2761 : : // guard to protect from null pointer dereference
2762 : 0 : if (other.break_expr != nullptr)
2763 : 0 : break_expr = other.break_expr->clone_expr ();
2764 : 0 : }
2765 : :
2766 : : // Overload assignment operator to clone unique pointer
2767 : : BreakExpr &operator= (BreakExpr const &other)
2768 : : {
2769 : : ExprWithoutBlock::operator= (other);
2770 : : label = other.label;
2771 : : locus = other.locus;
2772 : : marked_for_strip = other.marked_for_strip;
2773 : : outer_attrs = other.outer_attrs;
2774 : :
2775 : : // guard to protect from null pointer dereference
2776 : : if (other.break_expr != nullptr)
2777 : : break_expr = other.break_expr->clone_expr ();
2778 : : else
2779 : : break_expr = nullptr;
2780 : :
2781 : : return *this;
2782 : : }
2783 : :
2784 : : // move constructors
2785 : : BreakExpr (BreakExpr &&other) = default;
2786 : : BreakExpr &operator= (BreakExpr &&other) = default;
2787 : :
2788 : 114 : location_t get_locus () const override final { return locus; }
2789 : :
2790 : : void accept_vis (ASTVisitor &vis) override;
2791 : :
2792 : : // Can't think of any invalid invariants, so store boolean.
2793 : 0 : void mark_for_strip () override { marked_for_strip = true; }
2794 : 300 : bool is_marked_for_strip () const override { return marked_for_strip; }
2795 : :
2796 : : // TODO: is this better? Or is a "vis_block" better?
2797 : 310 : std::unique_ptr<Expr> &get_break_expr ()
2798 : : {
2799 : 310 : rust_assert (has_break_expr ());
2800 : 310 : return break_expr;
2801 : : }
2802 : :
2803 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
2804 : 1181 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
2805 : :
2806 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
2807 : : {
2808 : 0 : outer_attrs = std::move (new_attrs);
2809 : 0 : }
2810 : :
2811 : 179 : LoopLabel &get_label () { return label; }
2812 : :
2813 : : protected:
2814 : : /* Use covariance to implement clone function as returning this object rather
2815 : : * than base */
2816 : 0 : BreakExpr *clone_expr_without_block_impl () const override
2817 : : {
2818 : 0 : return new BreakExpr (*this);
2819 : : }
2820 : : };
2821 : :
2822 : : // Base range expression AST node object - abstract
2823 : 0 : class RangeExpr : public ExprWithoutBlock
2824 : : {
2825 : : location_t locus;
2826 : :
2827 : : protected:
2828 : : // outer attributes not allowed before range expressions
2829 : 156 : RangeExpr (location_t locus) : locus (locus) {}
2830 : :
2831 : : public:
2832 : 142 : location_t get_locus () const override final { return locus; }
2833 : :
2834 : 0 : std::vector<Attribute> &get_outer_attrs () override final
2835 : : {
2836 : : // RangeExpr cannot have any outer attributes
2837 : 0 : rust_assert (false);
2838 : : }
2839 : :
2840 : : // should never be called - error if called
2841 : 0 : void set_outer_attrs (std::vector<Attribute> /* new_attrs */) override
2842 : : {
2843 : 0 : rust_assert (false);
2844 : : }
2845 : : };
2846 : :
2847 : : // Range from (inclusive) and to (exclusive) expression AST node object
2848 : : // aka RangeExpr; constructs a std::ops::Range object
2849 : : class RangeFromToExpr : public RangeExpr
2850 : : {
2851 : : std::unique_ptr<Expr> from;
2852 : : std::unique_ptr<Expr> to;
2853 : :
2854 : : public:
2855 : : std::string as_string () const override;
2856 : :
2857 : 53 : RangeFromToExpr (std::unique_ptr<Expr> range_from,
2858 : : std::unique_ptr<Expr> range_to, location_t locus)
2859 : 106 : : RangeExpr (locus), from (std::move (range_from)),
2860 : 53 : to (std::move (range_to))
2861 : : {}
2862 : :
2863 : : // Copy constructor with cloning
2864 : 0 : RangeFromToExpr (RangeFromToExpr const &other) : RangeExpr (other)
2865 : : {
2866 : : // guard to prevent null dereference (only required if error state)
2867 : 0 : if (other.from != nullptr)
2868 : 0 : from = other.from->clone_expr ();
2869 : 0 : if (other.to != nullptr)
2870 : 0 : to = other.to->clone_expr ();
2871 : 0 : }
2872 : :
2873 : : // Overload assignment operator to clone unique pointers
2874 : : RangeFromToExpr &operator= (RangeFromToExpr const &other)
2875 : : {
2876 : : RangeExpr::operator= (other);
2877 : :
2878 : : // guard to prevent null dereference (only required if error state)
2879 : : if (other.from != nullptr)
2880 : : from = other.from->clone_expr ();
2881 : : else
2882 : : from = nullptr;
2883 : : if (other.to != nullptr)
2884 : : to = other.to->clone_expr ();
2885 : : else
2886 : : to = nullptr;
2887 : :
2888 : : return *this;
2889 : : }
2890 : :
2891 : : // move constructors
2892 : : RangeFromToExpr (RangeFromToExpr &&other) = default;
2893 : : RangeFromToExpr &operator= (RangeFromToExpr &&other) = default;
2894 : :
2895 : : void accept_vis (ASTVisitor &vis) override;
2896 : :
2897 : : // Invalid if either expr is null, so base stripping on that.
2898 : 0 : void mark_for_strip () override
2899 : : {
2900 : 0 : from = nullptr;
2901 : 0 : to = nullptr;
2902 : 0 : }
2903 : 132 : bool is_marked_for_strip () const override
2904 : : {
2905 : 132 : return from == nullptr && to == nullptr;
2906 : : }
2907 : :
2908 : : // TODO: is this better? Or is a "vis_block" better?
2909 : 546 : std::unique_ptr<Expr> &get_from_expr ()
2910 : : {
2911 : 546 : rust_assert (from != nullptr);
2912 : 546 : return from;
2913 : : }
2914 : :
2915 : : // TODO: is this better? Or is a "vis_block" better?
2916 : 546 : std::unique_ptr<Expr> &get_to_expr ()
2917 : : {
2918 : 546 : rust_assert (to != nullptr);
2919 : 546 : return to;
2920 : : }
2921 : :
2922 : : protected:
2923 : : /* Use covariance to implement clone function as returning this object rather
2924 : : * than base */
2925 : 0 : RangeFromToExpr *clone_expr_without_block_impl () const override
2926 : : {
2927 : 0 : return new RangeFromToExpr (*this);
2928 : : }
2929 : : };
2930 : :
2931 : : // Range from (inclusive) expression AST node object
2932 : : // constructs a std::ops::RangeFrom object
2933 : : class RangeFromExpr : public RangeExpr
2934 : : {
2935 : : std::unique_ptr<Expr> from;
2936 : :
2937 : : public:
2938 : : std::string as_string () const override;
2939 : :
2940 : 9 : RangeFromExpr (std::unique_ptr<Expr> range_from, location_t locus)
2941 : 9 : : RangeExpr (locus), from (std::move (range_from))
2942 : : {}
2943 : :
2944 : : // Copy constructor with clone
2945 : 0 : RangeFromExpr (RangeFromExpr const &other) : RangeExpr (other)
2946 : : {
2947 : : // guard to prevent null dereference (only required if error state)
2948 : 0 : if (other.from != nullptr)
2949 : 0 : from = other.from->clone_expr ();
2950 : 0 : }
2951 : :
2952 : : // Overload assignment operator to clone unique_ptr
2953 : : RangeFromExpr &operator= (RangeFromExpr const &other)
2954 : : {
2955 : : RangeExpr::operator= (other);
2956 : :
2957 : : // guard to prevent null dereference (only required if error state)
2958 : : if (other.from != nullptr)
2959 : : from = other.from->clone_expr ();
2960 : : else
2961 : : from = nullptr;
2962 : :
2963 : : return *this;
2964 : : }
2965 : :
2966 : : // move constructors
2967 : : RangeFromExpr (RangeFromExpr &&other) = default;
2968 : : RangeFromExpr &operator= (RangeFromExpr &&other) = default;
2969 : :
2970 : : void accept_vis (ASTVisitor &vis) override;
2971 : :
2972 : : // Invalid if expr is null, so base stripping on that.
2973 : 0 : void mark_for_strip () override { from = nullptr; }
2974 : 14 : bool is_marked_for_strip () const override { return from == nullptr; }
2975 : :
2976 : : // TODO: is this better? Or is a "vis_block" better?
2977 : 63 : std::unique_ptr<Expr> &get_from_expr ()
2978 : : {
2979 : 63 : rust_assert (from != nullptr);
2980 : 63 : return from;
2981 : : }
2982 : :
2983 : : protected:
2984 : : /* Use covariance to implement clone function as returning this object rather
2985 : : * than base */
2986 : 0 : RangeFromExpr *clone_expr_without_block_impl () const override
2987 : : {
2988 : 0 : return new RangeFromExpr (*this);
2989 : : }
2990 : : };
2991 : :
2992 : : // Range to (exclusive) expression AST node object
2993 : : // constructs a std::ops::RangeTo object
2994 : : class RangeToExpr : public RangeExpr
2995 : : {
2996 : : std::unique_ptr<Expr> to;
2997 : :
2998 : : public:
2999 : : std::string as_string () const override;
3000 : :
3001 : : // outer attributes not allowed
3002 : 8 : RangeToExpr (std::unique_ptr<Expr> range_to, location_t locus)
3003 : 8 : : RangeExpr (locus), to (std::move (range_to))
3004 : : {}
3005 : :
3006 : : // Copy constructor with clone
3007 : 0 : RangeToExpr (RangeToExpr const &other) : RangeExpr (other)
3008 : : {
3009 : : // guard to prevent null dereference (only required if error state)
3010 : 0 : if (other.to != nullptr)
3011 : 0 : to = other.to->clone_expr ();
3012 : 0 : }
3013 : :
3014 : : // Overload assignment operator to clone unique_ptr
3015 : : RangeToExpr &operator= (RangeToExpr const &other)
3016 : : {
3017 : : RangeExpr::operator= (other);
3018 : :
3019 : : // guard to prevent null dereference (only required if error state)
3020 : : if (other.to != nullptr)
3021 : : to = other.to->clone_expr ();
3022 : : else
3023 : : to = nullptr;
3024 : :
3025 : : return *this;
3026 : : }
3027 : :
3028 : : // move constructors
3029 : : RangeToExpr (RangeToExpr &&other) = default;
3030 : : RangeToExpr &operator= (RangeToExpr &&other) = default;
3031 : :
3032 : : void accept_vis (ASTVisitor &vis) override;
3033 : :
3034 : : // Invalid if expr is null, so base stripping on that.
3035 : 0 : void mark_for_strip () override { to = nullptr; }
3036 : 14 : bool is_marked_for_strip () const override { return to == nullptr; }
3037 : :
3038 : : // TODO: is this better? Or is a "vis_block" better?
3039 : 63 : std::unique_ptr<Expr> &get_to_expr ()
3040 : : {
3041 : 63 : rust_assert (to != nullptr);
3042 : 63 : return to;
3043 : : }
3044 : :
3045 : : protected:
3046 : : /* Use covariance to implement clone function as returning this object rather
3047 : : * than base */
3048 : 0 : RangeToExpr *clone_expr_without_block_impl () const override
3049 : : {
3050 : 0 : return new RangeToExpr (*this);
3051 : : }
3052 : : };
3053 : :
3054 : : // Full range expression AST node object
3055 : : // constructs a std::ops::RangeFull object
3056 : 0 : class RangeFullExpr : public RangeExpr
3057 : : {
3058 : : // TODO: find another way to store this to save memory?
3059 : : bool marked_for_strip = false;
3060 : :
3061 : : public:
3062 : : std::string as_string () const override;
3063 : :
3064 : 1 : RangeFullExpr (location_t locus) : RangeExpr (locus) {}
3065 : : // outer attributes not allowed
3066 : :
3067 : : void accept_vis (ASTVisitor &vis) override;
3068 : :
3069 : : // Can't think of any invalid invariants, so store boolean.
3070 : 0 : void mark_for_strip () override { marked_for_strip = true; }
3071 : 0 : bool is_marked_for_strip () const override { return marked_for_strip; }
3072 : :
3073 : : protected:
3074 : : /* Use covariance to implement clone function as returning this object rather
3075 : : * than base */
3076 : 0 : RangeFullExpr *clone_expr_without_block_impl () const override
3077 : : {
3078 : 0 : return new RangeFullExpr (*this);
3079 : : }
3080 : : };
3081 : :
3082 : : // Range from (inclusive) and to (inclusive) expression AST node object
3083 : : // aka RangeInclusiveExpr; constructs a std::ops::RangeInclusive object
3084 : : class RangeFromToInclExpr : public RangeExpr
3085 : : {
3086 : : std::unique_ptr<Expr> from;
3087 : : std::unique_ptr<Expr> to;
3088 : :
3089 : : public:
3090 : : std::string as_string () const override;
3091 : :
3092 : 7 : RangeFromToInclExpr (std::unique_ptr<Expr> range_from,
3093 : : std::unique_ptr<Expr> range_to, location_t locus)
3094 : 14 : : RangeExpr (locus), from (std::move (range_from)),
3095 : 7 : to (std::move (range_to))
3096 : : {}
3097 : : // outer attributes not allowed
3098 : :
3099 : : // Copy constructor with clone
3100 : 0 : RangeFromToInclExpr (RangeFromToInclExpr const &other) : RangeExpr (other)
3101 : : {
3102 : : // guard to prevent null dereference (only required if error state)
3103 : 0 : if (other.from != nullptr)
3104 : 0 : from = other.from->clone_expr ();
3105 : 0 : if (other.to != nullptr)
3106 : 0 : to = other.to->clone_expr ();
3107 : 0 : }
3108 : :
3109 : : // Overload assignment operator to use clone
3110 : : RangeFromToInclExpr &operator= (RangeFromToInclExpr const &other)
3111 : : {
3112 : : RangeExpr::operator= (other);
3113 : :
3114 : : // guard to prevent null dereference (only required if error state)
3115 : : if (other.from != nullptr)
3116 : : from = other.from->clone_expr ();
3117 : : else
3118 : : from = nullptr;
3119 : : if (other.to != nullptr)
3120 : : to = other.to->clone_expr ();
3121 : : else
3122 : : to = nullptr;
3123 : :
3124 : : return *this;
3125 : : }
3126 : :
3127 : : // move constructors
3128 : : RangeFromToInclExpr (RangeFromToInclExpr &&other) = default;
3129 : : RangeFromToInclExpr &operator= (RangeFromToInclExpr &&other) = default;
3130 : :
3131 : : void accept_vis (ASTVisitor &vis) override;
3132 : :
3133 : : // Invalid if either expr is null, so base stripping on that.
3134 : 0 : void mark_for_strip () override
3135 : : {
3136 : 0 : from = nullptr;
3137 : 0 : to = nullptr;
3138 : 0 : }
3139 : 14 : bool is_marked_for_strip () const override
3140 : : {
3141 : 14 : return from == nullptr && to == nullptr;
3142 : : }
3143 : :
3144 : : // TODO: is this better? Or is a "vis_block" better?
3145 : 63 : std::unique_ptr<Expr> &get_from_expr ()
3146 : : {
3147 : 63 : rust_assert (from != nullptr);
3148 : 63 : return from;
3149 : : }
3150 : :
3151 : : // TODO: is this better? Or is a "vis_block" better?
3152 : 63 : std::unique_ptr<Expr> &get_to_expr ()
3153 : : {
3154 : 63 : rust_assert (to != nullptr);
3155 : 63 : return to;
3156 : : }
3157 : :
3158 : : protected:
3159 : : /* Use covariance to implement clone function as returning this object rather
3160 : : * than base */
3161 : 0 : RangeFromToInclExpr *clone_expr_without_block_impl () const override
3162 : : {
3163 : 0 : return new RangeFromToInclExpr (*this);
3164 : : }
3165 : : };
3166 : :
3167 : : // Range to (inclusive) expression AST node object
3168 : : // aka RangeToInclusiveExpr; constructs a std::ops::RangeToInclusive object
3169 : : class RangeToInclExpr : public RangeExpr
3170 : : {
3171 : : std::unique_ptr<Expr> to;
3172 : :
3173 : : public:
3174 : : std::string as_string () const override;
3175 : :
3176 : 0 : RangeToInclExpr (std::unique_ptr<Expr> range_to, location_t locus)
3177 : 0 : : RangeExpr (locus), to (std::move (range_to))
3178 : : {}
3179 : : // outer attributes not allowed
3180 : :
3181 : : // Copy constructor with clone
3182 : 0 : RangeToInclExpr (RangeToInclExpr const &other) : RangeExpr (other)
3183 : : {
3184 : : // guard to prevent null dereference (only required if error state)
3185 : 0 : if (other.to != nullptr)
3186 : 0 : to = other.to->clone_expr ();
3187 : 0 : }
3188 : :
3189 : : // Overload assignment operator to clone pointer
3190 : : RangeToInclExpr &operator= (RangeToInclExpr const &other)
3191 : : {
3192 : : RangeExpr::operator= (other);
3193 : :
3194 : : // guard to prevent null dereference (only required if error state)
3195 : : if (other.to != nullptr)
3196 : : to = other.to->clone_expr ();
3197 : : else
3198 : : to = nullptr;
3199 : :
3200 : : return *this;
3201 : : }
3202 : :
3203 : : // move constructors
3204 : : RangeToInclExpr (RangeToInclExpr &&other) = default;
3205 : : RangeToInclExpr &operator= (RangeToInclExpr &&other) = default;
3206 : :
3207 : : void accept_vis (ASTVisitor &vis) override;
3208 : :
3209 : : // Invalid if expr is null, so base stripping on that.
3210 : 0 : void mark_for_strip () override { to = nullptr; }
3211 : 0 : bool is_marked_for_strip () const override { return to == nullptr; }
3212 : :
3213 : : // TODO: is this better? Or is a "vis_block" better?
3214 : 0 : std::unique_ptr<Expr> &get_to_expr ()
3215 : : {
3216 : 0 : rust_assert (to != nullptr);
3217 : 0 : return to;
3218 : : }
3219 : :
3220 : : protected:
3221 : : /* Use covariance to implement clone function as returning this object rather
3222 : : * than base */
3223 : 0 : RangeToInclExpr *clone_expr_without_block_impl () const override
3224 : : {
3225 : 0 : return new RangeToInclExpr (*this);
3226 : : }
3227 : : };
3228 : :
3229 : : // Return expression AST node representation
3230 : : class ReturnExpr : public ExprWithoutBlock
3231 : : {
3232 : : std::vector<Attribute> outer_attrs;
3233 : : std::unique_ptr<Expr> return_expr;
3234 : : location_t locus;
3235 : :
3236 : : // TODO: find another way to store this to save memory?
3237 : : bool marked_for_strip = false;
3238 : :
3239 : : public:
3240 : : std::string as_string () const override;
3241 : :
3242 : : /* Returns whether the object has an expression returned (i.e. not void return
3243 : : * type). */
3244 : 3266 : bool has_returned_expr () const { return return_expr != nullptr; }
3245 : :
3246 : : // Constructor for ReturnExpr.
3247 : 326 : ReturnExpr (std::unique_ptr<Expr> returned_expr,
3248 : : std::vector<Attribute> outer_attribs, location_t locus)
3249 : 652 : : outer_attrs (std::move (outer_attribs)),
3250 : 326 : return_expr (std::move (returned_expr)), locus (locus)
3251 : 326 : {}
3252 : :
3253 : : // Copy constructor with clone
3254 : 0 : ReturnExpr (ReturnExpr const &other)
3255 : 0 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
3256 : 0 : locus (other.locus), marked_for_strip (other.marked_for_strip)
3257 : : {
3258 : : // guard to protect from null pointer dereference
3259 : 0 : if (other.return_expr != nullptr)
3260 : 0 : return_expr = other.return_expr->clone_expr ();
3261 : 0 : }
3262 : :
3263 : : // Overloaded assignment operator to clone return_expr pointer
3264 : : ReturnExpr &operator= (ReturnExpr const &other)
3265 : : {
3266 : : ExprWithoutBlock::operator= (other);
3267 : : locus = other.locus;
3268 : : marked_for_strip = other.marked_for_strip;
3269 : : outer_attrs = other.outer_attrs;
3270 : :
3271 : : // guard to protect from null pointer dereference
3272 : : if (other.return_expr != nullptr)
3273 : : return_expr = other.return_expr->clone_expr ();
3274 : : else
3275 : : return_expr = nullptr;
3276 : :
3277 : : return *this;
3278 : : }
3279 : :
3280 : : // move constructors
3281 : : ReturnExpr (ReturnExpr &&other) = default;
3282 : : ReturnExpr &operator= (ReturnExpr &&other) = default;
3283 : :
3284 : 652 : location_t get_locus () const override final { return locus; }
3285 : :
3286 : : void accept_vis (ASTVisitor &vis) override;
3287 : :
3288 : : // Can't think of any invalid invariants, so store boolean.
3289 : 0 : void mark_for_strip () override { marked_for_strip = true; }
3290 : 817 : bool is_marked_for_strip () const override { return marked_for_strip; }
3291 : :
3292 : : // TODO: is this better? Or is a "vis_block" better?
3293 : 3140 : std::unique_ptr<Expr> &get_returned_expr ()
3294 : : {
3295 : 3140 : rust_assert (return_expr != nullptr);
3296 : 3140 : return return_expr;
3297 : : }
3298 : :
3299 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3300 : 3431 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3301 : :
3302 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3303 : : {
3304 : 0 : outer_attrs = std::move (new_attrs);
3305 : 0 : }
3306 : :
3307 : : protected:
3308 : : /* Use covariance to implement clone function as returning this object rather
3309 : : * than base */
3310 : 0 : ReturnExpr *clone_expr_without_block_impl () const override
3311 : : {
3312 : 0 : return new ReturnExpr (*this);
3313 : : }
3314 : : };
3315 : :
3316 : : // Forward decl - defined in rust-macro.h
3317 : : class MacroInvocation;
3318 : :
3319 : : // An unsafe block AST node
3320 : : class UnsafeBlockExpr : public ExprWithBlock
3321 : : {
3322 : : std::vector<Attribute> outer_attrs;
3323 : : // Or just have it extend BlockExpr
3324 : : std::unique_ptr<BlockExpr> expr;
3325 : : location_t locus;
3326 : :
3327 : : public:
3328 : : std::string as_string () const override;
3329 : :
3330 : 2503 : UnsafeBlockExpr (std::unique_ptr<BlockExpr> block_expr,
3331 : : std::vector<Attribute> outer_attribs, location_t locus)
3332 : 5006 : : outer_attrs (std::move (outer_attribs)), expr (std::move (block_expr)),
3333 : 2503 : locus (locus)
3334 : 2503 : {}
3335 : :
3336 : : // Copy constructor with clone
3337 : 1925 : UnsafeBlockExpr (UnsafeBlockExpr const &other)
3338 : 1925 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
3339 : 1925 : locus (other.locus)
3340 : : {
3341 : : // guard to prevent null dereference (only required if error state)
3342 : 1925 : if (other.expr != nullptr)
3343 : 1925 : expr = other.expr->clone_block_expr ();
3344 : 1925 : }
3345 : :
3346 : : // Overloaded assignment operator to clone
3347 : : UnsafeBlockExpr &operator= (UnsafeBlockExpr const &other)
3348 : : {
3349 : : ExprWithBlock::operator= (other);
3350 : : locus = other.locus;
3351 : : outer_attrs = other.outer_attrs;
3352 : :
3353 : : // guard to prevent null dereference (only required if error state)
3354 : : if (other.expr != nullptr)
3355 : : expr = other.expr->clone_block_expr ();
3356 : : else
3357 : : expr = nullptr;
3358 : :
3359 : : return *this;
3360 : : }
3361 : :
3362 : : // move constructors
3363 : : UnsafeBlockExpr (UnsafeBlockExpr &&other) = default;
3364 : : UnsafeBlockExpr &operator= (UnsafeBlockExpr &&other) = default;
3365 : :
3366 : 4975 : location_t get_locus () const override final { return locus; }
3367 : :
3368 : : void accept_vis (ASTVisitor &vis) override;
3369 : :
3370 : : // Invalid if block is null, so base stripping on that.
3371 : 7 : void mark_for_strip () override { expr = nullptr; }
3372 : 5755 : bool is_marked_for_strip () const override { return expr == nullptr; }
3373 : :
3374 : : // TODO: is this better? Or is a "vis_block" better?
3375 : 25640 : std::unique_ptr<BlockExpr> &get_block_expr ()
3376 : : {
3377 : 25640 : rust_assert (expr != nullptr);
3378 : 25640 : return expr;
3379 : : }
3380 : :
3381 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3382 : 30881 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3383 : :
3384 : 2235 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3385 : : {
3386 : 2235 : outer_attrs = std::move (new_attrs);
3387 : 2235 : }
3388 : :
3389 : : protected:
3390 : : /* Use covariance to implement clone function as returning this object rather
3391 : : * than base */
3392 : 1925 : UnsafeBlockExpr *clone_expr_with_block_impl () const override
3393 : : {
3394 : 1925 : return new UnsafeBlockExpr (*this);
3395 : : }
3396 : : };
3397 : :
3398 : : // Base loop expression AST node - aka LoopExpr
3399 : : class BaseLoopExpr : public ExprWithBlock
3400 : : {
3401 : : protected:
3402 : : // protected to allow subclasses better use of them
3403 : : std::vector<Attribute> outer_attrs;
3404 : : LoopLabel loop_label;
3405 : : std::unique_ptr<BlockExpr> loop_block;
3406 : :
3407 : : private:
3408 : : location_t locus;
3409 : :
3410 : : protected:
3411 : : // Constructor for BaseLoopExpr
3412 : 134 : BaseLoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus,
3413 : : LoopLabel loop_label = LoopLabel::error (),
3414 : : std::vector<Attribute> outer_attribs
3415 : : = std::vector<Attribute> ())
3416 : 268 : : outer_attrs (std::move (outer_attribs)),
3417 : 134 : loop_label (std::move (loop_label)), loop_block (std::move (loop_block)),
3418 : 134 : locus (locus)
3419 : 134 : {}
3420 : :
3421 : : // Copy constructor for BaseLoopExpr with clone
3422 : 0 : BaseLoopExpr (BaseLoopExpr const &other)
3423 : 0 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
3424 : 0 : loop_label (other.loop_label), locus (other.locus)
3425 : : {
3426 : : // guard to prevent null dereference (only required if error state)
3427 : 0 : if (other.loop_block != nullptr)
3428 : 0 : loop_block = other.loop_block->clone_block_expr ();
3429 : 0 : }
3430 : :
3431 : : // Overloaded assignment operator to clone
3432 : : BaseLoopExpr &operator= (BaseLoopExpr const &other)
3433 : : {
3434 : : ExprWithBlock::operator= (other);
3435 : : loop_label = other.loop_label;
3436 : : locus = other.locus;
3437 : : outer_attrs = other.outer_attrs;
3438 : :
3439 : : // guard to prevent null dereference (only required if error state)
3440 : : if (other.loop_block != nullptr)
3441 : : loop_block = other.loop_block->clone_block_expr ();
3442 : : else
3443 : : loop_block = nullptr;
3444 : :
3445 : : return *this;
3446 : : }
3447 : :
3448 : : // move constructors
3449 : : BaseLoopExpr (BaseLoopExpr &&other) = default;
3450 : : BaseLoopExpr &operator= (BaseLoopExpr &&other) = default;
3451 : :
3452 : : public:
3453 : 279 : bool has_loop_label () const { return !loop_label.is_error (); }
3454 : :
3455 : 854 : LoopLabel &get_loop_label () { return loop_label; }
3456 : :
3457 : 246 : location_t get_locus () const override final { return locus; }
3458 : :
3459 : : // Invalid if loop block is null, so base stripping on that.
3460 : 0 : void mark_for_strip () override { loop_block = nullptr; }
3461 : 249 : bool is_marked_for_strip () const override { return loop_block == nullptr; }
3462 : :
3463 : : // TODO: is this better? Or is a "vis_block" better?
3464 : 1199 : std::unique_ptr<BlockExpr> &get_loop_block ()
3465 : : {
3466 : 1199 : rust_assert (loop_block != nullptr);
3467 : 1199 : return loop_block;
3468 : : }
3469 : :
3470 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3471 : 1392 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3472 : :
3473 : 101 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3474 : : {
3475 : 101 : outer_attrs = std::move (new_attrs);
3476 : 101 : }
3477 : : };
3478 : :
3479 : : // 'Loop' expression (i.e. the infinite loop) AST node
3480 : 0 : class LoopExpr : public BaseLoopExpr
3481 : : {
3482 : : public:
3483 : : std::string as_string () const override;
3484 : :
3485 : : // Constructor for LoopExpr
3486 : 95 : LoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus,
3487 : : LoopLabel loop_label = LoopLabel::error (),
3488 : : std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
3489 : 95 : : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
3490 : 95 : std::move (outer_attribs))
3491 : 95 : {}
3492 : :
3493 : : void accept_vis (ASTVisitor &vis) override;
3494 : :
3495 : : protected:
3496 : : /* Use covariance to implement clone function as returning this object rather
3497 : : * than base */
3498 : 0 : LoopExpr *clone_expr_with_block_impl () const override
3499 : : {
3500 : 0 : return new LoopExpr (*this);
3501 : : }
3502 : : };
3503 : :
3504 : : // While loop expression AST node (predicate loop)
3505 : : class WhileLoopExpr : public BaseLoopExpr
3506 : : {
3507 : : std::unique_ptr<Expr> condition;
3508 : :
3509 : : public:
3510 : : std::string as_string () const override;
3511 : :
3512 : : // Constructor for while loop with loop label
3513 : 35 : WhileLoopExpr (std::unique_ptr<Expr> loop_condition,
3514 : : std::unique_ptr<BlockExpr> loop_block, location_t locus,
3515 : : LoopLabel loop_label = LoopLabel::error (),
3516 : : std::vector<Attribute> outer_attribs
3517 : : = std::vector<Attribute> ())
3518 : 35 : : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
3519 : : std::move (outer_attribs)),
3520 : 35 : condition (std::move (loop_condition))
3521 : 35 : {}
3522 : :
3523 : : // Copy constructor with clone
3524 : 0 : WhileLoopExpr (WhileLoopExpr const &other)
3525 : 0 : : BaseLoopExpr (other), condition (other.condition->clone_expr ())
3526 : 0 : {}
3527 : :
3528 : : // Overloaded assignment operator to clone
3529 : : WhileLoopExpr &operator= (WhileLoopExpr const &other)
3530 : : {
3531 : : BaseLoopExpr::operator= (other);
3532 : : condition = other.condition->clone_expr ();
3533 : : // loop_block = other.loop_block->clone_block_expr();
3534 : : // loop_label = other.loop_label;
3535 : : // outer_attrs = other.outer_attrs;
3536 : :
3537 : : return *this;
3538 : : }
3539 : :
3540 : : // move constructors
3541 : : WhileLoopExpr (WhileLoopExpr &&other) = default;
3542 : : WhileLoopExpr &operator= (WhileLoopExpr &&other) = default;
3543 : :
3544 : : void accept_vis (ASTVisitor &vis) override;
3545 : :
3546 : : // TODO: is this better? Or is a "vis_block" better?
3547 : 385 : std::unique_ptr<Expr> &get_predicate_expr ()
3548 : : {
3549 : 385 : rust_assert (condition != nullptr);
3550 : 385 : return condition;
3551 : : }
3552 : :
3553 : : protected:
3554 : : /* Use covariance to implement clone function as returning this object rather
3555 : : * than base */
3556 : 0 : WhileLoopExpr *clone_expr_with_block_impl () const override
3557 : : {
3558 : 0 : return new WhileLoopExpr (*this);
3559 : : }
3560 : : };
3561 : :
3562 : : // While let loop expression AST node (predicate pattern loop)
3563 : : class WhileLetLoopExpr : public BaseLoopExpr
3564 : : {
3565 : : // MatchArmPatterns patterns;
3566 : : std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined
3567 : : std::unique_ptr<Expr> scrutinee;
3568 : :
3569 : : public:
3570 : : std::string as_string () const override;
3571 : :
3572 : : // Constructor with a loop label
3573 : 1 : WhileLetLoopExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
3574 : : std::unique_ptr<Expr> scrutinee,
3575 : : std::unique_ptr<BlockExpr> loop_block, location_t locus,
3576 : : LoopLabel loop_label = LoopLabel::error (),
3577 : : std::vector<Attribute> outer_attribs
3578 : : = std::vector<Attribute> ())
3579 : 1 : : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label),
3580 : : std::move (outer_attribs)),
3581 : 1 : match_arm_patterns (std::move (match_arm_patterns)),
3582 : 1 : scrutinee (std::move (scrutinee))
3583 : 1 : {}
3584 : :
3585 : : // Copy constructor with clone
3586 : 0 : WhileLetLoopExpr (WhileLetLoopExpr const &other)
3587 : 0 : : BaseLoopExpr (other),
3588 : 0 : /*match_arm_patterns(other.match_arm_patterns),*/ scrutinee (
3589 : 0 : other.scrutinee->clone_expr ())
3590 : : {
3591 : 0 : match_arm_patterns.reserve (other.match_arm_patterns.size ());
3592 : 0 : for (const auto &e : other.match_arm_patterns)
3593 : 0 : match_arm_patterns.push_back (e->clone_pattern ());
3594 : 0 : }
3595 : :
3596 : : // Overloaded assignment operator to clone pointers
3597 : : WhileLetLoopExpr &operator= (WhileLetLoopExpr const &other)
3598 : : {
3599 : : BaseLoopExpr::operator= (other);
3600 : : // match_arm_patterns = other.match_arm_patterns;
3601 : : scrutinee = other.scrutinee->clone_expr ();
3602 : : // loop_block = other.loop_block->clone_block_expr();
3603 : : // loop_label = other.loop_label;
3604 : : // outer_attrs = other.outer_attrs;
3605 : :
3606 : : match_arm_patterns.reserve (other.match_arm_patterns.size ());
3607 : : for (const auto &e : other.match_arm_patterns)
3608 : : match_arm_patterns.push_back (e->clone_pattern ());
3609 : :
3610 : : return *this;
3611 : : }
3612 : :
3613 : : // move constructors
3614 : : WhileLetLoopExpr (WhileLetLoopExpr &&other) = default;
3615 : : WhileLetLoopExpr &operator= (WhileLetLoopExpr &&other) = default;
3616 : :
3617 : : void accept_vis (ASTVisitor &vis) override;
3618 : :
3619 : : // TODO: is this better? Or is a "vis_block" better?
3620 : 0 : std::unique_ptr<Expr> &get_scrutinee_expr ()
3621 : : {
3622 : 0 : rust_assert (scrutinee != nullptr);
3623 : 0 : return scrutinee;
3624 : : }
3625 : :
3626 : : // TODO: this mutable getter seems really dodgy. Think up better way.
3627 : : const std::vector<std::unique_ptr<Pattern> > &get_patterns () const
3628 : : {
3629 : : return match_arm_patterns;
3630 : : }
3631 : : std::vector<std::unique_ptr<Pattern> > &get_patterns ()
3632 : : {
3633 : 0 : return match_arm_patterns;
3634 : : }
3635 : :
3636 : : protected:
3637 : : /* Use covariance to implement clone function as returning this object rather
3638 : : * than base */
3639 : 0 : WhileLetLoopExpr *clone_expr_with_block_impl () const override
3640 : : {
3641 : 0 : return new WhileLetLoopExpr (*this);
3642 : : }
3643 : : };
3644 : :
3645 : : // For loop expression AST node (iterator loop)
3646 : : class ForLoopExpr : public BaseLoopExpr
3647 : : {
3648 : : std::unique_ptr<Pattern> pattern;
3649 : : std::unique_ptr<Expr> iterator_expr;
3650 : :
3651 : : public:
3652 : : std::string as_string () const override;
3653 : :
3654 : : // Constructor with loop label
3655 : 3 : ForLoopExpr (std::unique_ptr<Pattern> loop_pattern,
3656 : : std::unique_ptr<Expr> iterator_expr,
3657 : : std::unique_ptr<BlockExpr> loop_body, location_t locus,
3658 : : LoopLabel loop_label = LoopLabel::error (),
3659 : : std::vector<Attribute> outer_attribs = std::vector<Attribute> ())
3660 : 3 : : BaseLoopExpr (std::move (loop_body), locus, std::move (loop_label),
3661 : : std::move (outer_attribs)),
3662 : 3 : pattern (std::move (loop_pattern)),
3663 : 3 : iterator_expr (std::move (iterator_expr))
3664 : 3 : {}
3665 : :
3666 : : // Copy constructor with clone
3667 : 0 : ForLoopExpr (ForLoopExpr const &other)
3668 : 0 : : BaseLoopExpr (other), pattern (other.pattern->clone_pattern ()),
3669 : 0 : iterator_expr (other.iterator_expr->clone_expr ())
3670 : 0 : {}
3671 : :
3672 : : // Overloaded assignment operator to clone
3673 : : ForLoopExpr &operator= (ForLoopExpr const &other)
3674 : : {
3675 : : BaseLoopExpr::operator= (other);
3676 : : pattern = other.pattern->clone_pattern ();
3677 : : iterator_expr = other.iterator_expr->clone_expr ();
3678 : : /*loop_block = other.loop_block->clone_block_expr();
3679 : : loop_label = other.loop_label;
3680 : : outer_attrs = other.outer_attrs;*/
3681 : :
3682 : : return *this;
3683 : : }
3684 : :
3685 : : // move constructors
3686 : : ForLoopExpr (ForLoopExpr &&other) = default;
3687 : : ForLoopExpr &operator= (ForLoopExpr &&other) = default;
3688 : :
3689 : : void accept_vis (ASTVisitor &vis) override;
3690 : :
3691 : : // TODO: is this better? Or is a "vis_block" better?
3692 : 0 : std::unique_ptr<Expr> &get_iterator_expr ()
3693 : : {
3694 : 0 : rust_assert (iterator_expr != nullptr);
3695 : 0 : return iterator_expr;
3696 : : }
3697 : :
3698 : : // TODO: is this better? Or is a "vis_block" better?
3699 : 0 : std::unique_ptr<Pattern> &get_pattern ()
3700 : : {
3701 : 0 : rust_assert (pattern != nullptr);
3702 : 0 : return pattern;
3703 : : }
3704 : :
3705 : : protected:
3706 : : /* Use covariance to implement clone function as returning this object rather
3707 : : * than base */
3708 : 0 : ForLoopExpr *clone_expr_with_block_impl () const override
3709 : : {
3710 : 0 : return new ForLoopExpr (*this);
3711 : : }
3712 : : };
3713 : :
3714 : : // forward decl for IfExpr
3715 : : class IfLetExpr;
3716 : :
3717 : : // Base if expression with no "else" or "if let" AST node
3718 : : class IfExpr : public ExprWithBlock
3719 : : {
3720 : : std::vector<Attribute> outer_attrs;
3721 : : std::unique_ptr<Expr> condition;
3722 : : std::unique_ptr<BlockExpr> if_block;
3723 : : location_t locus;
3724 : :
3725 : : public:
3726 : : std::string as_string () const override;
3727 : :
3728 : 653 : IfExpr (std::unique_ptr<Expr> condition, std::unique_ptr<BlockExpr> if_block,
3729 : : std::vector<Attribute> outer_attrs, location_t locus)
3730 : 1306 : : outer_attrs (std::move (outer_attrs)), condition (std::move (condition)),
3731 : 653 : if_block (std::move (if_block)), locus (locus)
3732 : 653 : {}
3733 : : // outer attributes are never allowed on IfExprs
3734 : :
3735 : : // Copy constructor with clone
3736 : 270 : IfExpr (IfExpr const &other)
3737 : 270 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
3738 : 270 : locus (other.locus)
3739 : : {
3740 : : // guard to prevent null dereference (only required if error state)
3741 : 270 : if (other.condition != nullptr)
3742 : 270 : condition = other.condition->clone_expr ();
3743 : 270 : if (other.if_block != nullptr)
3744 : 270 : if_block = other.if_block->clone_block_expr ();
3745 : 270 : }
3746 : :
3747 : : // Overloaded assignment operator to clone expressions
3748 : : IfExpr &operator= (IfExpr const &other)
3749 : : {
3750 : : ExprWithBlock::operator= (other);
3751 : : outer_attrs = other.outer_attrs;
3752 : : locus = other.locus;
3753 : :
3754 : : // guard to prevent null dereference (only required if error state)
3755 : : if (other.condition != nullptr)
3756 : : condition = other.condition->clone_expr ();
3757 : : else
3758 : : condition = nullptr;
3759 : : if (other.if_block != nullptr)
3760 : : if_block = other.if_block->clone_block_expr ();
3761 : : else
3762 : : if_block = nullptr;
3763 : :
3764 : : return *this;
3765 : : }
3766 : :
3767 : : // move constructors
3768 : : IfExpr (IfExpr &&other) = default;
3769 : : IfExpr &operator= (IfExpr &&other) = default;
3770 : :
3771 : : // Unique pointer custom clone function
3772 : : std::unique_ptr<IfExpr> clone_if_expr () const
3773 : : {
3774 : : return std::unique_ptr<IfExpr> (clone_if_expr_impl ());
3775 : : }
3776 : :
3777 : : /* Note that multiple "else if"s are handled via nested ASTs rather than a
3778 : : * vector of else ifs - i.e. not like a switch statement. TODO - is this a
3779 : : * better approach? or does it not parse correctly and have downsides? */
3780 : :
3781 : 1256 : location_t get_locus () const override final { return locus; }
3782 : :
3783 : : void accept_vis (ASTVisitor &vis) override;
3784 : :
3785 : : void vis_if_condition (ASTVisitor &vis) { condition->accept_vis (vis); }
3786 : : void vis_if_block (ASTVisitor &vis) { if_block->accept_vis (vis); }
3787 : :
3788 : : // TODO: is this better? Or is a "vis_block" better?
3789 : 7313 : std::unique_ptr<Expr> &get_condition_expr ()
3790 : : {
3791 : 7313 : rust_assert (condition != nullptr);
3792 : 7313 : return condition;
3793 : : }
3794 : :
3795 : : // TODO: is this better? Or is a "vis_block" better?
3796 : 7313 : std::unique_ptr<BlockExpr> &get_if_block ()
3797 : : {
3798 : 7313 : rust_assert (if_block != nullptr);
3799 : 7313 : return if_block;
3800 : : }
3801 : :
3802 : : // Invalid if if block or condition is null, so base stripping on that.
3803 : 0 : void mark_for_strip () override
3804 : : {
3805 : 0 : if_block = nullptr;
3806 : 0 : condition = nullptr;
3807 : 0 : }
3808 : 1466 : bool is_marked_for_strip () const override
3809 : : {
3810 : 1466 : return if_block == nullptr && condition == nullptr;
3811 : : }
3812 : :
3813 : 582 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
3814 : : {
3815 : 582 : outer_attrs = std::move (new_attrs);
3816 : 582 : }
3817 : :
3818 : : // TODO: this mutable getter seems really dodgy. Think up better way.
3819 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
3820 : 7821 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
3821 : :
3822 : : protected:
3823 : : // Base clone function but still concrete as concrete base class
3824 : 0 : virtual IfExpr *clone_if_expr_impl () const { return new IfExpr (*this); }
3825 : :
3826 : : /* Use covariance to implement clone function as returning this object rather
3827 : : * than base */
3828 : 270 : IfExpr *clone_expr_with_block_impl () const final override
3829 : : {
3830 : 270 : return clone_if_expr_impl ();
3831 : : }
3832 : : };
3833 : :
3834 : : // If expression with an ending "else" expression AST node (trailing)
3835 : : class IfExprConseqElse : public IfExpr
3836 : : {
3837 : : std::unique_ptr<ExprWithBlock> else_block;
3838 : :
3839 : : public:
3840 : : std::string as_string () const override;
3841 : :
3842 : 353 : IfExprConseqElse (std::unique_ptr<Expr> condition,
3843 : : std::unique_ptr<BlockExpr> if_block,
3844 : : std::unique_ptr<ExprWithBlock> else_block,
3845 : : std::vector<Attribute> outer_attrs, location_t locus)
3846 : 353 : : IfExpr (std::move (condition), std::move (if_block),
3847 : : std::move (outer_attrs), locus),
3848 : 353 : else_block (std::move (else_block))
3849 : 353 : {}
3850 : : // again, outer attributes not allowed
3851 : :
3852 : : // Copy constructor with clone
3853 : 270 : IfExprConseqElse (IfExprConseqElse const &other)
3854 : 270 : : IfExpr (other), else_block (other.else_block->clone_expr_with_block ())
3855 : 270 : {}
3856 : :
3857 : : // Overloaded assignment operator with cloning
3858 : : IfExprConseqElse &operator= (IfExprConseqElse const &other)
3859 : : {
3860 : : IfExpr::operator= (other);
3861 : : // condition = other.condition->clone_expr();
3862 : : // if_block = other.if_block->clone_block_expr();
3863 : : else_block = other.else_block->clone_expr_with_block ();
3864 : :
3865 : : return *this;
3866 : : }
3867 : :
3868 : : // move constructors
3869 : : IfExprConseqElse (IfExprConseqElse &&other) = default;
3870 : : IfExprConseqElse &operator= (IfExprConseqElse &&other) = default;
3871 : :
3872 : : void accept_vis (ASTVisitor &vis) override;
3873 : :
3874 : : void vis_else_block (ASTVisitor &vis) { else_block->accept_vis (vis); }
3875 : :
3876 : : // TODO: is this better? Or is a "vis_block" better?
3877 : 3485 : std::unique_ptr<ExprWithBlock> &get_else_block ()
3878 : : {
3879 : 3485 : rust_assert (else_block != nullptr);
3880 : 3485 : return else_block;
3881 : : }
3882 : :
3883 : : protected:
3884 : : /* Use covariance to implement clone function as returning this object rather
3885 : : * than base */
3886 : 270 : IfExprConseqElse *clone_if_expr_impl () const override
3887 : : {
3888 : 270 : return new IfExprConseqElse (*this);
3889 : : }
3890 : : };
3891 : :
3892 : : // Basic "if let" expression AST node with no else
3893 : : class IfLetExpr : public ExprWithBlock
3894 : : {
3895 : : std::vector<Attribute> outer_attrs;
3896 : : std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined
3897 : : std::unique_ptr<Expr> value;
3898 : : std::unique_ptr<BlockExpr> if_block;
3899 : : location_t locus;
3900 : :
3901 : : public:
3902 : : std::string as_string () const override;
3903 : :
3904 : 3 : IfLetExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
3905 : : std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block,
3906 : : std::vector<Attribute> outer_attrs, location_t locus)
3907 : 6 : : outer_attrs (std::move (outer_attrs)),
3908 : 3 : match_arm_patterns (std::move (match_arm_patterns)),
3909 : 3 : value (std::move (value)), if_block (std::move (if_block)), locus (locus)
3910 : 3 : {}
3911 : :
3912 : : // copy constructor with clone
3913 : 0 : IfLetExpr (IfLetExpr const &other)
3914 : 0 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
3915 : 0 : locus (other.locus)
3916 : : {
3917 : : // guard to prevent null dereference (only required if error state)
3918 : 0 : if (other.value != nullptr)
3919 : 0 : value = other.value->clone_expr ();
3920 : 0 : if (other.if_block != nullptr)
3921 : 0 : if_block = other.if_block->clone_block_expr ();
3922 : :
3923 : 0 : match_arm_patterns.reserve (other.match_arm_patterns.size ());
3924 : 0 : for (const auto &e : other.match_arm_patterns)
3925 : 0 : match_arm_patterns.push_back (e->clone_pattern ());
3926 : 0 : }
3927 : :
3928 : : // overload assignment operator to clone
3929 : : IfLetExpr &operator= (IfLetExpr const &other)
3930 : : {
3931 : : ExprWithBlock::operator= (other);
3932 : : outer_attrs = other.outer_attrs;
3933 : : locus = other.locus;
3934 : :
3935 : : // guard to prevent null dereference (only required if error state)
3936 : : if (other.value != nullptr)
3937 : : value = other.value->clone_expr ();
3938 : : else
3939 : : value = nullptr;
3940 : : if (other.if_block != nullptr)
3941 : : if_block = other.if_block->clone_block_expr ();
3942 : : else
3943 : : if_block = nullptr;
3944 : :
3945 : : match_arm_patterns.reserve (other.match_arm_patterns.size ());
3946 : : for (const auto &e : other.match_arm_patterns)
3947 : : match_arm_patterns.push_back (e->clone_pattern ());
3948 : :
3949 : : return *this;
3950 : : }
3951 : :
3952 : : // move constructors
3953 : : IfLetExpr (IfLetExpr &&other) = default;
3954 : : IfLetExpr &operator= (IfLetExpr &&other) = default;
3955 : :
3956 : : // Unique pointer custom clone function
3957 : : std::unique_ptr<IfLetExpr> clone_if_let_expr () const
3958 : : {
3959 : : return std::unique_ptr<IfLetExpr> (clone_if_let_expr_impl ());
3960 : : }
3961 : :
3962 : 3 : location_t get_locus () const override final { return locus; }
3963 : :
3964 : : void accept_vis (ASTVisitor &vis) override;
3965 : :
3966 : : // Invalid if block or value is null, so base stripping on that.
3967 : 0 : void mark_for_strip () override
3968 : : {
3969 : 0 : if_block = nullptr;
3970 : 0 : value = nullptr;
3971 : 0 : }
3972 : 6 : bool is_marked_for_strip () const override
3973 : : {
3974 : 6 : return if_block == nullptr && value == nullptr;
3975 : : }
3976 : :
3977 : : // TODO: is this better? Or is a "vis_block" better?
3978 : 30 : std::unique_ptr<Expr> &get_value_expr ()
3979 : : {
3980 : 30 : rust_assert (value != nullptr);
3981 : 30 : return value;
3982 : : }
3983 : :
3984 : : // TODO: is this better? Or is a "vis_block" better?
3985 : 30 : std::unique_ptr<BlockExpr> &get_if_block ()
3986 : : {
3987 : 30 : rust_assert (if_block != nullptr);
3988 : 30 : return if_block;
3989 : : }
3990 : :
3991 : : // TODO: this mutable getter seems really dodgy. Think up better way.
3992 : : const std::vector<std::unique_ptr<Pattern> > &get_patterns () const
3993 : : {
3994 : : return match_arm_patterns;
3995 : : }
3996 : : std::vector<std::unique_ptr<Pattern> > &get_patterns ()
3997 : : {
3998 : 24 : return match_arm_patterns;
3999 : : }
4000 : :
4001 : 1 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4002 : : {
4003 : 1 : outer_attrs = std::move (new_attrs);
4004 : 1 : }
4005 : :
4006 : : // TODO: this mutable getter seems really dodgy. Think up better way.
4007 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4008 : 29 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4009 : :
4010 : : protected:
4011 : : /* Use covariance to implement clone function as returning this object rather
4012 : : * than base (or rather this or any derived object) */
4013 : 0 : IfLetExpr *clone_expr_with_block_impl () const final override
4014 : : {
4015 : 0 : return clone_if_let_expr_impl ();
4016 : : }
4017 : :
4018 : : // Base clone function but still concrete as concrete base class
4019 : 0 : virtual IfLetExpr *clone_if_let_expr_impl () const
4020 : : {
4021 : 0 : return new IfLetExpr (*this);
4022 : : }
4023 : : };
4024 : :
4025 : : /* AST node representing "if let" expression with an "else" expression at the
4026 : : * end */
4027 : : class IfLetExprConseqElse : public IfLetExpr
4028 : : {
4029 : : std::unique_ptr<ExprWithBlock> else_block;
4030 : :
4031 : : public:
4032 : : std::string as_string () const override;
4033 : :
4034 : 2 : IfLetExprConseqElse (
4035 : : std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
4036 : : std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block,
4037 : : std::unique_ptr<ExprWithBlock> else_block,
4038 : : std::vector<Attribute> outer_attrs, location_t locus)
4039 : 2 : : IfLetExpr (std::move (match_arm_patterns), std::move (value),
4040 : : std::move (if_block), std::move (outer_attrs), locus),
4041 : 2 : else_block (std::move (else_block))
4042 : 2 : {}
4043 : : // outer attributes not allowed
4044 : :
4045 : : // copy constructor with clone
4046 : 0 : IfLetExprConseqElse (IfLetExprConseqElse const &other)
4047 : 0 : : IfLetExpr (other), else_block (other.else_block->clone_expr_with_block ())
4048 : 0 : {}
4049 : :
4050 : : // overload assignment operator to clone
4051 : : IfLetExprConseqElse &operator= (IfLetExprConseqElse const &other)
4052 : : {
4053 : : IfLetExpr::operator= (other);
4054 : : // match_arm_patterns = other.match_arm_patterns;
4055 : : // value = other.value->clone_expr();
4056 : : // if_block = other.if_block->clone_block_expr();
4057 : : else_block = other.else_block->clone_expr_with_block ();
4058 : : // outer_attrs = other.outer_attrs;
4059 : :
4060 : : return *this;
4061 : : }
4062 : :
4063 : : // move constructors
4064 : : IfLetExprConseqElse (IfLetExprConseqElse &&other) = default;
4065 : : IfLetExprConseqElse &operator= (IfLetExprConseqElse &&other) = default;
4066 : :
4067 : : void accept_vis (ASTVisitor &vis) override;
4068 : :
4069 : : // TODO: is this better? Or is a "vis_block" better?
4070 : 18 : std::unique_ptr<ExprWithBlock> &get_else_block ()
4071 : : {
4072 : 18 : rust_assert (else_block != nullptr);
4073 : 18 : return else_block;
4074 : : }
4075 : :
4076 : : protected:
4077 : : /* Use covariance to implement clone function as returning this object rather
4078 : : * than base */
4079 : 0 : IfLetExprConseqElse *clone_if_let_expr_impl () const override
4080 : : {
4081 : 0 : return new IfLetExprConseqElse (*this);
4082 : : }
4083 : : };
4084 : :
4085 : : // Match arm expression
4086 : : struct MatchArm
4087 : : {
4088 : : private:
4089 : : std::vector<Attribute> outer_attrs;
4090 : : // MatchArmPatterns patterns;
4091 : : std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined
4092 : :
4093 : : // bool has_match_arm_guard;
4094 : : // inlined from MatchArmGuard
4095 : : std::unique_ptr<Expr> guard_expr;
4096 : :
4097 : : location_t locus;
4098 : :
4099 : : public:
4100 : : // Returns whether the MatchArm has a match arm guard expression
4101 : 4201 : bool has_match_arm_guard () const { return guard_expr != nullptr; }
4102 : :
4103 : : // Constructor for match arm with a guard expression
4104 : 501 : MatchArm (std::vector<std::unique_ptr<Pattern> > match_arm_patterns,
4105 : : location_t locus, std::unique_ptr<Expr> guard_expr = nullptr,
4106 : : std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
4107 : 0 : : outer_attrs (std::move (outer_attrs)),
4108 : 501 : match_arm_patterns (std::move (match_arm_patterns)),
4109 : 501 : guard_expr (std::move (guard_expr)), locus (locus)
4110 : : {}
4111 : :
4112 : : // Copy constructor with clone
4113 : 220 : MatchArm (MatchArm const &other) : outer_attrs (other.outer_attrs)
4114 : : {
4115 : : // guard to protect from null pointer dereference
4116 : 220 : if (other.guard_expr != nullptr)
4117 : 0 : guard_expr = other.guard_expr->clone_expr ();
4118 : :
4119 : 220 : match_arm_patterns.reserve (other.match_arm_patterns.size ());
4120 : 440 : for (const auto &e : other.match_arm_patterns)
4121 : 220 : match_arm_patterns.push_back (e->clone_pattern ());
4122 : :
4123 : 220 : locus = other.locus;
4124 : 220 : }
4125 : :
4126 : 2048 : ~MatchArm () = default;
4127 : :
4128 : : // Overload assignment operator to clone
4129 : : MatchArm &operator= (MatchArm const &other)
4130 : : {
4131 : : outer_attrs = other.outer_attrs;
4132 : :
4133 : : if (other.guard_expr != nullptr)
4134 : : guard_expr = other.guard_expr->clone_expr ();
4135 : : else
4136 : : guard_expr = nullptr;
4137 : :
4138 : : match_arm_patterns.reserve (other.match_arm_patterns.size ());
4139 : : for (const auto &e : other.match_arm_patterns)
4140 : : match_arm_patterns.push_back (e->clone_pattern ());
4141 : :
4142 : : return *this;
4143 : : }
4144 : :
4145 : : // move constructors
4146 : 1827 : MatchArm (MatchArm &&other) = default;
4147 : 0 : MatchArm &operator= (MatchArm &&other) = default;
4148 : :
4149 : : // Returns whether match arm is in an error state.
4150 : 6261 : bool is_error () const { return match_arm_patterns.empty (); }
4151 : :
4152 : : // Creates a match arm in an error state.
4153 : 0 : static MatchArm create_error ()
4154 : : {
4155 : 0 : location_t locus = UNDEF_LOCATION;
4156 : 0 : return MatchArm (std::vector<std::unique_ptr<Pattern> > (), locus);
4157 : : }
4158 : :
4159 : : std::string as_string () const;
4160 : :
4161 : : // TODO: is this better? Or is a "vis_block" better?
4162 : 11 : std::unique_ptr<Expr> &get_guard_expr ()
4163 : : {
4164 : 11 : rust_assert (has_match_arm_guard ());
4165 : 11 : return guard_expr;
4166 : : }
4167 : :
4168 : : // TODO: this mutable getter seems really dodgy. Think up better way.
4169 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4170 : 2555 : std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
4171 : :
4172 : : const std::vector<std::unique_ptr<Pattern> > &get_patterns () const
4173 : : {
4174 : : return match_arm_patterns;
4175 : : }
4176 : : std::vector<std::unique_ptr<Pattern> > &get_patterns ()
4177 : : {
4178 : 4201 : return match_arm_patterns;
4179 : : }
4180 : :
4181 : : location_t get_locus () const { return locus; }
4182 : : };
4183 : :
4184 : : /* A "match case" - a correlated match arm and resulting expression. Not
4185 : : * abstract. */
4186 : : struct MatchCase
4187 : : {
4188 : : private:
4189 : : MatchArm arm;
4190 : : std::unique_ptr<Expr> expr;
4191 : : NodeId node_id;
4192 : :
4193 : : /* TODO: does whether trailing comma exists need to be stored? currently
4194 : : * assuming it is only syntactical and has no effect on meaning. */
4195 : :
4196 : : public:
4197 : 501 : MatchCase (MatchArm arm, std::unique_ptr<Expr> expr)
4198 : 501 : : arm (std::move (arm)), expr (std::move (expr)),
4199 : 501 : node_id (Analysis::Mappings::get ()->get_next_node_id ())
4200 : 501 : {}
4201 : :
4202 : 220 : MatchCase (const MatchCase &other)
4203 : 220 : : arm (other.arm), expr (other.expr->clone_expr ()), node_id (other.node_id)
4204 : 220 : {}
4205 : :
4206 : : MatchCase &operator= (const MatchCase &other)
4207 : : {
4208 : : arm = other.arm;
4209 : : expr = other.expr->clone_expr ();
4210 : : node_id = other.node_id;
4211 : :
4212 : : return *this;
4213 : : }
4214 : :
4215 : 825 : MatchCase (MatchCase &&other) = default;
4216 : 0 : MatchCase &operator= (MatchCase &&other) = default;
4217 : :
4218 : 1046 : ~MatchCase () = default;
4219 : :
4220 : : std::string as_string () const;
4221 : :
4222 : : // TODO: is this better? Or is a "vis_block" better?
4223 : 4201 : std::unique_ptr<Expr> &get_expr ()
4224 : : {
4225 : 4201 : rust_assert (expr != nullptr);
4226 : 4201 : return expr;
4227 : : }
4228 : :
4229 : : // TODO: is this better? Or is a "vis_block" better?
4230 : 5760 : MatchArm &get_arm ()
4231 : : {
4232 : 5760 : rust_assert (!arm.is_error ());
4233 : 5760 : return arm;
4234 : : }
4235 : :
4236 : 1069 : NodeId get_node_id () const { return node_id; }
4237 : : };
4238 : :
4239 : : // Match expression AST node
4240 : : class MatchExpr : public ExprWithBlock
4241 : : {
4242 : : std::vector<Attribute> outer_attrs;
4243 : : std::unique_ptr<Expr> branch_value;
4244 : : std::vector<Attribute> inner_attrs;
4245 : : std::vector<MatchCase> match_arms;
4246 : : location_t locus;
4247 : :
4248 : : public:
4249 : : std::string as_string () const override;
4250 : :
4251 : : // Returns whether the match expression has any match arms.
4252 : : bool has_match_arms () const { return !match_arms.empty (); }
4253 : :
4254 : 200 : MatchExpr (std::unique_ptr<Expr> branch_value,
4255 : : std::vector<MatchCase> match_arms,
4256 : : std::vector<Attribute> inner_attrs,
4257 : : std::vector<Attribute> outer_attrs, location_t locus)
4258 : 400 : : outer_attrs (std::move (outer_attrs)),
4259 : 200 : branch_value (std::move (branch_value)),
4260 : 200 : inner_attrs (std::move (inner_attrs)),
4261 : 200 : match_arms (std::move (match_arms)), locus (locus)
4262 : 200 : {}
4263 : :
4264 : : // Copy constructor requires clone due to unique_ptr
4265 : 110 : MatchExpr (MatchExpr const &other)
4266 : 110 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4267 : 110 : inner_attrs (other.inner_attrs), match_arms (other.match_arms),
4268 : 110 : locus (other.locus)
4269 : : {
4270 : : // guard to prevent null dereference (only required if error state)
4271 : 110 : if (other.branch_value != nullptr)
4272 : 110 : branch_value = other.branch_value->clone_expr ();
4273 : 110 : }
4274 : :
4275 : : // Overloaded assignment operator to clone due to unique_ptr
4276 : : MatchExpr &operator= (MatchExpr const &other)
4277 : : {
4278 : : ExprWithBlock::operator= (other);
4279 : : inner_attrs = other.inner_attrs;
4280 : : match_arms = other.match_arms;
4281 : : outer_attrs = other.outer_attrs;
4282 : : locus = other.locus;
4283 : :
4284 : : // guard to prevent null dereference (only required if error state)
4285 : : if (other.branch_value != nullptr)
4286 : : branch_value = other.branch_value->clone_expr ();
4287 : : else
4288 : : branch_value = nullptr;
4289 : :
4290 : : return *this;
4291 : : }
4292 : :
4293 : : // move constructors
4294 : : MatchExpr (MatchExpr &&other) = default;
4295 : : MatchExpr &operator= (MatchExpr &&other) = default;
4296 : :
4297 : 882 : location_t get_locus () const override final { return locus; }
4298 : :
4299 : : void accept_vis (ASTVisitor &vis) override;
4300 : :
4301 : : // Invalid if branch value is null, so base stripping on that.
4302 : 0 : void mark_for_strip () override { branch_value = nullptr; }
4303 : 336 : bool is_marked_for_strip () const override { return branch_value == nullptr; }
4304 : :
4305 : : // TODO: this mutable getter seems really dodgy. Think up better way.
4306 : : const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; }
4307 : 1064 : std::vector<Attribute> &get_inner_attrs () { return inner_attrs; }
4308 : :
4309 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4310 : 1606 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4311 : :
4312 : 171 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4313 : : {
4314 : 171 : outer_attrs = std::move (new_attrs);
4315 : 171 : }
4316 : :
4317 : : // TODO: is this better? Or is a "vis_block" better?
4318 : 1736 : std::unique_ptr<Expr> &get_scrutinee_expr ()
4319 : : {
4320 : 1736 : rust_assert (branch_value != nullptr);
4321 : 1736 : return branch_value;
4322 : : }
4323 : :
4324 : : const std::vector<MatchCase> &get_match_cases () const { return match_arms; }
4325 : 1736 : std::vector<MatchCase> &get_match_cases () { return match_arms; }
4326 : :
4327 : : protected:
4328 : : /* Use covariance to implement clone function as returning this object rather
4329 : : * than base */
4330 : 110 : MatchExpr *clone_expr_with_block_impl () const override
4331 : : {
4332 : 110 : return new MatchExpr (*this);
4333 : : }
4334 : : };
4335 : :
4336 : : // Await expression AST node (pseudo-member variable access)
4337 : : class AwaitExpr : public ExprWithoutBlock
4338 : : {
4339 : : std::vector<Attribute> outer_attrs;
4340 : : std::unique_ptr<Expr> awaited_expr;
4341 : : location_t locus;
4342 : :
4343 : : public:
4344 : : // TODO: ensure outer attributes are actually allowed
4345 : 0 : AwaitExpr (std::unique_ptr<Expr> awaited_expr,
4346 : : std::vector<Attribute> outer_attrs, location_t locus)
4347 : 0 : : outer_attrs (std::move (outer_attrs)),
4348 : 0 : awaited_expr (std::move (awaited_expr)), locus (locus)
4349 : 0 : {}
4350 : :
4351 : : // copy constructor with clone
4352 : 0 : AwaitExpr (AwaitExpr const &other)
4353 : 0 : : ExprWithoutBlock (other), outer_attrs (other.outer_attrs),
4354 : 0 : locus (other.locus)
4355 : : {
4356 : : // guard to prevent null dereference (only required if error state)
4357 : 0 : if (other.awaited_expr != nullptr)
4358 : 0 : awaited_expr = other.awaited_expr->clone_expr ();
4359 : 0 : }
4360 : :
4361 : : // overloaded assignment operator with clone
4362 : : AwaitExpr &operator= (AwaitExpr const &other)
4363 : : {
4364 : : ExprWithoutBlock::operator= (other);
4365 : : outer_attrs = other.outer_attrs;
4366 : : locus = other.locus;
4367 : :
4368 : : // guard to prevent null dereference (only required if error state)
4369 : : if (other.awaited_expr != nullptr)
4370 : : awaited_expr = other.awaited_expr->clone_expr ();
4371 : : else
4372 : : awaited_expr = nullptr;
4373 : :
4374 : : return *this;
4375 : : }
4376 : :
4377 : : // move constructors
4378 : : AwaitExpr (AwaitExpr &&other) = default;
4379 : : AwaitExpr &operator= (AwaitExpr &&other) = default;
4380 : :
4381 : : std::string as_string () const override;
4382 : :
4383 : 0 : location_t get_locus () const override final { return locus; }
4384 : :
4385 : : void accept_vis (ASTVisitor &vis) override;
4386 : :
4387 : : // Invalid if awaited expr is null, so base stripping on that.
4388 : 0 : void mark_for_strip () override { awaited_expr = nullptr; }
4389 : 0 : bool is_marked_for_strip () const override { return awaited_expr == nullptr; }
4390 : :
4391 : : // TODO: is this better? Or is a "vis_block" better?
4392 : 0 : std::unique_ptr<Expr> &get_awaited_expr ()
4393 : : {
4394 : 0 : rust_assert (awaited_expr != nullptr);
4395 : 0 : return awaited_expr;
4396 : : }
4397 : :
4398 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4399 : 0 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4400 : :
4401 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4402 : : {
4403 : 0 : outer_attrs = std::move (new_attrs);
4404 : 0 : }
4405 : :
4406 : : protected:
4407 : : /* Use covariance to implement clone function as returning this object rather
4408 : : * than base */
4409 : 0 : AwaitExpr *clone_expr_without_block_impl () const override
4410 : : {
4411 : 0 : return new AwaitExpr (*this);
4412 : : }
4413 : : };
4414 : :
4415 : : // Async block expression AST node (block expr that evaluates to a future)
4416 : : class AsyncBlockExpr : public ExprWithBlock
4417 : : {
4418 : : // TODO: should this extend BlockExpr rather than be a composite of it?
4419 : : std::vector<Attribute> outer_attrs;
4420 : : bool has_move;
4421 : : std::unique_ptr<BlockExpr> block_expr;
4422 : : location_t locus;
4423 : :
4424 : : public:
4425 : : AsyncBlockExpr (std::unique_ptr<BlockExpr> block_expr, bool has_move,
4426 : : std::vector<Attribute> outer_attrs, location_t locus)
4427 : : : outer_attrs (std::move (outer_attrs)), has_move (has_move),
4428 : : block_expr (std::move (block_expr)), locus (locus)
4429 : : {}
4430 : :
4431 : : // copy constructor with clone
4432 : 0 : AsyncBlockExpr (AsyncBlockExpr const &other)
4433 : 0 : : ExprWithBlock (other), outer_attrs (other.outer_attrs),
4434 : 0 : has_move (other.has_move), locus (other.locus)
4435 : : {
4436 : : // guard to prevent null dereference (only required if error state)
4437 : 0 : if (other.block_expr != nullptr)
4438 : 0 : block_expr = other.block_expr->clone_block_expr ();
4439 : 0 : }
4440 : :
4441 : : // overloaded assignment operator to clone
4442 : : AsyncBlockExpr &operator= (AsyncBlockExpr const &other)
4443 : : {
4444 : : ExprWithBlock::operator= (other);
4445 : : outer_attrs = other.outer_attrs;
4446 : : has_move = other.has_move;
4447 : : locus = other.locus;
4448 : :
4449 : : // guard to prevent null dereference (only required if error state)
4450 : : if (other.block_expr != nullptr)
4451 : : block_expr = other.block_expr->clone_block_expr ();
4452 : : else
4453 : : block_expr = nullptr;
4454 : :
4455 : : return *this;
4456 : : }
4457 : :
4458 : : // move constructors
4459 : : AsyncBlockExpr (AsyncBlockExpr &&other) = default;
4460 : : AsyncBlockExpr &operator= (AsyncBlockExpr &&other) = default;
4461 : :
4462 : : std::string as_string () const override;
4463 : :
4464 : 0 : bool get_has_move () { return has_move; }
4465 : 0 : location_t get_locus () const override final { return locus; }
4466 : :
4467 : : void accept_vis (ASTVisitor &vis) override;
4468 : :
4469 : : // Invalid if block is null, so base stripping on that.
4470 : 0 : void mark_for_strip () override { block_expr = nullptr; }
4471 : 0 : bool is_marked_for_strip () const override { return block_expr == nullptr; }
4472 : :
4473 : : // TODO: is this better? Or is a "vis_block" better?
4474 : 0 : std::unique_ptr<BlockExpr> &get_block_expr ()
4475 : : {
4476 : 0 : rust_assert (block_expr != nullptr);
4477 : 0 : return block_expr;
4478 : : }
4479 : :
4480 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
4481 : 0 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
4482 : :
4483 : 0 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
4484 : : {
4485 : 0 : outer_attrs = std::move (new_attrs);
4486 : 0 : }
4487 : :
4488 : : protected:
4489 : : /* Use covariance to implement clone function as returning this object rather
4490 : : * than base */
4491 : 0 : AsyncBlockExpr *clone_expr_with_block_impl () const override
4492 : : {
4493 : 0 : return new AsyncBlockExpr (*this);
4494 : : }
4495 : : };
4496 : :
4497 : : // Inline-assembly specific options
4498 : : enum class InlineAsmOptions
4499 : : {
4500 : : PURE = 1 << 0,
4501 : : NOMEM = 1 << 1,
4502 : : READONLY = 1 << 2,
4503 : : PRESERVES_FLAGS = 1 << 3,
4504 : : NORETURN = 1 << 4,
4505 : : NOSTACK = 1 << 5,
4506 : : ATT_SYNTAX = 1 << 6,
4507 : : RAW = 1 << 7,
4508 : : MAY_UNWIND = 1 << 8,
4509 : : };
4510 : :
4511 : : struct AnonConst
4512 : : {
4513 : : NodeId id;
4514 : : std::unique_ptr<Expr> value;
4515 : : };
4516 : :
4517 : : struct InlineAsmRegOrRegClass
4518 : : {
4519 : : enum Type
4520 : : {
4521 : : Reg,
4522 : : RegClass,
4523 : : };
4524 : :
4525 : : struct Reg
4526 : : {
4527 : : std::string Symbol;
4528 : : };
4529 : :
4530 : : struct RegClass
4531 : : {
4532 : : std::string Symbol;
4533 : : };
4534 : :
4535 : : Identifier name;
4536 : : location_t locus;
4537 : : };
4538 : :
4539 : : struct InlineAsmOperand
4540 : : {
4541 : : enum RegisterType
4542 : : {
4543 : : In,
4544 : : Out,
4545 : : InOut,
4546 : : SplitInOut,
4547 : : Const,
4548 : : Sym,
4549 : : };
4550 : :
4551 : : struct In
4552 : : {
4553 : : InlineAsmRegOrRegClass reg;
4554 : : std::unique_ptr<Expr> expr;
4555 : : };
4556 : :
4557 : : struct Out
4558 : : {
4559 : : InlineAsmRegOrRegClass reg;
4560 : : bool late;
4561 : : std::unique_ptr<Expr> expr; // can be null
4562 : : };
4563 : :
4564 : : struct InOut
4565 : : {
4566 : : InlineAsmRegOrRegClass reg;
4567 : : bool late;
4568 : : std::unique_ptr<Expr> expr; // this can't be null
4569 : : };
4570 : :
4571 : : struct SplitInOut
4572 : : {
4573 : : InlineAsmRegOrRegClass reg;
4574 : : bool late;
4575 : : std::unique_ptr<Expr> in_expr;
4576 : : std::unique_ptr<Expr> out_expr; // could be null
4577 : : };
4578 : :
4579 : : struct Const
4580 : : {
4581 : : AnonConst anon_const;
4582 : : };
4583 : :
4584 : : struct Sym
4585 : : {
4586 : : std::unique_ptr<Expr> sym;
4587 : : };
4588 : : location_t locus;
4589 : : };
4590 : :
4591 : : struct InlineAsmPlaceHolder
4592 : : {
4593 : : size_t operand_idx;
4594 : : char modifier; // can be null
4595 : : location_t locus;
4596 : : };
4597 : :
4598 : : struct InlineAsmTemplatePiece
4599 : : {
4600 : : bool is_placeholder;
4601 : : union
4602 : : {
4603 : : std::string string;
4604 : : InlineAsmPlaceHolder placeholder;
4605 : : };
4606 : : };
4607 : :
4608 : : struct TupleClobber
4609 : : {
4610 : : // as gccrs still doesn't contain a symbol class I have put them as strings
4611 : : std::string symbol;
4612 : : location_t loc;
4613 : : };
4614 : :
4615 : : struct TupleTemplateStr
4616 : : {
4617 : : // as gccrs still doesn't contain a symbol class I have put them as strings
4618 : : std::string symbol;
4619 : : std::string optional_symbol;
4620 : : location_t loc;
4621 : : };
4622 : :
4623 : : // Inline Assembly Node
4624 : : class InlineAsm : public ExprWithoutBlock
4625 : : {
4626 : : public:
4627 : : std::vector<InlineAsmTemplatePiece> template_;
4628 : : std::vector<TupleTemplateStr> template_strs;
4629 : : std::vector<InlineAsmOperand> operands;
4630 : : TupleClobber clobber_abi;
4631 : : InlineAsmOptions options;
4632 : : std::vector<location_t> line_spans;
4633 : : };
4634 : :
4635 : : } // namespace AST
4636 : : } // namespace Rust
4637 : :
4638 : : #endif
|