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