Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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-make-unique.h"
28 : : #include "rust-macro-builtins.h"
29 : :
30 : : namespace Rust {
31 : : namespace AST {
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 : 676 : MacroFragSpec (Kind kind) : kind (kind) {}
54 : :
55 : 676 : static MacroFragSpec get_frag_spec_from_str (const std::string &str)
56 : : {
57 : 676 : if (str == "block")
58 : 2 : return MacroFragSpec (BLOCK);
59 : 674 : else if (str == "expr")
60 : 249 : return MacroFragSpec (EXPR);
61 : 425 : else if (str == "ident")
62 : 69 : return MacroFragSpec (IDENT);
63 : 356 : else if (str == "item")
64 : 3 : return MacroFragSpec (ITEM);
65 : 353 : else if (str == "lifetime")
66 : 0 : return MacroFragSpec (LIFETIME);
67 : 353 : else if (str == "literal")
68 : 88 : return MacroFragSpec (LITERAL);
69 : 265 : else if (str == "meta")
70 : 9 : return MacroFragSpec (META);
71 : 256 : else if (str == "pat" || str == "pat_param")
72 : 7 : return MacroFragSpec (PAT);
73 : 249 : else if (str == "path")
74 : 1 : return MacroFragSpec (PATH);
75 : 248 : else if (str == "stmt")
76 : 52 : return MacroFragSpec (STMT);
77 : 196 : else if (str == "tt")
78 : 34 : return MacroFragSpec (TT);
79 : 162 : else if (str == "ty")
80 : 159 : return MacroFragSpec (TY);
81 : 3 : else if (str == "vis")
82 : 3 : 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 : 6551 : Kind get_kind () const { return kind; }
92 : 676 : bool is_error () const { return kind == Kind::INVALID; }
93 : :
94 : : // Converts a frag spec enum item to a string form.
95 : 13 : std::string as_string () const
96 : : {
97 : 13 : switch (kind)
98 : : {
99 : 0 : case BLOCK:
100 : 0 : return "block";
101 : 10 : case EXPR:
102 : 10 : return "expr";
103 : 1 : case IDENT:
104 : 1 : 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 : 1 : case TY:
122 : 1 : return "ty";
123 : 1 : case VIS:
124 : 1 : 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 : 175 : bool has_follow_set_restrictions () const
133 : : {
134 : 175 : 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 : 6 : bool has_follow_set_fragment_restrictions () const
149 : : {
150 : 6 : switch (kind)
151 : : {
152 : : case PATH:
153 : : case PAT:
154 : : case TY:
155 : : case VIS:
156 : : return true;
157 : 2 : default:
158 : 2 : return false;
159 : : }
160 : : }
161 : :
162 : : private:
163 : : Kind kind;
164 : : };
165 : :
166 : : // A macro match that has an identifier and fragment spec
167 : : class MacroMatchFragment : public MacroMatch
168 : : {
169 : : Identifier ident;
170 : : MacroFragSpec frag_spec;
171 : : location_t locus;
172 : :
173 : : public:
174 : 676 : MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec,
175 : : location_t locus)
176 : 676 : : 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 : 12 : location_t get_match_locus () const override { return locus; };
195 : :
196 : : void accept_vis (ASTVisitor &vis) override;
197 : :
198 : 8481 : MacroMatchType get_macro_match_type () const override
199 : : {
200 : 8481 : return MacroMatchType::Fragment;
201 : : }
202 : :
203 : 8196 : Identifier get_ident () const { return ident; }
204 : 6874 : 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 : 666 : MacroMatchFragment *clone_macro_match_impl () const override
210 : : {
211 : 666 : 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 : 3277 : bool has_sep () const { return sep != nullptr; }
240 : :
241 : 351 : MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches,
242 : : MacroRepOp op, std::unique_ptr<MacroRepSep> sep,
243 : : location_t locus)
244 : 351 : : matches (std::move (matches)), op (op), sep (std::move (sep)),
245 : 351 : locus (locus)
246 : : {}
247 : :
248 : : // Copy constructor with clone
249 : 342 : MacroMatchRepetition (MacroMatchRepetition const &other)
250 : 342 : : op (other.op), locus (other.locus)
251 : : {
252 : : // guard to protect from null pointer dereference
253 : 342 : if (other.sep != nullptr)
254 : 105 : sep = other.sep->clone_token ();
255 : :
256 : 342 : matches.reserve (other.matches.size ());
257 : 740 : for (const auto &e : other.matches)
258 : 398 : matches.push_back (e->clone_macro_match ());
259 : 342 : }
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 : 1601 : location_t get_match_locus () const override { return locus; };
286 : :
287 : : void accept_vis (ASTVisitor &vis) override;
288 : :
289 : 1645 : MacroMatchType get_macro_match_type () const override
290 : : {
291 : 1645 : return MacroMatchType::Repetition;
292 : : }
293 : :
294 : 1606 : MacroRepOp get_op () const { return op; }
295 : 254 : const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; }
296 : 3420 : std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
297 : : const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
298 : : {
299 : 37 : return matches;
300 : : }
301 : :
302 : : protected:
303 : : /* Use covariance to implement clone function as returning this object rather
304 : : * than base */
305 : 342 : MacroMatchRepetition *clone_macro_match_impl () const override
306 : : {
307 : 342 : return new MacroMatchRepetition (*this);
308 : : }
309 : : };
310 : :
311 : : // can't inline due to polymorphism
312 : 1698 : 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 : 859 : MacroMatcher (DelimType delim_type,
323 : : std::vector<std::unique_ptr<MacroMatch>> matches,
324 : : location_t locus)
325 : 859 : : delim_type (delim_type), matches (std::move (matches)), locus (locus),
326 : 859 : is_invalid (false)
327 : : {}
328 : :
329 : : // copy constructor with vector clone
330 : 934 : MacroMatcher (MacroMatcher const &other)
331 : 934 : : delim_type (other.delim_type), locus (other.locus)
332 : : {
333 : 934 : matches.reserve (other.matches.size ());
334 : 1969 : for (const auto &e : other.matches)
335 : 1035 : matches.push_back (e->clone_macro_match ());
336 : 934 : }
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 : 858 : MacroMatcher (MacroMatcher &&other) = default;
353 : : MacroMatcher &operator= (MacroMatcher &&other) = default;
354 : :
355 : : // Creates an error state macro matcher.
356 : 27 : static MacroMatcher create_error (location_t locus)
357 : : {
358 : 27 : return MacroMatcher (true, locus);
359 : : }
360 : :
361 : : // Returns whether MacroMatcher is in an error state.
362 : 873 : bool is_error () const { return is_invalid; }
363 : 3 : 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 : 133 : MacroMatchType get_macro_match_type () const override
370 : : {
371 : 133 : return MacroMatchType::Matcher;
372 : : }
373 : :
374 : 101 : DelimType get_delim_type () const { return delim_type; }
375 : 4270 : 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 : 45 : MacroMatcher *clone_macro_match_impl () const override
385 : : {
386 : 45 : return new MacroMatcher (*this);
387 : : }
388 : :
389 : : // constructor only used to create error matcher
390 : 27 : MacroMatcher (bool is_invalid, location_t locus)
391 : 27 : : delim_type (PARENS), locus (locus), is_invalid (is_invalid)
392 : : {}
393 : : };
394 : :
395 : : // TODO: inline?
396 : 1637 : struct MacroTranscriber
397 : : {
398 : : private:
399 : : DelimTokenTree token_tree;
400 : : location_t locus;
401 : :
402 : : public:
403 : 826 : MacroTranscriber (DelimTokenTree token_tree, location_t locus)
404 : 813 : : 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 : 2809 : 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 : 825 : MacroRule (MacroMatcher matcher, MacroTranscriber transcriber,
425 : : location_t locus)
426 : 825 : : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
427 : 825 : locus (locus)
428 : 825 : {}
429 : :
430 : : // Returns whether macro rule is in error state.
431 : 813 : bool is_error () const { return matcher.is_error (); }
432 : :
433 : : // Creates an error state macro rule.
434 : 13 : static MacroRule create_error (location_t locus)
435 : : {
436 : 13 : return MacroRule (MacroMatcher::create_error (locus),
437 : 26 : MacroTranscriber (DelimTokenTree::create_empty (),
438 : : UNDEF_LOCATION),
439 : 13 : locus);
440 : : }
441 : :
442 : 1 : location_t get_locus () const { return locus; }
443 : :
444 : : std::string as_string () const;
445 : :
446 : 4132 : MacroMatcher &get_matcher () { return matcher; }
447 : 2809 : 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 &)
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 : 680 : 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 : 680 : : VisItem (std::move (vis), outer_attrs),
501 : 1360 : outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
502 : 680 : delim_type (delim_type), rules (std::move (rules)), locus (locus),
503 : 680 : associated_transcriber (dummy_builtin), is_builtin_rule (false),
504 : 680 : kind (kind)
505 : 680 : {}
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 : 644 : mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
522 : : std::vector<Attribute> outer_attrs, location_t locus)
523 : : {
524 : 644 : return Rust::make_unique<MacroRulesDefinition> (
525 : 1288 : MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
526 : : AST::MacroRulesDefinition::MacroKind::MBE,
527 : 1288 : AST::Visibility::create_error ()));
528 : : }
529 : :
530 : : static std::unique_ptr<MacroRulesDefinition>
531 : 36 : decl_macro (Identifier rule_name, std::vector<MacroRule> rules,
532 : : std::vector<Attribute> outer_attrs, location_t locus,
533 : : Visibility vis)
534 : : {
535 : 72 : return Rust::make_unique<MacroRulesDefinition> (MacroRulesDefinition (
536 : : rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus,
537 : 36 : 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 : 5280 : 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 : 12527 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
548 : 2450 : const std::vector<Attribute> &get_outer_attrs () const override
549 : : {
550 : 2450 : return outer_attrs;
551 : : }
552 : :
553 : 2683 : std::vector<MacroRule> &get_macro_rules () { return rules; }
554 : : const std::vector<MacroRule> &get_macro_rules () const { return rules; }
555 : :
556 : 3432 : location_t get_locus () const override final { return locus; }
557 : :
558 : 3031 : Identifier get_rule_name () const { return rule_name; }
559 : :
560 : 2049 : std::vector<MacroRule> &get_rules () { return rules; }
561 : : const std::vector<MacroRule> &get_rules () const { return rules; }
562 : :
563 : 2265 : bool is_builtin () const { return is_builtin_rule; }
564 : 217 : const MacroTranscriberFunc &get_builtin_transcriber () const
565 : : {
566 : 217 : rust_assert (is_builtin ());
567 : 217 : return associated_transcriber;
568 : : }
569 : 104 : void set_builtin_transcriber (MacroTranscriberFunc transcriber)
570 : : {
571 : 104 : associated_transcriber = transcriber;
572 : 104 : is_builtin_rule = true;
573 : : }
574 : :
575 : 2628 : AST::Kind get_ast_kind () const override
576 : : {
577 : 2628 : return AST::Kind::MACRO_RULES_DEFINITION;
578 : : }
579 : :
580 : 14 : MacroKind get_kind () const { return kind; }
581 : :
582 : : protected:
583 : : /* Use covariance to implement clone function as returning this object rather
584 : : * than base */
585 : 53 : MacroRulesDefinition *clone_item_impl () const override
586 : : {
587 : 53 : 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 : 2389 : Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
623 : : location_t locus, bool is_semi_coloned = false)
624 : : {
625 : 2389 : return std::unique_ptr<MacroInvocation> (
626 : : new MacroInvocation (InvocKind::Regular, tl::nullopt, invoc_data,
627 : 2389 : 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 : 7 : 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 : 7 : return std::unique_ptr<MacroInvocation> (
643 : : new MacroInvocation (InvocKind::Builtin, kind, invoc_data, outer_attrs,
644 : : locus, is_semi_coloned,
645 : 7 : std::move (pending_eager_invocations)));
646 : : }
647 : :
648 : 2748 : 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 : 2746 : bool is_marked_for_strip () const override
655 : : {
656 : 2746 : return invoc_data.is_marked_for_strip ();
657 : : }
658 : :
659 : 472 : const std::vector<Attribute> &get_outer_attrs () const override
660 : : {
661 : 472 : return outer_attrs;
662 : : }
663 : 6808 : 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 : 1703 : NodeId get_node_id () const override final
671 : : {
672 : 1703 : return ExprWithoutBlock::get_node_id ();
673 : : }
674 : :
675 : 230 : AST::Kind get_ast_kind () const override
676 : : {
677 : 230 : return AST::Kind::MACRO_INVOCATION;
678 : : }
679 : :
680 : 7379 : NodeId get_macro_node_id () const { return node_id; }
681 : :
682 : 4713 : MacroInvocData &get_invoc_data () { return invoc_data; }
683 : :
684 : 4533 : bool has_semicolon () const { return is_semi_coloned; }
685 : :
686 : 4541 : 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 : 217 : void map_to_builtin (BuiltinMacro macro)
693 : : {
694 : 217 : kind = InvocKind::Builtin;
695 : 217 : builtin_kind = macro;
696 : 217 : }
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 : 235 : get_pending_eager_invocations ()
704 : : {
705 : 235 : rust_assert (kind == InvocKind::Builtin);
706 : :
707 : 235 : return pending_eager_invocs;
708 : : }
709 : :
710 : : private:
711 : : /* Full constructor */
712 : 2396 : 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 : 4792 : : TraitItem (locus), outer_attrs (std::move (outer_attrs)), locus (locus),
718 : 2396 : node_id (Analysis::Mappings::get ()->get_next_node_id ()),
719 : 2396 : invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
720 : 2396 : kind (kind), builtin_kind (builtin_kind),
721 : 2396 : pending_eager_invocs (std::move (pending_eager_invocs))
722 : 2396 : {}
723 : :
724 : 9309 : MacroInvocation (const MacroInvocation &other)
725 : 27927 : : TraitItem (other.locus), outer_attrs (other.outer_attrs),
726 : 9309 : locus (other.locus), node_id (other.node_id),
727 : 9309 : invoc_data (other.invoc_data), is_semi_coloned (other.is_semi_coloned),
728 : 18618 : kind (other.kind), builtin_kind (other.builtin_kind)
729 : : {
730 : 9309 : if (other.kind == InvocKind::Builtin)
731 : 330 : for (auto &pending : other.pending_eager_invocs)
732 : 69 : pending_eager_invocs.emplace_back (
733 : 69 : pending->clone_macro_invocation_impl ());
734 : 9309 : }
735 : :
736 : : std::vector<Attribute> outer_attrs;
737 : : location_t locus;
738 : : NodeId node_id;
739 : :
740 : : /* The data given to the macro invocation */
741 : : MacroInvocData invoc_data;
742 : :
743 : : /* Important for when we actually expand the macro */
744 : : bool is_semi_coloned;
745 : :
746 : : /* Is this a builtin macro or a regular macro */
747 : : InvocKind kind;
748 : :
749 : : /* If it is a builtin macro, which one */
750 : : tl::optional<BuiltinMacro> builtin_kind = tl::nullopt;
751 : :
752 : : /**
753 : : * Pending invocations within a builtin macro invocation. This vector is empty
754 : : * and should not be accessed for a regular macro invocation. The macro
755 : : * invocations within should be name resolved and expanded before the builtin
756 : : * macro invocation get expanded again. It is then the role of the expander to
757 : : * insert these new tokens properly in the delimited token tree and try the
758 : : * builtin transcriber once again.
759 : : */
760 : : std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs;
761 : :
762 : : protected:
763 : : /* Use covariance to implement clone function as returning this object rather
764 : : * than base */
765 : 0 : MacroInvocation *clone_pattern_impl () const final override
766 : : {
767 : 0 : return clone_macro_invocation_impl ();
768 : : }
769 : :
770 : : /* Use covariance to implement clone function as returning this object rather
771 : : * than base */
772 : 0 : MacroInvocation *clone_expr_without_block_impl () const final override
773 : : {
774 : 0 : return clone_macro_invocation_impl ();
775 : : }
776 : :
777 : : /* Use covariance to implement clone function as returning this object rather
778 : : * than base */
779 : 0 : MacroInvocation *clone_type_no_bounds_impl () const final override
780 : : {
781 : 0 : return clone_macro_invocation_impl ();
782 : : }
783 : :
784 : 0 : MacroInvocation *clone_external_item_impl () const final override
785 : : {
786 : 0 : return clone_macro_invocation_impl ();
787 : : }
788 : :
789 : : public:
790 : 9309 : /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
791 : : {
792 : 9309 : return new MacroInvocation (*this);
793 : : }
794 : :
795 : 394 : void add_semicolon () override { is_semi_coloned = true; }
796 : :
797 : : protected:
798 : 595 : Item *clone_item_impl () const override
799 : : {
800 : 595 : return clone_macro_invocation_impl ();
801 : : }
802 : :
803 : 0 : bool is_item () const override { return !has_semicolon (); }
804 : :
805 : 0 : MacroInvocation *clone_associated_item_impl () const override
806 : : {
807 : 0 : return clone_macro_invocation_impl ();
808 : : };
809 : : };
810 : :
811 : : // more generic meta item path-only form
812 : 24 : class MetaItemPath : public MetaItem
813 : : {
814 : : SimplePath path;
815 : :
816 : : public:
817 : 24 : MetaItemPath (SimplePath path) : path (std::move (path)) {}
818 : :
819 : 0 : std::string as_string () const override { return path.as_string (); }
820 : :
821 : : void accept_vis (ASTVisitor &vis) override;
822 : :
823 : : // HACK: used to simplify parsing - returns non-empty only in this case
824 : 0 : SimplePath to_path_item () const override
825 : : {
826 : : // this should copy construct - TODO ensure it does
827 : 0 : return path;
828 : : }
829 : :
830 : 24 : SimplePath &get_path () { return path; }
831 : :
832 : 0 : location_t get_locus () const override { return path.get_locus (); }
833 : :
834 : : bool check_cfg_predicate (const Session &session) const override;
835 : :
836 : : Attribute to_attribute () const override;
837 : :
838 : 0 : MetaItem::ItemKind get_item_kind () const override
839 : : {
840 : 0 : return MetaItem::ItemKind::Path;
841 : : }
842 : :
843 : : protected:
844 : : // Use covariance to implement clone function as returning this type
845 : 0 : MetaItemPath *clone_meta_item_inner_impl () const override
846 : : {
847 : 0 : return new MetaItemPath (*this);
848 : : }
849 : : };
850 : :
851 : : // more generic meta item sequence form
852 : : class MetaItemSeq : public MetaItem
853 : : {
854 : : SimplePath path;
855 : : std::vector<std::unique_ptr<MetaItemInner>> seq;
856 : :
857 : : public:
858 : 54 : MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
859 : 54 : : path (std::move (path)), seq (std::move (seq))
860 : 54 : {}
861 : :
862 : : // copy constructor with vector clone
863 : 9 : MetaItemSeq (const MetaItemSeq &other) : path (other.path)
864 : : {
865 : 9 : seq.reserve (other.seq.size ());
866 : 20 : for (const auto &e : other.seq)
867 : 11 : seq.push_back (e->clone_meta_item_inner ());
868 : 9 : }
869 : :
870 : : // overloaded assignment operator with vector clone
871 : : MetaItemSeq &operator= (const MetaItemSeq &other)
872 : : {
873 : : MetaItem::operator= (other);
874 : : path = other.path;
875 : :
876 : : seq.reserve (other.seq.size ());
877 : : for (const auto &e : other.seq)
878 : : seq.push_back (e->clone_meta_item_inner ());
879 : :
880 : : return *this;
881 : : }
882 : :
883 : : // default move constructors
884 : : MetaItemSeq (MetaItemSeq &&other) = default;
885 : : MetaItemSeq &operator= (MetaItemSeq &&other) = default;
886 : :
887 : : std::string as_string () const override;
888 : :
889 : 0 : SimplePath &get_path () { return path; }
890 : :
891 : 0 : std::vector<std::unique_ptr<MetaItemInner>> &get_seq () { return seq; }
892 : :
893 : : void accept_vis (ASTVisitor &vis) override;
894 : :
895 : 0 : location_t get_locus () const override { return path.get_locus (); }
896 : :
897 : : bool check_cfg_predicate (const Session &session) const override;
898 : :
899 : : Attribute to_attribute () const override;
900 : :
901 : 0 : MetaItem::ItemKind get_item_kind () const override
902 : : {
903 : 0 : return MetaItem::ItemKind::Seq;
904 : : }
905 : :
906 : : protected:
907 : : // Use covariance to implement clone function as returning this type
908 : 9 : MetaItemSeq *clone_meta_item_inner_impl () const override
909 : : {
910 : 9 : return new MetaItemSeq (*this);
911 : : }
912 : : };
913 : :
914 : : // Preferred specialisation for single-identifier meta items.
915 : 158 : class MetaWord : public MetaItem
916 : : {
917 : : Identifier ident;
918 : : location_t ident_locus;
919 : :
920 : : public:
921 : 597 : MetaWord (Identifier ident, location_t ident_locus)
922 : 597 : : ident (std::move (ident)), ident_locus (ident_locus)
923 : : {}
924 : :
925 : 531 : std::string as_string () const override { return ident.as_string (); }
926 : :
927 : : void accept_vis (ASTVisitor &vis) override;
928 : :
929 : 24 : Identifier &get_ident () { return ident; }
930 : :
931 : 3 : location_t get_locus () const override { return ident_locus; }
932 : :
933 : : bool check_cfg_predicate (const Session &session) const override;
934 : :
935 : : Attribute to_attribute () const override;
936 : :
937 : 24 : MetaItem::ItemKind get_item_kind () const override
938 : : {
939 : 24 : return MetaItem::ItemKind::Word;
940 : : }
941 : :
942 : : protected:
943 : : // Use covariance to implement clone function as returning this type
944 : 79 : MetaWord *clone_meta_item_inner_impl () const override
945 : : {
946 : 79 : return new MetaWord (*this);
947 : : }
948 : : };
949 : :
950 : : // Preferred specialisation for "identifier '=' string literal" meta items.
951 : : class MetaNameValueStr : public MetaItem
952 : : {
953 : : Identifier ident;
954 : : location_t ident_locus;
955 : :
956 : : // NOTE: str stored without quotes
957 : : std::string str;
958 : : location_t str_locus;
959 : :
960 : : public:
961 : 163 : MetaNameValueStr (Identifier ident, location_t ident_locus, std::string str,
962 : : location_t str_locus)
963 : 326 : : ident (std::move (ident)), ident_locus (ident_locus),
964 : 163 : str (std::move (str)), str_locus (str_locus)
965 : 163 : {}
966 : :
967 : 407 : std::string as_string () const override
968 : : {
969 : 814 : return ident.as_string () + " = \"" + str + "\"";
970 : : }
971 : :
972 : : void accept_vis (ASTVisitor &vis) override;
973 : :
974 : : // HACK: used to simplify parsing - creates a copy of this
975 : 4 : std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
976 : : {
977 : 4 : return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
978 : : }
979 : :
980 : 0 : location_t get_locus () const override { return ident_locus; }
981 : :
982 : : bool check_cfg_predicate (const Session &session) const override;
983 : :
984 : : Attribute to_attribute () const override;
985 : :
986 : 25 : inline std::pair<Identifier, std::string> get_name_value_pair () const
987 : : {
988 : 25 : return std::pair<Identifier, std::string> (ident, str);
989 : : }
990 : :
991 : 21 : bool is_key_value_pair () const override { return true; }
992 : :
993 : 0 : MetaItem::ItemKind get_item_kind () const override
994 : : {
995 : 0 : return MetaItem::ItemKind::NameValueStr;
996 : : }
997 : :
998 : : protected:
999 : : // Use covariance to implement clone function as returning this type
1000 : 559 : MetaNameValueStr *clone_meta_item_inner_impl () const override
1001 : : {
1002 : 559 : return new MetaNameValueStr (*this);
1003 : : }
1004 : : };
1005 : :
1006 : : // doubles up as MetaListIdents - determine via iterating through each path?
1007 : : // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
1008 : : class MetaListPaths : public MetaItem
1009 : : {
1010 : : Identifier ident;
1011 : : location_t ident_locus;
1012 : : std::vector<SimplePath> paths;
1013 : :
1014 : : public:
1015 : 0 : MetaListPaths (Identifier ident, location_t ident_locus,
1016 : : std::vector<SimplePath> paths)
1017 : 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1018 : 0 : paths (std::move (paths))
1019 : 0 : {}
1020 : :
1021 : : std::string as_string () const override;
1022 : :
1023 : : void accept_vis (ASTVisitor &vis) override;
1024 : :
1025 : 0 : Identifier get_ident () const { return ident; }
1026 : :
1027 : 0 : std::vector<SimplePath> &get_paths () { return paths; };
1028 : :
1029 : 0 : location_t get_locus () const override { return ident_locus; }
1030 : :
1031 : : bool check_cfg_predicate (const Session &session) const override;
1032 : :
1033 : : Attribute to_attribute () const override;
1034 : :
1035 : 0 : MetaItem::ItemKind get_item_kind () const override
1036 : : {
1037 : 0 : return MetaItem::ItemKind::ListPaths;
1038 : : }
1039 : :
1040 : : private:
1041 : : bool check_path_exists_in_cfg (const Session &session,
1042 : : const SimplePath &path) const;
1043 : :
1044 : : protected:
1045 : : // Use covariance to implement clone function as returning this type
1046 : 0 : MetaListPaths *clone_meta_item_inner_impl () const override
1047 : : {
1048 : 0 : return new MetaListPaths (*this);
1049 : : }
1050 : : };
1051 : :
1052 : : // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
1053 : : class MetaListNameValueStr : public MetaItem
1054 : : {
1055 : : Identifier ident;
1056 : : location_t ident_locus;
1057 : : std::vector<MetaNameValueStr> strs;
1058 : :
1059 : : public:
1060 : 0 : MetaListNameValueStr (Identifier ident, location_t ident_locus,
1061 : : std::vector<MetaNameValueStr> strs)
1062 : 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1063 : 0 : strs (std::move (strs))
1064 : 0 : {}
1065 : :
1066 : : std::string as_string () const override;
1067 : :
1068 : : void accept_vis (ASTVisitor &vis) override;
1069 : :
1070 : 0 : Identifier get_ident () { return ident; }
1071 : :
1072 : 0 : std::vector<MetaNameValueStr> &get_values () { return strs; }
1073 : :
1074 : 0 : location_t get_locus () const override { return ident_locus; }
1075 : :
1076 : : bool check_cfg_predicate (const Session &session) const override;
1077 : :
1078 : : Attribute to_attribute () const override;
1079 : :
1080 : 0 : MetaItem::ItemKind get_item_kind () const override
1081 : : {
1082 : 0 : return MetaItem::ItemKind::ListNameValueStr;
1083 : : }
1084 : :
1085 : : protected:
1086 : : // Use covariance to implement clone function as returning this type
1087 : 0 : MetaListNameValueStr *clone_meta_item_inner_impl () const override
1088 : : {
1089 : 0 : return new MetaListNameValueStr (*this);
1090 : : }
1091 : : };
1092 : :
1093 : : // Object that parses macros from a token stream.
1094 : : /* TODO: would "AttributeParser" be a better name? MetaItems are only for
1095 : : * attributes, I believe */
1096 : : struct AttributeParser
1097 : : {
1098 : : private:
1099 : : // TODO: might as well rewrite to use lexer tokens
1100 : : std::vector<std::unique_ptr<Token>> token_stream;
1101 : : int stream_pos;
1102 : :
1103 : : public:
1104 : 746 : AttributeParser (std::vector<std::unique_ptr<Token>> token_stream,
1105 : : int stream_start_pos = 0)
1106 : 746 : : token_stream (std::move (token_stream)), stream_pos (stream_start_pos)
1107 : : {}
1108 : :
1109 : 746 : ~AttributeParser () = default;
1110 : :
1111 : : std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
1112 : :
1113 : : private:
1114 : : // Parses a MetaItemInner.
1115 : : std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
1116 : : // Returns whether token can end a meta item.
1117 : : bool is_end_meta_item_tok (TokenId id) const;
1118 : : // Parses a simple path.
1119 : : SimplePath parse_simple_path ();
1120 : : // Parses a segment of a simple path (but not scope resolution operator).
1121 : : SimplePathSegment parse_simple_path_segment ();
1122 : : // Parses a MetaItemLitExpr.
1123 : : std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
1124 : : // Parses a literal.
1125 : : Literal parse_literal ();
1126 : : // Parses a meta item that begins with a simple path.
1127 : : std::unique_ptr<MetaItem> parse_path_meta_item ();
1128 : :
1129 : : // TODO: should this be const?
1130 : 6783 : std::unique_ptr<Token> &peek_token (int i = 0)
1131 : : {
1132 : 4773 : return token_stream[stream_pos + i];
1133 : : }
1134 : :
1135 : 2484 : void skip_token (int i = 0) { stream_pos += 1 + i; }
1136 : : };
1137 : : } // namespace AST
1138 : : } // namespace Rust
1139 : :
1140 : : /* <https://stackoverflow.com/a/35304501> */
1141 : : namespace std {
1142 : : template <> struct hash<Rust::AST::MacroFragSpec::Kind>
1143 : : {
1144 : 1327 : size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
1145 : : {
1146 : 1327 : return size_t (t);
1147 : : }
1148 : : };
1149 : : } // namespace std
1150 : :
1151 : : #endif
|