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