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