Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-macro-expand.h"
20 : #include "optional.h"
21 : #include "rust-ast-fragment.h"
22 : #include "rust-macro-builtins.h"
23 : #include "rust-macro-substitute-ctx.h"
24 : #include "rust-ast-full.h"
25 : #include "rust-ast-visitor.h"
26 : #include "rust-diagnostics.h"
27 : #include "rust-macro.h"
28 : #include "rust-parse.h"
29 : #include "rust-cfg-strip.h"
30 : #include "rust-proc-macro.h"
31 : #include "rust-token-tree-desugar.h"
32 : #include "rust-session-manager.h"
33 :
34 : namespace Rust {
35 :
36 : AST::Fragment
37 55214 : MacroExpander::expand_decl_macro (location_t invoc_locus,
38 : AST::MacroInvocData &invoc,
39 : AST::MacroRulesDefinition &rules_def,
40 : AST::InvocKind semicolon)
41 : {
42 : // ensure that both invocation and rules are in a valid state
43 55214 : rust_assert (!invoc.is_marked_for_strip ());
44 55214 : rust_assert (!rules_def.is_marked_for_strip ());
45 55214 : rust_assert (rules_def.get_macro_rules ().size () > 0);
46 :
47 : /* probably something here about parsing invoc and rules def token trees to
48 : * token stream. if not, how would parser handle the captures of exprs and
49 : * stuff? on the other hand, token trees may be kind of useful in rules def
50 : * as creating a point where recursion can occur (like having
51 : * "compare_macro_match" and then it calling itself when it finds
52 : * delimiters)
53 : */
54 :
55 : /* find matching rule to invoc token tree, based on macro rule's matcher. if
56 : * none exist, error.
57 : * - specifically, check each matcher in order. if one fails to match, move
58 : * onto next. */
59 : /* TODO: does doing this require parsing expressions and whatever in the
60 : * invoc? if so, might as well save the results if referenced using $ or
61 : * whatever. If not, do another pass saving them. Except this is probably
62 : * useless as different rules could have different starting points for exprs
63 : * or whatever. Decision trees could avoid this, but they have their own
64 : * issues. */
65 : /* TODO: will need to modify the parser so that it can essentially "catch"
66 : * errors - maybe "try_parse_expr" or whatever methods. */
67 : // this technically creates a back-tracking parser - this will be the
68 : // implementation style
69 :
70 : /* then, after results are saved, generate the macro output from the
71 : * transcriber token tree. if i understand this correctly, the macro
72 : * invocation gets replaced by the transcriber tokens, except with
73 : * substitutions made (e.g. for $i variables) */
74 :
75 : /* TODO: it is probably better to modify AST::Token to store a pointer to a
76 : * Lexer::Token (rather than being converted) - i.e. not so much have
77 : * AST::Token as a Token but rather a TokenContainer (as it is another type
78 : * of TokenTree). This will prevent re-conversion of Tokens between each
79 : * type all the time, while still allowing the heterogenous storage of token
80 : * trees.
81 : */
82 :
83 55214 : AST::DelimTokenTree &invoc_token_tree_sugar = invoc.get_delim_tok_tree ();
84 :
85 : // We must first desugar doc comments into proper attributes
86 55214 : auto invoc_token_tree = AST::TokenTreeDesugar ().go (invoc_token_tree_sugar);
87 :
88 : // find matching arm
89 55214 : AST::MacroRule *matched_rule = nullptr;
90 55214 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>>
91 55214 : matched_fragments;
92 58973 : for (auto &rule : rules_def.get_rules ())
93 : {
94 58965 : sub_stack.push ();
95 58965 : bool did_match_rule = try_match_rule (rule, invoc_token_tree);
96 117930 : matched_fragments = sub_stack.pop ();
97 :
98 58965 : if (did_match_rule)
99 : {
100 : // // Debugging
101 : // for (auto &kv : matched_fragments)
102 : // rust_debug ("[fragment]: %s (%ld - %s)", kv.first.c_str (),
103 : // kv.second.get_fragments ().size (),
104 : // kv.second.get_kind ()
105 : // == MatchedFragmentContainer::Kind::Repetition
106 : // ? "repetition"
107 : // : "metavar");
108 :
109 : matched_rule = &rule;
110 : break;
111 : }
112 : }
113 :
114 55214 : if (matched_rule == nullptr)
115 : {
116 8 : if (!had_duplicate_error)
117 : {
118 7 : rich_location r (line_table, invoc_locus);
119 7 : r.add_range (rules_def.get_locus ());
120 7 : rust_error_at (r, "Failed to match any rule within macro");
121 7 : }
122 8 : had_duplicate_error = false;
123 8 : return AST::Fragment::create_error ();
124 : }
125 :
126 55206 : std::map<std::string, MatchedFragmentContainer *> matched_fragments_ptr;
127 :
128 227798 : for (auto &ent : matched_fragments)
129 172592 : matched_fragments_ptr.emplace (ent.first, ent.second.get ());
130 :
131 55206 : return transcribe_rule (rules_def, *matched_rule, invoc_token_tree,
132 55206 : matched_fragments_ptr, semicolon, peek_context ());
133 110420 : }
134 :
135 : void
136 382 : MacroExpander::expand_eager_invocations (AST::MacroInvocation &invoc)
137 : {
138 382 : if (invoc.get_pending_eager_invocations ().empty ())
139 0 : return;
140 :
141 : // We have to basically create a new delimited token tree which contains the
142 : // result of one step of expansion. In the case of builtin macros called with
143 : // other macro invocations, such as `concat!("h", 'a', a!())`, we need to
144 : // expand `a!()` before expanding the concat macro.
145 : // This will, ideally, give us a new token tree containing the various
146 : // existing tokens + the result of the expansion of a!().
147 : // To do this, we "parse" the given token tree to find anything that "looks
148 : // like a macro invocation". Then, we get the corresponding macro invocation
149 : // from the `pending_eager_invocations` vector and expand it.
150 : // Because the `pending_eager_invocations` vector is created in the same order
151 : // that the DelimTokenTree is parsed, we know that the first macro invocation
152 : // within the DelimTokenTree corresponds to the first element in
153 : // `pending_eager_invocations`. The idea is thus to:
154 : // 1. Find a macro invocation in the token tree, noting the index of the start
155 : // token and of the end token
156 : // 2. Get its associated invocation in `pending_eager_invocations`
157 : // 3. Expand that element
158 : // 4. Get the token tree associated with that AST fragment
159 : // 5. Replace the original tokens corresponding to the invocation with the new
160 : // tokens from the fragment
161 : // pseudo-code:
162 : //
163 : // i = 0;
164 : // for tok in dtt:
165 : // if tok is identifier && tok->next() is !:
166 : // start = index(tok);
167 : // l_delim = tok->next()->next();
168 : // tok = skip_until_r_delim();
169 : // end = index(tok);
170 : //
171 : // new_tt = expand_eager_invoc(eagers[i++]);
172 : // old_tt[start..end] = new_tt;
173 :
174 382 : auto dtt = invoc.get_invoc_data ().get_delim_tok_tree ();
175 382 : auto stream = dtt.to_token_stream ();
176 382 : std::vector<std::unique_ptr<AST::TokenTree>> new_stream;
177 382 : size_t current_pending = 0;
178 :
179 : // we need to create a clone of the delimited token tree as the lexer
180 : // expects ownership of the tokens
181 382 : std::vector<const_TokenPtr> dtt_clone;
182 8804 : for (auto &tok : stream)
183 16844 : dtt_clone.emplace_back (tok->get_tok_ptr ());
184 :
185 382 : MacroInvocLexer lex (std::move (dtt_clone));
186 382 : Parser<MacroInvocLexer> parser (lex);
187 :
188 : // we want to build a substitution map - basically, associating a `start` and
189 : // `end` index for each of the pending macro invocations
190 382 : std::map<std::pair<size_t, size_t>, AST::MacroInvocation *> substitution_map;
191 :
192 382 : auto &pending = invoc.get_pending_eager_invocations ();
193 :
194 9186 : for (size_t i = 0; i < stream.size (); i++)
195 : {
196 : // FIXME: Can't these offsets be figure out when we actually parse the
197 : // pending_eager_invocation in the first place?
198 8422 : auto invocation = parser.parse_macro_invocation ({});
199 :
200 : // if we've managed to parse a macro invocation, we look at the current
201 : // offset and store them in the substitution map. Otherwise, we skip one
202 : // token and try parsing again
203 8422 : if (invocation)
204 872 : substitution_map.insert ({{i, parser.get_token_source ().get_offs ()},
205 872 : pending[current_pending++].get ()});
206 : else
207 7550 : parser.skip_token (stream[i]->get_id ());
208 8422 : }
209 :
210 382 : auto pending_it = pending.begin ();
211 382 : size_t current_idx = 0;
212 1254 : for (auto kv : substitution_map)
213 : {
214 872 : AST::MacroInvocation *to_expand = kv.second;
215 872 : expand_invoc (*to_expand, AST::InvocKind::Expr);
216 :
217 872 : auto fragment = take_expanded_fragment ();
218 :
219 872 : if (fragment.is_error ())
220 : {
221 : // skip expansion of this macro
222 : // leave current_idx as-is, and continue
223 146 : pending_it++;
224 146 : continue;
225 : }
226 :
227 726 : auto &new_tokens = fragment.get_tokens ();
228 :
229 726 : auto start = kv.first.first;
230 726 : auto end = kv.first.second;
231 :
232 : // We're now going to re-add the tokens to the invocation's token tree.
233 : // 1. Basically, what we want to do is insert all tokens up until the
234 : // beginning of the macro invocation (start).
235 : // 2. Then, we'll insert all of the tokens resulting from the macro
236 : // expansion: These are in `new_tokens`.
237 : // 3. Finally, we'll do that again from
238 : // the end of macro and go back to 1.
239 :
240 3724 : for (size_t i = current_idx; i < start; i++)
241 2272 : new_stream.emplace_back (stream[i]->clone_token ());
242 :
243 1452 : for (auto &tok : new_tokens)
244 726 : new_stream.emplace_back (tok->clone_token ());
245 :
246 726 : current_idx = end;
247 726 : pending_it = pending.erase (pending_it);
248 872 : }
249 :
250 : // Once all of that is done, we copy the last remaining tokens from the
251 : // original stream
252 2922 : for (size_t i = current_idx; i < stream.size (); i++)
253 2540 : new_stream.emplace_back (stream[i]->clone_token ());
254 :
255 382 : auto new_dtt
256 382 : = AST::DelimTokenTree (dtt.get_delim_type (), std::move (new_stream));
257 :
258 382 : invoc.get_invoc_data ().set_delim_tok_tree (new_dtt);
259 382 : }
260 :
261 : void
262 57509 : MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
263 : AST::InvocKind semicolon)
264 : {
265 57509 : if (depth_exceeds_recursion_limit ())
266 : {
267 0 : rust_error_at (invoc.get_locus (), "reached recursion limit");
268 301 : return;
269 : }
270 :
271 57509 : if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
272 : {
273 : // Eager expansions are always expressions
274 382 : push_context (ContextType::EXPR);
275 382 : expand_eager_invocations (invoc);
276 382 : pop_context ();
277 :
278 : // if we have pending eager invocations still, don't expand
279 382 : if (!invoc.get_pending_eager_invocations ().empty ())
280 : {
281 37 : set_expanded_fragment (AST::Fragment::create_error ());
282 37 : return;
283 : }
284 : }
285 :
286 57472 : AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
287 :
288 : // ??
289 : // switch on type of macro:
290 : // - '!' syntax macro (inner switch)
291 : // - procedural macro - "A token-based function-like macro"
292 : // - 'macro_rules' (by example/pattern-match) macro? or not? "an
293 : // AST-based function-like macro"
294 : // - else is unreachable
295 : // - attribute syntax macro (inner switch)
296 : // - procedural macro attribute syntax - "A token-based attribute
297 : // macro"
298 : // - legacy macro attribute syntax? - "an AST-based attribute macro"
299 : // - non-macro attribute: mark known
300 : // - else is unreachable
301 : // - derive macro (inner switch)
302 : // - derive or legacy derive - "token-based" vs "AST-based"
303 : // - else is unreachable
304 : // - derive container macro - unreachable
305 :
306 57472 : auto fragment = AST::Fragment::create_error ();
307 57472 : invoc_data.set_expander (this);
308 :
309 : // lookup the rules
310 57472 : auto rules_def = mappings.lookup_macro_invocation (invoc);
311 :
312 : // We special case the `offset_of!()` macro if the flag is here and manually
313 : // resolve to the builtin transcriber we have specified
314 57472 : auto assume_builtin_offset_of
315 57472 : = Session::get_instance ().should_support_offset_of ()
316 94 : && (invoc.get_invoc_data ().get_path ().as_string () == "offset_of")
317 57490 : && !rules_def;
318 :
319 : // TODO: This is *massive hack* which should be removed as we progress to
320 : // Rust 1.71 when offset_of gets added to core
321 57472 : if (assume_builtin_offset_of)
322 : {
323 18 : fragment = MacroBuiltin::offset_of_handler (invoc.get_locus (),
324 : invoc_data, semicolon)
325 54 : .value_or (AST::Fragment::create_empty ());
326 :
327 18 : set_expanded_fragment (std::move (fragment));
328 :
329 18 : return;
330 : }
331 :
332 : // TODO: Also remove code below as we progress to Rust 1.90, when cfg_select
333 : // gets added to nightly.
334 57454 : auto assume_builtin_cfg_select
335 57454 : = Session::get_instance ().should_support_cfg_select ()
336 58 : && (invoc.get_invoc_data ().get_path ().as_string () == "cfg_select")
337 57483 : && !rules_def;
338 :
339 57454 : if (assume_builtin_cfg_select)
340 : {
341 29 : fragment = MacroBuiltin::cfg_select_handler (invoc.get_locus (),
342 : invoc_data, semicolon)
343 87 : .value_or (AST::Fragment::create_empty ());
344 :
345 29 : set_expanded_fragment (std::move (fragment));
346 :
347 29 : return;
348 : }
349 :
350 : // If there's no rule associated with the invocation, we can simply return
351 : // early. The early name resolver will have already emitted an error.
352 57425 : if (!rules_def)
353 : {
354 : // error fragment
355 217 : set_expanded_fragment (std::move (fragment));
356 217 : return;
357 : }
358 :
359 57208 : auto rdef = rules_def.value ();
360 :
361 : // We store the last expanded invocation and macro definition for error
362 : // reporting in case the recursion limit is reached
363 57208 : last_invoc = *invoc.clone_macro_invocation_impl ();
364 57208 : last_def = *rdef;
365 :
366 57208 : if (rdef->is_builtin ())
367 1994 : fragment = rdef
368 1994 : ->get_builtin_transcriber () (invoc.get_locus (), invoc_data,
369 : semicolon)
370 5982 : .value_or (AST::Fragment::create_empty ());
371 : else
372 55214 : fragment
373 110428 : = expand_decl_macro (invoc.get_locus (), invoc_data, *rdef, semicolon);
374 :
375 57208 : set_expanded_fragment (std::move (fragment));
376 57472 : }
377 :
378 : void
379 0 : MacroExpander::expand_crate ()
380 : {
381 : /* fill macro/decorator map from init list? not sure where init list comes
382 : * from? */
383 :
384 : // TODO: does cfg apply for inner attributes? research.
385 : // the apparent answer (from playground test) is yes
386 :
387 0 : push_context (ContextType::ITEM);
388 :
389 : // expand attributes recursively and strip items if required
390 : // AttrVisitor attr_visitor (*this);
391 0 : auto &items = crate.items;
392 0 : for (auto it = items.begin (); it != items.end ();)
393 : {
394 0 : auto &item = *it;
395 :
396 0 : auto fragment = take_expanded_fragment ();
397 0 : if (fragment.should_expand ())
398 : {
399 : // Remove the current expanded invocation
400 0 : it = items.erase (it);
401 0 : for (auto &node : fragment.get_nodes ())
402 : {
403 0 : it = items.insert (it, node.take_item ());
404 0 : it++;
405 : }
406 : }
407 0 : else if (item->is_marked_for_strip ())
408 0 : it = items.erase (it);
409 : else
410 0 : it++;
411 0 : }
412 :
413 0 : pop_context ();
414 :
415 : // TODO: should recursive attribute and macro expansion be done in the same
416 : // transversal? Or in separate ones like currently?
417 :
418 : // expand module tree recursively
419 :
420 : // post-process
421 :
422 : // extract exported macros?
423 0 : }
424 :
425 : bool
426 118567 : MacroExpander::depth_exceeds_recursion_limit () const
427 : {
428 118567 : return expansion_depth >= cfg.recursion_limit;
429 : }
430 :
431 : bool
432 58965 : MacroExpander::try_match_rule (AST::MacroRule &match_rule,
433 : AST::DelimTokenTree &invoc_token_tree)
434 : {
435 58965 : MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
436 58965 : Parser<MacroInvocLexer> parser (lex);
437 :
438 58965 : AST::MacroMatcher &matcher = match_rule.get_matcher ();
439 :
440 58965 : expansion_depth++;
441 58965 : if (!match_matcher (parser, matcher, false, false))
442 : {
443 3759 : expansion_depth--;
444 3759 : return false;
445 : }
446 55206 : expansion_depth--;
447 :
448 55206 : bool used_all_input_tokens = parser.skip_token (END_OF_FILE);
449 55206 : return used_all_input_tokens;
450 58965 : }
451 :
452 : bool
453 206282 : MacroExpander::match_fragment (Parser<MacroInvocLexer> &parser,
454 : AST::MacroMatchFragment &fragment)
455 : {
456 206282 : switch (fragment.get_frag_spec ().get_kind ())
457 : {
458 157464 : case AST::MacroFragSpec::EXPR:
459 314927 : parser.parse_expr ();
460 157464 : break;
461 :
462 11 : case AST::MacroFragSpec::BLOCK:
463 22 : parser.parse_block_expr ();
464 11 : break;
465 :
466 13321 : case AST::MacroFragSpec::IDENT:
467 13321 : parser.parse_identifier_or_keyword_token ();
468 13321 : break;
469 :
470 3768 : case AST::MacroFragSpec::LITERAL:
471 7531 : std::ignore = parser.parse_literal_expr ();
472 3768 : break;
473 :
474 1 : case AST::MacroFragSpec::ITEM:
475 1 : parser.parse_item (false);
476 1 : break;
477 :
478 11387 : case AST::MacroFragSpec::TY:
479 11387 : parser.parse_type ();
480 11387 : break;
481 :
482 58 : case AST::MacroFragSpec::PAT:
483 58 : parser.parse_pattern ();
484 58 : break;
485 :
486 3 : case AST::MacroFragSpec::PATH:
487 3 : parser.parse_path_in_expression ();
488 3 : break;
489 :
490 0 : case AST::MacroFragSpec::VIS:
491 0 : parser.parse_visibility ();
492 0 : break;
493 :
494 303 : case AST::MacroFragSpec::STMT:
495 303 : {
496 303 : auto restrictions = ParseRestrictions ();
497 303 : restrictions.consume_semi = false;
498 303 : parser.parse_stmt (restrictions);
499 303 : break;
500 : }
501 :
502 17 : case AST::MacroFragSpec::LIFETIME:
503 17 : parser.parse_lifetime_params ();
504 17 : break;
505 :
506 : // is meta attributes?
507 1786 : case AST::MacroFragSpec::META:
508 1786 : parser.parse_attribute_body ();
509 1786 : break;
510 :
511 18163 : case AST::MacroFragSpec::TT:
512 18163 : parser.parse_token_tree ();
513 18163 : break;
514 :
515 : // i guess we just ignore invalid and just error out
516 : case AST::MacroFragSpec::INVALID:
517 : return false;
518 : }
519 :
520 : // it matches if the parser did not produce errors trying to parse that type
521 : // of item
522 206282 : return !parser.has_errors ();
523 : }
524 :
525 : bool
526 61058 : MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
527 : AST::MacroMatcher &matcher, bool in_repetition,
528 : bool match_delim)
529 : {
530 61058 : if (depth_exceeds_recursion_limit ())
531 : {
532 0 : rust_error_at (matcher.get_match_locus (), "reached recursion limit");
533 0 : return false;
534 : }
535 :
536 61058 : auto delimiter = parser.peek_current_token ();
537 :
538 122074 : auto check_delim = [&matcher, match_delim] (AST::DelimType delim) {
539 2051 : return !match_delim || matcher.get_delim_type () == delim;
540 61058 : };
541 :
542 : // this is used so we can check that we delimit the stream correctly.
543 61058 : switch (delimiter->get_id ())
544 : {
545 55357 : case LEFT_PAREN:
546 55357 : {
547 55357 : if (!check_delim (AST::DelimType::PARENS))
548 : return false;
549 : }
550 : break;
551 :
552 1855 : case LEFT_SQUARE:
553 1855 : {
554 1855 : if (!check_delim (AST::DelimType::SQUARE))
555 : return false;
556 : }
557 : break;
558 :
559 3804 : case LEFT_CURLY:
560 3804 : {
561 64862 : if (!check_delim (AST::DelimType::CURLY))
562 : return false;
563 : }
564 : break;
565 : default:
566 : return false;
567 : }
568 61015 : parser.skip_token ();
569 :
570 61015 : const MacroInvocLexer &source = parser.get_token_source ();
571 :
572 122030 : std::unordered_map<std::string, location_t> duplicate_check;
573 :
574 368648 : for (auto &match : matcher.get_matches ())
575 : {
576 308132 : size_t offs_begin = source.get_offs ();
577 :
578 308132 : switch (match->get_macro_match_type ())
579 : {
580 175840 : case AST::MacroMatch::MacroMatchType::Fragment:
581 175840 : {
582 175840 : AST::MacroMatchFragment *fragment
583 175840 : = static_cast<AST::MacroMatchFragment *> (match.get ());
584 175840 : if (!match_fragment (parser, *fragment))
585 61015 : return false;
586 :
587 351670 : auto duplicate_result = duplicate_check.insert (
588 527505 : std::make_pair (fragment->get_ident ().as_string (),
589 175835 : fragment->get_ident ().get_locus ()));
590 :
591 175835 : if (!duplicate_result.second)
592 : {
593 : // TODO: add range labels?
594 1 : rich_location r (line_table,
595 1 : fragment->get_ident ().get_locus ());
596 1 : r.add_range (duplicate_result.first->second);
597 1 : rust_error_at (r, "duplicate matcher binding");
598 1 : had_duplicate_error = true;
599 1 : return false;
600 1 : }
601 :
602 : // matched fragment get the offset in the token stream
603 175834 : size_t offs_end = source.get_offs ();
604 351668 : sub_stack.insert_metavar (
605 351668 : MatchedFragment (fragment->get_ident ().as_string (), offs_begin,
606 527502 : offs_end));
607 : }
608 175834 : break;
609 :
610 126033 : case AST::MacroMatch::MacroMatchType::Tok:
611 126033 : {
612 126033 : AST::Token *tok = static_cast<AST::Token *> (match.get ());
613 126033 : if (!match_token (parser, *tok))
614 : return false;
615 : }
616 : break;
617 :
618 4723 : case AST::MacroMatch::MacroMatchType::Repetition:
619 4723 : {
620 4723 : AST::MacroMatchRepetition *rep
621 4723 : = static_cast<AST::MacroMatchRepetition *> (match.get ());
622 4723 : if (!match_repetition (parser, *rep))
623 : return false;
624 : }
625 : break;
626 :
627 1536 : case AST::MacroMatch::MacroMatchType::Matcher:
628 1536 : {
629 1536 : AST::MacroMatcher *m
630 1536 : = static_cast<AST::MacroMatcher *> (match.get ());
631 1536 : expansion_depth++;
632 1536 : if (!match_matcher (parser, *m, in_repetition))
633 : {
634 3 : expansion_depth--;
635 3 : return false;
636 : }
637 1533 : expansion_depth--;
638 : }
639 1533 : break;
640 : }
641 : }
642 :
643 60516 : switch (delimiter->get_id ())
644 : {
645 54966 : case LEFT_PAREN:
646 54966 : {
647 54966 : if (!parser.skip_token (RIGHT_PAREN))
648 : return false;
649 : }
650 : break;
651 :
652 1855 : case LEFT_SQUARE:
653 1855 : {
654 1855 : if (!parser.skip_token (RIGHT_SQUARE))
655 : return false;
656 : }
657 : break;
658 :
659 3695 : case LEFT_CURLY:
660 3695 : {
661 3695 : if (!parser.skip_token (RIGHT_CURLY))
662 : return false;
663 : }
664 : break;
665 0 : default:
666 0 : rust_unreachable ();
667 : }
668 :
669 : return true;
670 61058 : }
671 :
672 : bool
673 134769 : MacroExpander::match_token (Parser<MacroInvocLexer> &parser, AST::Token &token)
674 : {
675 269538 : return parser.skip_token (token.get_tok_ptr ());
676 : }
677 :
678 : bool
679 4786 : MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
680 : AST::MacroMatchRepetition &rep,
681 : size_t &match_amount, size_t lo_bound,
682 : size_t hi_bound)
683 : {
684 4786 : match_amount = 0;
685 4786 : auto &matches = rep.get_matches ();
686 :
687 4786 : const MacroInvocLexer &source = parser.get_token_source ();
688 62604 : while (true)
689 : {
690 : // If the current token is a closing macro delimiter, break away.
691 : // TODO: Is this correct?
692 33695 : auto t_id = parser.peek_current_token ()->get_id ();
693 33695 : if (t_id == RIGHT_PAREN || t_id == RIGHT_SQUARE || t_id == RIGHT_CURLY)
694 : break;
695 :
696 : // Skip parsing a separator on the first match, otherwise consume it.
697 : // If it isn't present, this is an error
698 29150 : if (rep.has_sep () && match_amount > 0)
699 3046 : if (!match_token (parser, *rep.get_sep ()))
700 : break;
701 :
702 29072 : sub_stack.push ();
703 29072 : bool valid_current_match = false;
704 65824 : for (auto &match : matches)
705 : {
706 36752 : size_t offs_begin = source.get_offs ();
707 36752 : switch (match->get_macro_match_type ())
708 : {
709 30442 : case AST::MacroMatch::MacroMatchType::Fragment:
710 30442 : {
711 30442 : AST::MacroMatchFragment *fragment
712 30442 : = static_cast<AST::MacroMatchFragment *> (match.get ());
713 30442 : valid_current_match = match_fragment (parser, *fragment);
714 :
715 : // matched fragment get the offset in the token stream
716 30442 : size_t offs_end = source.get_offs ();
717 :
718 30442 : if (valid_current_match)
719 60854 : sub_stack.insert_metavar (
720 60854 : MatchedFragment (fragment->get_ident ().as_string (),
721 91281 : offs_begin, offs_end));
722 : }
723 : break;
724 :
725 5690 : case AST::MacroMatch::MacroMatchType::Tok:
726 5690 : {
727 5690 : AST::Token *tok = static_cast<AST::Token *> (match.get ());
728 5690 : valid_current_match = match_token (parser, *tok);
729 : }
730 5690 : break;
731 :
732 63 : case AST::MacroMatch::MacroMatchType::Repetition:
733 63 : {
734 63 : AST::MacroMatchRepetition *rep
735 63 : = static_cast<AST::MacroMatchRepetition *> (match.get ());
736 63 : valid_current_match = match_repetition (parser, *rep);
737 : }
738 63 : break;
739 :
740 557 : case AST::MacroMatch::MacroMatchType::Matcher:
741 557 : {
742 557 : AST::MacroMatcher *m
743 557 : = static_cast<AST::MacroMatcher *> (match.get ());
744 557 : valid_current_match = match_matcher (parser, *m, true);
745 : }
746 557 : break;
747 : }
748 : }
749 29072 : auto old_stack = sub_stack.pop ();
750 :
751 : // If we've encountered an error once, stop trying to match more
752 : // repetitions
753 29072 : if (!valid_current_match)
754 : break;
755 :
756 : // nest metavars into repetitions
757 59926 : for (auto &ent : old_stack)
758 62032 : sub_stack.append_fragment (ent.first, std::move (ent.second));
759 :
760 28910 : match_amount++;
761 :
762 : // Break early if we notice there's too many expressions already
763 28910 : if (hi_bound && match_amount > hi_bound)
764 : break;
765 29072 : }
766 :
767 : // Check if the amount of matches we got is valid: Is it more than the lower
768 : // bound and less than the higher bound?
769 4786 : bool did_meet_lo_bound = match_amount >= lo_bound;
770 4786 : bool did_meet_hi_bound = hi_bound ? match_amount <= hi_bound : true;
771 :
772 : // If the end-result is valid, then we can clear the parse errors: Since
773 : // repetitions are parsed eagerly, it is okay to fail in some cases
774 9571 : auto res = did_meet_lo_bound && did_meet_hi_bound;
775 4785 : if (res)
776 4771 : parser.clear_errors ();
777 :
778 4786 : return res;
779 : }
780 :
781 : /*
782 : * Helper function for defining unmatched repetition metavars
783 : */
784 : void
785 7463 : MacroExpander::match_repetition_skipped_metavars (AST::MacroMatch &match)
786 : {
787 : // We have to handle zero fragments differently: They will not have been
788 : // "matched" but they are still valid and should be inserted as a special
789 : // case. So we go through the stack map, and for every fragment which doesn't
790 : // exist, insert a zero-matched fragment.
791 7463 : switch (match.get_macro_match_type ())
792 : {
793 4872 : case AST::MacroMatch::MacroMatchType::Fragment:
794 4872 : match_repetition_skipped_metavars (
795 : static_cast<AST::MacroMatchFragment &> (match));
796 4872 : break;
797 29 : case AST::MacroMatch::MacroMatchType::Repetition:
798 29 : match_repetition_skipped_metavars (
799 : static_cast<AST::MacroMatchRepetition &> (match));
800 29 : break;
801 76 : case AST::MacroMatch::MacroMatchType::Matcher:
802 76 : match_repetition_skipped_metavars (
803 : static_cast<AST::MacroMatcher &> (match));
804 76 : break;
805 : case AST::MacroMatch::MacroMatchType::Tok:
806 : break;
807 : }
808 7463 : }
809 :
810 : void
811 4872 : MacroExpander::match_repetition_skipped_metavars (
812 : AST::MacroMatchFragment &fragment)
813 : {
814 4872 : auto &stack_map = sub_stack.peek ();
815 4872 : auto it = stack_map.find (fragment.get_ident ().as_string ());
816 :
817 4872 : if (it == stack_map.end ())
818 256 : sub_stack.insert_matches (fragment.get_ident ().as_string (),
819 256 : MatchedFragmentContainer::zero ());
820 4872 : }
821 :
822 : void
823 4815 : MacroExpander::match_repetition_skipped_metavars (
824 : AST::MacroMatchRepetition &rep)
825 : {
826 12205 : for (auto &match : rep.get_matches ())
827 7390 : match_repetition_skipped_metavars (*match);
828 4815 : }
829 :
830 : void
831 76 : MacroExpander::match_repetition_skipped_metavars (AST::MacroMatcher &rep)
832 : {
833 149 : for (auto &match : rep.get_matches ())
834 73 : match_repetition_skipped_metavars (*match);
835 76 : }
836 :
837 : bool
838 4786 : MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
839 : AST::MacroMatchRepetition &rep)
840 : {
841 4786 : size_t match_amount = 0;
842 4786 : bool res = false;
843 :
844 4786 : std::string lo_str;
845 4786 : std::string hi_str;
846 4786 : switch (rep.get_op ())
847 : {
848 3192 : case AST::MacroMatchRepetition::MacroRepOp::ANY:
849 3192 : lo_str = "0";
850 3192 : hi_str = "+inf";
851 3192 : res = match_n_matches (parser, rep, match_amount);
852 3192 : break;
853 1102 : case AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE:
854 1102 : lo_str = "1";
855 1102 : hi_str = "+inf";
856 1102 : res = match_n_matches (parser, rep, match_amount, 1);
857 1102 : break;
858 492 : case AST::MacroMatchRepetition::MacroRepOp::ZERO_OR_ONE:
859 492 : lo_str = "0";
860 492 : hi_str = "1";
861 492 : res = match_n_matches (parser, rep, match_amount, 0, 1);
862 492 : break;
863 0 : default:
864 0 : rust_unreachable ();
865 : }
866 :
867 4801 : rust_debug_loc (rep.get_match_locus (), "%s matched %lu times",
868 : res ? "successfully" : "unsuccessfully",
869 : (unsigned long) match_amount);
870 :
871 4786 : match_repetition_skipped_metavars (rep);
872 :
873 4786 : return res;
874 4786 : }
875 :
876 : /**
877 : * Helper function to refactor calling a parsing function 0 or more times
878 : */
879 : static AST::Fragment
880 5435 : parse_many (Parser<MacroInvocLexer> &parser, TokenId delimiter,
881 : std::function<AST::SingleASTNode ()> parse_fn)
882 : {
883 5435 : auto &lexer = parser.get_token_source ();
884 5435 : auto start = lexer.get_offs ();
885 :
886 5435 : std::vector<AST::SingleASTNode> nodes;
887 13596 : while (true)
888 : {
889 38062 : if (parser.peek_current_token ()->get_id () == delimiter)
890 : break;
891 :
892 13600 : auto node = parse_fn ();
893 13600 : if (node.is_error ())
894 : {
895 9 : for (auto err : parser.get_errors ())
896 5 : err.emit ();
897 :
898 4 : return AST::Fragment::create_error ();
899 : }
900 :
901 13596 : nodes.emplace_back (std::move (node));
902 13600 : }
903 5431 : auto end = lexer.get_offs ();
904 :
905 5431 : return AST::Fragment (std::move (nodes), lexer.get_token_slice (start, end));
906 5435 : }
907 :
908 : /**
909 : * Transcribe 0 or more items from a macro invocation
910 : *
911 : * @param parser Parser to extract items from
912 : * @param delimiter Id of the token on which parsing should stop
913 : */
914 : static AST::Fragment
915 3756 : transcribe_many_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
916 : {
917 3756 : return parse_many (parser, delimiter, [&parser] () {
918 10769 : auto item = parser.parse_item (true);
919 10769 : if (!item)
920 1 : return AST::SingleASTNode (std::unique_ptr<AST::Item> (nullptr));
921 10768 : return AST::SingleASTNode (std::move (item.value ()));
922 3756 : });
923 : }
924 :
925 : /**
926 : * Transcribe 0 or more external items from a macro invocation
927 : *
928 : * @param parser Parser to extract items from
929 : * @param delimiter Id of the token on which parsing should stop
930 : */
931 : static AST::Fragment
932 2 : transcribe_many_ext (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
933 : {
934 2 : return parse_many (parser, delimiter, [&parser] () {
935 3 : auto item = parser.parse_external_item ();
936 3 : return AST::SingleASTNode (std::move (item));
937 5 : });
938 : }
939 :
940 : /**
941 : * Transcribe 0 or more trait items from a macro invocation
942 : *
943 : * @param parser Parser to extract items from
944 : * @param delimiter Id of the token on which parsing should stop
945 : */
946 : static AST::Fragment
947 1 : transcribe_many_trait_items (Parser<MacroInvocLexer> &parser,
948 : TokenId &delimiter)
949 : {
950 1 : return parse_many (parser, delimiter, [&parser] () {
951 2 : auto item = parser.parse_trait_item ();
952 2 : return AST::SingleASTNode (std::move (item));
953 3 : });
954 : }
955 :
956 : /**
957 : * Transcribe 0 or more impl items from a macro invocation
958 : *
959 : * @param parser Parser to extract items from
960 : * @param delimiter Id of the token on which parsing should stop
961 : */
962 : static AST::Fragment
963 1087 : transcribe_many_impl_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
964 : {
965 1087 : return parse_many (parser, delimiter, [&parser] () {
966 2006 : auto item = parser.parse_inherent_impl_item ();
967 2006 : return AST::SingleASTNode (std::move (item));
968 3093 : });
969 : }
970 :
971 : /**
972 : * Transcribe 0 or more trait impl items from a macro invocation
973 : *
974 : * @param parser Parser to extract items from
975 : * @param delimiter Id of the token on which parsing should stop
976 : */
977 : static AST::Fragment
978 64 : transcribe_many_trait_impl_items (Parser<MacroInvocLexer> &parser,
979 : TokenId &delimiter)
980 : {
981 64 : return parse_many (parser, delimiter, [&parser] () {
982 220 : auto item = parser.parse_trait_impl_item ();
983 220 : return AST::SingleASTNode (std::move (item));
984 284 : });
985 : }
986 :
987 : /**
988 : * Transcribe 0 or more statements from a macro invocation
989 : *
990 : * @param parser Parser to extract statements from
991 : * @param delimiter Id of the token on which parsing should stop
992 : */
993 : static AST::Fragment
994 525 : transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId delimiter,
995 : bool semicolon)
996 : {
997 525 : auto restrictions = ParseRestrictions ();
998 525 : restrictions.allow_close_after_expr_stmt = true;
999 :
1000 525 : return parse_many (parser, delimiter,
1001 525 : [&parser, restrictions, delimiter, semicolon] () {
1002 600 : auto stmt = parser.parse_stmt (restrictions);
1003 592 : if (semicolon && stmt
1004 1781 : && parser.peek_current_token ()->get_id ()
1005 589 : == delimiter)
1006 495 : stmt->add_semicolon ();
1007 :
1008 600 : return AST::SingleASTNode (std::move (stmt));
1009 1125 : });
1010 : }
1011 :
1012 : /**
1013 : * Transcribe one expression from a macro invocation
1014 : *
1015 : * @param parser Parser to extract statements from
1016 : */
1017 : static AST::Fragment
1018 49270 : transcribe_expression (Parser<MacroInvocLexer> &parser)
1019 : {
1020 49270 : auto &lexer = parser.get_token_source ();
1021 49270 : auto start = lexer.get_offs ();
1022 :
1023 49270 : auto attrs = parser.parse_outer_attributes ();
1024 49270 : auto expr = parser.parse_expr (std::move (attrs));
1025 49275 : for (auto error : parser.get_errors ())
1026 5 : error.emit ();
1027 49270 : if (!expr)
1028 1 : return AST::Fragment::create_error ();
1029 :
1030 : // FIXME: make this an error for some edititons
1031 98538 : if (parser.peek_current_token ()->get_id () == SEMICOLON)
1032 : {
1033 : // TODO bandaid for now, make this a member for MacroExpander instead in
1034 : // the future
1035 6994 : static std::unordered_set<location_t> warned_loc;
1036 6994 : auto locus = parser.peek_current_token ()->get_locus ();
1037 6994 : if (warned_loc.insert (locus).second)
1038 34 : rust_warning_at (
1039 68 : parser.peek_current_token ()->get_locus (), 0,
1040 : "trailing semicolon in macro used in expression context");
1041 6994 : parser.skip_token ();
1042 : }
1043 :
1044 49269 : auto end = lexer.get_offs ();
1045 :
1046 98538 : return AST::Fragment ({std::move (expr.value ())},
1047 197076 : lexer.get_token_slice (start, end));
1048 49270 : }
1049 :
1050 : /**
1051 : * Transcribe one type from a macro invocation
1052 : *
1053 : * @param parser Parser to extract statements from
1054 : */
1055 : static AST::Fragment
1056 497 : transcribe_type (Parser<MacroInvocLexer> &parser)
1057 : {
1058 497 : auto &lexer = parser.get_token_source ();
1059 497 : auto start = lexer.get_offs ();
1060 :
1061 497 : auto type = parser.parse_type (true);
1062 497 : for (auto err : parser.get_errors ())
1063 0 : err.emit ();
1064 497 : if (!type)
1065 0 : return AST::Fragment::create_error ();
1066 :
1067 497 : auto end = lexer.get_offs ();
1068 :
1069 994 : return AST::Fragment ({std::move (type)}, lexer.get_token_slice (start, end));
1070 497 : }
1071 :
1072 : /**
1073 : * Transcribe one pattern from a macro invocation
1074 : *
1075 : * @param parser Parser to extract statements from
1076 : */
1077 : static AST::Fragment
1078 4 : transcribe_pattern (Parser<MacroInvocLexer> &parser)
1079 : {
1080 4 : auto &lexer = parser.get_token_source ();
1081 4 : auto start = lexer.get_offs ();
1082 :
1083 4 : auto pattern = parser.parse_pattern ();
1084 8 : for (auto err : parser.get_errors ())
1085 4 : err.emit ();
1086 :
1087 4 : if (!pattern)
1088 2 : return AST::Fragment::create_error ();
1089 :
1090 2 : auto end = lexer.get_offs ();
1091 :
1092 4 : return AST::Fragment ({std::move (pattern)},
1093 6 : lexer.get_token_slice (start, end));
1094 4 : }
1095 :
1096 : static AST::Fragment
1097 55206 : transcribe_context (MacroExpander::ContextType ctx,
1098 : Parser<MacroInvocLexer> &parser, bool semicolon,
1099 : AST::DelimType delimiter, TokenId last_token_id)
1100 : {
1101 : // The flow-chart in order to choose a parsing function is as follows:
1102 : //
1103 : // [switch special context]
1104 : // -- Item --> parser.parse_item();
1105 : // -- Trait --> parser.parse_trait_item();
1106 : // -- Impl --> parser.parse_impl_item();
1107 : // -- Extern --> parser.parse_extern_item();
1108 : // -- Pattern --> parser.parse_pattern();
1109 : // -- None --> [has semicolon?]
1110 : // -- Yes --> parser.parse_stmt();
1111 : // -- No --> [switch invocation.delimiter()]
1112 : // -- { } --> parser.parse_stmt();
1113 : // -- _ --> parser.parse_expr(); // once!
1114 :
1115 : // If there is a semicolon OR we are expanding a MacroInvocationSemi, then
1116 : // we can parse multiple items. Otherwise, parse *one* expression
1117 :
1118 55206 : switch (ctx)
1119 : {
1120 3756 : case MacroExpander::ContextType::ITEM:
1121 3756 : return transcribe_many_items (parser, last_token_id);
1122 1 : break;
1123 1 : case MacroExpander::ContextType::TRAIT:
1124 1 : return transcribe_many_trait_items (parser, last_token_id);
1125 1087 : break;
1126 1087 : case MacroExpander::ContextType::IMPL:
1127 1087 : return transcribe_many_impl_items (parser, last_token_id);
1128 64 : break;
1129 64 : case MacroExpander::ContextType::TRAIT_IMPL:
1130 64 : return transcribe_many_trait_impl_items (parser, last_token_id);
1131 2 : break;
1132 2 : case MacroExpander::ContextType::EXTERN:
1133 2 : return transcribe_many_ext (parser, last_token_id);
1134 497 : break;
1135 497 : case MacroExpander::ContextType::TYPE:
1136 497 : return transcribe_type (parser);
1137 4 : case MacroExpander::ContextType::PATTERN:
1138 4 : return transcribe_pattern (parser);
1139 525 : break;
1140 525 : case MacroExpander::ContextType::STMT:
1141 525 : return transcribe_many_stmts (parser, last_token_id, semicolon);
1142 49270 : case MacroExpander::ContextType::EXPR:
1143 49270 : return transcribe_expression (parser);
1144 0 : default:
1145 0 : rust_unreachable ();
1146 : }
1147 : }
1148 :
1149 : static std::string
1150 55206 : tokens_to_str (std::vector<std::unique_ptr<AST::Token>> &tokens)
1151 : {
1152 55206 : std::string str;
1153 55206 : if (!tokens.empty ())
1154 : {
1155 110412 : str += tokens[0]->as_string ();
1156 2265518 : for (size_t i = 1; i < tokens.size (); i++)
1157 4420624 : str += " " + tokens[i]->as_string ();
1158 : }
1159 :
1160 55206 : return str;
1161 : }
1162 :
1163 : AST::Fragment
1164 55206 : MacroExpander::transcribe_rule (
1165 : AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
1166 : AST::DelimTokenTree &invoc_token_tree,
1167 : std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
1168 : AST::InvocKind invoc_kind, ContextType ctx)
1169 : {
1170 55206 : bool semicolon = invoc_kind == AST::InvocKind::Semicoloned;
1171 :
1172 : // we can manipulate the token tree to substitute the dollar identifiers so
1173 : // that when we call parse its already substituted for us
1174 55206 : AST::MacroTranscriber &transcriber = match_rule.get_transcriber ();
1175 55206 : AST::DelimTokenTree &transcribe_tree = transcriber.get_token_tree ();
1176 :
1177 55206 : auto invoc_stream = invoc_token_tree.to_token_stream ();
1178 55206 : auto macro_rule_tokens = transcribe_tree.to_token_stream ();
1179 :
1180 55206 : auto substitute_context
1181 : = SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments,
1182 55206 : definition, invoc_token_tree.get_locus ());
1183 55206 : std::vector<std::unique_ptr<AST::Token>> substituted_tokens
1184 55206 : = substitute_context.substitute_tokens ();
1185 :
1186 55206 : rust_debug ("substituted tokens: %s",
1187 : tokens_to_str (substituted_tokens).c_str ());
1188 :
1189 : // parse it to an Fragment
1190 55206 : MacroInvocLexer lex (std::move (substituted_tokens));
1191 55206 : Parser<MacroInvocLexer> parser (lex);
1192 :
1193 55206 : auto last_token_id = TokenId::RIGHT_CURLY;
1194 :
1195 : // this is used so we can check that we delimit the stream correctly.
1196 55206 : switch (transcribe_tree.get_delim_type ())
1197 : {
1198 656 : case AST::DelimType::PARENS:
1199 656 : last_token_id = TokenId::RIGHT_PAREN;
1200 656 : rust_assert (parser.skip_token (LEFT_PAREN));
1201 : break;
1202 :
1203 54550 : case AST::DelimType::CURLY:
1204 54550 : rust_assert (parser.skip_token (LEFT_CURLY));
1205 : break;
1206 :
1207 0 : case AST::DelimType::SQUARE:
1208 0 : last_token_id = TokenId::RIGHT_SQUARE;
1209 0 : rust_assert (parser.skip_token (LEFT_SQUARE));
1210 : break;
1211 : }
1212 :
1213 : // see https://github.com/Rust-GCC/gccrs/issues/22
1214 : // TL;DR:
1215 : // - Treat all macro invocations with parentheses, (), or square brackets,
1216 : // [], as expressions.
1217 : // - If the macro invocation has curly brackets, {}, it may be parsed as a
1218 : // statement depending on the context.
1219 : // - If the macro invocation has a semicolon at the end, it must be parsed
1220 : // as a statement (either via ExpressionStatement or
1221 : // MacroInvocationWithSemi)
1222 :
1223 55206 : auto fragment
1224 : = transcribe_context (ctx, parser, semicolon,
1225 55206 : invoc_token_tree.get_delim_type (), last_token_id);
1226 :
1227 : // emit any errors
1228 55206 : if (parser.has_errors ())
1229 12 : return AST::Fragment::create_error ();
1230 :
1231 : // are all the tokens used?
1232 55194 : bool did_delimit = parser.skip_token (last_token_id);
1233 :
1234 55194 : bool reached_end_of_stream = did_delimit && parser.skip_token (END_OF_FILE);
1235 0 : if (!reached_end_of_stream)
1236 : {
1237 : // FIXME: rustc has some cases it accepts this with a warning due to
1238 : // backwards compatibility.
1239 0 : const_TokenPtr current_token = parser.peek_current_token ();
1240 0 : rust_error_at (current_token->get_locus (),
1241 : "tokens here and after are unparsed");
1242 0 : }
1243 :
1244 55194 : return fragment;
1245 55206 : }
1246 :
1247 : AST::Fragment
1248 0 : MacroExpander::parse_proc_macro_output (ProcMacro::TokenStream ts)
1249 : {
1250 0 : MacroInvocLexer lex (convert (ts));
1251 0 : Parser<MacroInvocLexer> parser (lex);
1252 :
1253 0 : std::vector<AST::SingleASTNode> nodes;
1254 0 : switch (peek_context ())
1255 : {
1256 : case ContextType::ITEM:
1257 0 : while (lex.peek_token ()->get_id () != END_OF_FILE)
1258 : {
1259 0 : auto result = parser.parse_item (false);
1260 0 : if (!result)
1261 : break;
1262 0 : nodes.emplace_back (std::move (result.value ()));
1263 0 : }
1264 : break;
1265 : case ContextType::STMT:
1266 0 : while (lex.peek_token ()->get_id () != END_OF_FILE)
1267 : {
1268 0 : auto result = parser.parse_stmt ();
1269 0 : if (result == nullptr)
1270 : break;
1271 0 : nodes.emplace_back (std::move (result));
1272 0 : }
1273 : break;
1274 0 : case ContextType::TRAIT:
1275 0 : case ContextType::IMPL:
1276 0 : case ContextType::TRAIT_IMPL:
1277 0 : case ContextType::EXTERN:
1278 0 : case ContextType::TYPE:
1279 0 : case ContextType::EXPR:
1280 0 : default:
1281 0 : rust_unreachable ();
1282 : }
1283 :
1284 0 : if (parser.has_errors ())
1285 0 : return AST::Fragment::create_error ();
1286 : else
1287 0 : return {nodes, std::vector<std::unique_ptr<AST::Token>> ()};
1288 0 : }
1289 :
1290 : MatchedFragment &
1291 344423 : MatchedFragmentContainer::get_single_fragment ()
1292 : {
1293 344423 : rust_assert (is_single_fragment ());
1294 :
1295 344423 : return static_cast<MatchedFragmentContainerMetaVar &> (*this).get_fragment ();
1296 : }
1297 :
1298 : std::vector<std::unique_ptr<MatchedFragmentContainer>> &
1299 87676 : MatchedFragmentContainer::get_fragments ()
1300 : {
1301 87676 : rust_assert (!is_single_fragment ());
1302 :
1303 87676 : return static_cast<MatchedFragmentContainerRepetition &> (*this)
1304 87676 : .get_fragments ();
1305 : }
1306 :
1307 : void
1308 0 : MatchedFragmentContainer::add_fragment (MatchedFragment fragment)
1309 : {
1310 0 : rust_assert (!is_single_fragment ());
1311 :
1312 0 : return static_cast<MatchedFragmentContainerRepetition &> (*this)
1313 0 : .add_fragment (fragment);
1314 : }
1315 :
1316 : void
1317 31016 : MatchedFragmentContainer::add_fragment (
1318 : std::unique_ptr<MatchedFragmentContainer> fragment)
1319 : {
1320 31016 : rust_assert (!is_single_fragment ());
1321 :
1322 31016 : return static_cast<MatchedFragmentContainerRepetition &> (*this)
1323 31016 : .add_fragment (std::move (fragment));
1324 : }
1325 :
1326 : std::unique_ptr<MatchedFragmentContainer>
1327 128 : MatchedFragmentContainer::zero ()
1328 : {
1329 128 : return std::unique_ptr<MatchedFragmentContainer> (
1330 128 : new MatchedFragmentContainerRepetition ());
1331 : }
1332 :
1333 : std::unique_ptr<MatchedFragmentContainer>
1334 206261 : MatchedFragmentContainer::metavar (MatchedFragment fragment)
1335 : {
1336 206261 : return std::unique_ptr<MatchedFragmentContainer> (
1337 206261 : new MatchedFragmentContainerMetaVar (fragment));
1338 : }
1339 :
1340 : } // namespace Rust
|