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