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