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