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
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
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"
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"
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
)
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
);
78 return MacroFragSpec (TT
);
80 return MacroFragSpec (TY
);
81 else if (str
== "vis")
82 return MacroFragSpec (VIS
);
85 // error_at("invalid string '%s' used as fragment specifier",
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
126 return "INVALID_FRAG_SPEC";
128 return "ERROR_MARK_STRING - unknown frag spec";
132 bool has_follow_set_restrictions () const
148 bool has_follow_set_fragment_restrictions () const
166 // A macro match that has an identifier and fragment spec
167 class MacroMatchFragment
: public MacroMatch
170 MacroFragSpec frag_spec
;
174 MacroMatchFragment (Identifier ident
, MacroFragSpec frag_spec
,
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
),
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
; }
207 /* Use covariance to implement clone function as returning this object rather
209 MacroMatchFragment
*clone_macro_match_impl () const override
211 return new MacroMatchFragment (*this);
215 // A repetition macro match
216 class MacroMatchRepetition
: public MacroMatch
228 std::vector
<std::unique_ptr
<MacroMatch
>> matches
;
232 typedef Token MacroRepSep
;
233 // any token except delimiters and repetition operators
234 std::unique_ptr
<MacroRepSep
> sep
;
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
,
244 : matches (std::move (matches
)), op (op
), sep (std::move (sep
)),
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
)
267 // guard to protect from null pointer dereference
268 if (other
.sep
!= nullptr)
269 sep
= other
.sep
->clone_token ();
273 matches
.reserve (other
.matches
.size ());
274 for (const auto &e
: other
.matches
)
275 matches
.push_back (e
->clone_macro_match ());
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
303 /* Use covariance to implement clone function as returning this object rather
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
;
318 // TODO: think of way to mark invalid that doesn't take up more space
322 MacroMatcher (DelimType delim_type
,
323 std::vector
<std::unique_ptr
<MacroMatch
>> matches
,
325 : delim_type (delim_type
), matches (std::move (matches
)), locus (locus
),
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
;
344 matches
.reserve (other
.matches
.size ());
345 for (const auto &e
: other
.matches
)
346 matches
.push_back (e
->clone_macro_match ());
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
382 /* Use covariance to implement clone function as returning this object rather
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
)
396 struct MacroTranscriber
399 DelimTokenTree token_tree
;
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?
419 MacroMatcher matcher
;
420 MacroTranscriber transcriber
;
424 MacroRule (MacroMatcher matcher
, MacroTranscriber transcriber
,
426 : matcher (std::move (matcher
)), transcriber (std::move (transcriber
)),
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 (),
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
456 // Macro by Example (legacy macro rules)
458 // Declarative macros 2.0
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
;
469 std::vector
<MacroRule
> rules
; // inlined form
472 MacroTranscriberFunc associated_transcriber
;
474 // Since we can't compare std::functions, we need to use an extra boolean
475 bool is_builtin_rule
;
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
&)
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),
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
)
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
,
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
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
; }
583 /* Use covariance to implement clone function as returning this object rather
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
,
602 public ExprWithoutBlock
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
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
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
;
716 /* Full constructor */
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
;
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 */
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
;
769 /* Use covariance to implement clone function as returning this object rather
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
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
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 ();
796 /*virtual*/ MacroInvocation
*clone_macro_invocation_impl () const
798 return new MacroInvocation (*this);
801 void add_semicolon () override
{ is_semi_coloned
= true; }
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
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
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
;
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
861 std::vector
<std::unique_ptr
<MetaItemInner
>> seq
;
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
);
882 seq
.reserve (other
.seq
.size ());
883 for (const auto &e
: other
.seq
)
884 seq
.push_back (e
->clone_meta_item_inner ());
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
;
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
924 location_t ident_locus
;
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
;
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
960 location_t ident_locus
;
962 // NOTE: str stored without quotes
964 location_t str_locus
;
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
;
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
1017 location_t ident_locus
;
1018 std::vector
<SimplePath
> paths
;
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
;
1047 bool check_path_exists_in_cfg (const Session
&session
,
1048 const SimplePath
&path
) const;
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
1062 location_t ident_locus
;
1063 std::vector
<MetaNameValueStr
> strs
;
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
;
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
1105 // TODO: might as well rewrite to use lexer tokens
1106 std::vector
<std::unique_ptr
<Token
>> token_stream
;
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 ();
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
; }
1146 /* <https://stackoverflow.com/a/35304501> */
1148 template <> struct hash
<Rust::AST::MacroFragSpec::Kind
>
1150 size_t operator() (const Rust::AST::MacroFragSpec::Kind
&t
) const noexcept