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 113395 : Parser<ManagedTokenSource>::parse_pattern ()
30 : {
31 113395 : location_t start_locus = lexer.peek_token ()->get_locus ();
32 :
33 : /* skip optional starting pipe */
34 113395 : maybe_skip_token (PIPE);
35 :
36 113395 : auto first = parse_pattern_no_alt ();
37 :
38 226790 : if (lexer.peek_token ()->get_id () != PIPE)
39 : /* no alternates */
40 113142 : return first;
41 :
42 253 : std::vector<std::unique_ptr<AST::Pattern>> alts;
43 253 : if (first != nullptr)
44 252 : alts.push_back (std::move (first));
45 :
46 : do
47 : {
48 308 : lexer.skip_token ();
49 308 : auto follow = parse_pattern_no_alt ();
50 308 : if (follow != nullptr)
51 308 : alts.push_back (std::move (follow));
52 308 : }
53 :
54 616 : while (lexer.peek_token ()->get_id () == PIPE);
55 :
56 253 : if (alts.empty ())
57 0 : return nullptr;
58 :
59 : /* alternates */
60 : return std::unique_ptr<AST::Pattern> (
61 253 : new AST::AltPattern (std::move (alts), start_locus));
62 113395 : }
63 :
64 : // Parses a pattern without alternates ('|')
65 : // (will further disambiguate any pattern).
66 : template <typename ManagedTokenSource>
67 : std::unique_ptr<AST::Pattern>
68 114488 : Parser<ManagedTokenSource>::parse_pattern_no_alt ()
69 : {
70 114488 : const_TokenPtr t = lexer.peek_token ();
71 114488 : switch (t->get_id ())
72 : {
73 64 : case TRUE_LITERAL:
74 64 : lexer.skip_token ();
75 64 : return std::unique_ptr<AST::LiteralPattern> (
76 192 : new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
77 : AST::Literal::BOOL, t->get_locus (),
78 64 : t->get_type_hint ()));
79 57 : case FALSE_LITERAL:
80 57 : lexer.skip_token ();
81 57 : return std::unique_ptr<AST::LiteralPattern> (
82 171 : new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
83 : AST::Literal::BOOL, t->get_locus (),
84 57 : t->get_type_hint ()));
85 45670 : case CHAR_LITERAL:
86 : case BYTE_CHAR_LITERAL:
87 : case INT_LITERAL:
88 : case FLOAT_LITERAL:
89 45670 : 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 5608 : case UNDERSCORE:
125 5608 : lexer.skip_token ();
126 5608 : return std::unique_ptr<AST::WildcardPattern> (
127 5608 : new AST::WildcardPattern (t->get_locus ()));
128 65 : case DOT_DOT:
129 65 : lexer.skip_token ();
130 65 : return std::unique_ptr<AST::RestPattern> (
131 65 : new AST::RestPattern (t->get_locus ()));
132 2435 : case REF:
133 : case MUT:
134 2435 : return parse_identifier_pattern ();
135 56945 : 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 56945 : return parse_ident_leading_pattern ();
141 118 : case AMP:
142 : case LOGICAL_AND:
143 : // reference pattern
144 118 : return parse_reference_pattern ();
145 3367 : case LEFT_PAREN:
146 : // tuple pattern or grouped pattern
147 3367 : return parse_grouped_or_tuple_pattern ();
148 113 : case LEFT_SQUARE:
149 : // slice pattern
150 113 : 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 14 : 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 14 : AST::PathInExpression path = parse_path_in_expression ();
193 :
194 14 : const_TokenPtr next = lexer.peek_token ();
195 14 : 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 4 : case LEFT_CURLY:
245 : {
246 : // struct
247 4 : lexer.skip_token ();
248 :
249 : // parse elements (optional)
250 4 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
251 :
252 4 : if (!skip_token (RIGHT_CURLY))
253 : {
254 0 : return nullptr;
255 : }
256 :
257 4 : return std::unique_ptr<AST::StructPattern> (
258 8 : new AST::StructPattern (std::move (path), t->get_locus (),
259 4 : std::move (elems)));
260 4 : }
261 10 : default:
262 : // assume path in expression
263 10 : return std::unique_ptr<AST::PathInExpression> (
264 10 : new AST::PathInExpression (std::move (path)));
265 : }
266 14 : }
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 114488 : }
274 :
275 : // Parses a single or double reference pattern.
276 : template <typename ManagedTokenSource>
277 : std::unique_ptr<AST::ReferencePattern>
278 118 : Parser<ManagedTokenSource>::parse_reference_pattern ()
279 : {
280 : // parse double or single ref
281 118 : bool is_double_ref = false;
282 118 : const_TokenPtr t = lexer.peek_token ();
283 118 : switch (t->get_id ())
284 : {
285 104 : case AMP:
286 : // still false
287 104 : lexer.skip_token ();
288 104 : break;
289 14 : case LOGICAL_AND:
290 14 : is_double_ref = true;
291 14 : lexer.skip_token ();
292 14 : 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 118 : bool is_mut = false;
303 236 : if (lexer.peek_token ()->get_id () == MUT)
304 : {
305 5 : is_mut = true;
306 5 : lexer.skip_token ();
307 : }
308 :
309 : // parse pattern to get reference of (required)
310 118 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
311 118 : 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 118 : new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
323 118 : t->get_locus ()));
324 118 : }
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 3367 : Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
331 : {
332 3367 : location_t paren_locus = lexer.peek_token ()->get_locus ();
333 3367 : skip_token (LEFT_PAREN);
334 :
335 : // detect '..' token (ranged with no lower range)
336 6734 : 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 6722 : else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
385 : {
386 25 : skip_token (RIGHT_PAREN);
387 25 : auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> (
388 25 : new AST::TuplePatternItemsNoRest (
389 25 : std::vector<std::unique_ptr<AST::Pattern>> ()));
390 25 : return std::unique_ptr<AST::TuplePattern> (
391 25 : new AST::TuplePattern (std::move (items), paren_locus));
392 25 : }
393 :
394 : // parse initial pattern (required)
395 3336 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
396 3336 : 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 3336 : const_TokenPtr t = lexer.peek_token ();
407 3336 : 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 3287 : case COMMA:
416 : {
417 : // tuple pattern
418 3287 : lexer.skip_token ();
419 :
420 : // create vector of patterns
421 3287 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
422 3287 : patterns.push_back (std::move (initial_pattern));
423 :
424 3287 : t = lexer.peek_token ();
425 7463 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
426 : {
427 : // parse pattern (required)
428 4176 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
429 4176 : 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 4176 : patterns.push_back (std::move (pattern));
438 :
439 8352 : if (lexer.peek_token ()->get_id () != COMMA)
440 : break;
441 :
442 987 : lexer.skip_token ();
443 987 : t = lexer.peek_token ();
444 : }
445 :
446 3287 : t = lexer.peek_token ();
447 3287 : if (t->get_id () == RIGHT_PAREN)
448 : {
449 : // non-ranged tuple pattern
450 3255 : lexer.skip_token ();
451 :
452 3255 : std::unique_ptr<AST::TuplePatternItemsNoRest> items (
453 3255 : new AST::TuplePatternItemsNoRest (std::move (patterns)));
454 3255 : return std::unique_ptr<AST::TuplePattern> (
455 3255 : new AST::TuplePattern (std::move (items), paren_locus));
456 3255 : }
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 3287 : }
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 3336 : }
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 113 : Parser<ManagedTokenSource>::parse_slice_pattern ()
526 : {
527 113 : location_t square_locus = lexer.peek_token ()->get_locus ();
528 113 : std::vector<std::unique_ptr<AST::Pattern>> sub_patterns;
529 :
530 113 : skip_token (LEFT_SQUARE);
531 :
532 113 : bool is_first = true;
533 :
534 540 : while (true)
535 : {
536 383 : const_TokenPtr t = lexer.peek_token ();
537 :
538 383 : if (!is_first && t->get_id () == COMMA)
539 : {
540 163 : skip_token (COMMA);
541 163 : t = lexer.peek_token ();
542 : }
543 :
544 383 : if (t->get_id () == RIGHT_SQUARE)
545 : {
546 113 : skip_token (RIGHT_SQUARE);
547 : break;
548 : }
549 :
550 : // parse pattern (required)
551 270 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
552 270 : 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 270 : sub_patterns.push_back (std::move (pattern));
563 270 : is_first = false;
564 : }
565 :
566 : return std::make_unique<AST::SlicePattern> (std::move (sub_patterns),
567 113 : square_locus);
568 113 : }
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 2435 : Parser<ManagedTokenSource>::parse_identifier_pattern ()
575 : {
576 2435 : location_t locus = lexer.peek_token ()->get_locus ();
577 :
578 2435 : bool has_ref = false;
579 4870 : if (lexer.peek_token ()->get_id () == REF)
580 : {
581 251 : has_ref = true;
582 251 : lexer.skip_token ();
583 :
584 : // DEBUG
585 251 : rust_debug ("parsed ref in identifier pattern");
586 : }
587 :
588 2435 : bool has_mut = false;
589 4870 : if (lexer.peek_token ()->get_id () == MUT)
590 : {
591 2243 : has_mut = true;
592 2243 : lexer.skip_token ();
593 : }
594 :
595 : // parse identifier (required)
596 2435 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
597 2435 : if (ident_tok == nullptr)
598 : {
599 : // skip somewhere?
600 0 : return nullptr;
601 : }
602 4870 : Identifier ident{ident_tok};
603 :
604 : // DEBUG
605 2435 : rust_debug ("parsed identifier in identifier pattern");
606 :
607 : // parse optional pattern binding thing
608 2435 : std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
609 4870 : 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 2435 : rust_debug ("about to return identifier pattern");
627 :
628 : return std::unique_ptr<AST::IdentifierPattern> (
629 2435 : new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
630 2435 : std::move (bind_pattern)));
631 2435 : }
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 56945 : Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
639 : {
640 : // ensure first token is actually identifier
641 56945 : const_TokenPtr initial_tok = lexer.peek_token ();
642 56945 : 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 56945 : std::string initial_ident = initial_tok->get_str ();
649 :
650 : // parse next tokens as a PathInExpression
651 56945 : AST::PathInExpression path = parse_path_in_expression ();
652 :
653 : // branch on next token
654 56945 : const_TokenPtr t = lexer.peek_token ();
655 56945 : switch (t->get_id ())
656 : {
657 4 : case EXCLAM:
658 8 : return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
659 2021 : case LEFT_PAREN:
660 : {
661 : // tuple struct
662 2021 : lexer.skip_token ();
663 :
664 : // DEBUG
665 2021 : rust_debug ("parsing tuple struct pattern");
666 :
667 : // parse items
668 2021 : std::unique_ptr<AST::TupleStructItems> items
669 : = parse_tuple_struct_items ();
670 2021 : 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 2020 : rust_debug ("successfully parsed tuple struct items");
681 :
682 2020 : if (!skip_token (RIGHT_PAREN))
683 : {
684 0 : return nullptr;
685 : }
686 :
687 : // DEBUG
688 2020 : rust_debug ("successfully parsed tuple struct pattern");
689 :
690 2020 : return std::unique_ptr<AST::TupleStructPattern> (
691 2020 : new AST::TupleStructPattern (std::move (path), std::move (items)));
692 2021 : }
693 213 : case LEFT_CURLY:
694 : {
695 : // struct
696 213 : lexer.skip_token ();
697 :
698 : // parse elements (optional)
699 213 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
700 :
701 213 : if (!skip_token (RIGHT_CURLY))
702 : {
703 0 : return nullptr;
704 : }
705 :
706 : // DEBUG
707 213 : rust_debug ("successfully parsed struct pattern");
708 :
709 213 : return std::unique_ptr<AST::StructPattern> (
710 426 : new AST::StructPattern (std::move (path), initial_tok->get_locus (),
711 213 : std::move (elems)));
712 213 : }
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 55 : case PATTERN_BIND:
734 : {
735 : // only allow on single-segment paths
736 55 : if (path.is_single_segment ())
737 : {
738 : // identifier with pattern bind
739 55 : lexer.skip_token ();
740 :
741 55 : std::unique_ptr<AST::Pattern> bind_pattern
742 : = parse_pattern_no_alt ();
743 55 : 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 54 : return std::unique_ptr<AST::IdentifierPattern> (
753 162 : new AST::IdentifierPattern (std::move (initial_ident),
754 : initial_tok->get_locus (), false,
755 54 : false, std::move (bind_pattern)));
756 55 : }
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 54643 : default:
765 : // assume identifier if single segment
766 54643 : if (path.is_single_segment ())
767 : {
768 53507 : return std::unique_ptr<AST::IdentifierPattern> (
769 160521 : new AST::IdentifierPattern (std::move (initial_ident),
770 53507 : initial_tok->get_locus ()));
771 : }
772 : // return path otherwise
773 1136 : return std::unique_ptr<AST::PathInExpression> (
774 1136 : new AST::PathInExpression (std::move (path)));
775 : }
776 56945 : }
777 :
778 : // Parses struct pattern elements if they exist.
779 : template <typename ManagedTokenSource>
780 : AST::StructPatternElements
781 217 : Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
782 : {
783 217 : std::vector<std::unique_ptr<AST::StructPatternField>> fields;
784 :
785 217 : AST::AttrVec etc_attrs;
786 217 : bool has_rest = false;
787 :
788 : // try parsing struct pattern fields
789 217 : const_TokenPtr t = lexer.peek_token ();
790 707 : while (t->get_id () != RIGHT_CURLY)
791 : {
792 345 : AST::AttrVec outer_attrs = parse_outer_attributes ();
793 :
794 : // parse etc (must be last in struct pattern, so breaks)
795 690 : if (lexer.peek_token ()->get_id () == DOT_DOT)
796 : {
797 19 : lexer.skip_token ();
798 19 : etc_attrs = std::move (outer_attrs);
799 19 : has_rest = true;
800 19 : break;
801 : }
802 :
803 326 : std::unique_ptr<AST::StructPatternField> field
804 326 : = parse_struct_pattern_field_partial (std::move (outer_attrs));
805 326 : 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 326 : fields.push_back (std::move (field));
815 :
816 652 : if (lexer.peek_token ()->get_id () != COMMA)
817 : break;
818 :
819 : // skip comma
820 145 : lexer.skip_token ();
821 145 : t = lexer.peek_token ();
822 : }
823 :
824 217 : if (has_rest)
825 19 : return AST::StructPatternElements (std::move (fields),
826 19 : std::move (etc_attrs));
827 : else
828 198 : return AST::StructPatternElements (std::move (fields));
829 217 : }
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 326 : Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
848 : AST::AttrVec outer_attrs)
849 : {
850 : // branch based on next token
851 326 : const_TokenPtr t = lexer.peek_token ();
852 326 : switch (t->get_id ())
853 : {
854 34 : case INT_LITERAL:
855 : {
856 : // tuple index
857 68 : std::string index_str = t->get_str ();
858 34 : int index = atoi (index_str.c_str ());
859 :
860 34 : lexer.skip_token ();
861 :
862 34 : if (!skip_token (COLON))
863 : {
864 0 : return nullptr;
865 : }
866 :
867 : // parse required pattern
868 34 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
869 34 : 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 34 : return std::unique_ptr<AST::StructPatternFieldTuplePat> (
880 34 : new AST::StructPatternFieldTuplePat (index, std::move (pattern),
881 : std::move (outer_attrs),
882 34 : t->get_locus ()));
883 68 : }
884 290 : case IDENTIFIER:
885 : // identifier-pattern OR only identifier
886 : // branch on next token
887 580 : switch (lexer.peek_token (1)->get_id ())
888 : {
889 135 : case COLON:
890 : {
891 : // identifier-pattern
892 270 : Identifier ident{t};
893 135 : lexer.skip_token ();
894 :
895 135 : skip_token (COLON);
896 :
897 : // parse required pattern
898 135 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
899 135 : 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 135 : return std::unique_ptr<AST::StructPatternFieldIdentPat> (
909 270 : new AST::StructPatternFieldIdentPat (std::move (ident),
910 : std::move (pattern),
911 : std::move (outer_attrs),
912 135 : t->get_locus ()));
913 135 : }
914 155 : case COMMA:
915 : case RIGHT_CURLY:
916 : {
917 : // identifier only
918 310 : Identifier ident = {t};
919 155 : lexer.skip_token ();
920 :
921 155 : return std::unique_ptr<AST::StructPatternFieldIdent> (
922 310 : new AST::StructPatternFieldIdent (std::move (ident), false, false,
923 : std::move (outer_attrs),
924 155 : t->get_locus ()));
925 155 : }
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 4 : 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 326 : }
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 45697 : Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
976 : {
977 45697 : const_TokenPtr range_lower = lexer.peek_token ();
978 45697 : AST::Literal::LitType type = AST::Literal::STRING;
979 45697 : bool has_minus = false;
980 :
981 : // get lit type
982 45697 : switch (range_lower->get_id ())
983 : {
984 102 : case CHAR_LITERAL:
985 102 : type = AST::Literal::CHAR;
986 102 : lexer.skip_token ();
987 102 : break;
988 87 : case BYTE_CHAR_LITERAL:
989 87 : type = AST::Literal::BYTE;
990 87 : lexer.skip_token ();
991 87 : break;
992 45479 : case INT_LITERAL:
993 45479 : type = AST::Literal::INT;
994 45479 : lexer.skip_token ();
995 45479 : break;
996 2 : case FLOAT_LITERAL:
997 2 : type = AST::Literal::FLOAT;
998 2 : lexer.skip_token ();
999 2 : 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 45697 : std::string literal_value;
1034 45697 : if (range_lower->get_id () == INT_LITERAL)
1035 91008 : literal_value = LiteralResolve::evaluate_integer_literal (range_lower);
1036 193 : else if (range_lower->get_id () == FLOAT_LITERAL)
1037 8 : literal_value = LiteralResolve::evaluate_float_literal (range_lower);
1038 : else
1039 189 : literal_value = range_lower->get_str ();
1040 :
1041 45697 : const_TokenPtr next = lexer.peek_token ();
1042 45697 : if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
1043 91253 : || next->get_id () == DOT_DOT)
1044 : {
1045 169 : AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
1046 : // range pattern
1047 169 : lexer.skip_token ();
1048 169 : std::unique_ptr<AST::RangePatternBound> lower (
1049 338 : new AST::RangePatternBoundLiteral (
1050 338 : AST::Literal (std::move (literal_value), type,
1051 : PrimitiveCoreType::CORETYPE_UNKNOWN),
1052 : range_lower->get_locus (), has_minus));
1053 :
1054 169 : std::unique_ptr<AST::RangePatternBound> upper
1055 : = parse_range_pattern_bound ();
1056 169 : 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 168 : return std::unique_ptr<AST::RangePattern> (
1066 168 : new AST::RangePattern (std::move (lower), std::move (upper), kind,
1067 168 : range_lower->get_locus ()));
1068 169 : }
1069 : else
1070 : {
1071 : // literal pattern
1072 :
1073 45528 : auto type_hint = (range_lower->get_id () == INT_LITERAL
1074 104 : || range_lower->get_id () == FLOAT_LITERAL)
1075 136380 : ? LiteralResolve::resolve_literal_suffix (range_lower)
1076 45528 : : range_lower->get_type_hint ();
1077 :
1078 45528 : return std::unique_ptr<AST::LiteralPattern> (
1079 91056 : new AST::LiteralPattern (std::move (literal_value), type,
1080 : range_lower->get_locus (), type_hint,
1081 45528 : has_minus));
1082 : }
1083 45697 : }
1084 :
1085 : // Parses a range pattern bound (value only).
1086 : template <typename ManagedTokenSource>
1087 : std::unique_ptr<AST::RangePatternBound>
1088 178 : Parser<ManagedTokenSource>::parse_range_pattern_bound ()
1089 : {
1090 178 : const_TokenPtr range_lower = lexer.peek_token ();
1091 178 : location_t range_lower_locus = range_lower->get_locus ();
1092 :
1093 : // get lit type
1094 178 : 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 16 : 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 16 : AST::PathInExpression path = parse_path_in_expression ();
1169 16 : 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 16 : return std::unique_ptr<AST::RangePatternBoundPath> (
1179 16 : new AST::RangePatternBoundPath (std::move (path)));
1180 16 : }
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 178 : }
1208 :
1209 : } // namespace Rust
|