]> git.lizzy.rs Git - rust.git/blob - crates/parser/src/grammar/patterns.rs
Merge #5951 #5975
[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         IDENT => match p.nth(1) {
93             // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
94             // (T![x]).
95             T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
96             T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
97             _ => ident_pat(p, true),
98         },
99
100         // test type_path_in_pattern
101         // fn main() { let <_>::Foo = (); }
102         _ if paths::is_path_start(p) => path_or_macro_pat(p),
103         _ if is_literal_pat_start(p) => literal_pat(p),
104
105         T![.] if p.at(T![..]) => rest_pat(p),
106         T![_] => wildcard_pat(p),
107         T![&] => ref_pat(p),
108         T!['('] => tuple_pat(p),
109         T!['['] => slice_pat(p),
110
111         _ => {
112             p.err_recover("expected pattern", recovery_set);
113             return None;
114         }
115     };
116
117     Some(m)
118 }
119
120 fn is_literal_pat_start(p: &Parser) -> bool {
121     p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
122         || p.at_ts(expressions::LITERAL_FIRST)
123 }
124
125 // test literal_pattern
126 // fn main() {
127 //     match () {
128 //         -1 => (),
129 //         92 => (),
130 //         'c' => (),
131 //         "hello" => (),
132 //     }
133 // }
134 fn literal_pat(p: &mut Parser) -> CompletedMarker {
135     assert!(is_literal_pat_start(p));
136     let m = p.start();
137     if p.at(T![-]) {
138         p.bump(T![-]);
139     }
140     expressions::literal(p);
141     m.complete(p, LITERAL_PAT)
142 }
143
144 // test path_part
145 // fn foo() {
146 //     let foo::Bar = ();
147 //     let ::Bar = ();
148 //     let Bar { .. } = ();
149 //     let Bar(..) = ();
150 // }
151 fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
152     assert!(paths::is_path_start(p));
153     let m = p.start();
154     paths::expr_path(p);
155     let kind = match p.current() {
156         T!['('] => {
157             tuple_pat_fields(p);
158             TUPLE_STRUCT_PAT
159         }
160         T!['{'] => {
161             record_pat_field_list(p);
162             RECORD_PAT
163         }
164         // test marco_pat
165         // fn main() {
166         //     let m!(x) = 0;
167         // }
168         T![!] => {
169             items::macro_call_after_excl(p);
170             return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
171         }
172         _ => PATH_PAT,
173     };
174     m.complete(p, kind)
175 }
176
177 // test tuple_pat_fields
178 // fn foo() {
179 //     let S() = ();
180 //     let S(_) = ();
181 //     let S(_,) = ();
182 //     let S(_, .. , x) = ();
183 // }
184 fn tuple_pat_fields(p: &mut Parser) {
185     assert!(p.at(T!['(']));
186     p.bump(T!['(']);
187     pat_list(p, T![')']);
188     p.expect(T![')']);
189 }
190
191 // test record_pat_field_list
192 // fn foo() {
193 //     let S {} = ();
194 //     let S { f, ref mut g } = ();
195 //     let S { h: _, ..} = ();
196 //     let S { h: _, } = ();
197 // }
198 fn record_pat_field_list(p: &mut Parser) {
199     assert!(p.at(T!['{']));
200     let m = p.start();
201     p.bump(T!['{']);
202     while !p.at(EOF) && !p.at(T!['}']) {
203         match p.current() {
204             // A trailing `..` is *not* treated as a REST_PAT.
205             T![.] if p.at(T![..]) => p.bump(T![..]),
206             T!['{'] => error_block(p, "expected ident"),
207
208             c => {
209                 let m = p.start();
210                 match c {
211                     // test record_pat_field
212                     // fn foo() {
213                     //     let S { 0: 1 } = ();
214                     //     let S { x: 1 } = ();
215                     // }
216                     IDENT | INT_NUMBER if p.nth(1) == T![:] => {
217                         name_ref_or_index(p);
218                         p.bump(T![:]);
219                         pattern(p);
220                     }
221                     T![box] => {
222                         // FIXME: not all box patterns should be allowed
223                         box_pat(p);
224                     }
225                     _ => {
226                         ident_pat(p, false);
227                     }
228                 }
229                 m.complete(p, RECORD_PAT_FIELD);
230             }
231         }
232         if !p.at(T!['}']) {
233             p.expect(T![,]);
234         }
235     }
236     p.expect(T!['}']);
237     m.complete(p, RECORD_PAT_FIELD_LIST);
238 }
239
240 // test placeholder_pat
241 // fn main() { let _ = (); }
242 fn wildcard_pat(p: &mut Parser) -> CompletedMarker {
243     assert!(p.at(T![_]));
244     let m = p.start();
245     p.bump(T![_]);
246     m.complete(p, WILDCARD_PAT)
247 }
248
249 // test dot_dot_pat
250 // fn main() {
251 //     let .. = ();
252 //     //
253 //     // Tuples
254 //     //
255 //     let (a, ..) = ();
256 //     let (a, ..,) = ();
257 //     let Tuple(a, ..) = ();
258 //     let Tuple(a, ..,) = ();
259 //     let (.., ..) = ();
260 //     let Tuple(.., ..) = ();
261 //     let (.., a, ..) = ();
262 //     let Tuple(.., a, ..) = ();
263 //     //
264 //     // Slices
265 //     //
266 //     let [..] = ();
267 //     let [head, ..] = ();
268 //     let [head, tail @ ..] = ();
269 //     let [head, .., cons] = ();
270 //     let [head, mid @ .., cons] = ();
271 //     let [head, .., .., cons] = ();
272 //     let [head, .., mid, tail @ ..] = ();
273 //     let [head, .., mid, .., cons] = ();
274 // }
275 fn rest_pat(p: &mut Parser) -> CompletedMarker {
276     assert!(p.at(T![..]));
277     let m = p.start();
278     p.bump(T![..]);
279     m.complete(p, REST_PAT)
280 }
281
282 // test ref_pat
283 // fn main() {
284 //     let &a = ();
285 //     let &mut b = ();
286 // }
287 fn ref_pat(p: &mut Parser) -> CompletedMarker {
288     assert!(p.at(T![&]));
289     let m = p.start();
290     p.bump(T![&]);
291     p.eat(T![mut]);
292     pattern_single(p);
293     m.complete(p, REF_PAT)
294 }
295
296 // test tuple_pat
297 // fn main() {
298 //     let (a, b, ..) = ();
299 //     let (a,) = ();
300 //     let (..) = ();
301 //     let () = ();
302 // }
303 fn tuple_pat(p: &mut Parser) -> CompletedMarker {
304     assert!(p.at(T!['(']));
305     let m = p.start();
306     p.bump(T!['(']);
307     let mut has_comma = false;
308     let mut has_pat = false;
309     let mut has_rest = false;
310     while !p.at(EOF) && !p.at(T![')']) {
311         has_pat = true;
312         if !p.at_ts(PATTERN_FIRST) {
313             p.error("expected a pattern");
314             break;
315         }
316         has_rest |= p.at(T![..]);
317
318         pattern(p);
319         if !p.at(T![')']) {
320             has_comma = true;
321             p.expect(T![,]);
322         }
323     }
324     p.expect(T![')']);
325
326     m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
327 }
328
329 // test slice_pat
330 // fn main() {
331 //     let [a, b, ..] = [];
332 // }
333 fn slice_pat(p: &mut Parser) -> CompletedMarker {
334     assert!(p.at(T!['[']));
335     let m = p.start();
336     p.bump(T!['[']);
337     pat_list(p, T![']']);
338     p.expect(T![']']);
339     m.complete(p, SLICE_PAT)
340 }
341
342 fn pat_list(p: &mut Parser, ket: SyntaxKind) {
343     while !p.at(EOF) && !p.at(ket) {
344         if !p.at_ts(PATTERN_FIRST) {
345             p.error("expected a pattern");
346             break;
347         }
348
349         pattern(p);
350         if !p.at(ket) {
351             p.expect(T![,]);
352         }
353     }
354 }
355
356 // test bind_pat
357 // fn main() {
358 //     let a = ();
359 //     let mut b = ();
360 //     let ref c = ();
361 //     let ref mut d = ();
362 //     let e @ _ = ();
363 //     let ref mut f @ g @ _ = ();
364 // }
365 fn ident_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
366     let m = p.start();
367     p.eat(T![ref]);
368     p.eat(T![mut]);
369     name(p);
370     if with_at && p.eat(T![@]) {
371         pattern_single(p);
372     }
373     m.complete(p, IDENT_PAT)
374 }
375
376 // test box_pat
377 // fn main() {
378 //     let box i = ();
379 //     let box Outer { box i, j: box Inner(box &x) } = ();
380 //     let box ref mut i = ();
381 // }
382 fn box_pat(p: &mut Parser) -> CompletedMarker {
383     assert!(p.at(T![box]));
384     let m = p.start();
385     p.bump(T![box]);
386     pattern_single(p);
387     m.complete(p, BOX_PAT)
388 }