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