Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #include "rust-macro-expand.h"
20 : : #include "optional.h"
21 : : #include "rust-ast-fragment.h"
22 : : #include "rust-macro-substitute-ctx.h"
23 : : #include "rust-ast-full.h"
24 : : #include "rust-ast-visitor.h"
25 : : #include "rust-diagnostics.h"
26 : : #include "rust-macro.h"
27 : : #include "rust-parse.h"
28 : : #include "rust-cfg-strip.h"
29 : : #include "rust-early-name-resolver.h"
30 : : #include "rust-proc-macro.h"
31 : : #include "rust-token-tree-desugar.h"
32 : :
33 : : namespace Rust {
34 : :
35 : : AST::Fragment
36 : 3482 : 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 : 3482 : rust_assert (!invoc.is_marked_for_strip ());
43 : 3482 : rust_assert (!rules_def.is_marked_for_strip ());
44 : 3482 : 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 : 3482 : AST::DelimTokenTree &invoc_token_tree_sugar = invoc.get_delim_tok_tree ();
83 : :
84 : : // We must first desugar doc comments into proper attributes
85 : 3482 : auto invoc_token_tree = AST::TokenTreeDesugar ().go (invoc_token_tree_sugar);
86 : :
87 : : // find matching arm
88 : 3482 : AST::MacroRule *matched_rule = nullptr;
89 : 3482 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>>
90 : 3482 : matched_fragments;
91 : 5895 : for (auto &rule : rules_def.get_rules ())
92 : : {
93 : 5881 : sub_stack.push ();
94 : 5881 : bool did_match_rule = try_match_rule (rule, invoc_token_tree);
95 : 11762 : matched_fragments = sub_stack.pop ();
96 : :
97 : 5881 : 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 : 3482 : if (matched_rule == nullptr)
114 : : {
115 : 14 : rich_location r (line_table, invoc_locus);
116 : 14 : r.add_range (rules_def.get_locus ());
117 : 14 : rust_error_at (r, "Failed to match any rule within macro");
118 : 14 : return AST::Fragment::create_error ();
119 : 14 : }
120 : :
121 : 3468 : std::map<std::string, MatchedFragmentContainer *> matched_fragments_ptr;
122 : :
123 : 9443 : for (auto &ent : matched_fragments)
124 : 5975 : matched_fragments_ptr.emplace (ent.first, ent.second.get ());
125 : :
126 : 3468 : return transcribe_rule (rules_def, *matched_rule, invoc_token_tree,
127 : 3468 : matched_fragments_ptr, semicolon, peek_context ());
128 : 6950 : }
129 : :
130 : : void
131 : 356 : MacroExpander::expand_eager_invocations (AST::MacroInvocation &invoc)
132 : : {
133 : 356 : if (invoc.get_pending_eager_invocations ().empty ())
134 : 307 : return;
135 : :
136 : : // We have to basically create a new delimited token tree which contains the
137 : : // result of one step of expansion. In the case of builtin macros called with
138 : : // other macro invocations, such as `concat!("h", 'a', a!())`, we need to
139 : : // expand `a!()` before expanding the concat macro.
140 : : // This will, ideally, give us a new token tree containing the various
141 : : // existing tokens + the result of the expansion of a!().
142 : : // To do this, we "parse" the given token tree to find anything that "looks
143 : : // like a macro invocation". Then, we get the corresponding macro invocation
144 : : // from the `pending_eager_invocations` vector and expand it.
145 : : // Because the `pending_eager_invocations` vector is created in the same order
146 : : // that the DelimTokenTree is parsed, we know that the first macro invocation
147 : : // within the DelimTokenTree corresponds to the first element in
148 : : // `pending_eager_invocations`. The idea is thus to:
149 : : // 1. Find a macro invocation in the token tree, noting the index of the start
150 : : // token and of the end token
151 : : // 2. Get its associated invocation in `pending_eager_invocations`
152 : : // 3. Expand that element
153 : : // 4. Get the token tree associated with that AST fragment
154 : : // 5. Replace the original tokens corresponding to the invocation with the new
155 : : // tokens from the fragment
156 : : // pseudo-code:
157 : : //
158 : : // i = 0;
159 : : // for tok in dtt:
160 : : // if tok is identifier && tok->next() is !:
161 : : // start = index(tok);
162 : : // l_delim = tok->next()->next();
163 : : // tok = skip_until_r_delim();
164 : : // end = index(tok);
165 : : //
166 : : // new_tt = expand_eager_invoc(eagers[i++]);
167 : : // old_tt[start..end] = new_tt;
168 : :
169 : 49 : auto dtt = invoc.get_invoc_data ().get_delim_tok_tree ();
170 : 49 : auto stream = dtt.to_token_stream ();
171 : 49 : std::vector<std::unique_ptr<AST::TokenTree>> new_stream;
172 : 49 : size_t current_pending = 0;
173 : :
174 : : // we need to create a clone of the delimited token tree as the lexer
175 : : // expects ownership of the tokens
176 : 49 : std::vector<std::unique_ptr<Rust::AST::Token>> dtt_clone;
177 : 432 : for (auto &tok : stream)
178 : 383 : dtt_clone.emplace_back (tok->clone_token ());
179 : :
180 : 49 : MacroInvocLexer lex (std::move (dtt_clone));
181 : 49 : Parser<MacroInvocLexer> parser (lex);
182 : :
183 : : // we want to build a substitution map - basically, associating a `start` and
184 : : // `end` index for each of the pending macro invocations
185 : 49 : std::map<std::pair<size_t, size_t>, std::unique_ptr<AST::MacroInvocation> &>
186 : 49 : substitution_map;
187 : :
188 : 432 : for (size_t i = 0; i < stream.size (); i++)
189 : : {
190 : : // FIXME: Can't these offsets be figure out when we actually parse the
191 : : // pending_eager_invocation in the first place?
192 : 383 : auto invocation = parser.parse_macro_invocation ({});
193 : :
194 : : // if we've managed to parse a macro invocation, we look at the current
195 : : // offset and store them in the substitution map. Otherwise, we skip one
196 : : // token and try parsing again
197 : 383 : if (invocation)
198 : 55 : substitution_map.insert (
199 : 55 : {{i, parser.get_token_source ().get_offs ()},
200 : 55 : invoc.get_pending_eager_invocations ()[current_pending++]});
201 : : else
202 : 328 : parser.skip_token (stream[i]->get_id ());
203 : 383 : }
204 : :
205 : 49 : size_t current_idx = 0;
206 : 104 : for (auto kv : substitution_map)
207 : : {
208 : 55 : auto &to_expand = kv.second;
209 : 55 : expand_invoc (*to_expand, AST::InvocKind::Expr);
210 : :
211 : 55 : auto fragment = take_expanded_fragment ();
212 : 55 : auto &new_tokens = fragment.get_tokens ();
213 : :
214 : 55 : auto start = kv.first.first;
215 : 55 : auto end = kv.first.second;
216 : :
217 : : // We're now going to re-add the tokens to the invocation's token tree.
218 : : // 1. Basically, what we want to do is insert all tokens up until the
219 : : // beginning of the macro invocation (start).
220 : : // 2. Then, we'll insert all of the tokens resulting from the macro
221 : : // expansion: These are in `new_tokens`.
222 : : // 3. Finally, we'll do that again from
223 : : // the end of macro and go back to 1.
224 : :
225 : 122 : for (size_t i = current_idx; i < start; i++)
226 : 67 : new_stream.emplace_back (stream[i]->clone_token ());
227 : :
228 : 110 : for (auto &tok : new_tokens)
229 : 55 : new_stream.emplace_back (tok->clone_token ());
230 : :
231 : 55 : current_idx = end;
232 : 55 : }
233 : :
234 : : // Once all of that is done, we copy the last remaining tokens from the
235 : : // original stream
236 : 127 : for (size_t i = current_idx; i < stream.size (); i++)
237 : 78 : new_stream.emplace_back (stream[i]->clone_token ());
238 : :
239 : 49 : auto new_dtt
240 : 49 : = AST::DelimTokenTree (dtt.get_delim_type (), std::move (new_stream));
241 : :
242 : 49 : invoc.get_pending_eager_invocations ().clear ();
243 : 49 : invoc.get_invoc_data ().set_delim_tok_tree (new_dtt);
244 : 98 : }
245 : :
246 : : void
247 : 3961 : MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
248 : : AST::InvocKind semicolon)
249 : : {
250 : 3961 : if (depth_exceeds_recursion_limit ())
251 : : {
252 : 0 : rust_error_at (invoc.get_locus (), "reached recursion limit");
253 : 26 : return;
254 : : }
255 : :
256 : 3961 : if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
257 : : {
258 : : // Eager expansions are always expressions
259 : 356 : push_context (ContextType::EXPR);
260 : 356 : expand_eager_invocations (invoc);
261 : 356 : pop_context ();
262 : : }
263 : :
264 : 3961 : AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
265 : :
266 : : // ??
267 : : // switch on type of macro:
268 : : // - '!' syntax macro (inner switch)
269 : : // - procedural macro - "A token-based function-like macro"
270 : : // - 'macro_rules' (by example/pattern-match) macro? or not? "an
271 : : // AST-based function-like macro"
272 : : // - else is unreachable
273 : : // - attribute syntax macro (inner switch)
274 : : // - procedural macro attribute syntax - "A token-based attribute
275 : : // macro"
276 : : // - legacy macro attribute syntax? - "an AST-based attribute macro"
277 : : // - non-macro attribute: mark known
278 : : // - else is unreachable
279 : : // - derive macro (inner switch)
280 : : // - derive or legacy derive - "token-based" vs "AST-based"
281 : : // - else is unreachable
282 : : // - derive container macro - unreachable
283 : :
284 : 3961 : auto fragment = AST::Fragment::create_error ();
285 : 3961 : invoc_data.set_expander (this);
286 : :
287 : : // lookup the rules
288 : 3961 : auto rules_def = mappings.lookup_macro_invocation (invoc);
289 : :
290 : : // If there's no rule associated with the invocation, we can simply return
291 : : // early. The early name resolver will have already emitted an error.
292 : 3961 : if (!rules_def)
293 : 26 : return;
294 : :
295 : 3935 : auto rdef = rules_def.value ();
296 : :
297 : : // We store the last expanded invocation and macro definition for error
298 : : // reporting in case the recursion limit is reached
299 : 3935 : last_invoc = *invoc.clone_macro_invocation_impl ();
300 : 3935 : last_def = *rdef;
301 : :
302 : 3935 : if (rdef->is_builtin ())
303 : 453 : fragment = rdef
304 : 453 : ->get_builtin_transcriber () (invoc.get_locus (), invoc_data,
305 : : semicolon)
306 : 1359 : .value_or (AST::Fragment::create_empty ());
307 : : else
308 : 3482 : fragment
309 : 6964 : = expand_decl_macro (invoc.get_locus (), invoc_data, *rdef, semicolon);
310 : :
311 : 3935 : set_expanded_fragment (std::move (fragment));
312 : 3961 : }
313 : :
314 : : void
315 : 0 : MacroExpander::expand_crate ()
316 : : {
317 : 0 : NodeId scope_node_id = crate.get_node_id ();
318 : 0 : resolver->get_macro_scope ().push (scope_node_id);
319 : :
320 : : /* fill macro/decorator map from init list? not sure where init list comes
321 : : * from? */
322 : :
323 : : // TODO: does cfg apply for inner attributes? research.
324 : : // the apparent answer (from playground test) is yes
325 : :
326 : 0 : push_context (ContextType::ITEM);
327 : :
328 : : // expand attributes recursively and strip items if required
329 : : // AttrVisitor attr_visitor (*this);
330 : 0 : auto &items = crate.items;
331 : 0 : for (auto it = items.begin (); it != items.end ();)
332 : : {
333 : 0 : auto &item = *it;
334 : :
335 : 0 : auto fragment = take_expanded_fragment ();
336 : 0 : if (fragment.should_expand ())
337 : : {
338 : : // Remove the current expanded invocation
339 : 0 : it = items.erase (it);
340 : 0 : for (auto &node : fragment.get_nodes ())
341 : : {
342 : 0 : it = items.insert (it, node.take_item ());
343 : 0 : it++;
344 : : }
345 : : }
346 : 0 : else if (item->is_marked_for_strip ())
347 : 0 : it = items.erase (it);
348 : : else
349 : 0 : it++;
350 : 0 : }
351 : :
352 : 0 : pop_context ();
353 : :
354 : : // TODO: should recursive attribute and macro expansion be done in the same
355 : : // transversal? Or in separate ones like currently?
356 : :
357 : : // expand module tree recursively
358 : :
359 : : // post-process
360 : :
361 : : // extract exported macros?
362 : 0 : }
363 : :
364 : : bool
365 : 9983 : MacroExpander::depth_exceeds_recursion_limit () const
366 : : {
367 : 9983 : return expansion_depth >= cfg.recursion_limit;
368 : : }
369 : :
370 : : bool
371 : 5881 : MacroExpander::try_match_rule (AST::MacroRule &match_rule,
372 : : AST::DelimTokenTree &invoc_token_tree)
373 : : {
374 : 5881 : MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
375 : 5881 : Parser<MacroInvocLexer> parser (lex);
376 : :
377 : 5881 : AST::MacroMatcher &matcher = match_rule.get_matcher ();
378 : :
379 : 5881 : expansion_depth++;
380 : 5881 : if (!match_matcher (parser, matcher, false, false))
381 : : {
382 : 2413 : expansion_depth--;
383 : 2413 : return false;
384 : : }
385 : 3468 : expansion_depth--;
386 : :
387 : 3468 : bool used_all_input_tokens = parser.skip_token (END_OF_FILE);
388 : 3468 : return used_all_input_tokens;
389 : 5881 : }
390 : :
391 : : bool
392 : 11402 : MacroExpander::match_fragment (Parser<MacroInvocLexer> &parser,
393 : : AST::MacroMatchFragment &fragment)
394 : : {
395 : 11402 : switch (fragment.get_frag_spec ().get_kind ())
396 : : {
397 : 734 : case AST::MacroFragSpec::EXPR:
398 : 734 : parser.parse_expr ();
399 : 734 : break;
400 : :
401 : 4 : case AST::MacroFragSpec::BLOCK:
402 : 4 : parser.parse_block_expr ();
403 : 4 : break;
404 : :
405 : 661 : case AST::MacroFragSpec::IDENT:
406 : 661 : parser.parse_identifier_or_keyword_token ();
407 : 661 : break;
408 : :
409 : 6561 : case AST::MacroFragSpec::LITERAL:
410 : 6561 : parser.parse_literal_expr ();
411 : 6561 : break;
412 : :
413 : 2 : case AST::MacroFragSpec::ITEM:
414 : 2 : parser.parse_item (false);
415 : 2 : break;
416 : :
417 : 2718 : case AST::MacroFragSpec::TY:
418 : 2718 : parser.parse_type ();
419 : 2718 : break;
420 : :
421 : 14 : case AST::MacroFragSpec::PAT:
422 : 14 : parser.parse_pattern ();
423 : 14 : break;
424 : :
425 : 0 : case AST::MacroFragSpec::PATH:
426 : 0 : parser.parse_path_in_expression ();
427 : 0 : break;
428 : :
429 : 0 : case AST::MacroFragSpec::VIS:
430 : 0 : parser.parse_visibility ();
431 : 0 : break;
432 : :
433 : 328 : case AST::MacroFragSpec::STMT: {
434 : 328 : auto restrictions = ParseRestrictions ();
435 : 328 : restrictions.consume_semi = false;
436 : 328 : parser.parse_stmt (restrictions);
437 : 328 : break;
438 : : }
439 : :
440 : 8 : case AST::MacroFragSpec::LIFETIME:
441 : 8 : parser.parse_lifetime_params ();
442 : 8 : break;
443 : :
444 : : // is meta attributes?
445 : 76 : case AST::MacroFragSpec::META:
446 : 76 : parser.parse_attribute_body ();
447 : 76 : break;
448 : :
449 : 296 : case AST::MacroFragSpec::TT:
450 : 296 : parser.parse_token_tree ();
451 : 296 : break;
452 : :
453 : : // i guess we just ignore invalid and just error out
454 : : case AST::MacroFragSpec::INVALID:
455 : : return false;
456 : : }
457 : :
458 : : // it matches if the parser did not produce errors trying to parse that type
459 : : // of item
460 : 11402 : return !parser.has_errors ();
461 : : }
462 : :
463 : : bool
464 : 6022 : MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
465 : : AST::MacroMatcher &matcher, bool in_repetition,
466 : : bool match_delim)
467 : : {
468 : 6022 : if (depth_exceeds_recursion_limit ())
469 : : {
470 : 0 : rust_error_at (matcher.get_match_locus (), "reached recursion limit");
471 : 0 : return false;
472 : : }
473 : :
474 : 6022 : auto delimiter = parser.peek_current_token ();
475 : :
476 : 12036 : auto check_delim = [&matcher, match_delim] (AST::DelimType delim) {
477 : 133 : return !match_delim || matcher.get_delim_type () == delim;
478 : 6022 : };
479 : :
480 : : // this is used so we can check that we delimit the stream correctly.
481 : 6022 : switch (delimiter->get_id ())
482 : : {
483 : 5627 : case LEFT_PAREN: {
484 : 5627 : if (!check_delim (AST::DelimType::PARENS))
485 : : return false;
486 : : }
487 : : break;
488 : :
489 : 78 : case LEFT_SQUARE: {
490 : 78 : if (!check_delim (AST::DelimType::SQUARE))
491 : : return false;
492 : : }
493 : : break;
494 : :
495 : 309 : case LEFT_CURLY: {
496 : 2732 : if (!check_delim (AST::DelimType::CURLY))
497 : : return false;
498 : : }
499 : : break;
500 : : default:
501 : : return false;
502 : : }
503 : 6012 : parser.skip_token ();
504 : :
505 : 6012 : const MacroInvocLexer &source = parser.get_token_source ();
506 : :
507 : 15741 : for (auto &match : matcher.get_matches ())
508 : : {
509 : 9785 : size_t offs_begin = source.get_offs ();
510 : :
511 : 9785 : switch (match->get_macro_match_type ())
512 : : {
513 : 5675 : case AST::MacroMatch::MacroMatchType::Fragment: {
514 : 5675 : AST::MacroMatchFragment *fragment
515 : 5675 : = static_cast<AST::MacroMatchFragment *> (match.get ());
516 : 5675 : if (!match_fragment (parser, *fragment))
517 : 6022 : return false;
518 : :
519 : : // matched fragment get the offset in the token stream
520 : 5673 : size_t offs_end = source.get_offs ();
521 : 11346 : sub_stack.insert_metavar (
522 : 11346 : MatchedFragment (fragment->get_ident ().as_string (), offs_begin,
523 : 17019 : offs_end));
524 : : }
525 : 5673 : break;
526 : :
527 : 1225 : case AST::MacroMatch::MacroMatchType::Tok: {
528 : 1225 : AST::Token *tok = static_cast<AST::Token *> (match.get ());
529 : 1225 : if (!match_token (parser, *tok))
530 : : return false;
531 : : }
532 : : break;
533 : :
534 : 2789 : case AST::MacroMatch::MacroMatchType::Repetition: {
535 : 2789 : AST::MacroMatchRepetition *rep
536 : 2789 : = static_cast<AST::MacroMatchRepetition *> (match.get ());
537 : 2789 : if (!match_repetition (parser, *rep))
538 : : return false;
539 : : }
540 : : break;
541 : :
542 : 96 : case AST::MacroMatch::MacroMatchType::Matcher: {
543 : 96 : AST::MacroMatcher *m
544 : 96 : = static_cast<AST::MacroMatcher *> (match.get ());
545 : 96 : expansion_depth++;
546 : 96 : if (!match_matcher (parser, *m, in_repetition))
547 : : {
548 : 6 : expansion_depth--;
549 : 6 : return false;
550 : : }
551 : 90 : expansion_depth--;
552 : : }
553 : 90 : break;
554 : : }
555 : : }
556 : :
557 : 5956 : switch (delimiter->get_id ())
558 : : {
559 : 5569 : case LEFT_PAREN: {
560 : 5569 : if (!parser.skip_token (RIGHT_PAREN))
561 : : return false;
562 : : }
563 : : break;
564 : :
565 : 78 : case LEFT_SQUARE: {
566 : 78 : if (!parser.skip_token (RIGHT_SQUARE))
567 : : return false;
568 : : }
569 : : break;
570 : :
571 : 309 : case LEFT_CURLY: {
572 : 309 : if (!parser.skip_token (RIGHT_CURLY))
573 : : return false;
574 : : }
575 : : break;
576 : 0 : default:
577 : 0 : rust_unreachable ();
578 : : }
579 : :
580 : : return true;
581 : 6022 : }
582 : :
583 : : bool
584 : 3927 : MacroExpander::match_token (Parser<MacroInvocLexer> &parser, AST::Token &token)
585 : : {
586 : 7854 : return parser.skip_token (token.get_tok_ptr ());
587 : : }
588 : :
589 : : bool
590 : 2817 : MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
591 : : AST::MacroMatchRepetition &rep,
592 : : size_t &match_amount, size_t lo_bound,
593 : : size_t hi_bound)
594 : : {
595 : 2817 : match_amount = 0;
596 : 2817 : auto &matches = rep.get_matches ();
597 : :
598 : 2817 : const MacroInvocLexer &source = parser.get_token_source ();
599 : 13869 : while (true)
600 : : {
601 : : // If the current token is a closing macro delimiter, break away.
602 : : // TODO: Is this correct?
603 : 8343 : auto t_id = parser.peek_current_token ()->get_id ();
604 : 8343 : if (t_id == RIGHT_PAREN || t_id == RIGHT_SQUARE || t_id == RIGHT_CURLY)
605 : : break;
606 : :
607 : : // Skip parsing a separator on the first match, otherwise consume it.
608 : : // If it isn't present, this is an error
609 : 5571 : if (rep.has_sep () && match_amount > 0)
610 : 385 : if (!match_token (parser, *rep.get_sep ()))
611 : : break;
612 : :
613 : 5548 : sub_stack.push ();
614 : 5548 : bool valid_current_match = false;
615 : 13665 : for (auto &match : matches)
616 : : {
617 : 8117 : size_t offs_begin = source.get_offs ();
618 : 8117 : switch (match->get_macro_match_type ())
619 : : {
620 : 5727 : case AST::MacroMatch::MacroMatchType::Fragment: {
621 : 5727 : AST::MacroMatchFragment *fragment
622 : 5727 : = static_cast<AST::MacroMatchFragment *> (match.get ());
623 : 5727 : valid_current_match = match_fragment (parser, *fragment);
624 : :
625 : : // matched fragment get the offset in the token stream
626 : 5727 : size_t offs_end = source.get_offs ();
627 : :
628 : 5727 : if (valid_current_match)
629 : 11430 : sub_stack.insert_metavar (
630 : 11430 : MatchedFragment (fragment->get_ident ().as_string (),
631 : 17145 : offs_begin, offs_end));
632 : : }
633 : : break;
634 : :
635 : 2317 : case AST::MacroMatch::MacroMatchType::Tok: {
636 : 2317 : AST::Token *tok = static_cast<AST::Token *> (match.get ());
637 : 2317 : valid_current_match = match_token (parser, *tok);
638 : : }
639 : 2317 : break;
640 : :
641 : 28 : case AST::MacroMatch::MacroMatchType::Repetition: {
642 : 28 : AST::MacroMatchRepetition *rep
643 : 28 : = static_cast<AST::MacroMatchRepetition *> (match.get ());
644 : 28 : valid_current_match = match_repetition (parser, *rep);
645 : : }
646 : 28 : break;
647 : :
648 : 45 : case AST::MacroMatch::MacroMatchType::Matcher: {
649 : 45 : AST::MacroMatcher *m
650 : 45 : = static_cast<AST::MacroMatcher *> (match.get ());
651 : 45 : valid_current_match = match_matcher (parser, *m, true);
652 : : }
653 : 45 : break;
654 : : }
655 : : }
656 : 5548 : auto old_stack = sub_stack.pop ();
657 : :
658 : : // If we've encountered an error once, stop trying to match more
659 : : // repetitions
660 : 5548 : if (!valid_current_match)
661 : : break;
662 : :
663 : : // nest metavars into repetitions
664 : 11291 : for (auto &ent : old_stack)
665 : 11526 : sub_stack.append_fragment (ent.first, std::move (ent.second));
666 : :
667 : 5528 : match_amount++;
668 : :
669 : : // Break early if we notice there's too many expressions already
670 : 5528 : if (hi_bound && match_amount > hi_bound)
671 : : break;
672 : 5548 : }
673 : :
674 : : // Check if the amount of matches we got is valid: Is it more than the lower
675 : : // bound and less than the higher bound?
676 : 2817 : bool did_meet_lo_bound = match_amount >= lo_bound;
677 : 2817 : bool did_meet_hi_bound = hi_bound ? match_amount <= hi_bound : true;
678 : :
679 : : // If the end-result is valid, then we can clear the parse errors: Since
680 : : // repetitions are parsed eagerly, it is okay to fail in some cases
681 : 5632 : auto res = did_meet_lo_bound && did_meet_hi_bound;
682 : 2815 : if (res)
683 : 2807 : parser.clear_errors ();
684 : :
685 : 2817 : return res;
686 : : }
687 : :
688 : : /*
689 : : * Helper function for defining unmatched repetition metavars
690 : : */
691 : : void
692 : 5104 : MacroExpander::match_repetition_skipped_metavars (AST::MacroMatch &match)
693 : : {
694 : : // We have to handle zero fragments differently: They will not have been
695 : : // "matched" but they are still valid and should be inserted as a special
696 : : // case. So we go through the stack map, and for every fragment which doesn't
697 : : // exist, insert a zero-matched fragment.
698 : 5104 : switch (match.get_macro_match_type ())
699 : : {
700 : 2886 : case AST::MacroMatch::MacroMatchType::Fragment:
701 : 2886 : match_repetition_skipped_metavars (
702 : : static_cast<AST::MacroMatchFragment &> (match));
703 : 2886 : break;
704 : 24 : case AST::MacroMatch::MacroMatchType::Repetition:
705 : 24 : match_repetition_skipped_metavars (
706 : : static_cast<AST::MacroMatchRepetition &> (match));
707 : 24 : break;
708 : 19 : case AST::MacroMatch::MacroMatchType::Matcher:
709 : 19 : match_repetition_skipped_metavars (
710 : : static_cast<AST::MacroMatcher &> (match));
711 : 19 : break;
712 : : case AST::MacroMatch::MacroMatchType::Tok:
713 : : break;
714 : : }
715 : 5104 : }
716 : :
717 : : void
718 : 2886 : MacroExpander::match_repetition_skipped_metavars (
719 : : AST::MacroMatchFragment &fragment)
720 : : {
721 : 2886 : auto &stack_map = sub_stack.peek ();
722 : 2886 : auto it = stack_map.find (fragment.get_ident ().as_string ());
723 : :
724 : 2886 : if (it == stack_map.end ())
725 : 124 : sub_stack.insert_matches (fragment.get_ident ().as_string (),
726 : 124 : MatchedFragmentContainer::zero ());
727 : 2886 : }
728 : :
729 : : void
730 : 2841 : MacroExpander::match_repetition_skipped_metavars (
731 : : AST::MacroMatchRepetition &rep)
732 : : {
733 : 7933 : for (auto &match : rep.get_matches ())
734 : 5092 : match_repetition_skipped_metavars (*match);
735 : 2841 : }
736 : :
737 : : void
738 : 19 : MacroExpander::match_repetition_skipped_metavars (AST::MacroMatcher &rep)
739 : : {
740 : 31 : for (auto &match : rep.get_matches ())
741 : 12 : match_repetition_skipped_metavars (*match);
742 : 19 : }
743 : :
744 : : bool
745 : 2817 : MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
746 : : AST::MacroMatchRepetition &rep)
747 : : {
748 : 2817 : size_t match_amount = 0;
749 : 2817 : bool res = false;
750 : :
751 : 2817 : std::string lo_str;
752 : 2817 : std::string hi_str;
753 : 2817 : switch (rep.get_op ())
754 : : {
755 : 2635 : case AST::MacroMatchRepetition::MacroRepOp::ANY:
756 : 2635 : lo_str = "0";
757 : 2635 : hi_str = "+inf";
758 : 2635 : res = match_n_matches (parser, rep, match_amount);
759 : 2635 : break;
760 : 136 : case AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE:
761 : 136 : lo_str = "1";
762 : 136 : hi_str = "+inf";
763 : 136 : res = match_n_matches (parser, rep, match_amount, 1);
764 : 136 : break;
765 : 46 : case AST::MacroMatchRepetition::MacroRepOp::ZERO_OR_ONE:
766 : 46 : lo_str = "0";
767 : 46 : hi_str = "1";
768 : 46 : res = match_n_matches (parser, rep, match_amount, 0, 1);
769 : 46 : break;
770 : 0 : default:
771 : 0 : rust_unreachable ();
772 : : }
773 : :
774 : 2827 : rust_debug_loc (rep.get_match_locus (), "%s matched %lu times",
775 : : res ? "successfully" : "unsuccessfully",
776 : : (unsigned long) match_amount);
777 : :
778 : 2817 : match_repetition_skipped_metavars (rep);
779 : :
780 : 2817 : return res;
781 : 2817 : }
782 : :
783 : : /**
784 : : * Helper function to refactor calling a parsing function 0 or more times
785 : : */
786 : : static AST::Fragment
787 : 820 : parse_many (Parser<MacroInvocLexer> &parser, TokenId delimiter,
788 : : std::function<AST::SingleASTNode ()> parse_fn)
789 : : {
790 : 820 : auto &lexer = parser.get_token_source ();
791 : 820 : auto start = lexer.get_offs ();
792 : :
793 : 820 : std::vector<AST::SingleASTNode> nodes;
794 : 3458 : while (true)
795 : : {
796 : 8556 : if (parser.peek_current_token ()->get_id () == delimiter)
797 : : break;
798 : :
799 : 3464 : auto node = parse_fn ();
800 : 3464 : if (node.is_error ())
801 : : {
802 : 14 : for (auto err : parser.get_errors ())
803 : 8 : err.emit ();
804 : :
805 : 6 : return AST::Fragment::create_error ();
806 : : }
807 : :
808 : 3458 : nodes.emplace_back (std::move (node));
809 : 3464 : }
810 : 814 : auto end = lexer.get_offs ();
811 : :
812 : 814 : return AST::Fragment (std::move (nodes), lexer.get_token_slice (start, end));
813 : 820 : }
814 : :
815 : : /**
816 : : * Transcribe 0 or more items from a macro invocation
817 : : *
818 : : * @param parser Parser to extract items from
819 : : * @param delimiter Id of the token on which parsing should stop
820 : : */
821 : : static AST::Fragment
822 : 429 : transcribe_many_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
823 : : {
824 : 429 : return parse_many (parser, delimiter, [&parser] () {
825 : 2909 : auto item = parser.parse_item (true);
826 : 2909 : return AST::SingleASTNode (std::move (item));
827 : 3338 : });
828 : : }
829 : :
830 : : /**
831 : : * Transcribe 0 or more external items from a macro invocation
832 : : *
833 : : * @param parser Parser to extract items from
834 : : * @param delimiter Id of the token on which parsing should stop
835 : : */
836 : : static AST::Fragment
837 : 4 : transcribe_many_ext (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
838 : : {
839 : 4 : return parse_many (parser, delimiter, [&parser] () {
840 : 6 : auto item = parser.parse_external_item ();
841 : 6 : return AST::SingleASTNode (std::move (item));
842 : 10 : });
843 : : }
844 : :
845 : : /**
846 : : * Transcribe 0 or more trait items from a macro invocation
847 : : *
848 : : * @param parser Parser to extract items from
849 : : * @param delimiter Id of the token on which parsing should stop
850 : : */
851 : : static AST::Fragment
852 : 2 : transcribe_many_trait_items (Parser<MacroInvocLexer> &parser,
853 : : TokenId &delimiter)
854 : : {
855 : 2 : return parse_many (parser, delimiter, [&parser] () {
856 : 4 : auto item = parser.parse_trait_item ();
857 : 4 : return AST::SingleASTNode (std::move (item));
858 : 6 : });
859 : : }
860 : :
861 : : /**
862 : : * Transcribe 0 or more impl items from a macro invocation
863 : : *
864 : : * @param parser Parser to extract items from
865 : : * @param delimiter Id of the token on which parsing should stop
866 : : */
867 : : static AST::Fragment
868 : 2 : transcribe_many_impl_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
869 : : {
870 : 2 : return parse_many (parser, delimiter, [&parser] () {
871 : 4 : auto item = parser.parse_inherent_impl_item ();
872 : 4 : return AST::SingleASTNode (std::move (item));
873 : 6 : });
874 : : }
875 : :
876 : : /**
877 : : * Transcribe 0 or more trait impl items from a macro invocation
878 : : *
879 : : * @param parser Parser to extract items from
880 : : * @param delimiter Id of the token on which parsing should stop
881 : : */
882 : : static AST::Fragment
883 : 34 : transcribe_many_trait_impl_items (Parser<MacroInvocLexer> &parser,
884 : : TokenId &delimiter)
885 : : {
886 : 34 : return parse_many (parser, delimiter, [&parser] () {
887 : 115 : auto item = parser.parse_trait_impl_item ();
888 : 115 : return AST::SingleASTNode (std::move (item));
889 : 149 : });
890 : : }
891 : :
892 : : /**
893 : : * Transcribe 0 or more statements from a macro invocation
894 : : *
895 : : * @param parser Parser to extract statements from
896 : : * @param delimiter Id of the token on which parsing should stop
897 : : */
898 : : static AST::Fragment
899 : 349 : transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId delimiter,
900 : : bool semicolon)
901 : : {
902 : 349 : auto restrictions = ParseRestrictions ();
903 : 349 : restrictions.allow_close_after_expr_stmt = true;
904 : :
905 : 349 : return parse_many (parser, delimiter,
906 : 349 : [&parser, restrictions, delimiter, semicolon] () {
907 : 426 : auto stmt = parser.parse_stmt (restrictions);
908 : 416 : if (semicolon && stmt
909 : 1254 : && parser.peek_current_token ()->get_id ()
910 : 412 : == delimiter)
911 : 300 : stmt->add_semicolon ();
912 : :
913 : 426 : return AST::SingleASTNode (std::move (stmt));
914 : 775 : });
915 : : }
916 : :
917 : : /**
918 : : * Transcribe one expression from a macro invocation
919 : : *
920 : : * @param parser Parser to extract statements from
921 : : */
922 : : static AST::Fragment
923 : 2615 : transcribe_expression (Parser<MacroInvocLexer> &parser)
924 : : {
925 : 2615 : auto &lexer = parser.get_token_source ();
926 : 2615 : auto start = lexer.get_offs ();
927 : :
928 : 2615 : auto expr = parser.parse_expr ();
929 : 2615 : if (expr == nullptr)
930 : 2 : return AST::Fragment::create_error ();
931 : :
932 : : // FIXME: make this an error for some edititons
933 : 5226 : if (parser.peek_current_token ()->get_id () == SEMICOLON)
934 : : {
935 : 2 : rust_warning_at (
936 : 2 : parser.peek_current_token ()->get_locus (), 0,
937 : : "trailing semicolon in macro used in expression context");
938 : 2 : parser.skip_token ();
939 : : }
940 : :
941 : 2613 : auto end = lexer.get_offs ();
942 : :
943 : 5226 : return AST::Fragment ({std::move (expr)}, lexer.get_token_slice (start, end));
944 : 2615 : }
945 : :
946 : : /**
947 : : * Transcribe one type from a macro invocation
948 : : *
949 : : * @param parser Parser to extract statements from
950 : : */
951 : : static AST::Fragment
952 : 33 : transcribe_type (Parser<MacroInvocLexer> &parser)
953 : : {
954 : 33 : auto &lexer = parser.get_token_source ();
955 : 33 : auto start = lexer.get_offs ();
956 : :
957 : 33 : auto type = parser.parse_type (true);
958 : 33 : for (auto err : parser.get_errors ())
959 : 0 : err.emit ();
960 : :
961 : 33 : auto end = lexer.get_offs ();
962 : :
963 : 66 : return AST::Fragment ({std::move (type)}, lexer.get_token_slice (start, end));
964 : 33 : }
965 : :
966 : : static AST::Fragment
967 : 3468 : transcribe_context (MacroExpander::ContextType ctx,
968 : : Parser<MacroInvocLexer> &parser, bool semicolon,
969 : : AST::DelimType delimiter, TokenId last_token_id)
970 : : {
971 : : // The flow-chart in order to choose a parsing function is as follows:
972 : : //
973 : : // [switch special context]
974 : : // -- Item --> parser.parse_item();
975 : : // -- Trait --> parser.parse_trait_item();
976 : : // -- Impl --> parser.parse_impl_item();
977 : : // -- Extern --> parser.parse_extern_item();
978 : : // -- None --> [has semicolon?]
979 : : // -- Yes --> parser.parse_stmt();
980 : : // -- No --> [switch invocation.delimiter()]
981 : : // -- { } --> parser.parse_stmt();
982 : : // -- _ --> parser.parse_expr(); // once!
983 : :
984 : : // If there is a semicolon OR we are expanding a MacroInvocationSemi, then
985 : : // we can parse multiple items. Otherwise, parse *one* expression
986 : :
987 : 3468 : switch (ctx)
988 : : {
989 : 429 : case MacroExpander::ContextType::ITEM:
990 : 429 : return transcribe_many_items (parser, last_token_id);
991 : 2 : break;
992 : 2 : case MacroExpander::ContextType::TRAIT:
993 : 2 : return transcribe_many_trait_items (parser, last_token_id);
994 : 2 : break;
995 : 2 : case MacroExpander::ContextType::IMPL:
996 : 2 : return transcribe_many_impl_items (parser, last_token_id);
997 : 34 : break;
998 : 34 : case MacroExpander::ContextType::TRAIT_IMPL:
999 : 34 : return transcribe_many_trait_impl_items (parser, last_token_id);
1000 : 4 : break;
1001 : 4 : case MacroExpander::ContextType::EXTERN:
1002 : 4 : return transcribe_many_ext (parser, last_token_id);
1003 : 33 : break;
1004 : 33 : case MacroExpander::ContextType::TYPE:
1005 : 33 : return transcribe_type (parser);
1006 : 349 : break;
1007 : 349 : case MacroExpander::ContextType::STMT:
1008 : 349 : return transcribe_many_stmts (parser, last_token_id, semicolon);
1009 : 2615 : case MacroExpander::ContextType::EXPR:
1010 : 2615 : return transcribe_expression (parser);
1011 : 0 : default:
1012 : 0 : rust_unreachable ();
1013 : : }
1014 : : }
1015 : :
1016 : : static std::string
1017 : 3468 : tokens_to_str (std::vector<std::unique_ptr<AST::Token>> &tokens)
1018 : : {
1019 : 3468 : std::string str;
1020 : 3468 : if (!tokens.empty ())
1021 : : {
1022 : 6936 : str += tokens[0]->as_string ();
1023 : 142396 : for (size_t i = 1; i < tokens.size (); i++)
1024 : 277856 : str += " " + tokens[i]->as_string ();
1025 : : }
1026 : :
1027 : 3468 : return str;
1028 : : }
1029 : :
1030 : : AST::Fragment
1031 : 3468 : MacroExpander::transcribe_rule (
1032 : : AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
1033 : : AST::DelimTokenTree &invoc_token_tree,
1034 : : std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
1035 : : AST::InvocKind invoc_kind, ContextType ctx)
1036 : : {
1037 : 3468 : bool semicolon = invoc_kind == AST::InvocKind::Semicoloned;
1038 : :
1039 : : // we can manipulate the token tree to substitute the dollar identifiers so
1040 : : // that when we call parse its already substituted for us
1041 : 3468 : AST::MacroTranscriber &transcriber = match_rule.get_transcriber ();
1042 : 3468 : AST::DelimTokenTree &transcribe_tree = transcriber.get_token_tree ();
1043 : :
1044 : 3468 : auto invoc_stream = invoc_token_tree.to_token_stream ();
1045 : 3468 : auto macro_rule_tokens = transcribe_tree.to_token_stream ();
1046 : :
1047 : 3468 : auto substitute_context = SubstituteCtx (invoc_stream, macro_rule_tokens,
1048 : 3468 : matched_fragments, definition);
1049 : 3468 : std::vector<std::unique_ptr<AST::Token>> substituted_tokens
1050 : 3468 : = substitute_context.substitute_tokens ();
1051 : :
1052 : 3468 : rust_debug ("substituted tokens: %s",
1053 : : tokens_to_str (substituted_tokens).c_str ());
1054 : :
1055 : : // parse it to an Fragment
1056 : 3468 : MacroInvocLexer lex (std::move (substituted_tokens));
1057 : 3468 : Parser<MacroInvocLexer> parser (lex);
1058 : :
1059 : 3468 : auto last_token_id = TokenId::RIGHT_CURLY;
1060 : :
1061 : : // this is used so we can check that we delimit the stream correctly.
1062 : 3468 : switch (transcribe_tree.get_delim_type ())
1063 : : {
1064 : 139 : case AST::DelimType::PARENS:
1065 : 139 : last_token_id = TokenId::RIGHT_PAREN;
1066 : 139 : rust_assert (parser.skip_token (LEFT_PAREN));
1067 : : break;
1068 : :
1069 : 3329 : case AST::DelimType::CURLY:
1070 : 3329 : rust_assert (parser.skip_token (LEFT_CURLY));
1071 : : break;
1072 : :
1073 : 0 : case AST::DelimType::SQUARE:
1074 : 0 : last_token_id = TokenId::RIGHT_SQUARE;
1075 : 0 : rust_assert (parser.skip_token (LEFT_SQUARE));
1076 : : break;
1077 : : }
1078 : :
1079 : : // see https://github.com/Rust-GCC/gccrs/issues/22
1080 : : // TL;DR:
1081 : : // - Treat all macro invocations with parentheses, (), or square brackets,
1082 : : // [], as expressions.
1083 : : // - If the macro invocation has curly brackets, {}, it may be parsed as a
1084 : : // statement depending on the context.
1085 : : // - If the macro invocation has a semicolon at the end, it must be parsed
1086 : : // as a statement (either via ExpressionStatement or
1087 : : // MacroInvocationWithSemi)
1088 : :
1089 : 3468 : auto fragment
1090 : : = transcribe_context (ctx, parser, semicolon,
1091 : 3468 : invoc_token_tree.get_delim_type (), last_token_id);
1092 : :
1093 : : // emit any errors
1094 : 3468 : if (parser.has_errors ())
1095 : : {
1096 : 18 : for (auto &err : parser.get_errors ())
1097 : 10 : rust_error_at (err.locus, "%s", err.message.c_str ());
1098 : 8 : return AST::Fragment::create_error ();
1099 : : }
1100 : :
1101 : : // are all the tokens used?
1102 : 3460 : bool did_delimit = parser.skip_token (last_token_id);
1103 : :
1104 : 3460 : bool reached_end_of_stream = did_delimit && parser.skip_token (END_OF_FILE);
1105 : 0 : if (!reached_end_of_stream)
1106 : : {
1107 : : // FIXME: rustc has some cases it accepts this with a warning due to
1108 : : // backwards compatibility.
1109 : 0 : const_TokenPtr current_token = parser.peek_current_token ();
1110 : 0 : rust_error_at (current_token->get_locus (),
1111 : : "tokens here and after are unparsed");
1112 : 0 : }
1113 : :
1114 : 3460 : return fragment;
1115 : 6936 : }
1116 : :
1117 : : AST::Fragment
1118 : 0 : MacroExpander::parse_proc_macro_output (ProcMacro::TokenStream ts)
1119 : : {
1120 : 0 : ProcMacroInvocLexer lex (convert (ts));
1121 : 0 : Parser<ProcMacroInvocLexer> parser (lex);
1122 : :
1123 : 0 : std::vector<AST::SingleASTNode> nodes;
1124 : 0 : switch (peek_context ())
1125 : : {
1126 : : case ContextType::ITEM:
1127 : 0 : while (lex.peek_token ()->get_id () != END_OF_FILE)
1128 : : {
1129 : 0 : auto result = parser.parse_item (false);
1130 : 0 : if (result == nullptr)
1131 : : break;
1132 : 0 : nodes.push_back ({std::move (result)});
1133 : 0 : }
1134 : : break;
1135 : : case ContextType::STMT:
1136 : 0 : while (lex.peek_token ()->get_id () != END_OF_FILE)
1137 : : {
1138 : 0 : auto result = parser.parse_stmt ();
1139 : 0 : if (result == nullptr)
1140 : : break;
1141 : 0 : nodes.push_back ({std::move (result)});
1142 : 0 : }
1143 : : break;
1144 : 0 : case ContextType::TRAIT:
1145 : 0 : case ContextType::IMPL:
1146 : 0 : case ContextType::TRAIT_IMPL:
1147 : 0 : case ContextType::EXTERN:
1148 : 0 : case ContextType::TYPE:
1149 : 0 : case ContextType::EXPR:
1150 : 0 : default:
1151 : 0 : rust_unreachable ();
1152 : : }
1153 : :
1154 : 0 : if (parser.has_errors ())
1155 : 0 : return AST::Fragment::create_error ();
1156 : : else
1157 : 0 : return {nodes, std::vector<std::unique_ptr<AST::Token>> ()};
1158 : 0 : }
1159 : :
1160 : : MatchedFragment &
1161 : 12276 : MatchedFragmentContainer::get_single_fragment ()
1162 : : {
1163 : 12276 : rust_assert (is_single_fragment ());
1164 : :
1165 : 12276 : return static_cast<MatchedFragmentContainerMetaVar &> (*this).get_fragment ();
1166 : : }
1167 : :
1168 : : std::vector<std::unique_ptr<MatchedFragmentContainer>> &
1169 : 11630 : MatchedFragmentContainer::get_fragments ()
1170 : : {
1171 : 11630 : rust_assert (!is_single_fragment ());
1172 : :
1173 : 11630 : return static_cast<MatchedFragmentContainerRepetition &> (*this)
1174 : 11630 : .get_fragments ();
1175 : : }
1176 : :
1177 : : void
1178 : 0 : MatchedFragmentContainer::add_fragment (MatchedFragment fragment)
1179 : : {
1180 : 0 : rust_assert (!is_single_fragment ());
1181 : :
1182 : 0 : return static_cast<MatchedFragmentContainerRepetition &> (*this)
1183 : 0 : .add_fragment (fragment);
1184 : : }
1185 : :
1186 : : void
1187 : 5763 : MatchedFragmentContainer::add_fragment (
1188 : : std::unique_ptr<MatchedFragmentContainer> fragment)
1189 : : {
1190 : 5763 : rust_assert (!is_single_fragment ());
1191 : :
1192 : 5763 : return static_cast<MatchedFragmentContainerRepetition &> (*this)
1193 : 5763 : .add_fragment (std::move (fragment));
1194 : : }
1195 : :
1196 : : std::unique_ptr<MatchedFragmentContainer>
1197 : 62 : MatchedFragmentContainer::zero ()
1198 : : {
1199 : 62 : return std::unique_ptr<MatchedFragmentContainer> (
1200 : 62 : new MatchedFragmentContainerRepetition ());
1201 : : }
1202 : :
1203 : : std::unique_ptr<MatchedFragmentContainer>
1204 : 11388 : MatchedFragmentContainer::metavar (MatchedFragment fragment)
1205 : : {
1206 : 11388 : return std::unique_ptr<MatchedFragmentContainer> (
1207 : 11388 : new MatchedFragmentContainerMetaVar (fragment));
1208 : : }
1209 : :
1210 : : } // namespace Rust
|