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