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