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