]> git.lizzy.rs Git - rust.git/blob - crates/parser/src/grammar/patterns.rs
Parse ConstBlockPat
[rust.git] / crates / parser / src / grammar / patterns.rs
1 //! FIXME: write short doc here
2
3 use expressions::block_expr;
4
5 use super::*;
6
7 pub(super) const PATTERN_FIRST: TokenSet =
8     expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[
9         T![box],
10         T![ref],
11         T![mut],
12         T!['('],
13         T!['['],
14         T![&],
15         T![_],
16         T![-],
17         T![.],
18     ]));
19
20 pub(crate) fn pattern(p: &mut Parser) {
21     pattern_r(p, PAT_RECOVERY_SET);
22 }
23
24 /// Parses a pattern list separated by pipes `|`
25 pub(super) fn pattern_top(p: &mut Parser) {
26     pattern_top_r(p, PAT_RECOVERY_SET)
27 }
28
29 pub(crate) fn pattern_single(p: &mut Parser) {
30     pattern_single_r(p, PAT_RECOVERY_SET);
31 }
32
33 /// Parses a pattern list separated by pipes `|`
34 /// using the given `recovery_set`
35 pub(super) fn pattern_top_r(p: &mut Parser, recovery_set: TokenSet) {
36     p.eat(T![|]);
37     pattern_r(p, recovery_set);
38 }
39
40 /// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
41 /// given `recovery_set`
42 // test or_pattern
43 // fn main() {
44 //     match () {
45 //         (_ | _) => (),
46 //         &(_ | _) => (),
47 //         (_ | _,) => (),
48 //         [_ | _,] => (),
49 //     }
50 // }
51 fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
52     let m = p.start();
53     pattern_single_r(p, recovery_set);
54
55     if !p.at(T![|]) {
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
65 fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) {
66     if let Some(lhs) = atom_pat(p, recovery_set) {
67         // test range_pat
68         // fn main() {
69         //     match 92 {
70         //         0 ... 100 => (),
71         //         101 ..= 200 => (),
72         //         200 .. 301=> (),
73         //     }
74         // }
75         for &range_op in [T![...], T![..=], T![..]].iter() {
76             if p.at(range_op) {
77                 let m = lhs.precede(p);
78                 p.bump(range_op);
79                 atom_pat(p, recovery_set);
80                 m.complete(p, RANGE_PAT);
81                 return;
82             }
83         }
84     }
85 }
86
87 const PAT_RECOVERY_SET: TokenSet =
88     TokenSet::new(&[LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]);
89
90 fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
91     let m = match p.nth(0) {
92         T![box] => box_pat(p),
93         T![ref] | T![mut] => ident_pat(p, true),
94         T![const] => const_block_pat(p),
95         IDENT => match p.nth(1) {
96             // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
97             // (T![x]).
98             T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
99             T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
100             _ => ident_pat(p, true),
101         },
102
103         // test type_path_in_pattern
104         // fn main() { let <_>::Foo = (); }
105         _ if paths::is_path_start(p) => path_or_macro_pat(p),
106         _ if is_literal_pat_start(p) => literal_pat(p),
107
108         T![.] if p.at(T![..]) => rest_pat(p),
109         T![_] => wildcard_pat(p),
110         T![&] => ref_pat(p),
111         T!['('] => tuple_pat(p),
112         T!['['] => slice_pat(p),
113
114         _ => {
115             p.err_recover("expected pattern", recovery_set);
116             return None;
117         }
118     };
119
120     Some(m)
121 }
122
123 fn is_literal_pat_start(p: &Parser) -> bool {
124     p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
125         || p.at_ts(expressions::LITERAL_FIRST)
126 }
127
128 // test literal_pattern
129 // fn main() {
130 //     match () {
131 //         -1 => (),
132 //         92 => (),
133 //         'c' => (),
134 //         "hello" => (),
135 //     }
136 // }
137 fn literal_pat(p: &mut Parser) -> CompletedMarker {
138     assert!(is_literal_pat_start(p));
139     let m = p.start();
140     if p.at(T![-]) {
141         p.bump(T![-]);
142     }
143     expressions::literal(p);
144     m.complete(p, LITERAL_PAT)
145 }
146
147 // test path_part
148 // fn foo() {
149 //     let foo::Bar = ();
150 //     let ::Bar = ();
151 //     let Bar { .. } = ();
152 //     let Bar(..) = ();
153 // }
154 fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
155     assert!(paths::is_path_start(p));
156     let m = p.start();
157     paths::expr_path(p);
158     let kind = match p.current() {
159         T!['('] => {
160             tuple_pat_fields(p);
161             TUPLE_STRUCT_PAT
162         }
163         T!['{'] => {
164             record_pat_field_list(p);
165             RECORD_PAT
166         }
167         // test marco_pat
168         // fn main() {
169         //     let m!(x) = 0;
170         // }
171         T![!] => {
172             items::macro_call_after_excl(p);
173             return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
174         }
175         _ => PATH_PAT,
176     };
177     m.complete(p, kind)
178 }
179
180 // test tuple_pat_fields
181 // fn foo() {
182 //     let S() = ();
183 //     let S(_) = ();
184 //     let S(_,) = ();
185 //     let S(_, .. , x) = ();
186 // }
187 fn tuple_pat_fields(p: &mut Parser) {
188     assert!(p.at(T!['(']));
189     p.bump(T!['(']);
190     pat_list(p, T![')']);
191     p.expect(T![')']);
192 }
193
194 // test record_pat_field_list
195 // fn foo() {
196 //     let S {} = ();
197 //     let S { f, ref mut g } = ();
198 //     let S { h: _, ..} = ();
199 //     let S { h: _, } = ();
200 // }
201 fn record_pat_field_list(p: &mut Parser) {
202     assert!(p.at(T!['{']));
203     let m = p.start();
204     p.bump(T!['{']);
205     while !p.at(EOF) && !p.at(T!['}']) {
206         match p.current() {
207             // A trailing `..` is *not* treated as a REST_PAT.
208             T![.] if p.at(T![..]) => p.bump(T![..]),
209             T!['{'] => error_block(p, "expected ident"),
210
211             c => {
212                 let m = p.start();
213                 match c {
214                     // test record_pat_field
215                     // fn foo() {
216                     //     let S { 0: 1 } = ();
217                     //     let S { x: 1 } = ();
218                     // }
219                     IDENT | INT_NUMBER if p.nth(1) == T![:] => {
220                         name_ref_or_index(p);
221                         p.bump(T![:]);
222                         pattern(p);
223                     }
224                     T![box] => {
225                         // FIXME: not all box patterns should be allowed
226                         box_pat(p);
227                     }
228                     _ => {
229                         ident_pat(p, false);
230                     }
231                 }
232                 m.complete(p, RECORD_PAT_FIELD);
233             }
234         }
235         if !p.at(T!['}']) {
236             p.expect(T![,]);
237         }
238     }
239     p.expect(T!['}']);
240     m.complete(p, RECORD_PAT_FIELD_LIST);
241 }
242
243 // test placeholder_pat
244 // fn main() { let _ = (); }
245 fn wildcard_pat(p: &mut Parser) -> CompletedMarker {
246     assert!(p.at(T![_]));
247     let m = p.start();
248     p.bump(T![_]);
249     m.complete(p, WILDCARD_PAT)
250 }
251
252 // test dot_dot_pat
253 // fn main() {
254 //     let .. = ();
255 //     //
256 //     // Tuples
257 //     //
258 //     let (a, ..) = ();
259 //     let (a, ..,) = ();
260 //     let Tuple(a, ..) = ();
261 //     let Tuple(a, ..,) = ();
262 //     let (.., ..) = ();
263 //     let Tuple(.., ..) = ();
264 //     let (.., a, ..) = ();
265 //     let Tuple(.., a, ..) = ();
266 //     //
267 //     // Slices
268 //     //
269 //     let [..] = ();
270 //     let [head, ..] = ();
271 //     let [head, tail @ ..] = ();
272 //     let [head, .., cons] = ();
273 //     let [head, mid @ .., cons] = ();
274 //     let [head, .., .., cons] = ();
275 //     let [head, .., mid, tail @ ..] = ();
276 //     let [head, .., mid, .., cons] = ();
277 // }
278 fn rest_pat(p: &mut Parser) -> CompletedMarker {
279     assert!(p.at(T![..]));
280     let m = p.start();
281     p.bump(T![..]);
282     m.complete(p, REST_PAT)
283 }
284
285 // test ref_pat
286 // fn main() {
287 //     let &a = ();
288 //     let &mut b = ();
289 // }
290 fn ref_pat(p: &mut Parser) -> CompletedMarker {
291     assert!(p.at(T![&]));
292     let m = p.start();
293     p.bump(T![&]);
294     p.eat(T![mut]);
295     pattern_single(p);
296     m.complete(p, REF_PAT)
297 }
298
299 // test tuple_pat
300 // fn main() {
301 //     let (a, b, ..) = ();
302 //     let (a,) = ();
303 //     let (..) = ();
304 //     let () = ();
305 // }
306 fn tuple_pat(p: &mut Parser) -> CompletedMarker {
307     assert!(p.at(T!['(']));
308     let m = p.start();
309     p.bump(T!['(']);
310     let mut has_comma = false;
311     let mut has_pat = false;
312     let mut has_rest = false;
313     while !p.at(EOF) && !p.at(T![')']) {
314         has_pat = true;
315         if !p.at_ts(PATTERN_FIRST) {
316             p.error("expected a pattern");
317             break;
318         }
319         has_rest |= p.at(T![..]);
320
321         pattern(p);
322         if !p.at(T![')']) {
323             has_comma = true;
324             p.expect(T![,]);
325         }
326     }
327     p.expect(T![')']);
328
329     m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
330 }
331
332 // test slice_pat
333 // fn main() {
334 //     let [a, b, ..] = [];
335 // }
336 fn slice_pat(p: &mut Parser) -> CompletedMarker {
337     assert!(p.at(T!['[']));
338     let m = p.start();
339     p.bump(T!['[']);
340     pat_list(p, T![']']);
341     p.expect(T![']']);
342     m.complete(p, SLICE_PAT)
343 }
344
345 fn pat_list(p: &mut Parser, ket: SyntaxKind) {
346     while !p.at(EOF) && !p.at(ket) {
347         if !p.at_ts(PATTERN_FIRST) {
348             p.error("expected a pattern");
349             break;
350         }
351
352         pattern(p);
353         if !p.at(ket) {
354             p.expect(T![,]);
355         }
356     }
357 }
358
359 // test bind_pat
360 // fn main() {
361 //     let a = ();
362 //     let mut b = ();
363 //     let ref c = ();
364 //     let ref mut d = ();
365 //     let e @ _ = ();
366 //     let ref mut f @ g @ _ = ();
367 // }
368 fn ident_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
369     let m = p.start();
370     p.eat(T![ref]);
371     p.eat(T![mut]);
372     name(p);
373     if with_at && p.eat(T![@]) {
374         pattern_single(p);
375     }
376     m.complete(p, IDENT_PAT)
377 }
378
379 // test box_pat
380 // fn main() {
381 //     let box i = ();
382 //     let box Outer { box i, j: box Inner(box &x) } = ();
383 //     let box ref mut i = ();
384 // }
385 fn box_pat(p: &mut Parser) -> CompletedMarker {
386     assert!(p.at(T![box]));
387     let m = p.start();
388     p.bump(T![box]);
389     pattern_single(p);
390     m.complete(p, BOX_PAT)
391 }
392
393 // test const_block_pat
394 // fn main() {
395 //     let const { 15 } = ();
396 //     let const { foo(); bar() } = ();
397 // }
398 fn const_block_pat(p: &mut Parser) -> CompletedMarker {
399     assert!(p.at(T![const]));
400     let m = p.start();
401     p.bump(T![const]);
402     block_expr(p);
403     m.complete(p, CONST_BLOCK_PAT)
404 }