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 : 6688 : 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 : 15 : 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 : 1712 : 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 : 866 : MacroMatcher (DelimType delim_type,
323 : : std::vector<std::unique_ptr<MacroMatch>> matches,
324 : : location_t locus)
325 : 866 : : delim_type (delim_type), matches (std::move (matches)), locus (locus),
326 : 866 : is_invalid (false)
327 : : {}
328 : :
329 : : // copy constructor with vector clone
330 : 953 : MacroMatcher (MacroMatcher const &other)
331 : 953 : : delim_type (other.delim_type), locus (other.locus)
332 : : {
333 : 953 : matches.reserve (other.matches.size ());
334 : 1988 : for (const auto &e : other.matches)
335 : 1035 : matches.push_back (e->clone_macro_match ());
336 : 953 : }
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 : 865 : 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 : 880 : 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 : 108 : DelimType get_delim_type () const { return delim_type; }
375 : 4283 : 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 : 14 : : delim_type (PARENS), locus (locus), is_invalid (is_invalid)
392 : : {}
393 : : };
394 : :
395 : : // TODO: inline?
396 : 1657 : struct MacroTranscriber
397 : : {
398 : : private:
399 : : DelimTokenTree token_tree;
400 : : location_t locus;
401 : :
402 : : public:
403 : 833 : MacroTranscriber (DelimTokenTree token_tree, location_t locus)
404 : 820 : : 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 : 2822 : 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 : 832 : MacroRule (MacroMatcher matcher, MacroTranscriber transcriber,
425 : : location_t locus)
426 : 832 : : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
427 : 832 : locus (locus)
428 : 832 : {}
429 : :
430 : : // Returns whether macro rule is in error state.
431 : 814 : 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 : 13 : UNDEF_LOCATION),
439 : 13 : locus);
440 : : }
441 : :
442 : 2 : location_t get_locus () const { return locus; }
443 : :
444 : : std::string as_string () const;
445 : :
446 : 4145 : MacroMatcher &get_matcher () { return matcher; }
447 : 2820 : 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 : 687 : 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 : 687 : : VisItem (std::move (vis), outer_attrs),
501 : 1374 : outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
502 : 687 : delim_type (delim_type), rules (std::move (rules)), locus (locus),
503 : 687 : associated_transcriber (dummy_builtin), is_builtin_rule (false),
504 : 687 : kind (kind)
505 : 687 : {}
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 : 645 : mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
522 : : std::vector<Attribute> outer_attrs, location_t locus)
523 : : {
524 : 645 : return Rust::make_unique<MacroRulesDefinition> (
525 : 645 : MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
526 : : AST::MacroRulesDefinition::MacroKind::MBE,
527 : 1290 : AST::Visibility::create_error ()));
528 : : }
529 : :
530 : : static std::unique_ptr<MacroRulesDefinition>
531 : 42 : decl_macro (Identifier rule_name, std::vector<MacroRule> rules,
532 : : std::vector<Attribute> outer_attrs, location_t locus,
533 : : Visibility vis)
534 : : {
535 : 42 : return Rust::make_unique<MacroRulesDefinition> (MacroRulesDefinition (
536 : : rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus,
537 : 84 : 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 : 5279 : 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 : 12589 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
548 : 2452 : const std::vector<Attribute> &get_outer_attrs () const override
549 : : {
550 : 2452 : return outer_attrs;
551 : : }
552 : :
553 : 642 : std::vector<MacroRule> &get_macro_rules () { return rules; }
554 : : const std::vector<MacroRule> &get_macro_rules () const { return rules; }
555 : :
556 : 3451 : location_t get_locus () const override final { return locus; }
557 : :
558 : 3055 : Identifier get_rule_name () const { return rule_name; }
559 : :
560 : 2055 : std::vector<MacroRule> &get_rules () { return rules; }
561 : : const std::vector<MacroRule> &get_rules () const { return rules; }
562 : :
563 : 2271 : bool is_builtin () const { return is_builtin_rule; }
564 : 218 : const MacroTranscriberFunc &get_builtin_transcriber () const
565 : : {
566 : 218 : rust_assert (is_builtin ());
567 : 218 : return associated_transcriber;
568 : : }
569 : 105 : void set_builtin_transcriber (MacroTranscriberFunc transcriber)
570 : : {
571 : 105 : associated_transcriber = transcriber;
572 : 105 : is_builtin_rule = true;
573 : : }
574 : :
575 : 2630 : AST::Kind get_ast_kind () const override
576 : : {
577 : 2630 : return AST::Kind::MACRO_RULES_DEFINITION;
578 : : }
579 : :
580 : 23 : 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 : 0 : Pattern::Kind get_pattern_kind () override
614 : : {
615 : 0 : return Pattern::Kind::MacroInvocation;
616 : : }
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 : 2395 : Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
628 : : location_t locus, bool is_semi_coloned = false)
629 : : {
630 : 2395 : return std::unique_ptr<MacroInvocation> (
631 : : new MacroInvocation (InvocKind::Regular, tl::nullopt, invoc_data,
632 : 2395 : 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 : 7 : 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 : 7 : return std::unique_ptr<MacroInvocation> (
648 : : new MacroInvocation (InvocKind::Builtin, kind, invoc_data, outer_attrs,
649 : : locus, is_semi_coloned,
650 : 7 : std::move (pending_eager_invocations)));
651 : : }
652 : :
653 : 2757 : 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 : 2753 : bool is_marked_for_strip () const override
660 : : {
661 : 2753 : return invoc_data.is_marked_for_strip ();
662 : : }
663 : :
664 : 475 : const std::vector<Attribute> &get_outer_attrs () const override
665 : : {
666 : 475 : return outer_attrs;
667 : : }
668 : 6837 : 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 : 1704 : NodeId get_node_id () const override final
676 : : {
677 : 1704 : return ExprWithoutBlock::get_node_id ();
678 : : }
679 : :
680 : 230 : AST::Kind get_ast_kind () const override
681 : : {
682 : 230 : return AST::Kind::MACRO_INVOCATION;
683 : : }
684 : :
685 : 7402 : NodeId get_macro_node_id () const { return node_id; }
686 : :
687 : 4609 : MacroInvocData &get_invoc_data () { return invoc_data; }
688 : :
689 : 4540 : bool has_semicolon () const { return is_semi_coloned; }
690 : :
691 : 4548 : InvocKind get_kind () const { return kind; }
692 : : tl::optional<BuiltinMacro> get_builtin_kind () const { return builtin_kind; }
693 : :
694 : : /**
695 : : * Turn the current MacroInvocation into a builtin macro invocation
696 : : */
697 : 218 : void map_to_builtin (BuiltinMacro macro)
698 : : {
699 : 218 : kind = InvocKind::Builtin;
700 : 218 : builtin_kind = macro;
701 : : }
702 : :
703 : : /**
704 : : * Get the list of pending macro invcations within the builtin macro
705 : : * invocation that should get expanded eagerly.
706 : : */
707 : : std::vector<std::unique_ptr<MacroInvocation>> &
708 : 236 : get_pending_eager_invocations ()
709 : : {
710 : 236 : rust_assert (kind == InvocKind::Builtin);
711 : :
712 : 236 : return pending_eager_invocs;
713 : : }
714 : :
715 : : private:
716 : : /* Full constructor */
717 : 2402 : MacroInvocation (
718 : : InvocKind kind, tl::optional<BuiltinMacro> builtin_kind,
719 : : MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
720 : : location_t locus, bool is_semi_coloned,
721 : : std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocs)
722 : 4804 : : TraitItem (locus), outer_attrs (std::move (outer_attrs)), locus (locus),
723 : 2402 : node_id (Analysis::Mappings::get ()->get_next_node_id ()),
724 : 2402 : invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
725 : 2402 : kind (kind), builtin_kind (builtin_kind),
726 : 2402 : pending_eager_invocs (std::move (pending_eager_invocs))
727 : 2402 : {}
728 : :
729 : 9315 : MacroInvocation (const MacroInvocation &other)
730 : 27945 : : TraitItem (other.locus), ExternalItem (other.node_id),
731 : 18630 : outer_attrs (other.outer_attrs), locus (other.locus),
732 : 9315 : node_id (other.node_id), invoc_data (other.invoc_data),
733 : 9315 : is_semi_coloned (other.is_semi_coloned), kind (other.kind),
734 : 18630 : builtin_kind (other.builtin_kind)
735 : : {
736 : 9315 : if (other.kind == InvocKind::Builtin)
737 : 331 : for (auto &pending : other.pending_eager_invocs)
738 : 69 : pending_eager_invocs.emplace_back (
739 : 69 : pending->clone_macro_invocation_impl ());
740 : 9315 : }
741 : :
742 : : std::vector<Attribute> outer_attrs;
743 : : location_t locus;
744 : : NodeId node_id;
745 : :
746 : : /* The data given to the macro invocation */
747 : : MacroInvocData invoc_data;
748 : :
749 : : /* Important for when we actually expand the macro */
750 : : bool is_semi_coloned;
751 : :
752 : : /* Is this a builtin macro or a regular macro */
753 : : InvocKind kind;
754 : :
755 : : /* If it is a builtin macro, which one */
756 : : tl::optional<BuiltinMacro> builtin_kind = tl::nullopt;
757 : :
758 : : /**
759 : : * Pending invocations within a builtin macro invocation. This vector is empty
760 : : * and should not be accessed for a regular macro invocation. The macro
761 : : * invocations within should be name resolved and expanded before the builtin
762 : : * macro invocation get expanded again. It is then the role of the expander to
763 : : * insert these new tokens properly in the delimited token tree and try the
764 : : * builtin transcriber once again.
765 : : */
766 : : std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs;
767 : :
768 : : protected:
769 : : /* Use covariance to implement clone function as returning this object rather
770 : : * than base */
771 : 0 : MacroInvocation *clone_pattern_impl () const final override
772 : : {
773 : 0 : return clone_macro_invocation_impl ();
774 : : }
775 : :
776 : : /* Use covariance to implement clone function as returning this object rather
777 : : * than base */
778 : 0 : MacroInvocation *clone_expr_without_block_impl () const final override
779 : : {
780 : 0 : return clone_macro_invocation_impl ();
781 : : }
782 : :
783 : : /* Use covariance to implement clone function as returning this object rather
784 : : * than base */
785 : 0 : MacroInvocation *clone_type_no_bounds_impl () const final override
786 : : {
787 : 0 : return clone_macro_invocation_impl ();
788 : : }
789 : :
790 : 0 : MacroInvocation *clone_external_item_impl () const final override
791 : : {
792 : 0 : return clone_macro_invocation_impl ();
793 : : }
794 : :
795 : : public:
796 : 9315 : /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
797 : : {
798 : 9315 : return new MacroInvocation (*this);
799 : : }
800 : :
801 : 397 : void add_semicolon () override { is_semi_coloned = true; }
802 : :
803 : : protected:
804 : 595 : Item *clone_item_impl () const override
805 : : {
806 : 595 : return clone_macro_invocation_impl ();
807 : : }
808 : :
809 : 0 : bool is_item () const override { return !has_semicolon (); }
810 : :
811 : 0 : MacroInvocation *clone_associated_item_impl () const override
812 : : {
813 : 0 : return clone_macro_invocation_impl ();
814 : : };
815 : : };
816 : :
817 : : // more generic meta item path-only form
818 : 24 : class MetaItemPath : public MetaItem
819 : : {
820 : : SimplePath path;
821 : :
822 : : public:
823 : 24 : MetaItemPath (SimplePath path) : path (std::move (path)) {}
824 : :
825 : 0 : std::string as_string () const override { return path.as_string (); }
826 : :
827 : : void accept_vis (ASTVisitor &vis) override;
828 : :
829 : : // HACK: used to simplify parsing - returns non-empty only in this case
830 : 0 : SimplePath to_path_item () const override
831 : : {
832 : : // this should copy construct - TODO ensure it does
833 : 0 : return path;
834 : : }
835 : :
836 : 24 : SimplePath &get_path () { return path; }
837 : :
838 : 0 : location_t get_locus () const override { return path.get_locus (); }
839 : :
840 : : bool check_cfg_predicate (const Session &session) const override;
841 : :
842 : : Attribute to_attribute () const override;
843 : :
844 : 0 : MetaItem::ItemKind get_item_kind () const override
845 : : {
846 : 0 : return MetaItem::ItemKind::Path;
847 : : }
848 : :
849 : : protected:
850 : : // Use covariance to implement clone function as returning this type
851 : 0 : MetaItemPath *clone_meta_item_inner_impl () const override
852 : : {
853 : 0 : return new MetaItemPath (*this);
854 : : }
855 : : };
856 : :
857 : : // more generic meta item sequence form
858 : : class MetaItemSeq : public MetaItem
859 : : {
860 : : SimplePath path;
861 : : std::vector<std::unique_ptr<MetaItemInner>> seq;
862 : :
863 : : public:
864 : 54 : MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
865 : 54 : : path (std::move (path)), seq (std::move (seq))
866 : 54 : {}
867 : :
868 : : // copy constructor with vector clone
869 : 9 : MetaItemSeq (const MetaItemSeq &other) : path (other.path)
870 : : {
871 : 9 : seq.reserve (other.seq.size ());
872 : 20 : for (const auto &e : other.seq)
873 : 11 : seq.push_back (e->clone_meta_item_inner ());
874 : 9 : }
875 : :
876 : : // overloaded assignment operator with vector clone
877 : : MetaItemSeq &operator= (const MetaItemSeq &other)
878 : : {
879 : : MetaItem::operator= (other);
880 : : path = other.path;
881 : :
882 : : seq.reserve (other.seq.size ());
883 : : for (const auto &e : other.seq)
884 : : seq.push_back (e->clone_meta_item_inner ());
885 : :
886 : : return *this;
887 : : }
888 : :
889 : : // default move constructors
890 : : MetaItemSeq (MetaItemSeq &&other) = default;
891 : : MetaItemSeq &operator= (MetaItemSeq &&other) = default;
892 : :
893 : : std::string as_string () const override;
894 : :
895 : 0 : SimplePath &get_path () { return path; }
896 : :
897 : 0 : std::vector<std::unique_ptr<MetaItemInner>> &get_seq () { return seq; }
898 : :
899 : : void accept_vis (ASTVisitor &vis) override;
900 : :
901 : 0 : location_t get_locus () const override { return path.get_locus (); }
902 : :
903 : : bool check_cfg_predicate (const Session &session) const override;
904 : :
905 : : Attribute to_attribute () const override;
906 : :
907 : 0 : MetaItem::ItemKind get_item_kind () const override
908 : : {
909 : 0 : return MetaItem::ItemKind::Seq;
910 : : }
911 : :
912 : : protected:
913 : : // Use covariance to implement clone function as returning this type
914 : 9 : MetaItemSeq *clone_meta_item_inner_impl () const override
915 : : {
916 : 9 : return new MetaItemSeq (*this);
917 : : }
918 : : };
919 : :
920 : : // Preferred specialisation for single-identifier meta items.
921 : 158 : class MetaWord : public MetaItem
922 : : {
923 : : Identifier ident;
924 : : location_t ident_locus;
925 : :
926 : : public:
927 : 601 : MetaWord (Identifier ident, location_t ident_locus)
928 : 601 : : ident (std::move (ident)), ident_locus (ident_locus)
929 : : {}
930 : :
931 : 535 : std::string as_string () const override { return ident.as_string (); }
932 : :
933 : : void accept_vis (ASTVisitor &vis) override;
934 : :
935 : : Identifier &get_ident () { return ident; }
936 : :
937 : 3 : location_t get_locus () const override { return ident_locus; }
938 : :
939 : : bool check_cfg_predicate (const Session &session) const override;
940 : :
941 : : Attribute to_attribute () const override;
942 : :
943 : 24 : MetaItem::ItemKind get_item_kind () const override
944 : : {
945 : 24 : return MetaItem::ItemKind::Word;
946 : : }
947 : :
948 : : protected:
949 : : // Use covariance to implement clone function as returning this type
950 : 79 : MetaWord *clone_meta_item_inner_impl () const override
951 : : {
952 : 79 : return new MetaWord (*this);
953 : : }
954 : : };
955 : :
956 : : // Preferred specialisation for "identifier '=' string literal" meta items.
957 : : class MetaNameValueStr : public MetaItem
958 : : {
959 : : Identifier ident;
960 : : location_t ident_locus;
961 : :
962 : : // NOTE: str stored without quotes
963 : : std::string str;
964 : : location_t str_locus;
965 : :
966 : : public:
967 : 163 : MetaNameValueStr (Identifier ident, location_t ident_locus, std::string str,
968 : : location_t str_locus)
969 : 326 : : ident (std::move (ident)), ident_locus (ident_locus),
970 : 163 : str (std::move (str)), str_locus (str_locus)
971 : 163 : {}
972 : :
973 : 407 : std::string as_string () const override
974 : : {
975 : 814 : return ident.as_string () + " = \"" + str + "\"";
976 : : }
977 : :
978 : : void accept_vis (ASTVisitor &vis) override;
979 : :
980 : : // HACK: used to simplify parsing - creates a copy of this
981 : 4 : std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
982 : : {
983 : 4 : return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
984 : : }
985 : :
986 : 3 : location_t get_locus () const override { return ident_locus; }
987 : :
988 : : bool check_cfg_predicate (const Session &session) const override;
989 : :
990 : : Attribute to_attribute () const override;
991 : :
992 : 26 : inline std::pair<Identifier, std::string> get_name_value_pair () const
993 : : {
994 : 26 : return std::pair<Identifier, std::string> (ident, str);
995 : : }
996 : :
997 : 21 : bool is_key_value_pair () const override { return true; }
998 : :
999 : 0 : MetaItem::ItemKind get_item_kind () const override
1000 : : {
1001 : 0 : return MetaItem::ItemKind::NameValueStr;
1002 : : }
1003 : :
1004 : : protected:
1005 : : // Use covariance to implement clone function as returning this type
1006 : 559 : MetaNameValueStr *clone_meta_item_inner_impl () const override
1007 : : {
1008 : 559 : return new MetaNameValueStr (*this);
1009 : : }
1010 : : };
1011 : :
1012 : : // doubles up as MetaListIdents - determine via iterating through each path?
1013 : : // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
1014 : : class MetaListPaths : public MetaItem
1015 : : {
1016 : : Identifier ident;
1017 : : location_t ident_locus;
1018 : : std::vector<SimplePath> paths;
1019 : :
1020 : : public:
1021 : 0 : MetaListPaths (Identifier ident, location_t ident_locus,
1022 : : std::vector<SimplePath> paths)
1023 : 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1024 : 0 : paths (std::move (paths))
1025 : 0 : {}
1026 : :
1027 : : std::string as_string () const override;
1028 : :
1029 : : void accept_vis (ASTVisitor &vis) override;
1030 : :
1031 : 0 : Identifier get_ident () const { return ident; }
1032 : :
1033 : 0 : std::vector<SimplePath> &get_paths () { return paths; };
1034 : :
1035 : 0 : location_t get_locus () const override { return ident_locus; }
1036 : :
1037 : : bool check_cfg_predicate (const Session &session) const override;
1038 : :
1039 : : Attribute to_attribute () const override;
1040 : :
1041 : 0 : MetaItem::ItemKind get_item_kind () const override
1042 : : {
1043 : 0 : return MetaItem::ItemKind::ListPaths;
1044 : : }
1045 : :
1046 : : private:
1047 : : bool check_path_exists_in_cfg (const Session &session,
1048 : : const SimplePath &path) const;
1049 : :
1050 : : protected:
1051 : : // Use covariance to implement clone function as returning this type
1052 : 0 : MetaListPaths *clone_meta_item_inner_impl () const override
1053 : : {
1054 : 0 : return new MetaListPaths (*this);
1055 : : }
1056 : : };
1057 : :
1058 : : // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
1059 : : class MetaListNameValueStr : public MetaItem
1060 : : {
1061 : : Identifier ident;
1062 : : location_t ident_locus;
1063 : : std::vector<MetaNameValueStr> strs;
1064 : :
1065 : : public:
1066 : 0 : MetaListNameValueStr (Identifier ident, location_t ident_locus,
1067 : : std::vector<MetaNameValueStr> strs)
1068 : 0 : : ident (std::move (ident)), ident_locus (ident_locus),
1069 : 0 : strs (std::move (strs))
1070 : 0 : {}
1071 : :
1072 : : std::string as_string () const override;
1073 : :
1074 : : void accept_vis (ASTVisitor &vis) override;
1075 : :
1076 : 0 : Identifier get_ident () { return ident; }
1077 : :
1078 : 0 : std::vector<MetaNameValueStr> &get_values () { return strs; }
1079 : :
1080 : 0 : location_t get_locus () const override { return ident_locus; }
1081 : :
1082 : : bool check_cfg_predicate (const Session &session) const override;
1083 : :
1084 : : Attribute to_attribute () const override;
1085 : :
1086 : 0 : MetaItem::ItemKind get_item_kind () const override
1087 : : {
1088 : 0 : return MetaItem::ItemKind::ListNameValueStr;
1089 : : }
1090 : :
1091 : : protected:
1092 : : // Use covariance to implement clone function as returning this type
1093 : 0 : MetaListNameValueStr *clone_meta_item_inner_impl () const override
1094 : : {
1095 : 0 : return new MetaListNameValueStr (*this);
1096 : : }
1097 : : };
1098 : :
1099 : : // Object that parses macros from a token stream.
1100 : : /* TODO: would "AttributeParser" be a better name? MetaItems are only for
1101 : : * attributes, I believe */
1102 : : struct AttributeParser
1103 : : {
1104 : : private:
1105 : : // TODO: might as well rewrite to use lexer tokens
1106 : : std::vector<std::unique_ptr<Token>> token_stream;
1107 : : int stream_pos;
1108 : :
1109 : : public:
1110 : 750 : AttributeParser (std::vector<std::unique_ptr<Token>> token_stream,
1111 : : int stream_start_pos = 0)
1112 : 750 : : token_stream (std::move (token_stream)), stream_pos (stream_start_pos)
1113 : : {}
1114 : :
1115 : 750 : ~AttributeParser () = default;
1116 : :
1117 : : std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
1118 : :
1119 : : private:
1120 : : // Parses a MetaItemInner.
1121 : : std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
1122 : : // Returns whether token can end a meta item.
1123 : : bool is_end_meta_item_tok (TokenId id) const;
1124 : : // Parses a simple path.
1125 : : SimplePath parse_simple_path ();
1126 : : // Parses a segment of a simple path (but not scope resolution operator).
1127 : : SimplePathSegment parse_simple_path_segment ();
1128 : : // Parses a MetaItemLitExpr.
1129 : : std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
1130 : : // Parses a literal.
1131 : : Literal parse_literal ();
1132 : : // Parses a meta item that begins with a simple path.
1133 : : std::unique_ptr<MetaItem> parse_path_meta_item ();
1134 : :
1135 : : // TODO: should this be const?
1136 : 6811 : std::unique_ptr<Token> &peek_token (int i = 0)
1137 : : {
1138 : 4793 : return token_stream[stream_pos + i];
1139 : : }
1140 : :
1141 : 2496 : void skip_token (int i = 0) { stream_pos += 1 + i; }
1142 : : };
1143 : : } // namespace AST
1144 : : } // namespace Rust
1145 : :
1146 : : /* <https://stackoverflow.com/a/35304501> */
1147 : : namespace std {
1148 : : template <> struct hash<Rust::AST::MacroFragSpec::Kind>
1149 : : {
1150 : 1327 : size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
1151 : : {
1152 : 1327 : return size_t (t);
1153 : : }
1154 : : };
1155 : : } // namespace std
1156 : :
1157 : : #endif
|