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 979 : MacroFragSpec (Kind kind) : kind (kind) {}
59 :
60 979 : static MacroFragSpec get_frag_spec_from_str (const std::string &str)
61 : {
62 979 : if (str == "block")
63 4 : return MacroFragSpec (BLOCK);
64 975 : else if (str == "expr")
65 328 : return MacroFragSpec (EXPR);
66 647 : else if (str == "ident")
67 109 : return MacroFragSpec (IDENT);
68 538 : else if (str == "item")
69 3 : return MacroFragSpec (ITEM);
70 535 : else if (str == "lifetime")
71 2 : return MacroFragSpec (LIFETIME);
72 533 : else if (str == "literal")
73 111 : return MacroFragSpec (LITERAL);
74 422 : else if (str == "meta")
75 14 : return MacroFragSpec (META);
76 408 : else if (str == "pat" || str == "pat_param")
77 10 : return MacroFragSpec (PAT);
78 398 : else if (str == "path")
79 1 : return MacroFragSpec (PATH);
80 397 : else if (str == "stmt")
81 52 : return MacroFragSpec (STMT);
82 345 : else if (str == "tt")
83 39 : 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 8397 : Kind get_kind () const { return kind; }
97 979 : 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 257 : bool has_follow_set_restrictions () const
138 : {
139 257 : 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 4006 : class MacroMatchFragment : public MacroMatch
173 : {
174 : Identifier ident;
175 : MacroFragSpec frag_spec;
176 : location_t locus;
177 :
178 : public:
179 979 : MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec,
180 : location_t locus)
181 979 : : 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 10433 : MacroMatchType get_macro_match_type () const override
204 : {
205 10433 : return MacroMatchType::Fragment;
206 : }
207 :
208 13726 : 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 2003 : MacroMatchFragment *clone_macro_match_impl () const override
215 : {
216 2003 : 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 4239 : bool has_sep () const { return sep != nullptr; }
245 :
246 523 : MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches,
247 : MacroRepOp op, std::unique_ptr<MacroRepSep> sep,
248 : location_t locus)
249 523 : : matches (std::move (matches)), op (op), sep (std::move (sep)),
250 523 : locus (locus)
251 : {}
252 :
253 : // Copy constructor with clone
254 1038 : MacroMatchRepetition (MacroMatchRepetition const &other)
255 1038 : : op (other.op), locus (other.locus)
256 : {
257 : // guard to protect from null pointer dereference
258 1038 : if (other.sep != nullptr)
259 275 : sep = other.sep->clone_token ();
260 :
261 1038 : matches.reserve (other.matches.size ());
262 2370 : for (const auto &e : other.matches)
263 1332 : matches.push_back (e->clone_macro_match ());
264 1038 : }
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 1754 : location_t get_match_locus () const override { return locus; };
291 :
292 : void accept_vis (ASTVisitor &vis) override;
293 :
294 1808 : MacroMatchType get_macro_match_type () const override
295 : {
296 1808 : return MacroMatchType::Repetition;
297 : }
298 :
299 1749 : MacroRepOp get_op () const { return op; }
300 357 : const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; }
301 9254 : std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
302 : const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
303 : {
304 47 : return matches;
305 : }
306 :
307 : protected:
308 : /* Use covariance to implement clone function as returning this object rather
309 : * than base */
310 1038 : MacroMatchRepetition *clone_macro_match_impl () const override
311 : {
312 1038 : return new MacroMatchRepetition (*this);
313 : }
314 : };
315 :
316 : // can't inline due to polymorphism
317 2333 : 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 1187 : MacroMatcher (DelimType delim_type,
328 : std::vector<std::unique_ptr<MacroMatch>> matches,
329 : location_t locus)
330 1187 : : delim_type (delim_type), matches (std::move (matches)), locus (locus),
331 1187 : is_invalid (false)
332 : {}
333 :
334 : // copy constructor with vector clone
335 2429 : MacroMatcher (MacroMatcher const &other)
336 2429 : : delim_type (other.delim_type), locus (other.locus)
337 : {
338 2429 : matches.reserve (other.matches.size ());
339 5339 : for (const auto &e : other.matches)
340 2910 : matches.push_back (e->clone_macro_match ());
341 2429 : }
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 1186 : 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 1201 : 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 146 : MacroMatchType get_macro_match_type () const override
375 : {
376 146 : return MacroMatchType::Matcher;
377 : }
378 :
379 117 : DelimType get_delim_type () const { return delim_type; }
380 16400 : 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 132 : MacroMatcher *clone_macro_match_impl () const override
390 : {
391 132 : 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 2258 : struct MacroTranscriber
402 : {
403 : private:
404 : DelimTokenTree token_tree;
405 : location_t locus;
406 :
407 : public:
408 1133 : MacroTranscriber (DelimTokenTree token_tree, location_t locus)
409 1120 : : 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 14314 : 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 1132 : MacroRule (MacroMatcher matcher, MacroTranscriber transcriber,
430 : location_t locus)
431 1132 : : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
432 1132 : locus (locus)
433 1132 : {}
434 :
435 : // Returns whether macro rule is in error state.
436 1113 : 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 15710 : MacroMatcher &get_matcher () { return matcher; }
452 14310 : 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 975 : 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 975 : : VisItem (std::move (vis), outer_attrs),
506 1950 : outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
507 975 : delim_type (delim_type), rules (std::move (rules)), locus (locus),
508 975 : associated_transcriber (dummy_builtin), is_builtin_rule (false),
509 975 : kind (kind)
510 975 : {}
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 932 : mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
527 : std::vector<Attribute> outer_attrs, location_t locus)
528 : {
529 932 : return std::make_unique<MacroRulesDefinition> (
530 932 : MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
531 : AST::MacroRulesDefinition::MacroKind::MBE,
532 1864 : 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 6244 : 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 26156 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
553 3784 : const std::vector<Attribute> &get_outer_attrs () const override
554 : {
555 3784 : return outer_attrs;
556 : }
557 :
558 9491 : std::vector<MacroRule> &get_macro_rules () { return rules; }
559 : const std::vector<MacroRule> &get_macro_rules () const { return rules; }
560 :
561 507 : location_t get_locus () const override final { return locus; }
562 :
563 4249 : Identifier get_rule_name () const { return rule_name; }
564 :
565 2453 : std::vector<MacroRule> &get_rules () { return rules; }
566 : const std::vector<MacroRule> &get_rules () const { return rules; }
567 :
568 2805 : 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 146 : void set_builtin_transcriber (MacroTranscriberFunc transcriber)
575 : {
576 146 : associated_transcriber = transcriber;
577 146 : is_builtin_rule = true;
578 : }
579 :
580 4702 : 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 1005 : MacroRulesDefinition *clone_item_impl () const override
591 : {
592 1005 : 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 2960 : Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
628 : location_t locus, bool is_semi_coloned = false)
629 : {
630 2960 : return std::unique_ptr<MacroInvocation> (
631 : new MacroInvocation (InvocKind::Regular, tl::nullopt, invoc_data,
632 2960 : 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 2952 : 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 3924 : bool is_marked_for_strip () const override
660 : {
661 3924 : return invoc_data.is_marked_for_strip ();
662 : }
663 :
664 818 : const std::vector<Attribute> &get_outer_attrs () const override
665 : {
666 818 : return outer_attrs;
667 : }
668 14095 : 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 16855 : NodeId get_node_id () const override final { return node_id; }
676 :
677 7085 : MacroInvocData &get_invoc_data () { return invoc_data; }
678 :
679 2798 : bool has_semicolon () const { return is_semi_coloned; }
680 :
681 5691 : InvocKind get_kind () const { return kind; }
682 : tl::optional<BuiltinMacro> get_builtin_kind () const { return builtin_kind; }
683 :
684 : /**
685 : * Turn the current MacroInvocation into a builtin macro invocation
686 : */
687 : void map_to_builtin (BuiltinMacro macro)
688 : {
689 : kind = InvocKind::Builtin;
690 : builtin_kind = macro;
691 : }
692 :
693 : /**
694 : * Get the list of pending macro invcations within the builtin macro
695 : * invocation that should get expanded eagerly.
696 : */
697 : std::vector<std::unique_ptr<MacroInvocation>> &
698 175 : get_pending_eager_invocations ()
699 : {
700 175 : rust_assert (kind == InvocKind::Builtin);
701 :
702 175 : return pending_eager_invocs;
703 : }
704 :
705 : private:
706 : /* Full constructor */
707 3011 : MacroInvocation (
708 : InvocKind kind, tl::optional<BuiltinMacro> builtin_kind,
709 : MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
710 : location_t locus, bool is_semi_coloned,
711 : std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocs)
712 3011 : : TraitItem (locus),
713 3011 : ExternalItem (Analysis::Mappings::get ().get_next_node_id ()),
714 3011 : outer_attrs (std::move (outer_attrs)), locus (locus),
715 3011 : node_id (ExternalItem::get_node_id ()),
716 3011 : invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
717 3011 : kind (kind), builtin_kind (builtin_kind),
718 3011 : pending_eager_invocs (std::move (pending_eager_invocs))
719 3011 : {}
720 :
721 11922 : MacroInvocation (const MacroInvocation &other)
722 35766 : : TraitItem (other.locus), ExternalItem (other.node_id),
723 23844 : outer_attrs (other.outer_attrs), locus (other.locus),
724 11922 : node_id (other.node_id), invoc_data (other.invoc_data),
725 11922 : is_semi_coloned (other.is_semi_coloned), kind (other.kind),
726 23844 : builtin_kind (other.builtin_kind)
727 : {
728 11922 : if (other.kind == InvocKind::Builtin)
729 683 : for (auto &pending : other.pending_eager_invocs)
730 332 : pending_eager_invocs.emplace_back (
731 332 : pending->clone_macro_invocation_impl ());
732 11922 : }
733 :
734 : std::vector<Attribute> outer_attrs;
735 : location_t locus;
736 : NodeId node_id;
737 :
738 : /* The data given to the macro invocation */
739 : MacroInvocData invoc_data;
740 :
741 : /* Important for when we actually expand the macro */
742 : bool is_semi_coloned;
743 :
744 : /* Is this a builtin macro or a regular macro */
745 : InvocKind kind;
746 :
747 : /* If it is a builtin macro, which one */
748 : tl::optional<BuiltinMacro> builtin_kind = tl::nullopt;
749 :
750 : /**
751 : * Pending invocations within a builtin macro invocation. This vector is empty
752 : * and should not be accessed for a regular macro invocation. The macro
753 : * invocations within should be name resolved and expanded before the builtin
754 : * macro invocation get expanded again. It is then the role of the expander to
755 : * insert these new tokens properly in the delimited token tree and try the
756 : * builtin transcriber once again.
757 : */
758 : std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs;
759 :
760 : protected:
761 0 : MacroInvocation *clone_pattern_impl () const final override
762 : {
763 0 : return clone_macro_invocation_impl ();
764 : }
765 :
766 0 : MacroInvocation *clone_expr_without_block_impl () const final override
767 : {
768 0 : return clone_macro_invocation_impl ();
769 : }
770 :
771 29 : MacroInvocation *clone_type_no_bounds_impl () const final override
772 : {
773 29 : return clone_macro_invocation_impl ();
774 : }
775 :
776 0 : MacroInvocation *clone_external_item_impl () const final override
777 : {
778 0 : return clone_macro_invocation_impl ();
779 : }
780 :
781 : public:
782 11922 : /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
783 : {
784 11922 : return new MacroInvocation (*this);
785 : }
786 :
787 : std::unique_ptr<MacroInvocation> reconstruct_macro_invocation () const
788 : {
789 : return nullptr;
790 : // return reconstruct (this,
791 : // &MacroInvocation::reconstruct_macro_invocation_impl);
792 : }
793 :
794 0 : MacroInvocation *reconstruct_impl () const override
795 : {
796 0 : return new MacroInvocation (kind, builtin_kind, invoc_data, outer_attrs,
797 0 : locus, is_semi_coloned,
798 0 : reconstruct_vec (pending_eager_invocs));
799 : }
800 :
801 516 : void add_semicolon () override { is_semi_coloned = true; }
802 :
803 0 : Pattern::Kind get_pattern_kind () override
804 : {
805 0 : return Pattern::Kind::MacroInvocation;
806 : }
807 :
808 18 : Expr::Kind get_expr_kind () const override
809 : {
810 18 : return Expr::Kind::MacroInvocation;
811 : }
812 :
813 0 : Item::Kind get_item_kind () const override
814 : {
815 0 : return Item::Kind::MacroInvocation;
816 : }
817 :
818 0 : Type::Kind get_type_kind () const override
819 : {
820 0 : return Type::Kind::MacroInvocation;
821 : }
822 :
823 : protected:
824 1178 : Item *clone_item_impl () const override
825 : {
826 1178 : return clone_macro_invocation_impl ();
827 : }
828 :
829 0 : bool is_item () const override { return !has_semicolon (); }
830 :
831 0 : MacroInvocation *clone_associated_item_impl () const override
832 : {
833 0 : return clone_macro_invocation_impl ();
834 : };
835 : };
836 :
837 : // more generic meta item path-only form
838 300 : class MetaItemPath : public MetaItem
839 : {
840 : SimplePath path;
841 :
842 : public:
843 300 : MetaItemPath (SimplePath path) : path (std::move (path)) {}
844 :
845 0 : std::string as_string () const override { return path.as_string (); }
846 :
847 : void accept_vis (ASTVisitor &vis) override;
848 :
849 : // HACK: used to simplify parsing - returns non-empty only in this case
850 0 : SimplePath to_path_item () const override
851 : {
852 : // this should copy construct - TODO ensure it does
853 0 : return path;
854 : }
855 :
856 606 : SimplePath &get_path () { return path; }
857 :
858 0 : location_t get_locus () const override { return path.get_locus (); }
859 :
860 : bool check_cfg_predicate (const Session &session) const override;
861 :
862 : Attribute to_attribute () const override;
863 :
864 298 : MetaItem::ItemKind get_item_kind () const override
865 : {
866 298 : return MetaItem::ItemKind::Path;
867 : }
868 :
869 : protected:
870 : // Use covariance to implement clone function as returning this type
871 298 : MetaItemPath *clone_meta_item_inner_impl () const override
872 : {
873 298 : return new MetaItemPath (*this);
874 : }
875 : };
876 :
877 : // more generic meta item sequence form
878 : class MetaItemSeq : public MetaItem
879 : {
880 : SimplePath path;
881 : std::vector<std::unique_ptr<MetaItemInner>> seq;
882 :
883 : public:
884 111 : MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
885 111 : : path (std::move (path)), seq (std::move (seq))
886 111 : {}
887 :
888 : // copy constructor with vector clone
889 21 : MetaItemSeq (const MetaItemSeq &other) : path (other.path)
890 : {
891 21 : seq.reserve (other.seq.size ());
892 49 : for (const auto &e : other.seq)
893 28 : seq.push_back (e->clone_meta_item_inner ());
894 21 : }
895 :
896 : // overloaded assignment operator with vector clone
897 : MetaItemSeq &operator= (const MetaItemSeq &other)
898 : {
899 : MetaItem::operator= (other);
900 : path = other.path;
901 :
902 : seq.reserve (other.seq.size ());
903 : for (const auto &e : other.seq)
904 : seq.push_back (e->clone_meta_item_inner ());
905 :
906 : return *this;
907 : }
908 :
909 : // default move constructors
910 : MetaItemSeq (MetaItemSeq &&other) = default;
911 : MetaItemSeq &operator= (MetaItemSeq &&other) = default;
912 :
913 : std::string as_string () const override;
914 :
915 175 : SimplePath &get_path () { return path; }
916 :
917 175 : std::vector<std::unique_ptr<MetaItemInner>> &get_seq () { return seq; }
918 :
919 : void accept_vis (ASTVisitor &vis) override;
920 :
921 0 : location_t get_locus () const override { return path.get_locus (); }
922 :
923 : bool check_cfg_predicate (const Session &session) const override;
924 :
925 : Attribute to_attribute () const override;
926 :
927 0 : MetaItem::ItemKind get_item_kind () const override
928 : {
929 0 : return MetaItem::ItemKind::Seq;
930 : }
931 :
932 : protected:
933 : // Use covariance to implement clone function as returning this type
934 21 : MetaItemSeq *clone_meta_item_inner_impl () const override
935 : {
936 21 : return new MetaItemSeq (*this);
937 : }
938 : };
939 :
940 : // Preferred specialisation for single-identifier meta items.
941 258 : class MetaWord : public MetaItem
942 : {
943 : Identifier ident;
944 : location_t ident_locus;
945 :
946 : public:
947 7397 : MetaWord (Identifier ident, location_t ident_locus)
948 7397 : : ident (std::move (ident)), ident_locus (ident_locus)
949 : {}
950 :
951 7073 : std::string as_string () const override { return ident.as_string (); }
952 :
953 : void accept_vis (ASTVisitor &vis) override;
954 :
955 : Identifier &get_ident () { return ident; }
956 :
957 304 : location_t get_locus () const override { return ident_locus; }
958 :
959 : bool check_cfg_predicate (const Session &session) const override;
960 :
961 : Attribute to_attribute () const override;
962 :
963 300 : MetaItem::ItemKind get_item_kind () const override
964 : {
965 300 : return MetaItem::ItemKind::Word;
966 : }
967 :
968 : protected:
969 : // Use covariance to implement clone function as returning this type
970 129 : MetaWord *clone_meta_item_inner_impl () const override
971 : {
972 129 : return new MetaWord (*this);
973 : }
974 : };
975 :
976 : // Preferred specialisation for "identifier '=' string literal" meta items.
977 : class MetaNameValueStr : public MetaItem
978 : {
979 : Identifier ident;
980 : location_t ident_locus;
981 :
982 : // NOTE: str stored without quotes
983 : std::string str;
984 : location_t str_locus;
985 :
986 : public:
987 3598 : MetaNameValueStr (Identifier ident, location_t ident_locus, std::string str,
988 : location_t str_locus)
989 7196 : : ident (std::move (ident)), ident_locus (ident_locus),
990 3598 : str (std::move (str)), str_locus (str_locus)
991 3598 : {}
992 :
993 1867 : std::string as_string () const override
994 : {
995 3734 : return ident.as_string () + " = \"" + str + "\"";
996 : }
997 :
998 : const Identifier &get_name () const { return ident; }
999 :
1000 909 : const std::string &get_value () const { return str; }
1001 :
1002 : void accept_vis (ASTVisitor &vis) override;
1003 :
1004 : // HACK: used to simplify parsing - creates a copy of this
1005 4 : std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
1006 : {
1007 4 : return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
1008 : }
1009 :
1010 15 : location_t get_locus () const override { return ident_locus; }
1011 :
1012 : bool check_cfg_predicate (const Session &session) const override;
1013 :
1014 : Attribute to_attribute () const override;
1015 :
1016 716 : inline std::pair<Identifier, std::string> get_name_value_pair () const
1017 : {
1018 716 : return std::pair<Identifier, std::string> (ident, str);
1019 : }
1020 :
1021 2525 : bool is_key_value_pair () const override { return true; }
1022 :
1023 0 : MetaItem::ItemKind get_item_kind () const override
1024 : {
1025 0 : return MetaItem::ItemKind::NameValueStr;
1026 : }
1027 :
1028 : protected:
1029 : // Use covariance to implement clone function as returning this type
1030 2096 : MetaNameValueStr *clone_meta_item_inner_impl () const override
1031 : {
1032 2096 : return new MetaNameValueStr (*this);
1033 : }
1034 : };
1035 :
1036 : // doubles up as MetaListIdents - determine via iterating through each path?
1037 : // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
1038 : class MetaListPaths : public MetaItem
1039 : {
1040 : Identifier ident;
1041 : location_t ident_locus;
1042 : std::vector<SimplePath> paths;
1043 :
1044 : public:
1045 0 : MetaListPaths (Identifier ident, location_t ident_locus,
1046 : std::vector<SimplePath> paths)
1047 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1048 0 : paths (std::move (paths))
1049 0 : {}
1050 :
1051 : std::string as_string () const override;
1052 :
1053 : void accept_vis (ASTVisitor &vis) override;
1054 :
1055 0 : Identifier get_ident () const { return ident; }
1056 :
1057 0 : std::vector<SimplePath> &get_paths () { return paths; };
1058 :
1059 0 : location_t get_locus () const override { return ident_locus; }
1060 :
1061 : bool check_cfg_predicate (const Session &session) const override;
1062 :
1063 : Attribute to_attribute () const override;
1064 :
1065 0 : MetaItem::ItemKind get_item_kind () const override
1066 : {
1067 0 : return MetaItem::ItemKind::ListPaths;
1068 : }
1069 :
1070 : private:
1071 : bool check_path_exists_in_cfg (const Session &session,
1072 : const SimplePath &path) const;
1073 :
1074 : protected:
1075 : // Use covariance to implement clone function as returning this type
1076 0 : MetaListPaths *clone_meta_item_inner_impl () const override
1077 : {
1078 0 : return new MetaListPaths (*this);
1079 : }
1080 : };
1081 :
1082 : // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
1083 : class MetaListNameValueStr : public MetaItem
1084 : {
1085 : Identifier ident;
1086 : location_t ident_locus;
1087 : std::vector<MetaNameValueStr> strs;
1088 :
1089 : public:
1090 0 : MetaListNameValueStr (Identifier ident, location_t ident_locus,
1091 : std::vector<MetaNameValueStr> strs)
1092 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1093 0 : strs (std::move (strs))
1094 0 : {}
1095 :
1096 : std::string as_string () const override;
1097 :
1098 : void accept_vis (ASTVisitor &vis) override;
1099 :
1100 0 : Identifier get_ident () { return ident; }
1101 :
1102 0 : std::vector<MetaNameValueStr> &get_values () { return strs; }
1103 :
1104 0 : location_t get_locus () const override { return ident_locus; }
1105 :
1106 : bool check_cfg_predicate (const Session &session) const override;
1107 :
1108 : Attribute to_attribute () const override;
1109 :
1110 0 : MetaItem::ItemKind get_item_kind () const override
1111 : {
1112 0 : return MetaItem::ItemKind::ListNameValueStr;
1113 : }
1114 :
1115 : protected:
1116 : // Use covariance to implement clone function as returning this type
1117 0 : MetaListNameValueStr *clone_meta_item_inner_impl () const override
1118 : {
1119 0 : return new MetaListNameValueStr (*this);
1120 : }
1121 : };
1122 :
1123 : // Object that parses macros from a token stream.
1124 : /* TODO: would "AttributeParser" be a better name? MetaItems are only for
1125 : * attributes, I believe */
1126 : struct AttributeParser
1127 : {
1128 : private:
1129 : // TODO: might as well rewrite to use lexer tokens
1130 : std::unique_ptr<MacroInvocLexer> lexer;
1131 : std::unique_ptr<Parser<MacroInvocLexer>> parser;
1132 :
1133 : public:
1134 : AttributeParser (std::vector<const_TokenPtr> token_stream,
1135 : int stream_start_pos = 0);
1136 :
1137 : ~AttributeParser ();
1138 :
1139 : std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
1140 :
1141 : private:
1142 : // Parses a MetaItemInner.
1143 : std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
1144 : // Returns whether token can end a meta item.
1145 : bool is_end_meta_item_tok (TokenId id) const;
1146 : // Parses a MetaItemLitExpr.
1147 : std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
1148 : // Parses a meta item that begins with a simple path.
1149 : std::unique_ptr<MetaItem> parse_path_meta_item ();
1150 : };
1151 : } // namespace AST
1152 : } // namespace Rust
1153 :
1154 : /* <https://stackoverflow.com/a/35304501> */
1155 : namespace std {
1156 : template <> struct hash<Rust::AST::MacroFragSpec::Kind>
1157 : {
1158 1802 : size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
1159 : {
1160 1802 : return size_t (t);
1161 : }
1162 : };
1163 : } // namespace std
1164 :
1165 : #endif
|