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