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