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