• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 
3 pub(super) const PATTERN_FIRST: TokenSet =
4     expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[
5         T![box],
6         T![ref],
7         T![mut],
8         T![const],
9         T!['('],
10         T!['['],
11         T![&],
12         T![_],
13         T![-],
14         T![.],
15     ]));
16 
17 const PAT_TOP_FIRST: TokenSet = PATTERN_FIRST.union(TokenSet::new(&[T![|]]));
18 
19 /// Set of possible tokens at the start of a range pattern's end bound.
20 const RANGE_PAT_END_FIRST: TokenSet =
21     expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[T![-], T![const]]));
22 
pattern(p: &mut Parser<'_>)23 pub(crate) fn pattern(p: &mut Parser<'_>) {
24     pattern_r(p, PAT_RECOVERY_SET);
25 }
26 
27 /// Parses a pattern list separated by pipes `|`.
pattern_top(p: &mut Parser<'_>)28 pub(super) fn pattern_top(p: &mut Parser<'_>) {
29     pattern_top_r(p, PAT_RECOVERY_SET);
30 }
31 
pattern_single(p: &mut Parser<'_>)32 pub(crate) fn pattern_single(p: &mut Parser<'_>) {
33     pattern_single_r(p, PAT_RECOVERY_SET);
34 }
35 
36 /// Parses a pattern list separated by pipes `|`
37 /// using the given `recovery_set`.
pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet)38 pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
39     p.eat(T![|]);
40     pattern_r(p, recovery_set);
41 }
42 
43 /// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
44 /// given `recovery_set`.
45 
46 // test or_pattern
47 // fn main() {
48 //     match () {
49 //         (_ | _) => (),
50 //         &(_ | _) => (),
51 //         (_ | _,) => (),
52 //         [_ | _,] => (),
53 //     }
54 // }
pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet)55 fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
56     let m = p.start();
57     pattern_single_r(p, recovery_set);
58 
59     if !p.at(T![|]) {
60         m.abandon(p);
61         return;
62     }
63     while p.eat(T![|]) {
64         pattern_single_r(p, recovery_set);
65     }
66     m.complete(p, OR_PAT);
67 }
68 
pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet)69 fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
70     // test range_pat
71     // fn main() {
72     //     match 92 {
73     //         0 ... 100 => (),
74     //         101 ..= 200 => (),
75     //         200 .. 301 => (),
76     //         302 .. => (),
77     //         ..= 303 => (),
78     //     }
79     //
80     //     match Some(10 as u8) {
81     //         Some(0) | None => (),
82     //         Some(1..) => (),
83     //         Some(..=2) => (),
84     //     }
85     //
86     //     match () {
87     //         S { a: 0 } => (),
88     //         S { a: 1.. } => (),
89     //         S { a: ..=2 } => (),
90     //     }
91     //
92     //     match () {
93     //         [0] => (),
94     //         [1..] => (),
95     //         [..=2] => (),
96     //     }
97     //
98     //     match (10 as u8, 5 as u8) {
99     //         (0, _) => (),
100     //         (1.., _) => (),
101     //         (..=2, _) => (),
102     //     }
103     // }
104 
105     if p.at(T![..=]) {
106         let m = p.start();
107         p.bump(T![..=]);
108         atom_pat(p, recovery_set);
109         m.complete(p, RANGE_PAT);
110         return;
111     }
112 
113     // test exclusive_range_pat
114     // fn main() {
115     //     match 42 {
116     //         ..0 => {}
117     //         1..2 => {}
118     //     }
119     // }
120 
121     // test dot_dot_pat
122     // fn main() {
123     //     let .. = ();
124     //     //
125     //     // Tuples
126     //     //
127     //     let (a, ..) = ();
128     //     let (a, ..,) = ();
129     //     let Tuple(a, ..) = ();
130     //     let Tuple(a, ..,) = ();
131     //     let (.., ..) = ();
132     //     let Tuple(.., ..) = ();
133     //     let (.., a, ..) = ();
134     //     let Tuple(.., a, ..) = ();
135     //     //
136     //     // Slices
137     //     //
138     //     let [..] = ();
139     //     let [head, ..] = ();
140     //     let [head, tail @ ..] = ();
141     //     let [head, .., cons] = ();
142     //     let [head, mid @ .., cons] = ();
143     //     let [head, .., .., cons] = ();
144     //     let [head, .., mid, tail @ ..] = ();
145     //     let [head, .., mid, .., cons] = ();
146     // }
147     if p.at(T![..]) {
148         let m = p.start();
149         p.bump(T![..]);
150         if p.at_ts(RANGE_PAT_END_FIRST) {
151             atom_pat(p, recovery_set);
152             m.complete(p, RANGE_PAT);
153         } else {
154             m.complete(p, REST_PAT);
155         }
156         return;
157     }
158 
159     if let Some(lhs) = atom_pat(p, recovery_set) {
160         for range_op in [T![...], T![..=], T![..]] {
161             if p.at(range_op) {
162                 let m = lhs.precede(p);
163                 p.bump(range_op);
164 
165                 // testing if we're at one of the following positions:
166                 // `0 .. =>`
167                 //       ^
168                 // `let 0 .. =`
169                 //           ^
170                 // `let 0..: _ =`
171                 //         ^
172                 // (1.., _)
173                 //     ^
174                 // `Some(0 .. )`
175                 //            ^
176                 // `S { t: 0.. }`
177                 //             ^
178                 // `[0..]`
179                 //      ^
180                 // `0 .. if`
181                 //       ^
182                 if matches!(
183                     p.current(),
184                     T![=] | T![,] | T![:] | T![')'] | T!['}'] | T![']'] | T![if]
185                 ) {
186                     // test half_open_range_pat
187                     // fn f() {
188                     //     let 0 .. = 1u32;
189                     //     let 0..: _ = 1u32;
190                     //
191                     //     match 42 {
192                     //         0 .. if true => (),
193                     //         _ => (),
194                     //     }
195                     // }
196                 } else {
197                     atom_pat(p, recovery_set);
198                 }
199                 m.complete(p, RANGE_PAT);
200                 return;
201             }
202         }
203     }
204 }
205 
206 const PAT_RECOVERY_SET: TokenSet =
207     TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,], T![=]]);
208 
atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option<CompletedMarker>209 fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option<CompletedMarker> {
210     let m = match p.current() {
211         T![box] => box_pat(p),
212         T![ref] | T![mut] => ident_pat(p, true),
213         T![const] => const_block_pat(p),
214         IDENT => match p.nth(1) {
215             // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
216             // (T![x]).
217             T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
218             T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
219             _ => ident_pat(p, true),
220         },
221 
222         // test type_path_in_pattern
223         // fn main() { let <_>::Foo = (); }
224         _ if paths::is_path_start(p) => path_or_macro_pat(p),
225         _ if is_literal_pat_start(p) => literal_pat(p),
226 
227         T![_] => wildcard_pat(p),
228         T![&] => ref_pat(p),
229         T!['('] => tuple_pat(p),
230         T!['['] => slice_pat(p),
231 
232         _ => {
233             p.err_recover("expected pattern", recovery_set);
234             return None;
235         }
236     };
237 
238     Some(m)
239 }
240 
is_literal_pat_start(p: &Parser<'_>) -> bool241 fn is_literal_pat_start(p: &Parser<'_>) -> bool {
242     p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
243         || p.at_ts(expressions::LITERAL_FIRST)
244 }
245 
246 // test literal_pattern
247 // fn main() {
248 //     match () {
249 //         -1 => (),
250 //         92 => (),
251 //         'c' => (),
252 //         "hello" => (),
253 //     }
254 // }
literal_pat(p: &mut Parser<'_>) -> CompletedMarker255 fn literal_pat(p: &mut Parser<'_>) -> CompletedMarker {
256     assert!(is_literal_pat_start(p));
257     let m = p.start();
258     if p.at(T![-]) {
259         p.bump(T![-]);
260     }
261     expressions::literal(p);
262     m.complete(p, LITERAL_PAT)
263 }
264 
265 // test path_part
266 // fn foo() {
267 //     let foo::Bar = ();
268 //     let ::Bar = ();
269 //     let Bar { .. } = ();
270 //     let Bar(..) = ();
271 // }
path_or_macro_pat(p: &mut Parser<'_>) -> CompletedMarker272 fn path_or_macro_pat(p: &mut Parser<'_>) -> CompletedMarker {
273     assert!(paths::is_path_start(p));
274     let m = p.start();
275     paths::expr_path(p);
276     let kind = match p.current() {
277         T!['('] => {
278             tuple_pat_fields(p);
279             TUPLE_STRUCT_PAT
280         }
281         T!['{'] => {
282             record_pat_field_list(p);
283             RECORD_PAT
284         }
285         // test marco_pat
286         // fn main() {
287         //     let m!(x) = 0;
288         // }
289         T![!] => {
290             items::macro_call_after_excl(p);
291             return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
292         }
293         _ => PATH_PAT,
294     };
295     m.complete(p, kind)
296 }
297 
298 // test tuple_pat_fields
299 // fn foo() {
300 //     let S() = ();
301 //     let S(_) = ();
302 //     let S(_,) = ();
303 //     let S(_, .. , x) = ();
304 //     let S(| a) = ();
305 // }
tuple_pat_fields(p: &mut Parser<'_>)306 fn tuple_pat_fields(p: &mut Parser<'_>) {
307     assert!(p.at(T!['(']));
308     p.bump(T!['(']);
309     pat_list(p, T![')']);
310     p.expect(T![')']);
311 }
312 
313 // test record_pat_field
314 // fn foo() {
315 //     let S { 0: 1 } = ();
316 //     let S { x: 1 } = ();
317 //     let S { #[cfg(any())] x: 1 } = ();
318 // }
record_pat_field(p: &mut Parser<'_>)319 fn record_pat_field(p: &mut Parser<'_>) {
320     match p.current() {
321         IDENT | INT_NUMBER if p.nth(1) == T![:] => {
322             name_ref_or_index(p);
323             p.bump(T![:]);
324             pattern(p);
325         }
326         T![box] => {
327             // FIXME: not all box patterns should be allowed
328             box_pat(p);
329         }
330         T![ref] | T![mut] | IDENT => {
331             ident_pat(p, false);
332         }
333         _ => {
334             p.err_and_bump("expected identifier");
335         }
336     }
337 }
338 
339 // test record_pat_field_list
340 // fn foo() {
341 //     let S {} = ();
342 //     let S { f, ref mut g } = ();
343 //     let S { h: _, ..} = ();
344 //     let S { h: _, } = ();
345 //     let S { #[cfg(any())] .. } = ();
346 // }
record_pat_field_list(p: &mut Parser<'_>)347 fn record_pat_field_list(p: &mut Parser<'_>) {
348     assert!(p.at(T!['{']));
349     let m = p.start();
350     p.bump(T!['{']);
351     while !p.at(EOF) && !p.at(T!['}']) {
352         let m = p.start();
353         attributes::outer_attrs(p);
354 
355         match p.current() {
356             // A trailing `..` is *not* treated as a REST_PAT.
357             T![.] if p.at(T![..]) => {
358                 p.bump(T![..]);
359                 m.complete(p, REST_PAT);
360             }
361             T!['{'] => {
362                 error_block(p, "expected ident");
363                 m.abandon(p);
364             }
365             _ => {
366                 record_pat_field(p);
367                 m.complete(p, RECORD_PAT_FIELD);
368             }
369         }
370         if !p.at(T!['}']) {
371             p.expect(T![,]);
372         }
373     }
374     p.expect(T!['}']);
375     m.complete(p, RECORD_PAT_FIELD_LIST);
376 }
377 
378 // test placeholder_pat
379 // fn main() { let _ = (); }
wildcard_pat(p: &mut Parser<'_>) -> CompletedMarker380 fn wildcard_pat(p: &mut Parser<'_>) -> CompletedMarker {
381     assert!(p.at(T![_]));
382     let m = p.start();
383     p.bump(T![_]);
384     m.complete(p, WILDCARD_PAT)
385 }
386 
387 // test ref_pat
388 // fn main() {
389 //     let &a = ();
390 //     let &mut b = ();
391 // }
ref_pat(p: &mut Parser<'_>) -> CompletedMarker392 fn ref_pat(p: &mut Parser<'_>) -> CompletedMarker {
393     assert!(p.at(T![&]));
394     let m = p.start();
395     p.bump(T![&]);
396     p.eat(T![mut]);
397     pattern_single(p);
398     m.complete(p, REF_PAT)
399 }
400 
401 // test tuple_pat
402 // fn main() {
403 //     let (a, b, ..) = ();
404 //     let (a,) = ();
405 //     let (..) = ();
406 //     let () = ();
407 //     let (| a | a, | b) = ((),());
408 // }
tuple_pat(p: &mut Parser<'_>) -> CompletedMarker409 fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker {
410     assert!(p.at(T!['(']));
411     let m = p.start();
412     p.bump(T!['(']);
413     let mut has_comma = false;
414     let mut has_pat = false;
415     let mut has_rest = false;
416 
417     // test_err tuple_pat_leading_comma
418     // fn foo() {
419     //     let (,);
420     // }
421     if p.eat(T![,]) {
422         p.error("expected pattern");
423         has_comma = true;
424     }
425 
426     while !p.at(EOF) && !p.at(T![')']) {
427         has_pat = true;
428         if !p.at_ts(PAT_TOP_FIRST) {
429             p.error("expected a pattern");
430             break;
431         }
432         has_rest |= p.at(T![..]);
433 
434         pattern_top(p);
435         if !p.at(T![')']) {
436             has_comma = true;
437             p.expect(T![,]);
438         }
439     }
440     p.expect(T![')']);
441 
442     m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
443 }
444 
445 // test slice_pat
446 // fn main() {
447 //     let [a, b, ..] = [];
448 //     let [| a, ..] = [];
449 // }
slice_pat(p: &mut Parser<'_>) -> CompletedMarker450 fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker {
451     assert!(p.at(T!['[']));
452     let m = p.start();
453     p.bump(T!['[']);
454     pat_list(p, T![']']);
455     p.expect(T![']']);
456     m.complete(p, SLICE_PAT)
457 }
458 
pat_list(p: &mut Parser<'_>, ket: SyntaxKind)459 fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) {
460     while !p.at(EOF) && !p.at(ket) {
461         pattern_top(p);
462         if !p.at(T![,]) {
463             if p.at_ts(PAT_TOP_FIRST) {
464                 p.error(format!("expected {:?}, got {:?}", T![,], p.current()));
465             } else {
466                 break;
467             }
468         } else {
469             p.bump(T![,]);
470         }
471     }
472 }
473 
474 // test bind_pat
475 // fn main() {
476 //     let a = ();
477 //     let mut b = ();
478 //     let ref c = ();
479 //     let ref mut d = ();
480 //     let e @ _ = ();
481 //     let ref mut f @ g @ _ = ();
482 // }
ident_pat(p: &mut Parser<'_>, with_at: bool) -> CompletedMarker483 fn ident_pat(p: &mut Parser<'_>, with_at: bool) -> CompletedMarker {
484     assert!(matches!(p.current(), T![ref] | T![mut] | IDENT));
485     let m = p.start();
486     p.eat(T![ref]);
487     p.eat(T![mut]);
488     name_r(p, PAT_RECOVERY_SET);
489     if with_at && p.eat(T![@]) {
490         pattern_single(p);
491     }
492     m.complete(p, IDENT_PAT)
493 }
494 
495 // test box_pat
496 // fn main() {
497 //     let box i = ();
498 //     let box Outer { box i, j: box Inner(box &x) } = ();
499 //     let box ref mut i = ();
500 // }
box_pat(p: &mut Parser<'_>) -> CompletedMarker501 fn box_pat(p: &mut Parser<'_>) -> CompletedMarker {
502     assert!(p.at(T![box]));
503     let m = p.start();
504     p.bump(T![box]);
505     pattern_single(p);
506     m.complete(p, BOX_PAT)
507 }
508 
509 // test const_block_pat
510 // fn main() {
511 //     let const { 15 } = ();
512 //     let const { foo(); bar() } = ();
513 //
514 //     match 42 {
515 //         const { 0 } .. const { 1 } => (),
516 //         .. const { 0 } => (),
517 //         const { 2 } .. => (),
518 //     }
519 //
520 //     let (const { () },) = ();
521 // }
const_block_pat(p: &mut Parser<'_>) -> CompletedMarker522 fn const_block_pat(p: &mut Parser<'_>) -> CompletedMarker {
523     assert!(p.at(T![const]));
524     let m = p.start();
525     p.bump(T![const]);
526     expressions::block_expr(p);
527     m.complete(p, CONST_BLOCK_PAT)
528 }
529