parser/grammar/
patterns.rs

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