Line data Source code
1 : // Copyright (C) 2025-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : /* DO NOT INCLUDE ANYWHERE - this is automatically included
20 : * by rust-parse-impl.h
21 : * This is also the reason why there are no include guards. */
22 :
23 : #include "rust-parse.h"
24 :
25 : namespace Rust {
26 :
27 : template <typename ManagedTokenSource>
28 : std::unique_ptr<AST::Pattern>
29 107947 : Parser<ManagedTokenSource>::parse_pattern ()
30 : {
31 107947 : location_t start_locus = lexer.peek_token ()->get_locus ();
32 :
33 : /* skip optional starting pipe */
34 107947 : maybe_skip_token (PIPE);
35 :
36 107947 : auto first = parse_pattern_no_alt ();
37 :
38 215894 : if (lexer.peek_token ()->get_id () != PIPE)
39 : /* no alternates */
40 107699 : return first;
41 :
42 248 : std::vector<std::unique_ptr<AST::Pattern>> alts;
43 248 : if (first != nullptr)
44 247 : alts.push_back (std::move (first));
45 :
46 : do
47 : {
48 303 : lexer.skip_token ();
49 303 : auto follow = parse_pattern_no_alt ();
50 303 : if (follow != nullptr)
51 303 : alts.push_back (std::move (follow));
52 303 : }
53 :
54 606 : while (lexer.peek_token ()->get_id () == PIPE);
55 :
56 248 : if (alts.empty ())
57 0 : return nullptr;
58 :
59 : /* alternates */
60 : return std::unique_ptr<AST::Pattern> (
61 248 : new AST::AltPattern (std::move (alts), start_locus));
62 107947 : }
63 :
64 : // Parses a pattern without alternates ('|')
65 : // (will further disambiguate any pattern).
66 : template <typename ManagedTokenSource>
67 : std::unique_ptr<AST::Pattern>
68 108839 : Parser<ManagedTokenSource>::parse_pattern_no_alt ()
69 : {
70 108839 : const_TokenPtr t = lexer.peek_token ();
71 108839 : switch (t->get_id ())
72 : {
73 31 : case TRUE_LITERAL:
74 31 : lexer.skip_token ();
75 31 : return std::unique_ptr<AST::LiteralPattern> (
76 93 : new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
77 : AST::Literal::BOOL, t->get_locus (),
78 31 : t->get_type_hint ()));
79 23 : case FALSE_LITERAL:
80 23 : lexer.skip_token ();
81 23 : return std::unique_ptr<AST::LiteralPattern> (
82 69 : new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
83 : AST::Literal::BOOL, t->get_locus (),
84 23 : t->get_type_hint ()));
85 45646 : case CHAR_LITERAL:
86 : case BYTE_CHAR_LITERAL:
87 : case INT_LITERAL:
88 : case FLOAT_LITERAL:
89 45646 : return parse_literal_or_range_pattern ();
90 4 : case STRING_LITERAL:
91 4 : lexer.skip_token ();
92 4 : return std::unique_ptr<AST::LiteralPattern> (
93 16 : new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
94 4 : t->get_locus (), t->get_type_hint ()));
95 0 : case BYTE_STRING_LITERAL:
96 0 : lexer.skip_token ();
97 0 : return std::unique_ptr<AST::LiteralPattern> (
98 0 : new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING,
99 0 : t->get_locus (), t->get_type_hint ()));
100 0 : case RAW_STRING_LITERAL:
101 0 : lexer.skip_token ();
102 0 : return std::unique_ptr<AST::LiteralPattern> (
103 0 : new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING,
104 0 : t->get_locus (), t->get_type_hint ()));
105 : // raw string and raw byte string literals too if they are readded to
106 : // lexer
107 27 : case MINUS:
108 54 : if (lexer.peek_token (1)->get_id () == INT_LITERAL)
109 : {
110 25 : return parse_literal_or_range_pattern ();
111 : }
112 4 : else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL)
113 : {
114 2 : return parse_literal_or_range_pattern ();
115 : }
116 : else
117 : {
118 0 : Error error (t->get_locus (), "unexpected token %<-%> in pattern - "
119 : "did you forget an integer literal");
120 0 : add_error (std::move (error));
121 :
122 0 : return nullptr;
123 0 : }
124 5426 : case UNDERSCORE:
125 5426 : lexer.skip_token ();
126 5426 : return std::unique_ptr<AST::WildcardPattern> (
127 5426 : new AST::WildcardPattern (t->get_locus ()));
128 63 : case DOT_DOT:
129 63 : lexer.skip_token ();
130 63 : return std::unique_ptr<AST::RestPattern> (
131 63 : new AST::RestPattern (t->get_locus ()));
132 2072 : case REF:
133 : case MUT:
134 2072 : return parse_identifier_pattern ();
135 52300 : case IDENTIFIER:
136 : /* if identifier with no scope resolution afterwards, identifier
137 : * pattern. if scope resolution afterwards, path pattern (or range
138 : * pattern or struct pattern or tuple struct pattern) or macro
139 : * invocation */
140 52300 : return parse_ident_leading_pattern ();
141 101 : case AMP:
142 : case LOGICAL_AND:
143 : // reference pattern
144 101 : return parse_reference_pattern ();
145 3031 : case LEFT_PAREN:
146 : // tuple pattern or grouped pattern
147 3031 : return parse_grouped_or_tuple_pattern ();
148 104 : case LEFT_SQUARE:
149 : // slice pattern
150 104 : return parse_slice_pattern ();
151 0 : case LEFT_SHIFT:
152 : case LEFT_ANGLE:
153 : {
154 : // qualified path in expression or qualified range pattern bound
155 0 : AST::QualifiedPathInExpression path
156 : = parse_qualified_path_in_expression ();
157 :
158 0 : if (lexer.peek_token ()->get_id () == DOT_DOT_EQ
159 0 : || lexer.peek_token ()->get_id () == ELLIPSIS
160 0 : || lexer.peek_token ()->get_id () == DOT_DOT)
161 : {
162 : // qualified range pattern bound, so parse rest of range pattern
163 : AST::RangeKind kind
164 0 : = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
165 0 : lexer.skip_token ();
166 :
167 0 : std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound (
168 0 : new AST::RangePatternBoundQualPath (std::move (path)));
169 0 : std::unique_ptr<AST::RangePatternBound> upper_bound
170 : = parse_range_pattern_bound ();
171 :
172 0 : return std::unique_ptr<AST::RangePattern> (
173 0 : new AST::RangePattern (std::move (lower_bound),
174 : std::move (upper_bound), kind,
175 0 : t->get_locus ()));
176 0 : }
177 : else
178 : {
179 : // just qualified path in expression
180 0 : return std::unique_ptr<AST::QualifiedPathInExpression> (
181 0 : new AST::QualifiedPathInExpression (std::move (path)));
182 : }
183 0 : }
184 10 : case SUPER:
185 : case SELF:
186 : case SELF_ALIAS:
187 : case CRATE:
188 : case SCOPE_RESOLUTION:
189 : case DOLLAR_SIGN:
190 : {
191 : // path in expression or range pattern bound
192 10 : AST::PathInExpression path = parse_path_in_expression ();
193 :
194 10 : const_TokenPtr next = lexer.peek_token ();
195 10 : switch (next->get_id ())
196 : {
197 0 : case DOT_DOT_EQ:
198 : case DOT_DOT:
199 : case ELLIPSIS:
200 : {
201 : // qualified range pattern bound, so parse rest of range pattern
202 0 : AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
203 0 : lexer.skip_token ();
204 :
205 0 : std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
206 0 : new AST::RangePatternBoundPath (std::move (path)));
207 0 : std::unique_ptr<AST::RangePatternBound> upper_bound
208 : = parse_range_pattern_bound ();
209 :
210 0 : return std::unique_ptr<AST::RangePattern> (
211 0 : new AST::RangePattern (std::move (lower_bound),
212 : std::move (upper_bound), kind,
213 : next->get_locus ()));
214 0 : }
215 0 : case EXCLAM:
216 0 : return parse_macro_invocation_partial (std::move (path),
217 0 : AST::AttrVec ());
218 0 : case LEFT_PAREN:
219 : {
220 : // tuple struct
221 0 : lexer.skip_token ();
222 :
223 : // parse items
224 0 : std::unique_ptr<AST::TupleStructItems> items
225 : = parse_tuple_struct_items ();
226 0 : if (items == nullptr)
227 : {
228 0 : Error error (lexer.peek_token ()->get_locus (),
229 : "failed to parse tuple struct items");
230 0 : add_error (std::move (error));
231 :
232 0 : return nullptr;
233 0 : }
234 :
235 0 : if (!skip_token (RIGHT_PAREN))
236 : {
237 0 : return nullptr;
238 : }
239 :
240 0 : return std::unique_ptr<AST::TupleStructPattern> (
241 0 : new AST::TupleStructPattern (std::move (path),
242 0 : std::move (items)));
243 0 : }
244 1 : case LEFT_CURLY:
245 : {
246 : // struct
247 1 : lexer.skip_token ();
248 :
249 : // parse elements (optional)
250 1 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
251 :
252 1 : if (!skip_token (RIGHT_CURLY))
253 : {
254 0 : return nullptr;
255 : }
256 :
257 1 : return std::unique_ptr<AST::StructPattern> (
258 2 : new AST::StructPattern (std::move (path), t->get_locus (),
259 1 : std::move (elems)));
260 1 : }
261 9 : default:
262 : // assume path in expression
263 9 : return std::unique_ptr<AST::PathInExpression> (
264 9 : new AST::PathInExpression (std::move (path)));
265 : }
266 10 : }
267 1 : default:
268 1 : add_error (Error (t->get_locus (), "unexpected token %qs in pattern",
269 : t->get_token_description ()));
270 :
271 1 : return nullptr;
272 : }
273 108839 : }
274 :
275 : // Parses a single or double reference pattern.
276 : template <typename ManagedTokenSource>
277 : std::unique_ptr<AST::ReferencePattern>
278 101 : Parser<ManagedTokenSource>::parse_reference_pattern ()
279 : {
280 : // parse double or single ref
281 101 : bool is_double_ref = false;
282 101 : const_TokenPtr t = lexer.peek_token ();
283 101 : switch (t->get_id ())
284 : {
285 87 : case AMP:
286 : // still false
287 87 : lexer.skip_token ();
288 : break;
289 14 : case LOGICAL_AND:
290 14 : is_double_ref = true;
291 14 : lexer.skip_token ();
292 : break;
293 0 : default:
294 0 : add_error (Error (t->get_locus (),
295 : "unexpected token %qs in reference pattern",
296 : t->get_token_description ()));
297 :
298 0 : return nullptr;
299 : }
300 :
301 : // parse mut (if it exists)
302 101 : bool is_mut = false;
303 202 : if (lexer.peek_token ()->get_id () == MUT)
304 : {
305 4 : is_mut = true;
306 4 : lexer.skip_token ();
307 : }
308 :
309 : // parse pattern to get reference of (required)
310 101 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
311 101 : if (pattern == nullptr)
312 : {
313 0 : Error error (lexer.peek_token ()->get_locus (),
314 : "failed to parse pattern in reference pattern");
315 0 : add_error (std::move (error));
316 :
317 : // skip somewhere?
318 0 : return nullptr;
319 0 : }
320 :
321 : return std::unique_ptr<AST::ReferencePattern> (
322 101 : new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
323 101 : t->get_locus ()));
324 101 : }
325 :
326 : /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
327 : * only a single element with no commas. */
328 : template <typename ManagedTokenSource>
329 : std::unique_ptr<AST::Pattern>
330 3031 : Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
331 : {
332 3031 : location_t paren_locus = lexer.peek_token ()->get_locus ();
333 3031 : skip_token (LEFT_PAREN);
334 :
335 : // detect '..' token (ranged with no lower range)
336 6062 : if (lexer.peek_token ()->get_id () == DOT_DOT)
337 : {
338 6 : lexer.skip_token ();
339 :
340 : // parse new patterns while next token is a comma
341 6 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
342 :
343 6 : const_TokenPtr t = lexer.peek_token ();
344 6 : while (t->get_id () == COMMA)
345 : {
346 0 : lexer.skip_token ();
347 :
348 : // break if next token is ')'
349 0 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
350 : {
351 : break;
352 : }
353 :
354 : // parse pattern, which is required
355 0 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
356 0 : if (pattern == nullptr)
357 : {
358 0 : Error error (
359 0 : lexer.peek_token ()->get_locus (),
360 : "failed to parse pattern inside ranged tuple pattern");
361 0 : add_error (std::move (error));
362 :
363 : // skip somewhere?
364 0 : return nullptr;
365 0 : }
366 0 : patterns.push_back (std::move (pattern));
367 :
368 0 : t = lexer.peek_token ();
369 : }
370 :
371 6 : if (!skip_token (RIGHT_PAREN))
372 : {
373 : // skip somewhere?
374 0 : return nullptr;
375 : }
376 :
377 : // create tuple pattern items with only upper pattern items
378 6 : std::unique_ptr<AST::TuplePatternItemsHasRest> items (
379 6 : new AST::TuplePatternItemsHasRest (
380 6 : std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
381 6 : return std::unique_ptr<AST::TuplePattern> (
382 6 : new AST::TuplePattern (std::move (items), paren_locus));
383 12 : }
384 6050 : else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
385 : {
386 24 : skip_token (RIGHT_PAREN);
387 24 : auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> (
388 24 : new AST::TuplePatternItemsNoRest (
389 24 : std::vector<std::unique_ptr<AST::Pattern>> ()));
390 24 : return std::unique_ptr<AST::TuplePattern> (
391 24 : new AST::TuplePattern (std::move (items), paren_locus));
392 24 : }
393 :
394 : // parse initial pattern (required)
395 3001 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
396 3001 : if (initial_pattern == nullptr)
397 : {
398 0 : Error error (lexer.peek_token ()->get_locus (),
399 : "failed to parse pattern in grouped or tuple pattern");
400 0 : add_error (std::move (error));
401 :
402 0 : return nullptr;
403 0 : }
404 :
405 : // branch on whether next token is a comma or not
406 3001 : const_TokenPtr t = lexer.peek_token ();
407 3001 : switch (t->get_id ())
408 : {
409 48 : case RIGHT_PAREN:
410 : // grouped pattern
411 48 : lexer.skip_token ();
412 :
413 48 : return std::unique_ptr<AST::GroupedPattern> (
414 48 : new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
415 2952 : case COMMA:
416 : {
417 : // tuple pattern
418 2952 : lexer.skip_token ();
419 :
420 : // create vector of patterns
421 2952 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
422 2952 : patterns.push_back (std::move (initial_pattern));
423 :
424 2952 : t = lexer.peek_token ();
425 6760 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
426 : {
427 : // parse pattern (required)
428 3808 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
429 3808 : if (pattern == nullptr)
430 : {
431 0 : Error error (t->get_locus (),
432 : "failed to parse pattern in tuple pattern");
433 0 : add_error (std::move (error));
434 :
435 0 : return nullptr;
436 0 : }
437 3808 : patterns.push_back (std::move (pattern));
438 :
439 7616 : if (lexer.peek_token ()->get_id () != COMMA)
440 : break;
441 :
442 954 : lexer.skip_token ();
443 954 : t = lexer.peek_token ();
444 : }
445 :
446 2952 : t = lexer.peek_token ();
447 2952 : if (t->get_id () == RIGHT_PAREN)
448 : {
449 : // non-ranged tuple pattern
450 2920 : lexer.skip_token ();
451 :
452 2920 : std::unique_ptr<AST::TuplePatternItemsNoRest> items (
453 2920 : new AST::TuplePatternItemsNoRest (std::move (patterns)));
454 2920 : return std::unique_ptr<AST::TuplePattern> (
455 2920 : new AST::TuplePattern (std::move (items), paren_locus));
456 2920 : }
457 32 : else if (t->get_id () == DOT_DOT)
458 : {
459 : // ranged tuple pattern
460 32 : lexer.skip_token ();
461 :
462 : // parse upper patterns
463 32 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
464 32 : t = lexer.peek_token ();
465 68 : while (t->get_id () == COMMA)
466 : {
467 36 : lexer.skip_token ();
468 :
469 : // break if end
470 72 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
471 : break;
472 :
473 : // parse pattern (required)
474 36 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
475 36 : if (pattern == nullptr)
476 : {
477 0 : Error error (lexer.peek_token ()->get_locus (),
478 : "failed to parse pattern in tuple pattern");
479 0 : add_error (std::move (error));
480 :
481 0 : return nullptr;
482 0 : }
483 36 : upper_patterns.push_back (std::move (pattern));
484 :
485 36 : t = lexer.peek_token ();
486 : }
487 :
488 32 : if (!skip_token (RIGHT_PAREN))
489 : {
490 0 : return nullptr;
491 : }
492 :
493 32 : std::unique_ptr<AST::TuplePatternItemsHasRest> items (
494 32 : new AST::TuplePatternItemsHasRest (std::move (patterns),
495 : std::move (upper_patterns)));
496 32 : return std::unique_ptr<AST::TuplePattern> (
497 32 : new AST::TuplePattern (std::move (items), paren_locus));
498 32 : }
499 : else
500 : {
501 : // some kind of error
502 0 : Error error (t->get_locus (),
503 : "failed to parse tuple pattern (probably) or maybe "
504 : "grouped pattern");
505 0 : add_error (std::move (error));
506 :
507 0 : return nullptr;
508 0 : }
509 2952 : }
510 1 : default:
511 : // error
512 1 : add_error (Error (t->get_locus (),
513 : "unrecognised token %qs in grouped or tuple pattern "
514 : "after first pattern",
515 : t->get_token_description ()));
516 :
517 1 : return nullptr;
518 : }
519 3001 : }
520 :
521 : /* Parses a slice pattern that can match arrays or slices. Parses the square
522 : * brackets too. */
523 : template <typename ManagedTokenSource>
524 : std::unique_ptr<AST::SlicePattern>
525 104 : Parser<ManagedTokenSource>::parse_slice_pattern ()
526 : {
527 208 : location_t square_locus = lexer.peek_token ()->get_locus ();
528 104 : std::vector<std::unique_ptr<AST::Pattern>> sub_patterns;
529 :
530 104 : skip_token (LEFT_SQUARE);
531 :
532 104 : bool is_first = true;
533 :
534 496 : while (true)
535 : {
536 352 : const_TokenPtr t = lexer.peek_token ();
537 :
538 352 : if (!is_first && t->get_id () == COMMA)
539 : {
540 149 : skip_token (COMMA);
541 149 : t = lexer.peek_token ();
542 : }
543 :
544 352 : if (t->get_id () == RIGHT_SQUARE)
545 : {
546 104 : skip_token (RIGHT_SQUARE);
547 : break;
548 : }
549 :
550 : // parse pattern (required)
551 248 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
552 248 : if (pattern == nullptr)
553 : {
554 0 : Error error (lexer.peek_token ()->get_locus (),
555 : "failed to parse pattern in slice pattern");
556 0 : add_error (std::move (error));
557 : // TODO: skip until closing square bracket
558 :
559 0 : return nullptr;
560 0 : }
561 :
562 248 : sub_patterns.push_back (std::move (pattern));
563 248 : is_first = false;
564 : }
565 :
566 : return std::make_unique<AST::SlicePattern> (std::move (sub_patterns),
567 104 : square_locus);
568 104 : }
569 :
570 : /* Parses an identifier pattern (pattern that binds a value matched to a
571 : * variable). */
572 : template <typename ManagedTokenSource>
573 : std::unique_ptr<AST::IdentifierPattern>
574 2072 : Parser<ManagedTokenSource>::parse_identifier_pattern ()
575 : {
576 2072 : location_t locus = lexer.peek_token ()->get_locus ();
577 :
578 2072 : bool has_ref = false;
579 4144 : if (lexer.peek_token ()->get_id () == REF)
580 : {
581 233 : has_ref = true;
582 233 : lexer.skip_token ();
583 :
584 : // DEBUG
585 233 : rust_debug ("parsed ref in identifier pattern");
586 : }
587 :
588 2072 : bool has_mut = false;
589 4144 : if (lexer.peek_token ()->get_id () == MUT)
590 : {
591 1893 : has_mut = true;
592 1893 : lexer.skip_token ();
593 : }
594 :
595 : // parse identifier (required)
596 2072 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
597 2072 : if (ident_tok == nullptr)
598 : {
599 : // skip somewhere?
600 0 : return nullptr;
601 : }
602 2072 : Identifier ident{ident_tok};
603 :
604 : // DEBUG
605 2072 : rust_debug ("parsed identifier in identifier pattern");
606 :
607 : // parse optional pattern binding thing
608 2072 : std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
609 4144 : if (lexer.peek_token ()->get_id () == PATTERN_BIND)
610 : {
611 1 : lexer.skip_token ();
612 :
613 : // parse required pattern to bind
614 1 : bind_pattern = parse_pattern_no_alt ();
615 1 : if (bind_pattern == nullptr)
616 : {
617 0 : Error error (lexer.peek_token ()->get_locus (),
618 : "failed to parse pattern to bind in identifier pattern");
619 0 : add_error (std::move (error));
620 :
621 0 : return nullptr;
622 0 : }
623 : }
624 :
625 : // DEBUG
626 2072 : rust_debug ("about to return identifier pattern");
627 :
628 : return std::unique_ptr<AST::IdentifierPattern> (
629 2072 : new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
630 2072 : std::move (bind_pattern)));
631 2072 : }
632 :
633 : /* Parses a pattern that opens with an identifier. This includes identifier
634 : * patterns, path patterns (and derivatives such as struct patterns, tuple
635 : * struct patterns, and macro invocations), and ranges. */
636 : template <typename ManagedTokenSource>
637 : std::unique_ptr<AST::Pattern>
638 52300 : Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
639 : {
640 : // ensure first token is actually identifier
641 52300 : const_TokenPtr initial_tok = lexer.peek_token ();
642 52300 : if (initial_tok->get_id () != IDENTIFIER)
643 : {
644 0 : return nullptr;
645 : }
646 :
647 : // save initial identifier as it may be useful (but don't skip)
648 52300 : std::string initial_ident = initial_tok->get_str ();
649 :
650 : // parse next tokens as a PathInExpression
651 52300 : AST::PathInExpression path = parse_path_in_expression ();
652 :
653 : // branch on next token
654 52300 : const_TokenPtr t = lexer.peek_token ();
655 52300 : switch (t->get_id ())
656 : {
657 4 : case EXCLAM:
658 8 : return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
659 1675 : case LEFT_PAREN:
660 : {
661 : // tuple struct
662 1675 : lexer.skip_token ();
663 :
664 : // DEBUG
665 1675 : rust_debug ("parsing tuple struct pattern");
666 :
667 : // parse items
668 1675 : std::unique_ptr<AST::TupleStructItems> items
669 : = parse_tuple_struct_items ();
670 1675 : if (items == nullptr)
671 : {
672 1 : Error error (lexer.peek_token ()->get_locus (),
673 : "failed to parse tuple struct items");
674 1 : add_error (std::move (error));
675 :
676 1 : return nullptr;
677 1 : }
678 :
679 : // DEBUG
680 1674 : rust_debug ("successfully parsed tuple struct items");
681 :
682 1674 : if (!skip_token (RIGHT_PAREN))
683 : {
684 0 : return nullptr;
685 : }
686 :
687 : // DEBUG
688 1674 : rust_debug ("successfully parsed tuple struct pattern");
689 :
690 1674 : return std::unique_ptr<AST::TupleStructPattern> (
691 1674 : new AST::TupleStructPattern (std::move (path), std::move (items)));
692 1675 : }
693 161 : case LEFT_CURLY:
694 : {
695 : // struct
696 161 : lexer.skip_token ();
697 :
698 : // parse elements (optional)
699 161 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
700 :
701 161 : if (!skip_token (RIGHT_CURLY))
702 : {
703 0 : return nullptr;
704 : }
705 :
706 : // DEBUG
707 161 : rust_debug ("successfully parsed struct pattern");
708 :
709 161 : return std::unique_ptr<AST::StructPattern> (
710 322 : new AST::StructPattern (std::move (path), initial_tok->get_locus (),
711 161 : std::move (elems)));
712 161 : }
713 9 : case DOT_DOT_EQ:
714 : case DOT_DOT:
715 : case ELLIPSIS:
716 : {
717 : // range
718 : AST::RangeKind kind
719 9 : = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
720 :
721 9 : lexer.skip_token ();
722 :
723 9 : std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
724 9 : new AST::RangePatternBoundPath (std::move (path)));
725 9 : std::unique_ptr<AST::RangePatternBound> upper_bound
726 : = parse_range_pattern_bound ();
727 :
728 9 : return std::unique_ptr<AST::RangePattern> (
729 9 : new AST::RangePattern (std::move (lower_bound),
730 : std::move (upper_bound), kind,
731 9 : t->get_locus ()));
732 9 : }
733 47 : case PATTERN_BIND:
734 : {
735 : // only allow on single-segment paths
736 47 : if (path.is_single_segment ())
737 : {
738 : // identifier with pattern bind
739 47 : lexer.skip_token ();
740 :
741 47 : std::unique_ptr<AST::Pattern> bind_pattern
742 : = parse_pattern_no_alt ();
743 47 : if (bind_pattern == nullptr)
744 : {
745 1 : Error error (
746 : t->get_locus (),
747 : "failed to parse pattern to bind to identifier pattern");
748 1 : add_error (std::move (error));
749 :
750 1 : return nullptr;
751 1 : }
752 46 : return std::unique_ptr<AST::IdentifierPattern> (
753 138 : new AST::IdentifierPattern (std::move (initial_ident),
754 : initial_tok->get_locus (), false,
755 46 : false, std::move (bind_pattern)));
756 47 : }
757 0 : Error error (
758 : t->get_locus (),
759 : "failed to parse pattern bind to a path, not an identifier");
760 0 : add_error (std::move (error));
761 :
762 0 : return nullptr;
763 0 : }
764 50404 : default:
765 : // assume identifier if single segment
766 50404 : if (path.is_single_segment ())
767 : {
768 49288 : return std::unique_ptr<AST::IdentifierPattern> (
769 147864 : new AST::IdentifierPattern (std::move (initial_ident),
770 49288 : initial_tok->get_locus ()));
771 : }
772 : // return path otherwise
773 1116 : return std::unique_ptr<AST::PathInExpression> (
774 1116 : new AST::PathInExpression (std::move (path)));
775 : }
776 52300 : }
777 :
778 : // Parses struct pattern elements if they exist.
779 : template <typename ManagedTokenSource>
780 : AST::StructPatternElements
781 162 : Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
782 : {
783 162 : std::vector<std::unique_ptr<AST::StructPatternField>> fields;
784 :
785 162 : AST::AttrVec etc_attrs;
786 162 : bool has_rest = false;
787 :
788 : // try parsing struct pattern fields
789 162 : const_TokenPtr t = lexer.peek_token ();
790 520 : while (t->get_id () != RIGHT_CURLY)
791 : {
792 253 : AST::AttrVec outer_attrs = parse_outer_attributes ();
793 :
794 : // parse etc (must be last in struct pattern, so breaks)
795 506 : if (lexer.peek_token ()->get_id () == DOT_DOT)
796 : {
797 6 : lexer.skip_token ();
798 6 : etc_attrs = std::move (outer_attrs);
799 6 : has_rest = true;
800 6 : break;
801 : }
802 :
803 247 : std::unique_ptr<AST::StructPatternField> field
804 247 : = parse_struct_pattern_field_partial (std::move (outer_attrs));
805 247 : if (field == nullptr)
806 : {
807 0 : Error error (lexer.peek_token ()->get_locus (),
808 : "failed to parse struct pattern field");
809 0 : add_error (std::move (error));
810 :
811 : // skip after somewhere?
812 0 : return AST::StructPatternElements::create_empty ();
813 0 : }
814 247 : fields.push_back (std::move (field));
815 :
816 494 : if (lexer.peek_token ()->get_id () != COMMA)
817 : break;
818 :
819 : // skip comma
820 105 : lexer.skip_token ();
821 105 : t = lexer.peek_token ();
822 : }
823 :
824 162 : if (has_rest)
825 6 : return AST::StructPatternElements (std::move (fields),
826 6 : std::move (etc_attrs));
827 : else
828 156 : return AST::StructPatternElements (std::move (fields));
829 162 : }
830 :
831 : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
832 : * identifier). */
833 : template <typename ManagedTokenSource>
834 : std::unique_ptr<AST::StructPatternField>
835 0 : Parser<ManagedTokenSource>::parse_struct_pattern_field ()
836 : {
837 : // parse outer attributes (if they exist)
838 0 : AST::AttrVec outer_attrs = parse_outer_attributes ();
839 :
840 0 : return parse_struct_pattern_field_partial (std::move (outer_attrs));
841 0 : }
842 :
843 : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
844 : * identifier), with outer attributes passed in. */
845 : template <typename ManagedTokenSource>
846 : std::unique_ptr<AST::StructPatternField>
847 247 : Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
848 : AST::AttrVec outer_attrs)
849 : {
850 : // branch based on next token
851 247 : const_TokenPtr t = lexer.peek_token ();
852 247 : switch (t->get_id ())
853 : {
854 26 : case INT_LITERAL:
855 : {
856 : // tuple index
857 52 : std::string index_str = t->get_str ();
858 26 : int index = atoi (index_str.c_str ());
859 :
860 26 : lexer.skip_token ();
861 :
862 26 : if (!skip_token (COLON))
863 : {
864 0 : return nullptr;
865 : }
866 :
867 : // parse required pattern
868 26 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
869 26 : if (pattern == nullptr)
870 : {
871 0 : Error error (
872 : t->get_locus (),
873 : "failed to parse pattern in tuple index struct pattern field");
874 0 : add_error (std::move (error));
875 :
876 0 : return nullptr;
877 0 : }
878 :
879 26 : return std::unique_ptr<AST::StructPatternFieldTuplePat> (
880 26 : new AST::StructPatternFieldTuplePat (index, std::move (pattern),
881 : std::move (outer_attrs),
882 26 : t->get_locus ()));
883 52 : }
884 219 : case IDENTIFIER:
885 : // identifier-pattern OR only identifier
886 : // branch on next token
887 438 : switch (lexer.peek_token (1)->get_id ())
888 : {
889 115 : case COLON:
890 : {
891 : // identifier-pattern
892 115 : Identifier ident{t};
893 115 : lexer.skip_token ();
894 :
895 115 : skip_token (COLON);
896 :
897 : // parse required pattern
898 115 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
899 115 : if (pattern == nullptr)
900 : {
901 0 : Error error (t->get_locus (),
902 : "failed to parse pattern in struct pattern field");
903 0 : add_error (std::move (error));
904 :
905 0 : return nullptr;
906 0 : }
907 :
908 115 : return std::unique_ptr<AST::StructPatternFieldIdentPat> (
909 230 : new AST::StructPatternFieldIdentPat (std::move (ident),
910 : std::move (pattern),
911 : std::move (outer_attrs),
912 115 : t->get_locus ()));
913 115 : }
914 104 : case COMMA:
915 : case RIGHT_CURLY:
916 : {
917 : // identifier only
918 104 : Identifier ident = {t};
919 104 : lexer.skip_token ();
920 :
921 104 : return std::unique_ptr<AST::StructPatternFieldIdent> (
922 208 : new AST::StructPatternFieldIdent (std::move (ident), false, false,
923 : std::move (outer_attrs),
924 104 : t->get_locus ()));
925 104 : }
926 0 : default:
927 : // error
928 0 : add_error (Error (t->get_locus (),
929 : "unrecognised token %qs in struct pattern field",
930 : t->get_token_description ()));
931 :
932 0 : return nullptr;
933 : }
934 2 : case REF:
935 : case MUT:
936 : {
937 : // only identifier
938 2 : bool has_ref = false;
939 2 : if (t->get_id () == REF)
940 : {
941 0 : has_ref = true;
942 0 : lexer.skip_token ();
943 : }
944 :
945 2 : bool has_mut = false;
946 4 : if (lexer.peek_token ()->get_id () == MUT)
947 : {
948 2 : has_mut = true;
949 2 : lexer.skip_token ();
950 : }
951 :
952 2 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
953 2 : if (ident_tok == nullptr)
954 : {
955 0 : return nullptr;
956 : }
957 2 : Identifier ident{ident_tok};
958 :
959 2 : return std::unique_ptr<AST::StructPatternFieldIdent> (
960 4 : new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
961 : std::move (outer_attrs),
962 2 : t->get_locus ()));
963 4 : }
964 0 : default:
965 : // not necessarily an error
966 0 : return nullptr;
967 : }
968 247 : }
969 :
970 : /* Parses a literal pattern or range pattern. Assumes that literals passed in
971 : * are valid range pattern bounds. Do not pass in paths in expressions, for
972 : * instance. */
973 : template <typename ManagedTokenSource>
974 : std::unique_ptr<AST::Pattern>
975 45673 : Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
976 : {
977 45673 : const_TokenPtr range_lower = lexer.peek_token ();
978 45673 : AST::Literal::LitType type = AST::Literal::STRING;
979 45673 : bool has_minus = false;
980 :
981 : // get lit type
982 45673 : switch (range_lower->get_id ())
983 : {
984 98 : case CHAR_LITERAL:
985 98 : type = AST::Literal::CHAR;
986 98 : lexer.skip_token ();
987 : break;
988 87 : case BYTE_CHAR_LITERAL:
989 87 : type = AST::Literal::BYTE;
990 87 : lexer.skip_token ();
991 : break;
992 45459 : case INT_LITERAL:
993 45459 : type = AST::Literal::INT;
994 45459 : lexer.skip_token ();
995 : break;
996 2 : case FLOAT_LITERAL:
997 2 : type = AST::Literal::FLOAT;
998 2 : lexer.skip_token ();
999 : break;
1000 27 : case MINUS:
1001 : // branch on next token
1002 27 : range_lower = lexer.peek_token (1);
1003 27 : switch (range_lower->get_id ())
1004 : {
1005 25 : case INT_LITERAL:
1006 25 : type = AST::Literal::INT;
1007 25 : has_minus = true;
1008 25 : lexer.skip_token (1);
1009 25 : break;
1010 2 : case FLOAT_LITERAL:
1011 2 : type = AST::Literal::FLOAT;
1012 2 : has_minus = true;
1013 2 : lexer.skip_token (1);
1014 2 : break;
1015 0 : default:
1016 0 : add_error (Error (range_lower->get_locus (),
1017 : "token type %qs cannot be parsed as range pattern "
1018 : "bound or literal after minus symbol",
1019 : range_lower->get_token_description ()));
1020 :
1021 0 : return nullptr;
1022 : }
1023 : break;
1024 0 : default:
1025 0 : add_error (
1026 0 : Error (range_lower->get_locus (),
1027 : "token type %qs cannot be parsed as range pattern bound",
1028 : range_lower->get_token_description ()));
1029 :
1030 0 : return nullptr;
1031 : }
1032 :
1033 45673 : std::string literal_value;
1034 45673 : if (range_lower->get_id () == INT_LITERAL)
1035 90968 : literal_value = LiteralResolve::evaluate_integer_literal (range_lower);
1036 189 : else if (range_lower->get_id () == FLOAT_LITERAL)
1037 8 : literal_value = LiteralResolve::evaluate_float_literal (range_lower);
1038 : else
1039 185 : literal_value = range_lower->get_str ();
1040 :
1041 45673 : const_TokenPtr next = lexer.peek_token ();
1042 45673 : if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
1043 91205 : || next->get_id () == DOT_DOT)
1044 : {
1045 168 : AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
1046 : // range pattern
1047 168 : lexer.skip_token ();
1048 168 : std::unique_ptr<AST::RangePatternBound> lower (
1049 336 : new AST::RangePatternBoundLiteral (
1050 336 : AST::Literal (std::move (literal_value), type,
1051 : PrimitiveCoreType::CORETYPE_UNKNOWN),
1052 : range_lower->get_locus (), has_minus));
1053 :
1054 168 : std::unique_ptr<AST::RangePatternBound> upper
1055 : = parse_range_pattern_bound ();
1056 168 : if (upper == nullptr)
1057 : {
1058 1 : Error error (next->get_locus (),
1059 : "failed to parse range pattern bound in range pattern");
1060 1 : add_error (std::move (error));
1061 :
1062 1 : return nullptr;
1063 1 : }
1064 :
1065 167 : return std::unique_ptr<AST::RangePattern> (
1066 167 : new AST::RangePattern (std::move (lower), std::move (upper), kind,
1067 167 : range_lower->get_locus ()));
1068 168 : }
1069 : else
1070 : {
1071 : // literal pattern
1072 :
1073 45505 : auto type_hint = (range_lower->get_id () == INT_LITERAL
1074 100 : || range_lower->get_id () == FLOAT_LITERAL)
1075 136319 : ? LiteralResolve::resolve_literal_suffix (range_lower)
1076 98 : : range_lower->get_type_hint ();
1077 :
1078 45505 : return std::unique_ptr<AST::LiteralPattern> (
1079 91010 : new AST::LiteralPattern (std::move (literal_value), type,
1080 : range_lower->get_locus (), type_hint,
1081 45505 : has_minus));
1082 : }
1083 45673 : }
1084 :
1085 : // Parses a range pattern bound (value only).
1086 : template <typename ManagedTokenSource>
1087 : std::unique_ptr<AST::RangePatternBound>
1088 177 : Parser<ManagedTokenSource>::parse_range_pattern_bound ()
1089 : {
1090 177 : const_TokenPtr range_lower = lexer.peek_token ();
1091 177 : location_t range_lower_locus = range_lower->get_locus ();
1092 :
1093 : // get lit type
1094 177 : switch (range_lower->get_id ())
1095 : {
1096 52 : case CHAR_LITERAL:
1097 52 : lexer.skip_token ();
1098 52 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1099 104 : new AST::RangePatternBoundLiteral (
1100 208 : AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
1101 : range_lower->get_type_hint ()),
1102 52 : range_lower_locus));
1103 35 : case BYTE_CHAR_LITERAL:
1104 35 : lexer.skip_token ();
1105 35 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1106 70 : new AST::RangePatternBoundLiteral (
1107 140 : AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
1108 : range_lower->get_type_hint ()),
1109 35 : range_lower_locus));
1110 61 : case INT_LITERAL:
1111 61 : lexer.skip_token ();
1112 61 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1113 122 : new AST::RangePatternBoundLiteral (
1114 244 : AST::Literal (LiteralResolve::evaluate_integer_literal (range_lower),
1115 : AST::Literal::INT,
1116 122 : LiteralResolve::resolve_literal_suffix (range_lower)),
1117 61 : range_lower_locus));
1118 0 : case FLOAT_LITERAL:
1119 0 : lexer.skip_token ();
1120 0 : rust_debug ("warning: used deprecated float range pattern bound");
1121 0 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1122 0 : new AST::RangePatternBoundLiteral (
1123 0 : AST::Literal (LiteralResolve::evaluate_float_literal (range_lower),
1124 : AST::Literal::FLOAT,
1125 0 : LiteralResolve::resolve_literal_suffix (range_lower)),
1126 0 : range_lower_locus));
1127 12 : case MINUS:
1128 : // branch on next token
1129 12 : range_lower = lexer.peek_token (1);
1130 12 : switch (range_lower->get_id ())
1131 : {
1132 10 : case INT_LITERAL:
1133 10 : lexer.skip_token (1);
1134 10 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1135 20 : new AST::RangePatternBoundLiteral (
1136 30 : AST::Literal (
1137 30 : LiteralResolve::evaluate_integer_literal (range_lower),
1138 : AST::Literal::INT,
1139 20 : LiteralResolve::resolve_literal_suffix (range_lower)),
1140 10 : range_lower_locus, true));
1141 2 : case FLOAT_LITERAL:
1142 2 : lexer.skip_token (1);
1143 2 : rust_debug ("warning: used deprecated float range pattern bound");
1144 2 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1145 4 : new AST::RangePatternBoundLiteral (
1146 6 : AST::Literal (
1147 6 : LiteralResolve::evaluate_float_literal (range_lower),
1148 : AST::Literal::FLOAT,
1149 4 : LiteralResolve::resolve_literal_suffix (range_lower)),
1150 2 : range_lower_locus, true));
1151 0 : default:
1152 0 : add_error (Error (range_lower->get_locus (),
1153 : "token type %qs cannot be parsed as range pattern "
1154 : "bound after minus symbol",
1155 : range_lower->get_token_description ()));
1156 :
1157 0 : return nullptr;
1158 : }
1159 15 : case IDENTIFIER:
1160 : case SUPER:
1161 : case SELF:
1162 : case SELF_ALIAS:
1163 : case CRATE:
1164 : case SCOPE_RESOLUTION:
1165 : case DOLLAR_SIGN:
1166 : {
1167 : // path in expression
1168 15 : AST::PathInExpression path = parse_path_in_expression ();
1169 15 : if (path.is_error ())
1170 : {
1171 0 : Error error (
1172 : range_lower->get_locus (),
1173 : "failed to parse path in expression range pattern bound");
1174 0 : add_error (std::move (error));
1175 :
1176 0 : return nullptr;
1177 0 : }
1178 15 : return std::unique_ptr<AST::RangePatternBoundPath> (
1179 15 : new AST::RangePatternBoundPath (std::move (path)));
1180 15 : }
1181 0 : case LEFT_SHIFT:
1182 : case LEFT_ANGLE:
1183 : {
1184 : // qualified path in expression
1185 0 : AST::QualifiedPathInExpression path
1186 : = parse_qualified_path_in_expression ();
1187 0 : if (path.is_error ())
1188 : {
1189 0 : Error error (range_lower->get_locus (),
1190 : "failed to parse qualified path in expression range "
1191 : "pattern bound");
1192 0 : add_error (std::move (error));
1193 :
1194 0 : return nullptr;
1195 0 : }
1196 0 : return std::unique_ptr<AST::RangePatternBoundQualPath> (
1197 0 : new AST::RangePatternBoundQualPath (std::move (path)));
1198 0 : }
1199 2 : default:
1200 2 : add_error (
1201 2 : Error (range_lower->get_locus (),
1202 : "token type %qs cannot be parsed as range pattern bound",
1203 : range_lower->get_token_description ()));
1204 :
1205 2 : return nullptr;
1206 : }
1207 177 : }
1208 :
1209 : } // namespace Rust
|