1 //! FIXME: write short doc here
3 use expressions::block_expr;
7 pub(super) const PATTERN_FIRST: TokenSet =
8 expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[
20 pub(crate) fn pattern(p: &mut Parser) {
21 pattern_r(p, PAT_RECOVERY_SET);
24 /// Parses a pattern list separated by pipes `|`
25 pub(super) fn pattern_top(p: &mut Parser) {
26 pattern_top_r(p, PAT_RECOVERY_SET)
29 pub(crate) fn pattern_single(p: &mut Parser) {
30 pattern_single_r(p, PAT_RECOVERY_SET);
33 /// Parses a pattern list separated by pipes `|`
34 /// using the given `recovery_set`
35 pub(super) fn pattern_top_r(p: &mut Parser, recovery_set: TokenSet) {
37 pattern_r(p, recovery_set);
40 /// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
41 /// given `recovery_set`
51 fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
53 pattern_single_r(p, recovery_set);
60 pattern_single_r(p, recovery_set);
62 m.complete(p, OR_PAT);
65 fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) {
66 if let Some(lhs) = atom_pat(p, recovery_set) {
75 for &range_op in [T![...], T![..=], T![..]].iter() {
77 let m = lhs.precede(p);
79 atom_pat(p, recovery_set);
80 m.complete(p, RANGE_PAT);
87 const PAT_RECOVERY_SET: TokenSet =
88 TokenSet::new(&[LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]);
90 fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
91 let m = match p.nth(0) {
92 T![box] => box_pat(p),
93 T![ref] | T![mut] => ident_pat(p, true),
94 T![const] => const_block_pat(p),
95 IDENT => match p.nth(1) {
96 // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
98 T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
99 T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
100 _ => ident_pat(p, true),
103 // test type_path_in_pattern
104 // fn main() { let <_>::Foo = (); }
105 _ if paths::is_path_start(p) => path_or_macro_pat(p),
106 _ if is_literal_pat_start(p) => literal_pat(p),
108 T![.] if p.at(T![..]) => rest_pat(p),
109 T![_] => wildcard_pat(p),
111 T!['('] => tuple_pat(p),
112 T!['['] => slice_pat(p),
115 p.err_recover("expected pattern", recovery_set);
123 fn is_literal_pat_start(p: &Parser) -> bool {
124 p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
125 || p.at_ts(expressions::LITERAL_FIRST)
128 // test literal_pattern
137 fn literal_pat(p: &mut Parser) -> CompletedMarker {
138 assert!(is_literal_pat_start(p));
143 expressions::literal(p);
144 m.complete(p, LITERAL_PAT)
149 // let foo::Bar = ();
151 // let Bar { .. } = ();
154 fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
155 assert!(paths::is_path_start(p));
158 let kind = match p.current() {
164 record_pat_field_list(p);
172 items::macro_call_after_excl(p);
173 return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
180 // test tuple_pat_fields
185 // let S(_, .. , x) = ();
187 fn tuple_pat_fields(p: &mut Parser) {
188 assert!(p.at(T!['(']));
190 pat_list(p, T![')']);
194 // test record_pat_field_list
197 // let S { f, ref mut g } = ();
198 // let S { h: _, ..} = ();
199 // let S { h: _, } = ();
201 fn record_pat_field_list(p: &mut Parser) {
202 assert!(p.at(T!['{']));
205 while !p.at(EOF) && !p.at(T!['}']) {
207 // A trailing `..` is *not* treated as a REST_PAT.
208 T![.] if p.at(T![..]) => p.bump(T![..]),
209 T!['{'] => error_block(p, "expected ident"),
214 // test record_pat_field
216 // let S { 0: 1 } = ();
217 // let S { x: 1 } = ();
219 IDENT | INT_NUMBER if p.nth(1) == T![:] => {
220 name_ref_or_index(p);
225 // FIXME: not all box patterns should be allowed
232 m.complete(p, RECORD_PAT_FIELD);
240 m.complete(p, RECORD_PAT_FIELD_LIST);
243 // test placeholder_pat
244 // fn main() { let _ = (); }
245 fn wildcard_pat(p: &mut Parser) -> CompletedMarker {
246 assert!(p.at(T![_]));
249 m.complete(p, WILDCARD_PAT)
259 // let (a, ..,) = ();
260 // let Tuple(a, ..) = ();
261 // let Tuple(a, ..,) = ();
262 // let (.., ..) = ();
263 // let Tuple(.., ..) = ();
264 // let (.., a, ..) = ();
265 // let Tuple(.., a, ..) = ();
270 // let [head, ..] = ();
271 // let [head, tail @ ..] = ();
272 // let [head, .., cons] = ();
273 // let [head, mid @ .., cons] = ();
274 // let [head, .., .., cons] = ();
275 // let [head, .., mid, tail @ ..] = ();
276 // let [head, .., mid, .., cons] = ();
278 fn rest_pat(p: &mut Parser) -> CompletedMarker {
279 assert!(p.at(T![..]));
282 m.complete(p, REST_PAT)
290 fn ref_pat(p: &mut Parser) -> CompletedMarker {
291 assert!(p.at(T![&]));
296 m.complete(p, REF_PAT)
301 // let (a, b, ..) = ();
306 fn tuple_pat(p: &mut Parser) -> CompletedMarker {
307 assert!(p.at(T!['(']));
310 let mut has_comma = false;
311 let mut has_pat = false;
312 let mut has_rest = false;
313 while !p.at(EOF) && !p.at(T![')']) {
315 if !p.at_ts(PATTERN_FIRST) {
316 p.error("expected a pattern");
319 has_rest |= p.at(T![..]);
329 m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
334 // let [a, b, ..] = [];
336 fn slice_pat(p: &mut Parser) -> CompletedMarker {
337 assert!(p.at(T!['[']));
340 pat_list(p, T![']']);
342 m.complete(p, SLICE_PAT)
345 fn pat_list(p: &mut Parser, ket: SyntaxKind) {
346 while !p.at(EOF) && !p.at(ket) {
347 if !p.at_ts(PATTERN_FIRST) {
348 p.error("expected a pattern");
364 // let ref mut d = ();
366 // let ref mut f @ g @ _ = ();
368 fn ident_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
373 if with_at && p.eat(T![@]) {
376 m.complete(p, IDENT_PAT)
382 // let box Outer { box i, j: box Inner(box &x) } = ();
383 // let box ref mut i = ();
385 fn box_pat(p: &mut Parser) -> CompletedMarker {
386 assert!(p.at(T![box]));
390 m.complete(p, BOX_PAT)
393 // test const_block_pat
395 // let const { 15 } = ();
396 // let const { foo(); bar() } = ();
398 fn const_block_pat(p: &mut Parser) -> CompletedMarker {
399 assert!(p.at(T![const]));
403 m.complete(p, CONST_BLOCK_PAT)