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