[PR testsuite/116860] Testsuite adjustment for recently added tests
[official-gcc.git] / gcc / rust / ast / rust-macro.h
blobb0b02ca680d06f5fda53c631a42e68006bf3f500
1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
19 #ifndef RUST_AST_MACRO_H
20 #define RUST_AST_MACRO_H
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 #include "rust-macro-builtins.h"
30 namespace Rust {
31 namespace AST {
32 class MacroFragSpec
34 public:
35 enum Kind
37 BLOCK,
38 EXPR,
39 IDENT,
40 ITEM,
41 LIFETIME,
42 LITERAL,
43 META,
44 PAT,
45 PATH,
46 STMT,
47 TT,
48 TY,
49 VIS,
50 INVALID // not really a specifier, but used to mark invalid one passed in
53 MacroFragSpec (Kind kind) : kind (kind) {}
55 static MacroFragSpec get_frag_spec_from_str (const std::string &str)
57 if (str == "block")
58 return MacroFragSpec (BLOCK);
59 else if (str == "expr")
60 return MacroFragSpec (EXPR);
61 else if (str == "ident")
62 return MacroFragSpec (IDENT);
63 else if (str == "item")
64 return MacroFragSpec (ITEM);
65 else if (str == "lifetime")
66 return MacroFragSpec (LIFETIME);
67 else if (str == "literal")
68 return MacroFragSpec (LITERAL);
69 else if (str == "meta")
70 return MacroFragSpec (META);
71 else if (str == "pat" || str == "pat_param")
72 return MacroFragSpec (PAT);
73 else if (str == "path")
74 return MacroFragSpec (PATH);
75 else if (str == "stmt")
76 return MacroFragSpec (STMT);
77 else if (str == "tt")
78 return MacroFragSpec (TT);
79 else if (str == "ty")
80 return MacroFragSpec (TY);
81 else if (str == "vis")
82 return MacroFragSpec (VIS);
83 else
85 // error_at("invalid string '%s' used as fragment specifier",
86 // str->c_str()));
87 return MacroFragSpec (INVALID);
91 Kind get_kind () const { return kind; }
92 bool is_error () const { return kind == Kind::INVALID; }
94 // Converts a frag spec enum item to a string form.
95 std::string as_string () const
97 switch (kind)
99 case BLOCK:
100 return "block";
101 case EXPR:
102 return "expr";
103 case IDENT:
104 return "ident";
105 case ITEM:
106 return "item";
107 case LIFETIME:
108 return "lifetime";
109 case LITERAL:
110 return "literal";
111 case META:
112 return "meta";
113 case PAT:
114 return "pat";
115 case PATH:
116 return "path";
117 case STMT:
118 return "stmt";
119 case TT:
120 return "tt";
121 case TY:
122 return "ty";
123 case VIS:
124 return "vis";
125 case INVALID:
126 return "INVALID_FRAG_SPEC";
127 default:
128 return "ERROR_MARK_STRING - unknown frag spec";
132 bool has_follow_set_restrictions () const
134 switch (kind)
136 case EXPR:
137 case STMT:
138 case PAT:
139 case PATH:
140 case TY:
141 case VIS:
142 return true;
143 default:
144 return false;
148 bool has_follow_set_fragment_restrictions () const
150 switch (kind)
152 case PATH:
153 case PAT:
154 case TY:
155 case VIS:
156 return true;
157 default:
158 return false;
162 private:
163 Kind kind;
166 // A macro match that has an identifier and fragment spec
167 class MacroMatchFragment : public MacroMatch
169 Identifier ident;
170 MacroFragSpec frag_spec;
171 location_t locus;
173 public:
174 MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec,
175 location_t locus)
176 : ident (std::move (ident)), frag_spec (frag_spec), locus (locus)
179 // Returns whether macro match fragment is in an error state.
180 bool is_error () const
182 return frag_spec.get_kind () == MacroFragSpec::INVALID;
185 // Creates an error state macro match fragment.
186 static MacroMatchFragment create_error (location_t locus)
188 return MacroMatchFragment (std::string (""),
189 MacroFragSpec (MacroFragSpec::Kind::INVALID),
190 locus);
193 std::string as_string () const override;
194 location_t get_match_locus () const override { return locus; };
196 void accept_vis (ASTVisitor &vis) override;
198 MacroMatchType get_macro_match_type () const override
200 return MacroMatchType::Fragment;
203 Identifier get_ident () const { return ident; }
204 const MacroFragSpec &get_frag_spec () const { return frag_spec; }
206 protected:
207 /* Use covariance to implement clone function as returning this object rather
208 * than base */
209 MacroMatchFragment *clone_macro_match_impl () const override
211 return new MacroMatchFragment (*this);
215 // A repetition macro match
216 class MacroMatchRepetition : public MacroMatch
218 public:
219 enum MacroRepOp
221 NONE,
222 ANY,
223 ONE_OR_MORE,
224 ZERO_OR_ONE,
227 private:
228 std::vector<std::unique_ptr<MacroMatch>> matches;
229 MacroRepOp op;
231 // bool has_sep;
232 typedef Token MacroRepSep;
233 // any token except delimiters and repetition operators
234 std::unique_ptr<MacroRepSep> sep;
235 location_t locus;
237 public:
238 // Returns whether macro match repetition has separator token.
239 bool has_sep () const { return sep != nullptr; }
241 MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches,
242 MacroRepOp op, std::unique_ptr<MacroRepSep> sep,
243 location_t locus)
244 : matches (std::move (matches)), op (op), sep (std::move (sep)),
245 locus (locus)
248 // Copy constructor with clone
249 MacroMatchRepetition (MacroMatchRepetition const &other)
250 : op (other.op), locus (other.locus)
252 // guard to protect from null pointer dereference
253 if (other.sep != nullptr)
254 sep = other.sep->clone_token ();
256 matches.reserve (other.matches.size ());
257 for (const auto &e : other.matches)
258 matches.push_back (e->clone_macro_match ());
261 // Overloaded assignment operator to clone
262 MacroMatchRepetition &operator= (MacroMatchRepetition const &other)
264 op = other.op;
265 locus = other.locus;
267 // guard to protect from null pointer dereference
268 if (other.sep != nullptr)
269 sep = other.sep->clone_token ();
270 else
271 sep = nullptr;
273 matches.reserve (other.matches.size ());
274 for (const auto &e : other.matches)
275 matches.push_back (e->clone_macro_match ());
277 return *this;
280 // move constructors
281 MacroMatchRepetition (MacroMatchRepetition &&other) = default;
282 MacroMatchRepetition &operator= (MacroMatchRepetition &&other) = default;
284 std::string as_string () const override;
285 location_t get_match_locus () const override { return locus; };
287 void accept_vis (ASTVisitor &vis) override;
289 MacroMatchType get_macro_match_type () const override
291 return MacroMatchType::Repetition;
294 MacroRepOp get_op () const { return op; }
295 const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; }
296 std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
297 const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
299 return matches;
302 protected:
303 /* Use covariance to implement clone function as returning this object rather
304 * than base */
305 MacroMatchRepetition *clone_macro_match_impl () const override
307 return new MacroMatchRepetition (*this);
311 // can't inline due to polymorphism
312 class MacroMatcher : public MacroMatch
314 DelimType delim_type;
315 std::vector<std::unique_ptr<MacroMatch>> matches;
316 location_t locus;
318 // TODO: think of way to mark invalid that doesn't take up more space
319 bool is_invalid;
321 public:
322 MacroMatcher (DelimType delim_type,
323 std::vector<std::unique_ptr<MacroMatch>> matches,
324 location_t locus)
325 : delim_type (delim_type), matches (std::move (matches)), locus (locus),
326 is_invalid (false)
329 // copy constructor with vector clone
330 MacroMatcher (MacroMatcher const &other)
331 : delim_type (other.delim_type), locus (other.locus)
333 matches.reserve (other.matches.size ());
334 for (const auto &e : other.matches)
335 matches.push_back (e->clone_macro_match ());
338 // overloaded assignment operator with vector clone
339 MacroMatcher &operator= (MacroMatcher const &other)
341 delim_type = other.delim_type;
342 locus = other.locus;
344 matches.reserve (other.matches.size ());
345 for (const auto &e : other.matches)
346 matches.push_back (e->clone_macro_match ());
348 return *this;
351 // move constructors
352 MacroMatcher (MacroMatcher &&other) = default;
353 MacroMatcher &operator= (MacroMatcher &&other) = default;
355 // Creates an error state macro matcher.
356 static MacroMatcher create_error (location_t locus)
358 return MacroMatcher (true, locus);
361 // Returns whether MacroMatcher is in an error state.
362 bool is_error () const { return is_invalid; }
363 location_t get_match_locus () const override { return locus; }
365 std::string as_string () const override;
367 void accept_vis (ASTVisitor &vis) override;
369 MacroMatchType get_macro_match_type () const override
371 return MacroMatchType::Matcher;
374 DelimType get_delim_type () const { return delim_type; }
375 std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
376 const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
378 return matches;
381 protected:
382 /* Use covariance to implement clone function as returning this object rather
383 * than base */
384 MacroMatcher *clone_macro_match_impl () const override
386 return new MacroMatcher (*this);
389 // constructor only used to create error matcher
390 MacroMatcher (bool is_invalid, location_t locus)
391 : delim_type (PARENS), locus (locus), is_invalid (is_invalid)
395 // TODO: inline?
396 struct MacroTranscriber
398 private:
399 DelimTokenTree token_tree;
400 location_t locus;
402 public:
403 MacroTranscriber (DelimTokenTree token_tree, location_t locus)
404 : token_tree (std::move (token_tree)), locus (locus)
407 std::string as_string () const { return token_tree.as_string (); }
409 location_t get_locus () const { return locus; }
411 DelimTokenTree &get_token_tree () { return token_tree; }
412 const DelimTokenTree &get_token_tree () const { return token_tree; }
415 // A macro rule? Matcher and transcriber pair?
416 struct MacroRule
418 private:
419 MacroMatcher matcher;
420 MacroTranscriber transcriber;
421 location_t locus;
423 public:
424 MacroRule (MacroMatcher matcher, MacroTranscriber transcriber,
425 location_t locus)
426 : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
427 locus (locus)
430 // Returns whether macro rule is in error state.
431 bool is_error () const { return matcher.is_error (); }
433 // Creates an error state macro rule.
434 static MacroRule create_error (location_t locus)
436 return MacroRule (MacroMatcher::create_error (locus),
437 MacroTranscriber (DelimTokenTree::create_empty (),
438 UNDEF_LOCATION),
439 locus);
442 location_t get_locus () const { return locus; }
444 std::string as_string () const;
446 MacroMatcher &get_matcher () { return matcher; }
447 MacroTranscriber &get_transcriber () { return transcriber; }
450 // A macro rules definition item AST node
451 class MacroRulesDefinition : public VisItem
453 public:
454 enum MacroKind
456 // Macro by Example (legacy macro rules)
457 MBE,
458 // Declarative macros 2.0
459 DeclMacro,
462 private:
463 std::vector<Attribute> outer_attrs;
464 Identifier rule_name;
465 // MacroRulesDef rules_def;
466 // only curly without required semicolon at end
467 DelimType delim_type;
468 // MacroRules rules;
469 std::vector<MacroRule> rules; // inlined form
470 location_t locus;
472 MacroTranscriberFunc associated_transcriber;
474 // Since we can't compare std::functions, we need to use an extra boolean
475 bool is_builtin_rule;
476 MacroKind kind;
479 * Default function to use as an associated transcriber. This function should
480 * never be called, hence the rust_unreachable().
481 * If this function is used, then the macro is not builtin and the compiler
482 * should make use of the actual rules. If the macro is builtin, then another
483 * associated transcriber should be used
485 static Fragment dummy_builtin (location_t, MacroInvocData &)
487 rust_unreachable ();
488 return Fragment::create_error ();
491 /* NOTE: in rustc, macro definitions are considered (and parsed as) a type
492 * of macro, whereas here they are considered part of the language itself.
493 * I am not aware of the implications of this decision. The rustc spec does
494 * mention that using the same parser for macro definitions and invocations
495 * is "extremely self-referential and non-intuitive". */
496 MacroRulesDefinition (Identifier rule_name, DelimType delim_type,
497 std::vector<MacroRule> rules,
498 std::vector<Attribute> outer_attrs, location_t locus,
499 MacroKind kind, Visibility vis)
500 : VisItem (std::move (vis), outer_attrs),
501 outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
502 delim_type (delim_type), rules (std::move (rules)), locus (locus),
503 associated_transcriber (dummy_builtin), is_builtin_rule (false),
504 kind (kind)
507 MacroRulesDefinition (Identifier builtin_name, DelimType delim_type,
508 MacroTranscriberFunc associated_transcriber,
509 MacroKind kind, Visibility vis)
510 : VisItem (std::move (vis), std::vector<Attribute> ()),
511 outer_attrs (std::vector<Attribute> ()), rule_name (builtin_name),
512 delim_type (delim_type), rules (std::vector<MacroRule> ()),
513 locus (UNDEF_LOCATION), associated_transcriber (associated_transcriber),
514 is_builtin_rule (true), kind (kind)
517 public:
518 std::string as_string () const override;
520 static std::unique_ptr<MacroRulesDefinition>
521 mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
522 std::vector<Attribute> outer_attrs, location_t locus)
524 return Rust::make_unique<MacroRulesDefinition> (
525 MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
526 AST::MacroRulesDefinition::MacroKind::MBE,
527 AST::Visibility::create_error ()));
530 static std::unique_ptr<MacroRulesDefinition>
531 decl_macro (Identifier rule_name, std::vector<MacroRule> rules,
532 std::vector<Attribute> outer_attrs, location_t locus,
533 Visibility vis)
535 return Rust::make_unique<MacroRulesDefinition> (MacroRulesDefinition (
536 rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus,
537 AST::MacroRulesDefinition::MacroKind::DeclMacro, vis));
540 void accept_vis (ASTVisitor &vis) override;
542 // Invalid if rule name is empty, so base stripping on that.
543 void mark_for_strip () override { rule_name = {""}; }
544 bool is_marked_for_strip () const override { return rule_name.empty (); }
546 // TODO: this mutable getter seems really dodgy. Think up better way.
547 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
548 const std::vector<Attribute> &get_outer_attrs () const override
550 return outer_attrs;
553 std::vector<MacroRule> &get_macro_rules () { return rules; }
554 const std::vector<MacroRule> &get_macro_rules () const { return rules; }
556 location_t get_locus () const override final { return locus; }
558 Identifier get_rule_name () const { return rule_name; }
560 std::vector<MacroRule> &get_rules () { return rules; }
561 const std::vector<MacroRule> &get_rules () const { return rules; }
563 bool is_builtin () const { return is_builtin_rule; }
564 const MacroTranscriberFunc &get_builtin_transcriber () const
566 rust_assert (is_builtin ());
567 return associated_transcriber;
569 void set_builtin_transcriber (MacroTranscriberFunc transcriber)
571 associated_transcriber = transcriber;
572 is_builtin_rule = true;
575 AST::Kind get_ast_kind () const override
577 return AST::Kind::MACRO_RULES_DEFINITION;
580 MacroKind get_kind () const { return kind; }
582 protected:
583 /* Use covariance to implement clone function as returning this object rather
584 * than base */
585 MacroRulesDefinition *clone_item_impl () const override
587 return new MacroRulesDefinition (*this);
591 /* AST node of a macro invocation, which is replaced by the macro result at
592 * compile time. This is technically a sum-type/tagged-union, which represents
593 * both classic macro invocations and builtin macro invocations. Regular macro
594 * invocations are expanded lazily, but builtin macro invocations need to be
595 * expanded eagerly, hence the differentiation.
597 class MacroInvocation : public TypeNoBounds,
598 public Pattern,
599 public Item,
600 public TraitItem,
601 public ExternalItem,
602 public ExprWithoutBlock
604 public:
605 enum class InvocKind
607 Regular,
608 Builtin,
611 std::string as_string () const override;
613 Pattern::Kind get_pattern_kind () override
615 return Pattern::Kind::MacroInvocation;
619 * The default constructor you should use. Whenever we parse a macro call, we
620 * cannot possibly know whether or not this call refers to a builtin macro or
621 * a regular macro. With name resolution and scopes and nested macro calls,
622 * this is literally impossible. Hence, always start by creating a `Regular`
623 * MacroInvocation which will then (maybe!) become a `Builtin` macro
624 * invocation in the expander.
626 static std::unique_ptr<MacroInvocation>
627 Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
628 location_t locus, bool is_semi_coloned = false)
630 return std::unique_ptr<MacroInvocation> (
631 new MacroInvocation (InvocKind::Regular, tl::nullopt, invoc_data,
632 outer_attrs, locus, is_semi_coloned, {}));
636 * Create a builtin macro invocation. This can only be done after macro
637 * name-resolution and within the macro expander, so unless you're modifying
638 * these visitors, you probably do not want to use this function.
640 static std::unique_ptr<MacroInvocation> Builtin (
641 BuiltinMacro kind, MacroInvocData invoc_data,
642 std::vector<Attribute> outer_attrs, location_t locus,
643 std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocations
644 = {},
645 bool is_semi_coloned = false)
647 return std::unique_ptr<MacroInvocation> (
648 new MacroInvocation (InvocKind::Builtin, kind, invoc_data, outer_attrs,
649 locus, is_semi_coloned,
650 std::move (pending_eager_invocations)));
653 location_t get_locus () const override final { return locus; }
655 void accept_vis (ASTVisitor &vis) override;
657 // Invalid if path is empty, so base stripping on that.
658 void mark_for_strip () override { invoc_data.mark_for_strip (); }
659 bool is_marked_for_strip () const override
661 return invoc_data.is_marked_for_strip ();
664 const std::vector<Attribute> &get_outer_attrs () const override
666 return outer_attrs;
668 std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
670 void set_outer_attrs (std::vector<Attribute> new_attrs) override
672 outer_attrs = std::move (new_attrs);
675 NodeId get_node_id () const override final
677 return ExprWithoutBlock::get_node_id ();
680 AST::Kind get_ast_kind () const override
682 return AST::Kind::MACRO_INVOCATION;
685 NodeId get_macro_node_id () const { return node_id; }
687 MacroInvocData &get_invoc_data () { return invoc_data; }
689 bool has_semicolon () const { return is_semi_coloned; }
691 InvocKind get_kind () const { return kind; }
692 tl::optional<BuiltinMacro> get_builtin_kind () const { return builtin_kind; }
695 * Turn the current MacroInvocation into a builtin macro invocation
697 void map_to_builtin (BuiltinMacro macro)
699 kind = InvocKind::Builtin;
700 builtin_kind = macro;
704 * Get the list of pending macro invcations within the builtin macro
705 * invocation that should get expanded eagerly.
707 std::vector<std::unique_ptr<MacroInvocation>> &
708 get_pending_eager_invocations ()
710 rust_assert (kind == InvocKind::Builtin);
712 return pending_eager_invocs;
715 private:
716 /* Full constructor */
717 MacroInvocation (
718 InvocKind kind, tl::optional<BuiltinMacro> builtin_kind,
719 MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
720 location_t locus, bool is_semi_coloned,
721 std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocs)
722 : TraitItem (locus), outer_attrs (std::move (outer_attrs)), locus (locus),
723 node_id (Analysis::Mappings::get ()->get_next_node_id ()),
724 invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
725 kind (kind), builtin_kind (builtin_kind),
726 pending_eager_invocs (std::move (pending_eager_invocs))
729 MacroInvocation (const MacroInvocation &other)
730 : TraitItem (other.locus), ExternalItem (other.node_id),
731 outer_attrs (other.outer_attrs), locus (other.locus),
732 node_id (other.node_id), invoc_data (other.invoc_data),
733 is_semi_coloned (other.is_semi_coloned), kind (other.kind),
734 builtin_kind (other.builtin_kind)
736 if (other.kind == InvocKind::Builtin)
737 for (auto &pending : other.pending_eager_invocs)
738 pending_eager_invocs.emplace_back (
739 pending->clone_macro_invocation_impl ());
742 std::vector<Attribute> outer_attrs;
743 location_t locus;
744 NodeId node_id;
746 /* The data given to the macro invocation */
747 MacroInvocData invoc_data;
749 /* Important for when we actually expand the macro */
750 bool is_semi_coloned;
752 /* Is this a builtin macro or a regular macro */
753 InvocKind kind;
755 /* If it is a builtin macro, which one */
756 tl::optional<BuiltinMacro> builtin_kind = tl::nullopt;
759 * Pending invocations within a builtin macro invocation. This vector is empty
760 * and should not be accessed for a regular macro invocation. The macro
761 * invocations within should be name resolved and expanded before the builtin
762 * macro invocation get expanded again. It is then the role of the expander to
763 * insert these new tokens properly in the delimited token tree and try the
764 * builtin transcriber once again.
766 std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs;
768 protected:
769 /* Use covariance to implement clone function as returning this object rather
770 * than base */
771 MacroInvocation *clone_pattern_impl () const final override
773 return clone_macro_invocation_impl ();
776 /* Use covariance to implement clone function as returning this object rather
777 * than base */
778 MacroInvocation *clone_expr_without_block_impl () const final override
780 return clone_macro_invocation_impl ();
783 /* Use covariance to implement clone function as returning this object rather
784 * than base */
785 MacroInvocation *clone_type_no_bounds_impl () const final override
787 return clone_macro_invocation_impl ();
790 MacroInvocation *clone_external_item_impl () const final override
792 return clone_macro_invocation_impl ();
795 public:
796 /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
798 return new MacroInvocation (*this);
801 void add_semicolon () override { is_semi_coloned = true; }
803 protected:
804 Item *clone_item_impl () const override
806 return clone_macro_invocation_impl ();
809 bool is_item () const override { return !has_semicolon (); }
811 MacroInvocation *clone_associated_item_impl () const override
813 return clone_macro_invocation_impl ();
817 // more generic meta item path-only form
818 class MetaItemPath : public MetaItem
820 SimplePath path;
822 public:
823 MetaItemPath (SimplePath path) : path (std::move (path)) {}
825 std::string as_string () const override { return path.as_string (); }
827 void accept_vis (ASTVisitor &vis) override;
829 // HACK: used to simplify parsing - returns non-empty only in this case
830 SimplePath to_path_item () const override
832 // this should copy construct - TODO ensure it does
833 return path;
836 SimplePath &get_path () { return path; }
838 location_t get_locus () const override { return path.get_locus (); }
840 bool check_cfg_predicate (const Session &session) const override;
842 Attribute to_attribute () const override;
844 MetaItem::ItemKind get_item_kind () const override
846 return MetaItem::ItemKind::Path;
849 protected:
850 // Use covariance to implement clone function as returning this type
851 MetaItemPath *clone_meta_item_inner_impl () const override
853 return new MetaItemPath (*this);
857 // more generic meta item sequence form
858 class MetaItemSeq : public MetaItem
860 SimplePath path;
861 std::vector<std::unique_ptr<MetaItemInner>> seq;
863 public:
864 MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
865 : path (std::move (path)), seq (std::move (seq))
868 // copy constructor with vector clone
869 MetaItemSeq (const MetaItemSeq &other) : path (other.path)
871 seq.reserve (other.seq.size ());
872 for (const auto &e : other.seq)
873 seq.push_back (e->clone_meta_item_inner ());
876 // overloaded assignment operator with vector clone
877 MetaItemSeq &operator= (const MetaItemSeq &other)
879 MetaItem::operator= (other);
880 path = other.path;
882 seq.reserve (other.seq.size ());
883 for (const auto &e : other.seq)
884 seq.push_back (e->clone_meta_item_inner ());
886 return *this;
889 // default move constructors
890 MetaItemSeq (MetaItemSeq &&other) = default;
891 MetaItemSeq &operator= (MetaItemSeq &&other) = default;
893 std::string as_string () const override;
895 SimplePath &get_path () { return path; }
897 std::vector<std::unique_ptr<MetaItemInner>> &get_seq () { return seq; }
899 void accept_vis (ASTVisitor &vis) override;
901 location_t get_locus () const override { return path.get_locus (); }
903 bool check_cfg_predicate (const Session &session) const override;
905 Attribute to_attribute () const override;
907 MetaItem::ItemKind get_item_kind () const override
909 return MetaItem::ItemKind::Seq;
912 protected:
913 // Use covariance to implement clone function as returning this type
914 MetaItemSeq *clone_meta_item_inner_impl () const override
916 return new MetaItemSeq (*this);
920 // Preferred specialisation for single-identifier meta items.
921 class MetaWord : public MetaItem
923 Identifier ident;
924 location_t ident_locus;
926 public:
927 MetaWord (Identifier ident, location_t ident_locus)
928 : ident (std::move (ident)), ident_locus (ident_locus)
931 std::string as_string () const override { return ident.as_string (); }
933 void accept_vis (ASTVisitor &vis) override;
935 Identifier &get_ident () { return ident; }
937 location_t get_locus () const override { return ident_locus; }
939 bool check_cfg_predicate (const Session &session) const override;
941 Attribute to_attribute () const override;
943 MetaItem::ItemKind get_item_kind () const override
945 return MetaItem::ItemKind::Word;
948 protected:
949 // Use covariance to implement clone function as returning this type
950 MetaWord *clone_meta_item_inner_impl () const override
952 return new MetaWord (*this);
956 // Preferred specialisation for "identifier '=' string literal" meta items.
957 class MetaNameValueStr : public MetaItem
959 Identifier ident;
960 location_t ident_locus;
962 // NOTE: str stored without quotes
963 std::string str;
964 location_t str_locus;
966 public:
967 MetaNameValueStr (Identifier ident, location_t ident_locus, std::string str,
968 location_t str_locus)
969 : ident (std::move (ident)), ident_locus (ident_locus),
970 str (std::move (str)), str_locus (str_locus)
973 std::string as_string () const override
975 return ident.as_string () + " = \"" + str + "\"";
978 void accept_vis (ASTVisitor &vis) override;
980 // HACK: used to simplify parsing - creates a copy of this
981 std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
983 return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
986 location_t get_locus () const override { return ident_locus; }
988 bool check_cfg_predicate (const Session &session) const override;
990 Attribute to_attribute () const override;
992 inline std::pair<Identifier, std::string> get_name_value_pair () const
994 return std::pair<Identifier, std::string> (ident, str);
997 bool is_key_value_pair () const override { return true; }
999 MetaItem::ItemKind get_item_kind () const override
1001 return MetaItem::ItemKind::NameValueStr;
1004 protected:
1005 // Use covariance to implement clone function as returning this type
1006 MetaNameValueStr *clone_meta_item_inner_impl () const override
1008 return new MetaNameValueStr (*this);
1012 // doubles up as MetaListIdents - determine via iterating through each path?
1013 // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
1014 class MetaListPaths : public MetaItem
1016 Identifier ident;
1017 location_t ident_locus;
1018 std::vector<SimplePath> paths;
1020 public:
1021 MetaListPaths (Identifier ident, location_t ident_locus,
1022 std::vector<SimplePath> paths)
1023 : ident (std::move (ident)), ident_locus (ident_locus),
1024 paths (std::move (paths))
1027 std::string as_string () const override;
1029 void accept_vis (ASTVisitor &vis) override;
1031 Identifier get_ident () const { return ident; }
1033 std::vector<SimplePath> &get_paths () { return paths; };
1035 location_t get_locus () const override { return ident_locus; }
1037 bool check_cfg_predicate (const Session &session) const override;
1039 Attribute to_attribute () const override;
1041 MetaItem::ItemKind get_item_kind () const override
1043 return MetaItem::ItemKind::ListPaths;
1046 private:
1047 bool check_path_exists_in_cfg (const Session &session,
1048 const SimplePath &path) const;
1050 protected:
1051 // Use covariance to implement clone function as returning this type
1052 MetaListPaths *clone_meta_item_inner_impl () const override
1054 return new MetaListPaths (*this);
1058 // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
1059 class MetaListNameValueStr : public MetaItem
1061 Identifier ident;
1062 location_t ident_locus;
1063 std::vector<MetaNameValueStr> strs;
1065 public:
1066 MetaListNameValueStr (Identifier ident, location_t ident_locus,
1067 std::vector<MetaNameValueStr> strs)
1068 : ident (std::move (ident)), ident_locus (ident_locus),
1069 strs (std::move (strs))
1072 std::string as_string () const override;
1074 void accept_vis (ASTVisitor &vis) override;
1076 Identifier get_ident () { return ident; }
1078 std::vector<MetaNameValueStr> &get_values () { return strs; }
1080 location_t get_locus () const override { return ident_locus; }
1082 bool check_cfg_predicate (const Session &session) const override;
1084 Attribute to_attribute () const override;
1086 MetaItem::ItemKind get_item_kind () const override
1088 return MetaItem::ItemKind::ListNameValueStr;
1091 protected:
1092 // Use covariance to implement clone function as returning this type
1093 MetaListNameValueStr *clone_meta_item_inner_impl () const override
1095 return new MetaListNameValueStr (*this);
1099 // Object that parses macros from a token stream.
1100 /* TODO: would "AttributeParser" be a better name? MetaItems are only for
1101 * attributes, I believe */
1102 struct AttributeParser
1104 private:
1105 // TODO: might as well rewrite to use lexer tokens
1106 std::vector<std::unique_ptr<Token>> token_stream;
1107 int stream_pos;
1109 public:
1110 AttributeParser (std::vector<std::unique_ptr<Token>> token_stream,
1111 int stream_start_pos = 0)
1112 : token_stream (std::move (token_stream)), stream_pos (stream_start_pos)
1115 ~AttributeParser () = default;
1117 std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
1119 private:
1120 // Parses a MetaItemInner.
1121 std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
1122 // Returns whether token can end a meta item.
1123 bool is_end_meta_item_tok (TokenId id) const;
1124 // Parses a simple path.
1125 SimplePath parse_simple_path ();
1126 // Parses a segment of a simple path (but not scope resolution operator).
1127 SimplePathSegment parse_simple_path_segment ();
1128 // Parses a MetaItemLitExpr.
1129 std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
1130 // Parses a literal.
1131 Literal parse_literal ();
1132 // Parses a meta item that begins with a simple path.
1133 std::unique_ptr<MetaItem> parse_path_meta_item ();
1135 // TODO: should this be const?
1136 std::unique_ptr<Token> &peek_token (int i = 0)
1138 return token_stream[stream_pos + i];
1141 void skip_token (int i = 0) { stream_pos += 1 + i; }
1143 } // namespace AST
1144 } // namespace Rust
1146 /* <https://stackoverflow.com/a/35304501> */
1147 namespace std {
1148 template <> struct hash<Rust::AST::MacroFragSpec::Kind>
1150 size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
1152 return size_t (t);
1155 } // namespace std
1157 #endif