Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : 934 : MacroFragSpec (Kind kind) : kind (kind) {}
59 : :
60 : 934 : static MacroFragSpec get_frag_spec_from_str (const std::string &str)
61 : : {
62 : 934 : if (str == "block")
63 : 4 : return MacroFragSpec (BLOCK);
64 : 930 : else if (str == "expr")
65 : 300 : return MacroFragSpec (EXPR);
66 : 630 : else if (str == "ident")
67 : 103 : return MacroFragSpec (IDENT);
68 : 527 : else if (str == "item")
69 : 3 : return MacroFragSpec (ITEM);
70 : 524 : else if (str == "lifetime")
71 : 2 : return MacroFragSpec (LIFETIME);
72 : 522 : else if (str == "literal")
73 : 111 : return MacroFragSpec (LITERAL);
74 : 411 : else if (str == "meta")
75 : 14 : return MacroFragSpec (META);
76 : 397 : else if (str == "pat" || str == "pat_param")
77 : 7 : return MacroFragSpec (PAT);
78 : 390 : else if (str == "path")
79 : 1 : return MacroFragSpec (PATH);
80 : 389 : else if (str == "stmt")
81 : 52 : return MacroFragSpec (STMT);
82 : 337 : else if (str == "tt")
83 : 34 : return MacroFragSpec (TT);
84 : 303 : else if (str == "ty")
85 : 300 : 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 : 8302 : Kind get_kind () const { return kind; }
97 : 934 : 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 : 226 : bool has_follow_set_restrictions () const
138 : : {
139 : 226 : 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 : 2006 : class MacroMatchFragment : public MacroMatch
173 : : {
174 : : Identifier ident;
175 : : MacroFragSpec frag_spec;
176 : : location_t locus;
177 : :
178 : : public:
179 : 934 : MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec,
180 : : location_t locus)
181 : 934 : : 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 : 10308 : MacroMatchType get_macro_match_type () const override
204 : : {
205 : 10308 : return MacroMatchType::Fragment;
206 : : }
207 : :
208 : 9918 : 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 : 1003 : MacroMatchFragment *clone_macro_match_impl () const override
215 : : {
216 : 1003 : 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 : 4235 : bool has_sep () const { return sep != nullptr; }
245 : :
246 : 506 : MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches,
247 : : MacroRepOp op, std::unique_ptr<MacroRepSep> sep,
248 : : location_t locus)
249 : 506 : : matches (std::move (matches)), op (op), sep (std::move (sep)),
250 : 506 : locus (locus)
251 : : {}
252 : :
253 : : // Copy constructor with clone
254 : 511 : MacroMatchRepetition (MacroMatchRepetition const &other)
255 : 511 : : op (other.op), locus (other.locus)
256 : : {
257 : : // guard to protect from null pointer dereference
258 : 511 : if (other.sep != nullptr)
259 : 139 : sep = other.sep->clone_token ();
260 : :
261 : 511 : matches.reserve (other.matches.size ());
262 : 1175 : for (const auto &e : other.matches)
263 : 664 : matches.push_back (e->clone_macro_match ());
264 : 511 : }
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 : 1726 : location_t get_match_locus () const override { return locus; };
291 : :
292 : : void accept_vis (ASTVisitor &vis) override;
293 : :
294 : 1780 : MacroMatchType get_macro_match_type () const override
295 : : {
296 : 1780 : return MacroMatchType::Repetition;
297 : : }
298 : :
299 : 1731 : MacroRepOp get_op () const { return op; }
300 : 357 : const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; }
301 : 8603 : std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
302 : : const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
303 : : {
304 : 37 : return matches;
305 : : }
306 : :
307 : : protected:
308 : : /* Use covariance to implement clone function as returning this object rather
309 : : * than base */
310 : 511 : MacroMatchRepetition *clone_macro_match_impl () const override
311 : : {
312 : 511 : return new MacroMatchRepetition (*this);
313 : : }
314 : : };
315 : :
316 : : // can't inline due to polymorphism
317 : 2258 : 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 : 1149 : MacroMatcher (DelimType delim_type,
328 : : std::vector<std::unique_ptr<MacroMatch>> matches,
329 : : location_t locus)
330 : 1149 : : delim_type (delim_type), matches (std::move (matches)), locus (locus),
331 : 1149 : is_invalid (false)
332 : : {}
333 : :
334 : : // copy constructor with vector clone
335 : 1224 : MacroMatcher (MacroMatcher const &other)
336 : 1224 : : delim_type (other.delim_type), locus (other.locus)
337 : : {
338 : 1224 : matches.reserve (other.matches.size ());
339 : 2661 : for (const auto &e : other.matches)
340 : 1437 : matches.push_back (e->clone_macro_match ());
341 : 1224 : }
342 : :
343 : : // overloaded assignment operator with vector clone
344 : : MacroMatcher &operator= (MacroMatcher const &other)
345 : : {
346 : : delim_type = other.delim_type;
347 : : locus = other.locus;
348 : :
349 : : matches.reserve (other.matches.size ());
350 : : for (const auto &e : other.matches)
351 : : matches.push_back (e->clone_macro_match ());
352 : :
353 : : return *this;
354 : : }
355 : :
356 : : // move constructors
357 : 1148 : 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 : 1163 : 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 : 114 : DelimType get_delim_type () const { return delim_type; }
380 : 14936 : 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 : 65 : MacroMatcher *clone_macro_match_impl () const override
390 : : {
391 : 65 : 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 : 2184 : struct MacroTranscriber
402 : : {
403 : : private:
404 : : DelimTokenTree token_tree;
405 : : location_t locus;
406 : :
407 : : public:
408 : 1096 : MacroTranscriber (DelimTokenTree token_tree, location_t locus)
409 : 1083 : : 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 : 12928 : 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 : 1095 : MacroRule (MacroMatcher matcher, MacroTranscriber transcriber,
430 : : location_t locus)
431 : 1095 : : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
432 : 1095 : locus (locus)
433 : 1095 : {}
434 : :
435 : : // Returns whether macro rule is in error state.
436 : 1076 : 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 : 2 : location_t get_locus () const { return locus; }
448 : :
449 : : std::string as_string () const;
450 : :
451 : 14321 : MacroMatcher &get_matcher () { return matcher; }
452 : 12926 : 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 : 943 : 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 : 943 : : VisItem (std::move (vis), outer_attrs),
506 : 1886 : outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
507 : 943 : delim_type (delim_type), rules (std::move (rules)), locus (locus),
508 : 943 : associated_transcriber (dummy_builtin), is_builtin_rule (false),
509 : 943 : kind (kind)
510 : 943 : {}
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 : 900 : mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
527 : : std::vector<Attribute> outer_attrs, location_t locus)
528 : : {
529 : 900 : return std::make_unique<MacroRulesDefinition> (
530 : 900 : MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
531 : : AST::MacroRulesDefinition::MacroKind::MBE,
532 : 1800 : AST::Visibility::create_error ()));
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 : 6126 : 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 : 23665 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
553 : 3723 : const std::vector<Attribute> &get_outer_attrs () const override
554 : : {
555 : 3723 : return outer_attrs;
556 : : }
557 : :
558 : 8326 : std::vector<MacroRule> &get_macro_rules () { return rules; }
559 : : const std::vector<MacroRule> &get_macro_rules () const { return rules; }
560 : :
561 : 654 : location_t get_locus () const override final { return locus; }
562 : :
563 : 4177 : Identifier get_rule_name () const { return rule_name; }
564 : :
565 : 2400 : std::vector<MacroRule> &get_rules () { return rules; }
566 : : const std::vector<MacroRule> &get_rules () const { return rules; }
567 : :
568 : 2751 : bool is_builtin () const { return is_builtin_rule; }
569 : 353 : const MacroTranscriberFunc &get_builtin_transcriber () const
570 : : {
571 : 353 : rust_assert (is_builtin ());
572 : 353 : return associated_transcriber;
573 : : }
574 : 143 : void set_builtin_transcriber (MacroTranscriberFunc transcriber)
575 : : {
576 : 143 : associated_transcriber = transcriber;
577 : 143 : is_builtin_rule = true;
578 : : }
579 : :
580 : 4619 : 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 : 32 : MacroRulesDefinition *clone_item_impl () const override
591 : : {
592 : 32 : 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 : 2901 : Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
628 : : location_t locus, bool is_semi_coloned = false)
629 : : {
630 : 2901 : return std::unique_ptr<MacroInvocation> (
631 : : new MacroInvocation (InvocKind::Regular, tl::nullopt, invoc_data,
632 : 2901 : 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 : 50 : 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 : 50 : return std::unique_ptr<MacroInvocation> (
648 : 50 : new MacroInvocation (InvocKind::Builtin, kind, invoc_data, outer_attrs,
649 : : locus, is_semi_coloned,
650 : 50 : std::move (pending_eager_invocations)));
651 : : }
652 : :
653 : 3391 : 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 : 3722 : bool is_marked_for_strip () const override
660 : : {
661 : 3722 : return invoc_data.is_marked_for_strip ();
662 : : }
663 : :
664 : 806 : const std::vector<Attribute> &get_outer_attrs () const override
665 : : {
666 : 806 : return outer_attrs;
667 : : }
668 : 13575 : 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 : 0 : NodeId get_node_id () const override final
676 : : {
677 : 0 : return ExprWithoutBlock::get_node_id ();
678 : : }
679 : :
680 : 11041 : NodeId get_macro_node_id () const { return node_id; }
681 : :
682 : 6962 : MacroInvocData &get_invoc_data () { return invoc_data; }
683 : :
684 : 2743 : bool has_semicolon () const { return is_semi_coloned; }
685 : :
686 : 5579 : 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 : 0 : void map_to_builtin (BuiltinMacro macro)
693 : : {
694 : 0 : kind = InvocKind::Builtin;
695 : 0 : 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 : 171 : get_pending_eager_invocations ()
704 : : {
705 : 171 : rust_assert (kind == InvocKind::Builtin);
706 : :
707 : 171 : return pending_eager_invocs;
708 : : }
709 : :
710 : : private:
711 : : /* Full constructor */
712 : 2951 : 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 : 5902 : : TraitItem (locus), outer_attrs (std::move (outer_attrs)), locus (locus),
718 : 2951 : node_id (Analysis::Mappings::get ().get_next_node_id ()),
719 : 2951 : invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
720 : 2951 : kind (kind), builtin_kind (builtin_kind),
721 : 2951 : pending_eager_invocs (std::move (pending_eager_invocs))
722 : 2951 : {}
723 : :
724 : 10535 : MacroInvocation (const MacroInvocation &other)
725 : 31605 : : TraitItem (other.locus), ExternalItem (other.node_id),
726 : 21070 : outer_attrs (other.outer_attrs), locus (other.locus),
727 : 10535 : node_id (other.node_id), invoc_data (other.invoc_data),
728 : 10535 : is_semi_coloned (other.is_semi_coloned), kind (other.kind),
729 : 21070 : builtin_kind (other.builtin_kind)
730 : : {
731 : 10535 : if (other.kind == InvocKind::Builtin)
732 : 666 : for (auto &pending : other.pending_eager_invocs)
733 : 324 : pending_eager_invocs.emplace_back (
734 : 324 : pending->clone_macro_invocation_impl ());
735 : 10535 : }
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 : 0 : MacroInvocation *clone_type_no_bounds_impl () const final override
775 : : {
776 : 0 : 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 : 10535 : /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
786 : : {
787 : 10535 : 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 : 512 : 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 : 17 : Expr::Kind get_expr_kind () const override
812 : : {
813 : 17 : 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 : : protected:
822 : 482 : Item *clone_item_impl () const override
823 : : {
824 : 482 : return clone_macro_invocation_impl ();
825 : : }
826 : :
827 : 0 : bool is_item () const override { return !has_semicolon (); }
828 : :
829 : 0 : MacroInvocation *clone_associated_item_impl () const override
830 : : {
831 : 0 : return clone_macro_invocation_impl ();
832 : : };
833 : : };
834 : :
835 : : // more generic meta item path-only form
836 : 286 : class MetaItemPath : public MetaItem
837 : : {
838 : : SimplePath path;
839 : :
840 : : public:
841 : 286 : MetaItemPath (SimplePath path) : path (std::move (path)) {}
842 : :
843 : 0 : std::string as_string () const override { return path.as_string (); }
844 : :
845 : : void accept_vis (ASTVisitor &vis) override;
846 : :
847 : : // HACK: used to simplify parsing - returns non-empty only in this case
848 : 0 : SimplePath to_path_item () const override
849 : : {
850 : : // this should copy construct - TODO ensure it does
851 : 0 : return path;
852 : : }
853 : :
854 : 481 : SimplePath &get_path () { return path; }
855 : :
856 : 0 : location_t get_locus () const override { return path.get_locus (); }
857 : :
858 : : bool check_cfg_predicate (const Session &session) const override;
859 : :
860 : : Attribute to_attribute () const override;
861 : :
862 : 195 : MetaItem::ItemKind get_item_kind () const override
863 : : {
864 : 195 : return MetaItem::ItemKind::Path;
865 : : }
866 : :
867 : : protected:
868 : : // Use covariance to implement clone function as returning this type
869 : 195 : MetaItemPath *clone_meta_item_inner_impl () const override
870 : : {
871 : 195 : return new MetaItemPath (*this);
872 : : }
873 : : };
874 : :
875 : : // more generic meta item sequence form
876 : : class MetaItemSeq : public MetaItem
877 : : {
878 : : SimplePath path;
879 : : std::vector<std::unique_ptr<MetaItemInner>> seq;
880 : :
881 : : public:
882 : 108 : MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
883 : 108 : : path (std::move (path)), seq (std::move (seq))
884 : 108 : {}
885 : :
886 : : // copy constructor with vector clone
887 : 16 : MetaItemSeq (const MetaItemSeq &other) : path (other.path)
888 : : {
889 : 16 : seq.reserve (other.seq.size ());
890 : 39 : for (const auto &e : other.seq)
891 : 23 : seq.push_back (e->clone_meta_item_inner ());
892 : 16 : }
893 : :
894 : : // overloaded assignment operator with vector clone
895 : : MetaItemSeq &operator= (const MetaItemSeq &other)
896 : : {
897 : : MetaItem::operator= (other);
898 : : path = other.path;
899 : :
900 : : seq.reserve (other.seq.size ());
901 : : for (const auto &e : other.seq)
902 : : seq.push_back (e->clone_meta_item_inner ());
903 : :
904 : : return *this;
905 : : }
906 : :
907 : : // default move constructors
908 : : MetaItemSeq (MetaItemSeq &&other) = default;
909 : : MetaItemSeq &operator= (MetaItemSeq &&other) = default;
910 : :
911 : : std::string as_string () const override;
912 : :
913 : 2 : SimplePath &get_path () { return path; }
914 : :
915 : 2 : std::vector<std::unique_ptr<MetaItemInner>> &get_seq () { return seq; }
916 : :
917 : : void accept_vis (ASTVisitor &vis) override;
918 : :
919 : 0 : location_t get_locus () const override { return path.get_locus (); }
920 : :
921 : : bool check_cfg_predicate (const Session &session) const override;
922 : :
923 : : Attribute to_attribute () const override;
924 : :
925 : 0 : MetaItem::ItemKind get_item_kind () const override
926 : : {
927 : 0 : return MetaItem::ItemKind::Seq;
928 : : }
929 : :
930 : : protected:
931 : : // Use covariance to implement clone function as returning this type
932 : 16 : MetaItemSeq *clone_meta_item_inner_impl () const override
933 : : {
934 : 16 : return new MetaItemSeq (*this);
935 : : }
936 : : };
937 : :
938 : : // Preferred specialisation for single-identifier meta items.
939 : 234 : class MetaWord : public MetaItem
940 : : {
941 : : Identifier ident;
942 : : location_t ident_locus;
943 : :
944 : : public:
945 : 1211 : MetaWord (Identifier ident, location_t ident_locus)
946 : 1211 : : ident (std::move (ident)), ident_locus (ident_locus)
947 : : {}
948 : :
949 : 908 : std::string as_string () const override { return ident.as_string (); }
950 : :
951 : : void accept_vis (ASTVisitor &vis) override;
952 : :
953 : 286 : Identifier &get_ident () { return ident; }
954 : :
955 : 3 : location_t get_locus () const override { return ident_locus; }
956 : :
957 : : bool check_cfg_predicate (const Session &session) const override;
958 : :
959 : : Attribute to_attribute () const override;
960 : :
961 : 286 : MetaItem::ItemKind get_item_kind () const override
962 : : {
963 : 286 : return MetaItem::ItemKind::Word;
964 : : }
965 : :
966 : : protected:
967 : : // Use covariance to implement clone function as returning this type
968 : 117 : MetaWord *clone_meta_item_inner_impl () const override
969 : : {
970 : 117 : return new MetaWord (*this);
971 : : }
972 : : };
973 : :
974 : : // Preferred specialisation for "identifier '=' string literal" meta items.
975 : : class MetaNameValueStr : public MetaItem
976 : : {
977 : : Identifier ident;
978 : : location_t ident_locus;
979 : :
980 : : // NOTE: str stored without quotes
981 : : std::string str;
982 : : location_t str_locus;
983 : :
984 : : public:
985 : 1093 : MetaNameValueStr (Identifier ident, location_t ident_locus, std::string str,
986 : : location_t str_locus)
987 : 2186 : : ident (std::move (ident)), ident_locus (ident_locus),
988 : 1093 : str (std::move (str)), str_locus (str_locus)
989 : 1093 : {}
990 : :
991 : 1867 : std::string as_string () const override
992 : : {
993 : 3734 : return ident.as_string () + " = \"" + str + "\"";
994 : : }
995 : :
996 : : void accept_vis (ASTVisitor &vis) override;
997 : :
998 : : // HACK: used to simplify parsing - creates a copy of this
999 : 4 : std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
1000 : : {
1001 : 4 : return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
1002 : : }
1003 : :
1004 : 15 : location_t get_locus () const override { return ident_locus; }
1005 : :
1006 : : bool check_cfg_predicate (const Session &session) const override;
1007 : :
1008 : : Attribute to_attribute () const override;
1009 : :
1010 : 30 : inline std::pair<Identifier, std::string> get_name_value_pair () const
1011 : : {
1012 : 30 : return std::pair<Identifier, std::string> (ident, str);
1013 : : }
1014 : :
1015 : 21 : bool is_key_value_pair () const override { return true; }
1016 : :
1017 : 0 : MetaItem::ItemKind get_item_kind () const override
1018 : : {
1019 : 0 : return MetaItem::ItemKind::NameValueStr;
1020 : : }
1021 : :
1022 : : protected:
1023 : : // Use covariance to implement clone function as returning this type
1024 : 2124 : MetaNameValueStr *clone_meta_item_inner_impl () const override
1025 : : {
1026 : 2124 : return new MetaNameValueStr (*this);
1027 : : }
1028 : : };
1029 : :
1030 : : // doubles up as MetaListIdents - determine via iterating through each path?
1031 : : // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
1032 : : class MetaListPaths : public MetaItem
1033 : : {
1034 : : Identifier ident;
1035 : : location_t ident_locus;
1036 : : std::vector<SimplePath> paths;
1037 : :
1038 : : public:
1039 : 0 : MetaListPaths (Identifier ident, location_t ident_locus,
1040 : : std::vector<SimplePath> paths)
1041 : 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1042 : 0 : paths (std::move (paths))
1043 : 0 : {}
1044 : :
1045 : : std::string as_string () const override;
1046 : :
1047 : : void accept_vis (ASTVisitor &vis) override;
1048 : :
1049 : 0 : Identifier get_ident () const { return ident; }
1050 : :
1051 : 0 : std::vector<SimplePath> &get_paths () { return paths; };
1052 : :
1053 : 0 : location_t get_locus () const override { return ident_locus; }
1054 : :
1055 : : bool check_cfg_predicate (const Session &session) const override;
1056 : :
1057 : : Attribute to_attribute () const override;
1058 : :
1059 : 0 : MetaItem::ItemKind get_item_kind () const override
1060 : : {
1061 : 0 : return MetaItem::ItemKind::ListPaths;
1062 : : }
1063 : :
1064 : : private:
1065 : : bool check_path_exists_in_cfg (const Session &session,
1066 : : const SimplePath &path) const;
1067 : :
1068 : : protected:
1069 : : // Use covariance to implement clone function as returning this type
1070 : 0 : MetaListPaths *clone_meta_item_inner_impl () const override
1071 : : {
1072 : 0 : return new MetaListPaths (*this);
1073 : : }
1074 : : };
1075 : :
1076 : : // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
1077 : : class MetaListNameValueStr : public MetaItem
1078 : : {
1079 : : Identifier ident;
1080 : : location_t ident_locus;
1081 : : std::vector<MetaNameValueStr> strs;
1082 : :
1083 : : public:
1084 : 0 : MetaListNameValueStr (Identifier ident, location_t ident_locus,
1085 : : std::vector<MetaNameValueStr> strs)
1086 : 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1087 : 0 : strs (std::move (strs))
1088 : 0 : {}
1089 : :
1090 : : std::string as_string () const override;
1091 : :
1092 : : void accept_vis (ASTVisitor &vis) override;
1093 : :
1094 : 0 : Identifier get_ident () { return ident; }
1095 : :
1096 : 0 : std::vector<MetaNameValueStr> &get_values () { return strs; }
1097 : :
1098 : 0 : location_t get_locus () const override { return ident_locus; }
1099 : :
1100 : : bool check_cfg_predicate (const Session &session) const override;
1101 : :
1102 : : Attribute to_attribute () const override;
1103 : :
1104 : 0 : MetaItem::ItemKind get_item_kind () const override
1105 : : {
1106 : 0 : return MetaItem::ItemKind::ListNameValueStr;
1107 : : }
1108 : :
1109 : : protected:
1110 : : // Use covariance to implement clone function as returning this type
1111 : 0 : MetaListNameValueStr *clone_meta_item_inner_impl () const override
1112 : : {
1113 : 0 : return new MetaListNameValueStr (*this);
1114 : : }
1115 : : };
1116 : :
1117 : : // Object that parses macros from a token stream.
1118 : : /* TODO: would "AttributeParser" be a better name? MetaItems are only for
1119 : : * attributes, I believe */
1120 : : struct AttributeParser
1121 : : {
1122 : : private:
1123 : : // TODO: might as well rewrite to use lexer tokens
1124 : : std::unique_ptr<MacroInvocLexer> lexer;
1125 : : std::unique_ptr<Parser<MacroInvocLexer>> parser;
1126 : :
1127 : : public:
1128 : : AttributeParser (std::vector<std::unique_ptr<Token>> token_stream,
1129 : : int stream_start_pos = 0);
1130 : :
1131 : : ~AttributeParser ();
1132 : :
1133 : : std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
1134 : :
1135 : : private:
1136 : : // Parses a MetaItemInner.
1137 : : std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
1138 : : // Returns whether token can end a meta item.
1139 : : bool is_end_meta_item_tok (TokenId id) const;
1140 : : // Parses a MetaItemLitExpr.
1141 : : std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
1142 : : // Parses a meta item that begins with a simple path.
1143 : : std::unique_ptr<MetaItem> parse_path_meta_item ();
1144 : : };
1145 : : } // namespace AST
1146 : : } // namespace Rust
1147 : :
1148 : : /* <https://stackoverflow.com/a/35304501> */
1149 : : namespace std {
1150 : : template <> struct hash<Rust::AST::MacroFragSpec::Kind>
1151 : : {
1152 : 1631 : size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
1153 : : {
1154 : 1631 : return size_t (t);
1155 : : }
1156 : : };
1157 : : } // namespace std
1158 : :
1159 : : #endif
|