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