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