1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
2
3 // This file is part of GCC.
4
5 // GCC is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3, or (at your option) any later
8 // version.
9
10 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 // for more details.
14
15 // You should have received a copy of the GNU General Public License
16 // along with GCC; see the file COPYING3. If not see
17 // <http://www.gnu.org/licenses/>.
18
19 #ifndef RUST_AST_MACRO_H
20 #define RUST_AST_MACRO_H
21
22 #include "rust-system.h"
23 #include "rust-ast.h"
24 #include "rust-ast-fragment.h"
25 #include "rust-location.h"
26 #include "rust-item.h"
27 #include "rust-make-unique.h"
28
29 namespace Rust {
30 namespace AST {
31 class MacroFragSpec
32 {
33 public:
34 enum Kind
35 {
36 BLOCK,
37 EXPR,
38 IDENT,
39 ITEM,
40 LIFETIME,
41 LITERAL,
42 META,
43 PAT,
44 PATH,
45 STMT,
46 TT,
47 TY,
48 VIS,
49 INVALID // not really a specifier, but used to mark invalid one passed in
50 };
51
52 MacroFragSpec (Kind kind) : kind (kind) {}
53
54 static MacroFragSpec get_frag_spec_from_str (const std::string &str)
55 {
56 if (str == "block")
57 return MacroFragSpec (BLOCK);
58 else if (str == "expr")
59 return MacroFragSpec (EXPR);
60 else if (str == "ident")
61 return MacroFragSpec (IDENT);
62 else if (str == "item")
63 return MacroFragSpec (ITEM);
64 else if (str == "lifetime")
65 return MacroFragSpec (LIFETIME);
66 else if (str == "literal")
67 return MacroFragSpec (LITERAL);
68 else if (str == "meta")
69 return MacroFragSpec (META);
70 else if (str == "pat" || str == "pat_param")
71 return MacroFragSpec (PAT);
72 else if (str == "path")
73 return MacroFragSpec (PATH);
74 else if (str == "stmt")
75 return MacroFragSpec (STMT);
76 else if (str == "tt")
77 return MacroFragSpec (TT);
78 else if (str == "ty")
79 return MacroFragSpec (TY);
80 else if (str == "vis")
81 return MacroFragSpec (VIS);
82 else
83 {
84 // error_at("invalid string '%s' used as fragment specifier",
85 // str->c_str()));
86 return MacroFragSpec (INVALID);
87 }
88 }
89
90 Kind get_kind () const { return kind; }
91 bool is_error () const { return kind == Kind::INVALID; }
92
93 // Converts a frag spec enum item to a string form.
94 std::string as_string () const
95 {
96 switch (kind)
97 {
98 case BLOCK:
99 return "block";
100 case EXPR:
101 return "expr";
102 case IDENT:
103 return "ident";
104 case ITEM:
105 return "item";
106 case LIFETIME:
107 return "lifetime";
108 case LITERAL:
109 return "literal";
110 case META:
111 return "meta";
112 case PAT:
113 return "pat";
114 case PATH:
115 return "path";
116 case STMT:
117 return "stmt";
118 case TT:
119 return "tt";
120 case TY:
121 return "ty";
122 case VIS:
123 return "vis";
124 case INVALID:
125 return "INVALID_FRAG_SPEC";
126 default:
127 return "ERROR_MARK_STRING - unknown frag spec";
128 }
129 }
130
131 bool has_follow_set_restrictions () const
132 {
133 switch (kind)
134 {
135 case EXPR:
136 case STMT:
137 case PAT:
138 case PATH:
139 case TY:
140 case VIS:
141 return true;
142 default:
143 return false;
144 }
145 }
146
147 bool has_follow_set_fragment_restrictions () const
148 {
149 switch (kind)
150 {
151 case PAT:
152 case TY:
153 case VIS:
154 return true;
155 default:
156 return false;
157 }
158 }
159
160 private:
161 Kind kind;
162 };
163
164 // A macro match that has an identifier and fragment spec
165 class MacroMatchFragment : public MacroMatch
166 {
167 Identifier ident;
168 MacroFragSpec frag_spec;
169 Location locus;
170
171 public:
172 MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec, Location locus)
173 : ident (std::move (ident)), frag_spec (frag_spec), locus (locus)
174 {}
175
176 // Returns whether macro match fragment is in an error state.
177 bool is_error () const
178 {
179 return frag_spec.get_kind () == MacroFragSpec::INVALID;
180 }
181
182 // Creates an error state macro match fragment.
183 static MacroMatchFragment create_error (Location locus)
184 {
185 return MacroMatchFragment (std::string (""),
186 MacroFragSpec (MacroFragSpec::Kind::INVALID),
187 locus);
188 }
189
190 std::string as_string () const override;
191 Location get_match_locus () const override { return locus; };
192
193 void accept_vis (ASTVisitor &vis) override;
194
195 MacroMatchType get_macro_match_type () const override
196 {
197 return MacroMatchType::Fragment;
198 }
199
200 Identifier get_ident () const { return ident; }
201 const MacroFragSpec &get_frag_spec () const { return frag_spec; }
202
203 protected:
204 /* Use covariance to implement clone function as returning this object rather
205 * than base */
206 MacroMatchFragment *clone_macro_match_impl () const override
207 {
208 return new MacroMatchFragment (*this);
209 }
210 };
211
212 // A repetition macro match
213 class MacroMatchRepetition : public MacroMatch
214 {
215 public:
216 enum MacroRepOp
217 {
218 NONE,
219 ANY,
220 ONE_OR_MORE,
221 ZERO_OR_ONE,
222 };
223
224 private:
225 std::vector<std::unique_ptr<MacroMatch>> matches;
226 MacroRepOp op;
227
228 // bool has_sep;
229 typedef Token MacroRepSep;
230 // any token except delimiters and repetition operators
231 std::unique_ptr<MacroRepSep> sep;
232 Location locus;
233
234 public:
235 // Returns whether macro match repetition has separator token.
236 bool has_sep () const { return sep != nullptr; }
237
238 MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches,
239 MacroRepOp op, std::unique_ptr<MacroRepSep> sep,
240 Location locus)
241 : matches (std::move (matches)), op (op), sep (std::move (sep)),
242 locus (locus)
243 {}
244
245 // Copy constructor with clone
246 MacroMatchRepetition (MacroMatchRepetition const &other)
247 : op (other.op), locus (other.locus)
248 {
249 // guard to protect from null pointer dereference
250 if (other.sep != nullptr)
251 sep = other.sep->clone_token ();
252
253 matches.reserve (other.matches.size ());
254 for (const auto &e : other.matches)
255 matches.push_back (e->clone_macro_match ());
256 }
257
258 // Overloaded assignment operator to clone
259 MacroMatchRepetition &operator= (MacroMatchRepetition const &other)
260 {
261 op = other.op;
262 locus = other.locus;
263
264 // guard to protect from null pointer dereference
265 if (other.sep != nullptr)
266 sep = other.sep->clone_token ();
267 else
268 sep = nullptr;
269
270 matches.reserve (other.matches.size ());
271 for (const auto &e : other.matches)
272 matches.push_back (e->clone_macro_match ());
273
274 return *this;
275 }
276
277 // move constructors
278 MacroMatchRepetition (MacroMatchRepetition &&other) = default;
279 MacroMatchRepetition &operator= (MacroMatchRepetition &&other) = default;
280
281 std::string as_string () const override;
282 Location get_match_locus () const override { return locus; };
283
284 void accept_vis (ASTVisitor &vis) override;
285
286 MacroMatchType get_macro_match_type () const override
287 {
288 return MacroMatchType::Repetition;
289 }
290
291 MacroRepOp get_op () const { return op; }
292 const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; }
293 std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
294 const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
295 {
296 return matches;
297 }
298
299 protected:
300 /* Use covariance to implement clone function as returning this object rather
301 * than base */
302 MacroMatchRepetition *clone_macro_match_impl () const override
303 {
304 return new MacroMatchRepetition (*this);
305 }
306 };
307
308 // can't inline due to polymorphism
309 class MacroMatcher : public MacroMatch
310 {
311 DelimType delim_type;
312 std::vector<std::unique_ptr<MacroMatch>> matches;
313 Location locus;
314
315 // TODO: think of way to mark invalid that doesn't take up more space
316 bool is_invalid;
317
318 public:
319 MacroMatcher (DelimType delim_type,
320 std::vector<std::unique_ptr<MacroMatch>> matches,
321 Location locus)
322 : delim_type (delim_type), matches (std::move (matches)), locus (locus),
323 is_invalid (false)
324 {}
325
326 // copy constructor with vector clone
327 MacroMatcher (MacroMatcher const &other)
328 : delim_type (other.delim_type), locus (other.locus)
329 {
330 matches.reserve (other.matches.size ());
331 for (const auto &e : other.matches)
332 matches.push_back (e->clone_macro_match ());
333 }
334
335 // overloaded assignment operator with vector clone
336 MacroMatcher &operator= (MacroMatcher const &other)
337 {
338 delim_type = other.delim_type;
339 locus = other.locus;
340
341 matches.reserve (other.matches.size ());
342 for (const auto &e : other.matches)
343 matches.push_back (e->clone_macro_match ());
344
345 return *this;
346 }
347
348 // move constructors
349 MacroMatcher (MacroMatcher &&other) = default;
350 MacroMatcher &operator= (MacroMatcher &&other) = default;
351
352 // Creates an error state macro matcher.
353 static MacroMatcher create_error (Location locus)
354 {
355 return MacroMatcher (true, locus);
356 }
357
358 // Returns whether MacroMatcher is in an error state.
359 bool is_error () const { return is_invalid; }
360 Location get_match_locus () const override { return locus; }
361
362 std::string as_string () const override;
363
364 void accept_vis (ASTVisitor &vis) override;
365
366 MacroMatchType get_macro_match_type () const override
367 {
368 return MacroMatchType::Matcher;
369 }
370
371 DelimType get_delim_type () const { return delim_type; }
372 std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
373 const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
374 {
375 return matches;
376 }
377
378 protected:
379 /* Use covariance to implement clone function as returning this object rather
380 * than base */
381 MacroMatcher *clone_macro_match_impl () const override
382 {
383 return new MacroMatcher (*this);
384 }
385
386 // constructor only used to create error matcher
387 MacroMatcher (bool is_invalid, Location locus)
388 : delim_type (PARENS), locus (locus), is_invalid (is_invalid)
389 {}
390 };
391
392 // TODO: inline?
393 struct MacroTranscriber
394 {
395 private:
396 DelimTokenTree token_tree;
397 Location locus;
398
399 public:
400 MacroTranscriber (DelimTokenTree token_tree, Location locus)
401 : token_tree (std::move (token_tree)), locus (locus)
402 {}
403
404 std::string as_string () const { return token_tree.as_string (); }
405
406 Location get_locus () const { return locus; }
407
408 DelimTokenTree &get_token_tree () { return token_tree; }
409 const DelimTokenTree &get_token_tree () const { return token_tree; }
410 };
411
412 // A macro rule? Matcher and transcriber pair?
413 struct MacroRule
414 {
415 private:
416 MacroMatcher matcher;
417 MacroTranscriber transcriber;
418 Location locus;
419
420 public:
421 MacroRule (MacroMatcher matcher, MacroTranscriber transcriber, Location locus)
422 : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
423 locus (locus)
424 {}
425
426 // Returns whether macro rule is in error state.
427 bool is_error () const { return matcher.is_error (); }
428
429 // Creates an error state macro rule.
430 static MacroRule create_error (Location locus)
431 {
432 return MacroRule (MacroMatcher::create_error (locus),
433 MacroTranscriber (DelimTokenTree::create_empty (),
434 Location ()),
435 locus);
436 }
437
438 Location get_locus () const { return locus; }
439
440 std::string as_string () const;
441
442 MacroMatcher &get_matcher () { return matcher; }
443 MacroTranscriber &get_transcriber () { return transcriber; }
444 };
445
446 // A macro rules definition item AST node
447 class MacroRulesDefinition : public VisItem
448 {
449 public:
450 enum MacroKind
451 {
452 // Macro by Example (legacy macro rules)
453 MBE,
454 // Declarative macros 2.0
455 DeclMacro,
456 };
457
458 private:
459 std::vector<Attribute> outer_attrs;
460 Identifier rule_name;
461 // MacroRulesDef rules_def;
462 // only curly without required semicolon at end
463 DelimType delim_type;
464 // MacroRules rules;
465 std::vector<MacroRule> rules; // inlined form
466 Location locus;
467
468 std::function<Fragment (Location, MacroInvocData &)> associated_transcriber;
469 // Since we can't compare std::functions, we need to use an extra boolean
470 bool is_builtin_rule;
471 MacroKind kind;
472
473 /**
474 * Default function to use as an associated transcriber. This function should
475 * never be called, hence the gcc_unreachable().
476 * If this function is used, then the macro is not builtin and the compiler
477 * should make use of the actual rules. If the macro is builtin, then another
478 * associated transcriber should be used
479 */
480 static Fragment dummy_builtin (Location, MacroInvocData &)
481 {
482 gcc_unreachable ();
483 return Fragment::create_error ();
484 }
485
486 /* NOTE: in rustc, macro definitions are considered (and parsed as) a type
487 * of macro, whereas here they are considered part of the language itself.
488 * I am not aware of the implications of this decision. The rustc spec does
489 * mention that using the same parser for macro definitions and invocations
490 * is "extremely self-referential and non-intuitive". */
491 MacroRulesDefinition (Identifier rule_name, DelimType delim_type,
492 std::vector<MacroRule> rules,
493 std::vector<Attribute> outer_attrs, Location locus,
494 MacroKind kind, Visibility vis)
495 : VisItem (std::move (vis), outer_attrs),
496 outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
497 delim_type (delim_type), rules (std::move (rules)), locus (locus),
498 associated_transcriber (dummy_builtin), is_builtin_rule (false),
499 kind (kind)
500 {}
501
502 MacroRulesDefinition (
503 Identifier builtin_name, DelimType delim_type,
504 std::function<Fragment (Location, MacroInvocData &)> associated_transcriber,
505 MacroKind kind, Visibility vis)
506 : VisItem (std::move (vis), std::vector<Attribute> ()),
507 outer_attrs (std::vector<Attribute> ()), rule_name (builtin_name),
508 delim_type (delim_type), rules (std::vector<MacroRule> ()),
509 locus (Location ()), associated_transcriber (associated_transcriber),
510 is_builtin_rule (true), kind (kind)
511 {}
512
513 public:
514 std::string as_string () const override;
515
516 static std::unique_ptr<MacroRulesDefinition>
517 mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
518 std::vector<Attribute> outer_attrs, Location locus)
519 {
520 return Rust::make_unique<MacroRulesDefinition> (
521 MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
522 AST::MacroRulesDefinition::MacroKind::MBE,
523 AST::Visibility::create_error ()));
524 }
525
526 static std::unique_ptr<MacroRulesDefinition>
527 decl_macro (Identifier rule_name, std::vector<MacroRule> rules,
528 std::vector<Attribute> outer_attrs, Location locus,
529 Visibility vis)
530 {
531 return Rust::make_unique<MacroRulesDefinition> (MacroRulesDefinition (
532 rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus,
533 AST::MacroRulesDefinition::MacroKind::DeclMacro, vis));
534 }
535
536 void accept_vis (ASTVisitor &vis) override;
537
538 // Invalid if rule name is empty, so base stripping on that.
539 void mark_for_strip () override { rule_name = ""; }
540 bool is_marked_for_strip () const override { return rule_name.empty (); }
541
542 // TODO: this mutable getter seems really dodgy. Think up better way.
543 std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
544 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
545
546 std::vector<MacroRule> &get_macro_rules () { return rules; }
547 const std::vector<MacroRule> &get_macro_rules () const { return rules; }
548
549 Location get_locus () const override final { return locus; }
550
551 Identifier get_rule_name () const { return rule_name; }
552
553 std::vector<MacroRule> &get_rules () { return rules; }
554 const std::vector<MacroRule> &get_rules () const { return rules; }
555
556 bool is_builtin () const { return is_builtin_rule; }
557 const std::function<Fragment (Location, MacroInvocData &)> &
558 get_builtin_transcriber () const
559 {
560 rust_assert (is_builtin ());
561 return associated_transcriber;
562 }
563 void set_builtin_transcriber (
564 std::function<Fragment (Location, MacroInvocData &)> transcriber)
565 {
566 associated_transcriber = transcriber;
567 is_builtin_rule = true;
568 }
569
570 Kind get_ast_kind () const override { return Kind::MACRO_RULES_DEFINITION; }
571
572 protected:
573 /* Use covariance to implement clone function as returning this object rather
574 * than base */
575 MacroRulesDefinition *clone_item_impl () const override
576 {
577 return new MacroRulesDefinition (*this);
578 }
579 };
580
581 /**
582 * All builtin macros possible
583 */
584 enum class BuiltinMacro
585 {
586 Assert,
587 File,
588 Line,
589 Column,
590 IncludeBytes,
591 IncludeStr,
592 CompileError,
593 Concat,
594 Env,
595 Cfg,
596 Include
597 };
598
599 BuiltinMacro
600 builtin_macro_from_string (const std::string &identifier);
601
602 /* AST node of a macro invocation, which is replaced by the macro result at
603 * compile time. This is technically a sum-type/tagged-union, which represents
604 * both classic macro invocations and builtin macro invocations. Regular macro
605 * invocations are expanded lazily, but builtin macro invocations need to be
606 * expanded eagerly, hence the differentiation.
607 */
608 class MacroInvocation : public TypeNoBounds,
609 public Pattern,
610 public Item,
611 public TraitItem,
612 public TraitImplItem,
613 public InherentImplItem,
614 public ExternalItem,
615 public ExprWithoutBlock
616 {
617 public:
618 enum class InvocKind
619 {
620 Regular,
621 Builtin,
622 };
623
624 std::string as_string () const override;
625
626 /**
627 * The default constructor you should use. Whenever we parse a macro call, we
628 * cannot possibly know whether or not this call refers to a builtin macro or
629 * a regular macro. With name resolution and scopes and nested macro calls,
630 * this is literally impossible. Hence, always start by creating a `Regular`
631 * MacroInvocation which will then (maybe!) become a `Builtin` macro
632 * invocation in the expander.
633 */
634 static std::unique_ptr<MacroInvocation>
635 Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
636 Location locus, bool is_semi_coloned = false)
637 {
638 return std::unique_ptr<MacroInvocation> (
639 new MacroInvocation (InvocKind::Regular, Optional<BuiltinMacro>::none (),
640 invoc_data, outer_attrs, locus, is_semi_coloned,
641 {}));
642 }
643
644 /**
645 * Create a builtin macro invocation. This can only be done after macro
646 * name-resolution and within the macro expander, so unless you're modifying
647 * these visitors, you probably do not want to use this function.
648 */
649 static std::unique_ptr<MacroInvocation> Builtin (
650 BuiltinMacro kind, MacroInvocData invoc_data,
651 std::vector<Attribute> outer_attrs, Location locus,
652 std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocations
653 = {},
654 bool is_semi_coloned = false)
655 {
656 return std::unique_ptr<MacroInvocation> (
657 new MacroInvocation (InvocKind::Builtin,
658 Optional<BuiltinMacro>::some (kind), invoc_data,
659 outer_attrs, locus, is_semi_coloned,
660 std::move (pending_eager_invocations)));
661 }
662
663 Location get_locus () const override final { return locus; }
664
665 void accept_vis (ASTVisitor &vis) override;
666
667 // Invalid if path is empty, so base stripping on that.
668 void mark_for_strip () override { invoc_data.mark_for_strip (); }
669 bool is_marked_for_strip () const override
670 {
671 return invoc_data.is_marked_for_strip ();
672 }
673
674 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
675 std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
676
677 void set_outer_attrs (std::vector<Attribute> new_attrs) override
678 {
679 outer_attrs = std::move (new_attrs);
680 }
681
682 NodeId get_pattern_node_id () const override final
683 {
684 return ExprWithoutBlock::get_node_id ();
685 }
686
687 Kind get_ast_kind () const override { return Kind::MACRO_INVOCATION; }
688
689 NodeId get_macro_node_id () const { return node_id; }
690
691 MacroInvocData &get_invoc_data () { return invoc_data; }
692
693 bool has_semicolon () const { return is_semi_coloned; }
694
695 InvocKind get_kind () const { return kind; }
696 Optional<BuiltinMacro> get_builtin_kind () const { return builtin_kind; }
697
698 /**
699 * Turn the current MacroInvocation into a builtin macro invocation
700 */
701 void map_to_builtin (BuiltinMacro macro)
702 {
703 kind = InvocKind::Builtin;
704 builtin_kind = Optional<BuiltinMacro>::some (macro);
705 }
706
707 /**
708 * Get the list of pending macro invcations within the builtin macro
709 * invocation that should get expanded eagerly.
710 */
711 std::vector<std::unique_ptr<MacroInvocation>> &
712 get_pending_eager_invocations ()
713 {
714 rust_assert (kind == InvocKind::Builtin);
715
716 return pending_eager_invocs;
717 }
718
719 private:
720 /* Full constructor */
721 MacroInvocation (
722 InvocKind kind, Optional<BuiltinMacro> builtin_kind,
723 MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
724 Location locus, bool is_semi_coloned,
725 std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocs)
726 : TraitItem (locus), outer_attrs (std::move (outer_attrs)), locus (locus),
727 node_id (Analysis::Mappings::get ()->get_next_node_id ()),
728 invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
729 kind (kind), builtin_kind (builtin_kind),
730 pending_eager_invocs (std::move (pending_eager_invocs))
731 {}
732
733 MacroInvocation (const MacroInvocation &other)
734 : TraitItem (other.locus), outer_attrs (other.outer_attrs),
735 locus (other.locus), node_id (other.node_id),
736 invoc_data (other.invoc_data), is_semi_coloned (other.is_semi_coloned),
737 kind (other.kind), builtin_kind (other.builtin_kind)
738 {
739 if (other.kind == InvocKind::Builtin)
740 for (auto &pending : other.pending_eager_invocs)
741 pending_eager_invocs.emplace_back (
742 pending->clone_macro_invocation_impl ());
743 }
744
745 std::vector<Attribute> outer_attrs;
746 Location locus;
747 NodeId node_id;
748
749 /* The data given to the macro invocation */
750 MacroInvocData invoc_data;
751
752 /* Important for when we actually expand the macro */
753 bool is_semi_coloned;
754
755 /* Is this a builtin macro or a regular macro */
756 InvocKind kind;
757
758 /* If it is a builtin macro, which one */
759 Optional<BuiltinMacro> builtin_kind = Optional<BuiltinMacro>::none ();
760
761 /**
762 * Pending invocations within a builtin macro invocation. This vector is empty
763 * and should not be accessed for a regular macro invocation. The macro
764 * invocations within should be name resolved and expanded before the builtin
765 * macro invocation get expanded again. It is then the role of the expander to
766 * insert these new tokens properly in the delimited token tree and try the
767 * builtin transcriber once again.
768 */
769 std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs;
770
771 protected:
772 /* Use covariance to implement clone function as returning this object rather
773 * than base */
774 MacroInvocation *clone_pattern_impl () const final override
775 {
776 return clone_macro_invocation_impl ();
777 }
778
779 /* Use covariance to implement clone function as returning this object rather
780 * than base */
781 MacroInvocation *clone_expr_without_block_impl () const final override
782 {
783 return clone_macro_invocation_impl ();
784 }
785
786 /* Use covariance to implement clone function as returning this object rather
787 * than base */
788 MacroInvocation *clone_type_no_bounds_impl () const final override
789 {
790 return clone_macro_invocation_impl ();
791 }
792
793 MacroInvocation *clone_external_item_impl () const final override
794 {
795 return clone_macro_invocation_impl ();
796 }
797
798 /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
799 {
800 return new MacroInvocation (*this);
801 }
802
803 Item *clone_item_impl () const override
804 {
805 return clone_macro_invocation_impl ();
806 }
807
808 bool is_item () const override { return !has_semicolon (); }
809
810 TraitItem *clone_trait_item_impl () const override
811 {
812 return clone_macro_invocation_impl ();
813 };
814
815 TraitImplItem *clone_trait_impl_item_impl () const override
816 {
817 return clone_macro_invocation_impl ();
818 };
819
820 InherentImplItem *clone_inherent_impl_item_impl () const override
821 {
822 return clone_macro_invocation_impl ();
823 }
824
825 ExprWithoutBlock *to_stmt () const override
826
827 {
828 auto new_impl = clone_macro_invocation_impl ();
829 new_impl->is_semi_coloned = true;
830
831 return new_impl;
832 }
833 };
834
835 // more generic meta item path-only form
836 class MetaItemPath : public MetaItem
837 {
838 SimplePath path;
839
840 public:
841 MetaItemPath (SimplePath path) : path (std::move (path)) {}
842
843 std::string as_string () const override { return path.as_string (); }
844
845 void accept_vis (ASTVisitor &vis) override;
846
847 // HACK: used to simplify parsing - returns non-empty only in this case
848 SimplePath to_path_item () const override
849 {
850 // this should copy construct - TODO ensure it does
851 return path;
852 }
853
854 Location get_locus () const override { return path.get_locus (); }
855
856 bool check_cfg_predicate (const Session &session) const override;
857
858 Attribute to_attribute () const override;
859
860 protected:
861 // Use covariance to implement clone function as returning this type
862 MetaItemPath *clone_meta_item_inner_impl () const override
863 {
864 return new MetaItemPath (*this);
865 }
866 };
867
868 // more generic meta item sequence form
869 class MetaItemSeq : public MetaItem
870 {
871 SimplePath path;
872 std::vector<std::unique_ptr<MetaItemInner>> seq;
873
874 public:
875 MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
876 : path (std::move (path)), seq (std::move (seq))
877 {}
878
879 // copy constructor with vector clone
880 MetaItemSeq (const MetaItemSeq &other) : path (other.path)
881 {
882 seq.reserve (other.seq.size ());
883 for (const auto &e : other.seq)
884 seq.push_back (e->clone_meta_item_inner ());
885 }
886
887 // overloaded assignment operator with vector clone
888 MetaItemSeq &operator= (const MetaItemSeq &other)
889 {
890 MetaItem::operator= (other);
891 path = other.path;
892
893 seq.reserve (other.seq.size ());
894 for (const auto &e : other.seq)
895 seq.push_back (e->clone_meta_item_inner ());
896
897 return *this;
898 }
899
900 // default move constructors
901 MetaItemSeq (MetaItemSeq &&other) = default;
902 MetaItemSeq &operator= (MetaItemSeq &&other) = default;
903
904 std::string as_string () const override;
905
906 void accept_vis (ASTVisitor &vis) override;
907
908 Location get_locus () const override { return path.get_locus (); }
909
910 bool check_cfg_predicate (const Session &session) const override;
911
912 Attribute to_attribute () const override;
913
914 protected:
915 // Use covariance to implement clone function as returning this type
916 MetaItemSeq *clone_meta_item_inner_impl () const override
917 {
918 return new MetaItemSeq (*this);
919 }
920 };
921
922 // Preferred specialisation for single-identifier meta items.
923 class MetaWord : public MetaItem
924 {
925 Identifier ident;
926 Location ident_locus;
927
928 public:
929 MetaWord (Identifier ident, Location ident_locus)
930 : ident (std::move (ident)), ident_locus (ident_locus)
931 {}
932
933 std::string as_string () const override { return ident; }
934
935 void accept_vis (ASTVisitor &vis) override;
936
937 Location get_locus () const override { return ident_locus; }
938
939 bool check_cfg_predicate (const Session &session) const override;
940
941 Attribute to_attribute () const override;
942
943 protected:
944 // Use covariance to implement clone function as returning this type
945 MetaWord *clone_meta_item_inner_impl () const override
946 {
947 return new MetaWord (*this);
948 }
949 };
950
951 // Preferred specialisation for "identifier '=' string literal" meta items.
952 class MetaNameValueStr : public MetaItem
953 {
954 Identifier ident;
955 Location ident_locus;
956
957 // NOTE: str stored without quotes
958 std::string str;
959 Location str_locus;
960
961 public:
962 MetaNameValueStr (Identifier ident, Location ident_locus, std::string str,
963 Location str_locus)
964 : ident (std::move (ident)), ident_locus (ident_locus),
965 str (std::move (str)), str_locus (str_locus)
966 {}
967
968 std::string as_string () const override
969 {
970 return ident + " = \"" + str + "\"";
971 }
972
973 void accept_vis (ASTVisitor &vis) override;
974
975 // HACK: used to simplify parsing - creates a copy of this
976 std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
977 {
978 return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
979 }
980
981 Location get_locus () const override { return ident_locus; }
982
983 bool check_cfg_predicate (const Session &session) const override;
984
985 Attribute to_attribute () const override;
986
987 inline std::pair<Identifier, std::string> get_name_value_pair () const
988 {
989 return std::pair<Identifier, std::string> (ident, str);
990 }
991
992 bool is_key_value_pair () const override { return true; }
993
994 protected:
995 // Use covariance to implement clone function as returning this type
996 MetaNameValueStr *clone_meta_item_inner_impl () const override
997 {
998 return new MetaNameValueStr (*this);
999 }
1000 };
1001
1002 // doubles up as MetaListIdents - determine via iterating through each path?
1003 // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
1004 class MetaListPaths : public MetaItem
1005 {
1006 Identifier ident;
1007 Location ident_locus;
1008 std::vector<SimplePath> paths;
1009
1010 public:
1011 MetaListPaths (Identifier ident, Location ident_locus,
1012 std::vector<SimplePath> paths)
1013 : ident (std::move (ident)), ident_locus (ident_locus),
1014 paths (std::move (paths))
1015 {}
1016
1017 std::string as_string () const override;
1018
1019 void accept_vis (ASTVisitor &vis) override;
1020
1021 Location get_locus () const override { return ident_locus; }
1022
1023 bool check_cfg_predicate (const Session &session) const override;
1024
1025 Attribute to_attribute () const override;
1026
1027 private:
1028 bool check_path_exists_in_cfg (const Session &session,
1029 const SimplePath &path) const;
1030
1031 protected:
1032 // Use covariance to implement clone function as returning this type
1033 MetaListPaths *clone_meta_item_inner_impl () const override
1034 {
1035 return new MetaListPaths (*this);
1036 }
1037 };
1038
1039 // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
1040 class MetaListNameValueStr : public MetaItem
1041 {
1042 Identifier ident;
1043 Location ident_locus;
1044 std::vector<MetaNameValueStr> strs;
1045
1046 public:
1047 MetaListNameValueStr (Identifier ident, Location ident_locus,
1048 std::vector<MetaNameValueStr> strs)
1049 : ident (std::move (ident)), ident_locus (ident_locus),
1050 strs (std::move (strs))
1051 {}
1052
1053 std::string as_string () const override;
1054
1055 void accept_vis (ASTVisitor &vis) override;
1056
1057 Location get_locus () const override { return ident_locus; }
1058
1059 bool check_cfg_predicate (const Session &session) const override;
1060
1061 Attribute to_attribute () const override;
1062
1063 protected:
1064 // Use covariance to implement clone function as returning this type
1065 MetaListNameValueStr *clone_meta_item_inner_impl () const override
1066 {
1067 return new MetaListNameValueStr (*this);
1068 }
1069 };
1070
1071 // Object that parses macros from a token stream.
1072 /* TODO: would "AttributeParser" be a better name? MetaItems are only for
1073 * attributes, I believe */
1074 struct AttributeParser
1075 {
1076 private:
1077 // TODO: might as well rewrite to use lexer tokens
1078 std::vector<std::unique_ptr<Token>> token_stream;
1079 int stream_pos;
1080
1081 public:
1082 AttributeParser (std::vector<std::unique_ptr<Token>> token_stream,
1083 int stream_start_pos = 0)
1084 : token_stream (std::move (token_stream)), stream_pos (stream_start_pos)
1085 {}
1086
1087 ~AttributeParser () = default;
1088
1089 std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
1090
1091 private:
1092 // Parses a MetaItemInner.
1093 std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
1094 // Returns whether token can end a meta item.
1095 bool is_end_meta_item_tok (TokenId id) const;
1096 // Parses a simple path.
1097 SimplePath parse_simple_path ();
1098 // Parses a segment of a simple path (but not scope resolution operator).
1099 SimplePathSegment parse_simple_path_segment ();
1100 // Parses a MetaItemLitExpr.
1101 std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
1102 // Parses a literal.
1103 Literal parse_literal ();
1104 // Parses a meta item that begins with a simple path.
1105 std::unique_ptr<MetaItem> parse_path_meta_item ();
1106
1107 // TODO: should this be const?
1108 std::unique_ptr<Token> &peek_token (int i = 0)
1109 {
1110 return token_stream[stream_pos + i];
1111 }
1112
1113 void skip_token (int i = 0) { stream_pos += 1 + i; }
1114 };
1115 } // namespace AST
1116 } // namespace Rust
1117
1118 /* <https://stackoverflow.com/a/35304501> */
1119 namespace std {
1120 template <> struct hash<Rust::AST::MacroFragSpec::Kind>
1121 {
1122 size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
1123 {
1124 return size_t (t);
1125 }
1126 };
1127 } // namespace std
1128
1129 #endif