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 27826 : Parser<ManagedTokenSource>::parse_pattern ()
30 : {
31 27826 : location_t start_locus = lexer.peek_token ()->get_locus ();
32 :
33 : /* skip optional starting pipe */
34 27826 : maybe_skip_token (PIPE);
35 :
36 27826 : auto first = parse_pattern_no_alt ();
37 :
38 55652 : if (lexer.peek_token ()->get_id () != PIPE)
39 : /* no alternates */
40 27633 : return first;
41 :
42 193 : std::vector<std::unique_ptr<AST::Pattern>> alts;
43 193 : if (first != nullptr)
44 192 : alts.push_back (std::move (first));
45 :
46 : do
47 : {
48 211 : lexer.skip_token ();
49 211 : auto follow = parse_pattern_no_alt ();
50 211 : if (follow != nullptr)
51 211 : alts.push_back (std::move (follow));
52 211 : }
53 :
54 422 : while (lexer.peek_token ()->get_id () == PIPE);
55 :
56 193 : if (alts.empty ())
57 0 : return nullptr;
58 :
59 : /* alternates */
60 : return std::unique_ptr<AST::Pattern> (
61 193 : new AST::AltPattern (std::move (alts), start_locus));
62 27826 : }
63 :
64 : // Parses a pattern without alternates ('|')
65 : // (will further disambiguate any pattern).
66 : template <typename ManagedTokenSource>
67 : std::unique_ptr<AST::Pattern>
68 28160 : Parser<ManagedTokenSource>::parse_pattern_no_alt ()
69 : {
70 28160 : const_TokenPtr t = lexer.peek_token ();
71 28160 : switch (t->get_id ())
72 : {
73 17 : case TRUE_LITERAL:
74 17 : lexer.skip_token ();
75 17 : return std::unique_ptr<AST::LiteralPattern> (
76 51 : new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
77 : AST::Literal::BOOL, t->get_locus (),
78 17 : t->get_type_hint ()));
79 9 : case FALSE_LITERAL:
80 9 : lexer.skip_token ();
81 9 : return std::unique_ptr<AST::LiteralPattern> (
82 27 : new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
83 : AST::Literal::BOOL, t->get_locus (),
84 9 : t->get_type_hint ()));
85 457 : case CHAR_LITERAL:
86 : case BYTE_CHAR_LITERAL:
87 : case INT_LITERAL:
88 : case FLOAT_LITERAL:
89 457 : return parse_literal_or_range_pattern ();
90 0 : case STRING_LITERAL:
91 0 : lexer.skip_token ();
92 0 : return std::unique_ptr<AST::LiteralPattern> (
93 0 : new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
94 0 : 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 26 : case MINUS:
108 52 : if (lexer.peek_token (1)->get_id () == INT_LITERAL)
109 : {
110 24 : 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 1058 : case UNDERSCORE:
125 1058 : lexer.skip_token ();
126 1058 : return std::unique_ptr<AST::WildcardPattern> (
127 1058 : new AST::WildcardPattern (t->get_locus ()));
128 0 : case DOT_DOT:
129 0 : lexer.skip_token ();
130 0 : return std::unique_ptr<AST::RestPattern> (
131 0 : new AST::RestPattern (t->get_locus ()));
132 924 : case REF:
133 : case MUT:
134 924 : return parse_identifier_pattern ();
135 25117 : 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 25117 : return parse_ident_leading_pattern ();
141 32 : case AMP:
142 : case LOGICAL_AND:
143 : // reference pattern
144 32 : return parse_reference_pattern ();
145 434 : case LEFT_PAREN:
146 : // tuple pattern or grouped pattern
147 434 : return parse_grouped_or_tuple_pattern ();
148 77 : case LEFT_SQUARE:
149 : // slice pattern
150 77 : 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 8 : 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 8 : AST::PathInExpression path = parse_path_in_expression ();
193 :
194 8 : const_TokenPtr next = lexer.peek_token ();
195 8 : 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 0 : case LEFT_CURLY:
245 : {
246 : // struct
247 0 : lexer.skip_token ();
248 :
249 : // parse elements (optional)
250 0 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
251 :
252 0 : if (!skip_token (RIGHT_CURLY))
253 : {
254 0 : return nullptr;
255 : }
256 :
257 0 : return std::unique_ptr<AST::StructPattern> (
258 0 : new AST::StructPattern (std::move (path), t->get_locus (),
259 0 : std::move (elems)));
260 0 : }
261 8 : default:
262 : // assume path in expression
263 8 : return std::unique_ptr<AST::PathInExpression> (
264 8 : new AST::PathInExpression (std::move (path)));
265 : }
266 8 : }
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 28160 : }
274 :
275 : // Parses a single or double reference pattern.
276 : template <typename ManagedTokenSource>
277 : std::unique_ptr<AST::ReferencePattern>
278 32 : Parser<ManagedTokenSource>::parse_reference_pattern ()
279 : {
280 : // parse double or single ref
281 32 : bool is_double_ref = false;
282 32 : const_TokenPtr t = lexer.peek_token ();
283 32 : switch (t->get_id ())
284 : {
285 23 : case AMP:
286 : // still false
287 23 : lexer.skip_token ();
288 : break;
289 9 : case LOGICAL_AND:
290 9 : is_double_ref = true;
291 9 : 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 32 : bool is_mut = false;
303 64 : if (lexer.peek_token ()->get_id () == MUT)
304 : {
305 2 : is_mut = true;
306 2 : lexer.skip_token ();
307 : }
308 :
309 : // parse pattern to get reference of (required)
310 32 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
311 32 : 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 32 : new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
323 32 : t->get_locus ()));
324 32 : }
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 434 : Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
331 : {
332 434 : location_t paren_locus = lexer.peek_token ()->get_locus ();
333 434 : skip_token (LEFT_PAREN);
334 :
335 : // detect '..' token (ranged with no lower range)
336 868 : if (lexer.peek_token ()->get_id () == DOT_DOT)
337 : {
338 0 : lexer.skip_token ();
339 :
340 : // parse new patterns while next token is a comma
341 0 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
342 :
343 0 : const_TokenPtr t = lexer.peek_token ();
344 0 : 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 0 : 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 0 : std::unique_ptr<AST::TuplePatternItemsHasRest> items (
379 0 : new AST::TuplePatternItemsHasRest (
380 0 : std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
381 0 : return std::unique_ptr<AST::TuplePattern> (
382 0 : new AST::TuplePattern (std::move (items), paren_locus));
383 0 : }
384 868 : else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
385 : {
386 3 : skip_token (RIGHT_PAREN);
387 3 : auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> (
388 3 : new AST::TuplePatternItemsNoRest (
389 3 : std::vector<std::unique_ptr<AST::Pattern>> ()));
390 3 : return std::unique_ptr<AST::TuplePattern> (
391 3 : new AST::TuplePattern (std::move (items), paren_locus));
392 3 : }
393 :
394 : // parse initial pattern (required)
395 431 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
396 431 : 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 431 : const_TokenPtr t = lexer.peek_token ();
407 431 : switch (t->get_id ())
408 : {
409 44 : case RIGHT_PAREN:
410 : // grouped pattern
411 44 : lexer.skip_token ();
412 :
413 44 : return std::unique_ptr<AST::GroupedPattern> (
414 44 : new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
415 386 : case COMMA:
416 : {
417 : // tuple pattern
418 386 : lexer.skip_token ();
419 :
420 : // create vector of patterns
421 386 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
422 386 : patterns.push_back (std::move (initial_pattern));
423 :
424 386 : t = lexer.peek_token ();
425 772 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
426 : {
427 : // parse pattern (required)
428 386 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
429 386 : 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 386 : patterns.push_back (std::move (pattern));
438 :
439 772 : if (lexer.peek_token ()->get_id () != COMMA)
440 : break;
441 :
442 36 : lexer.skip_token ();
443 36 : t = lexer.peek_token ();
444 : }
445 :
446 386 : t = lexer.peek_token ();
447 386 : if (t->get_id () == RIGHT_PAREN)
448 : {
449 : // non-ranged tuple pattern
450 359 : lexer.skip_token ();
451 :
452 359 : std::unique_ptr<AST::TuplePatternItemsNoRest> items (
453 359 : new AST::TuplePatternItemsNoRest (std::move (patterns)));
454 359 : return std::unique_ptr<AST::TuplePattern> (
455 359 : new AST::TuplePattern (std::move (items), paren_locus));
456 359 : }
457 27 : else if (t->get_id () == DOT_DOT)
458 : {
459 : // ranged tuple pattern
460 27 : lexer.skip_token ();
461 :
462 : // parse upper patterns
463 27 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
464 27 : t = lexer.peek_token ();
465 59 : while (t->get_id () == COMMA)
466 : {
467 32 : lexer.skip_token ();
468 :
469 : // break if end
470 64 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
471 : break;
472 :
473 : // parse pattern (required)
474 32 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
475 32 : 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 32 : upper_patterns.push_back (std::move (pattern));
484 :
485 32 : t = lexer.peek_token ();
486 : }
487 :
488 27 : if (!skip_token (RIGHT_PAREN))
489 : {
490 0 : return nullptr;
491 : }
492 :
493 27 : std::unique_ptr<AST::TuplePatternItemsHasRest> items (
494 27 : new AST::TuplePatternItemsHasRest (std::move (patterns),
495 : std::move (upper_patterns)));
496 27 : return std::unique_ptr<AST::TuplePattern> (
497 27 : new AST::TuplePattern (std::move (items), paren_locus));
498 27 : }
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 386 : }
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 431 : }
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 77 : Parser<ManagedTokenSource>::parse_slice_pattern ()
526 : {
527 154 : location_t square_locus = lexer.peek_token ()->get_locus ();
528 77 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
529 77 : tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns
530 : = tl::nullopt;
531 :
532 : // lambda function to determine which vector to push new patterns into
533 77 : auto get_pattern_ref
534 75 : = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & {
535 75 : return upper_patterns.has_value () ? upper_patterns.value () : patterns;
536 : };
537 :
538 77 : skip_token (LEFT_SQUARE);
539 :
540 154 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
541 : {
542 1 : skip_token (RIGHT_SQUARE);
543 1 : std::unique_ptr<AST::SlicePatternItemsNoRest> items (
544 1 : new AST::SlicePatternItemsNoRest (std::move (patterns)));
545 : return std::unique_ptr<AST::SlicePattern> (
546 1 : new AST::SlicePattern (std::move (items), square_locus));
547 1 : }
548 :
549 : // parse initial pattern (required)
550 152 : if (lexer.peek_token ()->get_id () == DOT_DOT)
551 : {
552 1 : lexer.skip_token ();
553 1 : upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
554 : }
555 : else
556 : {
557 : // Not a rest pattern `..`, parse normally
558 75 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
559 75 : if (initial_pattern == nullptr)
560 : {
561 0 : Error error (lexer.peek_token ()->get_locus (),
562 : "failed to parse initial pattern in slice pattern");
563 0 : add_error (std::move (error));
564 :
565 0 : return nullptr;
566 0 : }
567 :
568 75 : patterns.push_back (std::move (initial_pattern));
569 75 : }
570 :
571 76 : const_TokenPtr t = lexer.peek_token ();
572 194 : while (t->get_id () == COMMA)
573 : {
574 118 : lexer.skip_token ();
575 :
576 : // break if end bracket
577 236 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
578 : break;
579 :
580 236 : if (lexer.peek_token ()->get_id () == DOT_DOT)
581 : {
582 43 : if (upper_patterns.has_value ())
583 : {
584 : // DOT_DOT has been parsed before
585 0 : Error error (lexer.peek_token ()->get_locus (), "%s",
586 : "`..` can only be used once per slice pattern");
587 0 : add_error (std::move (error));
588 :
589 0 : return nullptr;
590 0 : }
591 43 : upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
592 43 : lexer.skip_token ();
593 43 : t = lexer.peek_token ();
594 43 : continue;
595 43 : }
596 :
597 : // parse pattern (required)
598 75 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
599 75 : if (pattern == nullptr)
600 : {
601 0 : Error error (lexer.peek_token ()->get_locus (),
602 : "failed to parse pattern in slice pattern");
603 0 : add_error (std::move (error));
604 :
605 0 : return nullptr;
606 0 : }
607 75 : get_pattern_ref ().push_back (std::move (pattern));
608 :
609 75 : t = lexer.peek_token ();
610 : }
611 :
612 76 : if (!skip_token (RIGHT_SQUARE))
613 : {
614 0 : return nullptr;
615 : }
616 :
617 76 : if (upper_patterns.has_value ())
618 : {
619 : // Slice pattern with rest
620 44 : std::unique_ptr<AST::SlicePatternItemsHasRest> items (
621 88 : new AST::SlicePatternItemsHasRest (
622 44 : std::move (patterns), std::move (upper_patterns.value ())));
623 : return std::unique_ptr<AST::SlicePattern> (
624 44 : new AST::SlicePattern (std::move (items), square_locus));
625 44 : }
626 :
627 : // Rest-less slice pattern
628 32 : std::unique_ptr<AST::SlicePatternItemsNoRest> items (
629 32 : new AST::SlicePatternItemsNoRest (std::move (patterns)));
630 : return std::unique_ptr<AST::SlicePattern> (
631 32 : new AST::SlicePattern (std::move (items), square_locus));
632 185 : }
633 :
634 : /* Parses an identifier pattern (pattern that binds a value matched to a
635 : * variable). */
636 : template <typename ManagedTokenSource>
637 : std::unique_ptr<AST::IdentifierPattern>
638 924 : Parser<ManagedTokenSource>::parse_identifier_pattern ()
639 : {
640 924 : location_t locus = lexer.peek_token ()->get_locus ();
641 :
642 924 : bool has_ref = false;
643 1848 : if (lexer.peek_token ()->get_id () == REF)
644 : {
645 6 : has_ref = true;
646 6 : lexer.skip_token ();
647 :
648 : // DEBUG
649 6 : rust_debug ("parsed ref in identifier pattern");
650 : }
651 :
652 924 : bool has_mut = false;
653 1848 : if (lexer.peek_token ()->get_id () == MUT)
654 : {
655 922 : has_mut = true;
656 922 : lexer.skip_token ();
657 : }
658 :
659 : // parse identifier (required)
660 924 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
661 924 : if (ident_tok == nullptr)
662 : {
663 : // skip somewhere?
664 0 : return nullptr;
665 : }
666 924 : Identifier ident{ident_tok};
667 :
668 : // DEBUG
669 924 : rust_debug ("parsed identifier in identifier pattern");
670 :
671 : // parse optional pattern binding thing
672 924 : std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
673 1848 : if (lexer.peek_token ()->get_id () == PATTERN_BIND)
674 : {
675 1 : lexer.skip_token ();
676 :
677 : // parse required pattern to bind
678 1 : bind_pattern = parse_pattern_no_alt ();
679 1 : if (bind_pattern == nullptr)
680 : {
681 0 : Error error (lexer.peek_token ()->get_locus (),
682 : "failed to parse pattern to bind in identifier pattern");
683 0 : add_error (std::move (error));
684 :
685 0 : return nullptr;
686 0 : }
687 : }
688 :
689 : // DEBUG
690 924 : rust_debug ("about to return identifier pattern");
691 :
692 : return std::unique_ptr<AST::IdentifierPattern> (
693 924 : new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
694 924 : std::move (bind_pattern)));
695 924 : }
696 :
697 : /* Parses a pattern that opens with an identifier. This includes identifier
698 : * patterns, path patterns (and derivatives such as struct patterns, tuple
699 : * struct patterns, and macro invocations), and ranges. */
700 : template <typename ManagedTokenSource>
701 : std::unique_ptr<AST::Pattern>
702 25117 : Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
703 : {
704 : // ensure first token is actually identifier
705 25117 : const_TokenPtr initial_tok = lexer.peek_token ();
706 25117 : if (initial_tok->get_id () != IDENTIFIER)
707 : {
708 0 : return nullptr;
709 : }
710 :
711 : // save initial identifier as it may be useful (but don't skip)
712 25117 : std::string initial_ident = initial_tok->get_str ();
713 :
714 : // parse next tokens as a PathInExpression
715 25117 : AST::PathInExpression path = parse_path_in_expression ();
716 :
717 : // branch on next token
718 25117 : const_TokenPtr t = lexer.peek_token ();
719 25117 : switch (t->get_id ())
720 : {
721 3 : case EXCLAM:
722 6 : return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
723 924 : case LEFT_PAREN:
724 : {
725 : // tuple struct
726 924 : lexer.skip_token ();
727 :
728 : // DEBUG
729 924 : rust_debug ("parsing tuple struct pattern");
730 :
731 : // parse items
732 924 : std::unique_ptr<AST::TupleStructItems> items
733 : = parse_tuple_struct_items ();
734 924 : if (items == nullptr)
735 : {
736 1 : Error error (lexer.peek_token ()->get_locus (),
737 : "failed to parse tuple struct items");
738 1 : add_error (std::move (error));
739 :
740 1 : return nullptr;
741 1 : }
742 :
743 : // DEBUG
744 923 : rust_debug ("successfully parsed tuple struct items");
745 :
746 923 : if (!skip_token (RIGHT_PAREN))
747 : {
748 0 : return nullptr;
749 : }
750 :
751 : // DEBUG
752 923 : rust_debug ("successfully parsed tuple struct pattern");
753 :
754 923 : return std::unique_ptr<AST::TupleStructPattern> (
755 923 : new AST::TupleStructPattern (std::move (path), std::move (items)));
756 924 : }
757 110 : case LEFT_CURLY:
758 : {
759 : // struct
760 110 : lexer.skip_token ();
761 :
762 : // parse elements (optional)
763 110 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
764 :
765 110 : if (!skip_token (RIGHT_CURLY))
766 : {
767 0 : return nullptr;
768 : }
769 :
770 : // DEBUG
771 110 : rust_debug ("successfully parsed struct pattern");
772 :
773 110 : return std::unique_ptr<AST::StructPattern> (
774 220 : new AST::StructPattern (std::move (path), initial_tok->get_locus (),
775 110 : std::move (elems)));
776 110 : }
777 8 : case DOT_DOT_EQ:
778 : case DOT_DOT:
779 : case ELLIPSIS:
780 : {
781 : // range
782 : AST::RangeKind kind
783 8 : = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
784 :
785 8 : lexer.skip_token ();
786 :
787 8 : std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
788 8 : new AST::RangePatternBoundPath (std::move (path)));
789 8 : std::unique_ptr<AST::RangePatternBound> upper_bound
790 : = parse_range_pattern_bound ();
791 :
792 8 : return std::unique_ptr<AST::RangePattern> (
793 8 : new AST::RangePattern (std::move (lower_bound),
794 : std::move (upper_bound), kind,
795 8 : t->get_locus ()));
796 8 : }
797 18 : case PATTERN_BIND:
798 : {
799 : // only allow on single-segment paths
800 18 : if (path.is_single_segment ())
801 : {
802 : // identifier with pattern bind
803 18 : lexer.skip_token ();
804 :
805 18 : std::unique_ptr<AST::Pattern> bind_pattern
806 : = parse_pattern_no_alt ();
807 18 : if (bind_pattern == nullptr)
808 : {
809 1 : Error error (
810 : t->get_locus (),
811 : "failed to parse pattern to bind to identifier pattern");
812 1 : add_error (std::move (error));
813 :
814 1 : return nullptr;
815 1 : }
816 17 : return std::unique_ptr<AST::IdentifierPattern> (
817 51 : new AST::IdentifierPattern (std::move (initial_ident),
818 : initial_tok->get_locus (), false,
819 17 : false, std::move (bind_pattern)));
820 18 : }
821 0 : Error error (
822 : t->get_locus (),
823 : "failed to parse pattern bind to a path, not an identifier");
824 0 : add_error (std::move (error));
825 :
826 0 : return nullptr;
827 0 : }
828 24054 : default:
829 : // assume identifier if single segment
830 24054 : if (path.is_single_segment ())
831 : {
832 23079 : return std::unique_ptr<AST::IdentifierPattern> (
833 69237 : new AST::IdentifierPattern (std::move (initial_ident),
834 23079 : initial_tok->get_locus ()));
835 : }
836 : // return path otherwise
837 975 : return std::unique_ptr<AST::PathInExpression> (
838 975 : new AST::PathInExpression (std::move (path)));
839 : }
840 25117 : }
841 :
842 : // Parses struct pattern elements if they exist.
843 : template <typename ManagedTokenSource>
844 : AST::StructPatternElements
845 110 : Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
846 : {
847 110 : std::vector<std::unique_ptr<AST::StructPatternField>> fields;
848 :
849 110 : AST::AttrVec etc_attrs;
850 110 : bool has_rest = false;
851 :
852 : // try parsing struct pattern fields
853 110 : const_TokenPtr t = lexer.peek_token ();
854 370 : while (t->get_id () != RIGHT_CURLY)
855 : {
856 178 : AST::AttrVec outer_attrs = parse_outer_attributes ();
857 :
858 : // parse etc (must be last in struct pattern, so breaks)
859 356 : if (lexer.peek_token ()->get_id () == DOT_DOT)
860 : {
861 5 : lexer.skip_token ();
862 5 : etc_attrs = std::move (outer_attrs);
863 5 : has_rest = true;
864 5 : break;
865 : }
866 :
867 173 : std::unique_ptr<AST::StructPatternField> field
868 173 : = parse_struct_pattern_field_partial (std::move (outer_attrs));
869 173 : if (field == nullptr)
870 : {
871 0 : Error error (lexer.peek_token ()->get_locus (),
872 : "failed to parse struct pattern field");
873 0 : add_error (std::move (error));
874 :
875 : // skip after somewhere?
876 0 : return AST::StructPatternElements::create_empty ();
877 0 : }
878 173 : fields.push_back (std::move (field));
879 :
880 346 : if (lexer.peek_token ()->get_id () != COMMA)
881 : break;
882 :
883 : // skip comma
884 82 : lexer.skip_token ();
885 82 : t = lexer.peek_token ();
886 : }
887 :
888 110 : if (has_rest)
889 5 : return AST::StructPatternElements (std::move (fields),
890 : std::move (etc_attrs));
891 : else
892 105 : return AST::StructPatternElements (std::move (fields));
893 110 : }
894 :
895 : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
896 : * identifier). */
897 : template <typename ManagedTokenSource>
898 : std::unique_ptr<AST::StructPatternField>
899 0 : Parser<ManagedTokenSource>::parse_struct_pattern_field ()
900 : {
901 : // parse outer attributes (if they exist)
902 0 : AST::AttrVec outer_attrs = parse_outer_attributes ();
903 :
904 0 : return parse_struct_pattern_field_partial (std::move (outer_attrs));
905 0 : }
906 :
907 : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
908 : * identifier), with outer attributes passed in. */
909 : template <typename ManagedTokenSource>
910 : std::unique_ptr<AST::StructPatternField>
911 173 : Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
912 : AST::AttrVec outer_attrs)
913 : {
914 : // branch based on next token
915 173 : const_TokenPtr t = lexer.peek_token ();
916 173 : switch (t->get_id ())
917 : {
918 26 : case INT_LITERAL:
919 : {
920 : // tuple index
921 52 : std::string index_str = t->get_str ();
922 26 : int index = atoi (index_str.c_str ());
923 :
924 26 : lexer.skip_token ();
925 :
926 26 : if (!skip_token (COLON))
927 : {
928 0 : return nullptr;
929 : }
930 :
931 : // parse required pattern
932 26 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
933 26 : if (pattern == nullptr)
934 : {
935 0 : Error error (
936 : t->get_locus (),
937 : "failed to parse pattern in tuple index struct pattern field");
938 0 : add_error (std::move (error));
939 :
940 0 : return nullptr;
941 0 : }
942 :
943 26 : return std::unique_ptr<AST::StructPatternFieldTuplePat> (
944 26 : new AST::StructPatternFieldTuplePat (index, std::move (pattern),
945 : std::move (outer_attrs),
946 26 : t->get_locus ()));
947 52 : }
948 145 : case IDENTIFIER:
949 : // identifier-pattern OR only identifier
950 : // branch on next token
951 290 : switch (lexer.peek_token (1)->get_id ())
952 : {
953 59 : case COLON:
954 : {
955 : // identifier-pattern
956 59 : Identifier ident{t};
957 59 : lexer.skip_token ();
958 :
959 59 : skip_token (COLON);
960 :
961 : // parse required pattern
962 59 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
963 59 : if (pattern == nullptr)
964 : {
965 0 : Error error (t->get_locus (),
966 : "failed to parse pattern in struct pattern field");
967 0 : add_error (std::move (error));
968 :
969 0 : return nullptr;
970 0 : }
971 :
972 59 : return std::unique_ptr<AST::StructPatternFieldIdentPat> (
973 118 : new AST::StructPatternFieldIdentPat (std::move (ident),
974 : std::move (pattern),
975 : std::move (outer_attrs),
976 59 : t->get_locus ()));
977 59 : }
978 86 : case COMMA:
979 : case RIGHT_CURLY:
980 : {
981 : // identifier only
982 86 : Identifier ident = {t};
983 86 : lexer.skip_token ();
984 :
985 86 : return std::unique_ptr<AST::StructPatternFieldIdent> (
986 172 : new AST::StructPatternFieldIdent (std::move (ident), false, false,
987 : std::move (outer_attrs),
988 86 : t->get_locus ()));
989 86 : }
990 0 : default:
991 : // error
992 0 : add_error (Error (t->get_locus (),
993 : "unrecognised token %qs in struct pattern field",
994 : t->get_token_description ()));
995 :
996 0 : return nullptr;
997 : }
998 2 : case REF:
999 : case MUT:
1000 : {
1001 : // only identifier
1002 2 : bool has_ref = false;
1003 2 : if (t->get_id () == REF)
1004 : {
1005 0 : has_ref = true;
1006 0 : lexer.skip_token ();
1007 : }
1008 :
1009 2 : bool has_mut = false;
1010 4 : if (lexer.peek_token ()->get_id () == MUT)
1011 : {
1012 2 : has_mut = true;
1013 2 : lexer.skip_token ();
1014 : }
1015 :
1016 2 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
1017 2 : if (ident_tok == nullptr)
1018 : {
1019 0 : return nullptr;
1020 : }
1021 2 : Identifier ident{ident_tok};
1022 :
1023 2 : return std::unique_ptr<AST::StructPatternFieldIdent> (
1024 4 : new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
1025 : std::move (outer_attrs),
1026 2 : t->get_locus ()));
1027 4 : }
1028 0 : default:
1029 : // not necessarily an error
1030 0 : return nullptr;
1031 : }
1032 173 : }
1033 :
1034 : /* Parses a literal pattern or range pattern. Assumes that literals passed in
1035 : * are valid range pattern bounds. Do not pass in paths in expressions, for
1036 : * instance. */
1037 : template <typename ManagedTokenSource>
1038 : std::unique_ptr<AST::Pattern>
1039 483 : Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
1040 : {
1041 483 : const_TokenPtr range_lower = lexer.peek_token ();
1042 483 : AST::Literal::LitType type = AST::Literal::STRING;
1043 483 : bool has_minus = false;
1044 :
1045 : // get lit type
1046 483 : switch (range_lower->get_id ())
1047 : {
1048 28 : case CHAR_LITERAL:
1049 28 : type = AST::Literal::CHAR;
1050 28 : lexer.skip_token ();
1051 : break;
1052 21 : case BYTE_CHAR_LITERAL:
1053 21 : type = AST::Literal::BYTE;
1054 21 : lexer.skip_token ();
1055 : break;
1056 406 : case INT_LITERAL:
1057 406 : type = AST::Literal::INT;
1058 406 : lexer.skip_token ();
1059 : break;
1060 2 : case FLOAT_LITERAL:
1061 2 : type = AST::Literal::FLOAT;
1062 2 : lexer.skip_token ();
1063 : break;
1064 26 : case MINUS:
1065 : // branch on next token
1066 52 : range_lower = lexer.peek_token (1);
1067 26 : switch (range_lower->get_id ())
1068 : {
1069 24 : case INT_LITERAL:
1070 24 : type = AST::Literal::INT;
1071 24 : has_minus = true;
1072 24 : lexer.skip_token (1);
1073 24 : break;
1074 2 : case FLOAT_LITERAL:
1075 2 : type = AST::Literal::FLOAT;
1076 2 : has_minus = true;
1077 2 : lexer.skip_token (1);
1078 2 : break;
1079 0 : default:
1080 0 : add_error (Error (range_lower->get_locus (),
1081 : "token type %qs cannot be parsed as range pattern "
1082 : "bound or literal after minus symbol",
1083 : range_lower->get_token_description ()));
1084 :
1085 0 : return nullptr;
1086 : }
1087 : break;
1088 0 : default:
1089 0 : add_error (
1090 0 : Error (range_lower->get_locus (),
1091 : "token type %qs cannot be parsed as range pattern bound",
1092 : range_lower->get_token_description ()));
1093 :
1094 0 : return nullptr;
1095 : }
1096 :
1097 483 : const_TokenPtr next = lexer.peek_token ();
1098 483 : if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
1099 942 : || next->get_id () == DOT_DOT)
1100 : {
1101 48 : AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
1102 : // range pattern
1103 48 : lexer.skip_token ();
1104 48 : std::unique_ptr<AST::RangePatternBound> lower (
1105 96 : new AST::RangePatternBoundLiteral (
1106 144 : AST::Literal (range_lower->get_str (), type,
1107 : PrimitiveCoreType::CORETYPE_UNKNOWN),
1108 : range_lower->get_locus (), has_minus));
1109 :
1110 48 : std::unique_ptr<AST::RangePatternBound> upper
1111 : = parse_range_pattern_bound ();
1112 48 : if (upper == nullptr)
1113 : {
1114 0 : Error error (next->get_locus (),
1115 : "failed to parse range pattern bound in range pattern");
1116 0 : add_error (std::move (error));
1117 :
1118 0 : return nullptr;
1119 0 : }
1120 :
1121 48 : return std::unique_ptr<AST::RangePattern> (
1122 48 : new AST::RangePattern (std::move (lower), std::move (upper), kind,
1123 48 : range_lower->get_locus ()));
1124 48 : }
1125 : else
1126 : {
1127 : // literal pattern
1128 435 : return std::unique_ptr<AST::LiteralPattern> (
1129 1353 : new AST::LiteralPattern (range_lower->get_str (), type,
1130 : range_lower->get_locus (),
1131 435 : range_lower->get_type_hint (), has_minus));
1132 : }
1133 483 : }
1134 :
1135 : // Parses a range pattern bound (value only).
1136 : template <typename ManagedTokenSource>
1137 : std::unique_ptr<AST::RangePatternBound>
1138 56 : Parser<ManagedTokenSource>::parse_range_pattern_bound ()
1139 : {
1140 56 : const_TokenPtr range_lower = lexer.peek_token ();
1141 56 : location_t range_lower_locus = range_lower->get_locus ();
1142 :
1143 : // get lit type
1144 56 : switch (range_lower->get_id ())
1145 : {
1146 7 : case CHAR_LITERAL:
1147 7 : lexer.skip_token ();
1148 7 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1149 14 : new AST::RangePatternBoundLiteral (
1150 28 : AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
1151 : range_lower->get_type_hint ()),
1152 7 : range_lower_locus));
1153 0 : case BYTE_CHAR_LITERAL:
1154 0 : lexer.skip_token ();
1155 0 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1156 0 : new AST::RangePatternBoundLiteral (
1157 0 : AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
1158 : range_lower->get_type_hint ()),
1159 0 : range_lower_locus));
1160 22 : case INT_LITERAL:
1161 22 : lexer.skip_token ();
1162 22 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1163 44 : new AST::RangePatternBoundLiteral (
1164 76 : AST::Literal (range_lower->get_str (), AST::Literal::INT,
1165 : range_lower->get_type_hint ()),
1166 22 : range_lower_locus));
1167 0 : case FLOAT_LITERAL:
1168 0 : lexer.skip_token ();
1169 0 : rust_debug ("warning: used deprecated float range pattern bound");
1170 0 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1171 0 : new AST::RangePatternBoundLiteral (
1172 0 : AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
1173 : range_lower->get_type_hint ()),
1174 0 : range_lower_locus));
1175 12 : case MINUS:
1176 : // branch on next token
1177 12 : range_lower = lexer.peek_token (1);
1178 12 : switch (range_lower->get_id ())
1179 : {
1180 10 : case INT_LITERAL:
1181 10 : lexer.skip_token (1);
1182 10 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1183 20 : new AST::RangePatternBoundLiteral (
1184 30 : AST::Literal (range_lower->get_str (), AST::Literal::INT,
1185 : range_lower->get_type_hint ()),
1186 10 : range_lower_locus, true));
1187 2 : case FLOAT_LITERAL:
1188 2 : lexer.skip_token (1);
1189 2 : rust_debug ("warning: used deprecated float range pattern bound");
1190 2 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
1191 4 : new AST::RangePatternBoundLiteral (
1192 8 : AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
1193 : range_lower->get_type_hint ()),
1194 2 : range_lower_locus, true));
1195 0 : default:
1196 0 : add_error (Error (range_lower->get_locus (),
1197 : "token type %qs cannot be parsed as range pattern "
1198 : "bound after minus symbol",
1199 : range_lower->get_token_description ()));
1200 :
1201 0 : return nullptr;
1202 : }
1203 15 : case IDENTIFIER:
1204 : case SUPER:
1205 : case SELF:
1206 : case SELF_ALIAS:
1207 : case CRATE:
1208 : case SCOPE_RESOLUTION:
1209 : case DOLLAR_SIGN:
1210 : {
1211 : // path in expression
1212 15 : AST::PathInExpression path = parse_path_in_expression ();
1213 15 : if (path.is_error ())
1214 : {
1215 0 : Error error (
1216 : range_lower->get_locus (),
1217 : "failed to parse path in expression range pattern bound");
1218 0 : add_error (std::move (error));
1219 :
1220 0 : return nullptr;
1221 0 : }
1222 15 : return std::unique_ptr<AST::RangePatternBoundPath> (
1223 15 : new AST::RangePatternBoundPath (std::move (path)));
1224 15 : }
1225 0 : case LEFT_SHIFT:
1226 : case LEFT_ANGLE:
1227 : {
1228 : // qualified path in expression
1229 0 : AST::QualifiedPathInExpression path
1230 : = parse_qualified_path_in_expression ();
1231 0 : if (path.is_error ())
1232 : {
1233 0 : Error error (range_lower->get_locus (),
1234 : "failed to parse qualified path in expression range "
1235 : "pattern bound");
1236 0 : add_error (std::move (error));
1237 :
1238 0 : return nullptr;
1239 0 : }
1240 0 : return std::unique_ptr<AST::RangePatternBoundQualPath> (
1241 0 : new AST::RangePatternBoundQualPath (std::move (path)));
1242 0 : }
1243 0 : default:
1244 0 : add_error (
1245 0 : Error (range_lower->get_locus (),
1246 : "token type %qs cannot be parsed as range pattern bound",
1247 : range_lower->get_token_description ()));
1248 :
1249 0 : return nullptr;
1250 : }
1251 56 : }
1252 :
1253 : } // namespace Rust
|