]> git.lizzy.rs Git - rust.git/blob - crates/ra_syntax/src/grammar/patterns.rs
Merge #273
[rust.git] / crates / ra_syntax / src / grammar / patterns.rs
1 use super::*;
2
3 pub(super) const PATTERN_FIRST: TokenSet = token_set_union![
4     token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE],
5     expressions::LITERAL_FIRST,
6     paths::PATH_FIRST,
7 ];
8
9 pub(super) fn pattern(p: &mut Parser) {
10     pattern_r(p, PAT_RECOVERY_SET)
11 }
12
13 pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
14     if let Some(lhs) = atom_pat(p, recovery_set) {
15         // test range_pat
16         // fn main() {
17         //     match 92 {
18         //         0 ... 100 => (),
19         //         101 ..= 200 => (),
20         //         200 .. 301=> (),
21         //     }
22         // }
23         if p.at(DOTDOTDOT) || p.at(DOTDOTEQ) || p.at(DOTDOT) {
24             let m = lhs.precede(p);
25             p.bump();
26             atom_pat(p, recovery_set);
27             m.complete(p, RANGE_PAT);
28         }
29     }
30 }
31
32 const PAT_RECOVERY_SET: TokenSet =
33     token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
34
35 fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
36     let la0 = p.nth(0);
37     let la1 = p.nth(1);
38     if la0 == REF_KW
39         || la0 == MUT_KW
40         || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY))
41     {
42         return Some(bind_pat(p, true));
43     }
44     if paths::is_path_start(p) {
45         return Some(path_pat(p));
46     }
47
48     // test literal_pattern
49     // fn main() {
50     //     match () {
51     //         92 => (),
52     //         'c' => (),
53     //         "hello" => (),
54     //     }
55     // }
56     if let Some(m) = expressions::literal(p) {
57         return Some(m);
58     }
59
60     let m = match la0 {
61         UNDERSCORE => placeholder_pat(p),
62         AMP => ref_pat(p),
63         L_PAREN => tuple_pat(p),
64         L_BRACK => slice_pat(p),
65         _ => {
66             p.err_recover("expected pattern", recovery_set);
67             return None;
68         }
69     };
70     Some(m)
71 }
72
73 // test path_part
74 // fn foo() {
75 //     let foo::Bar = ();
76 //     let ::Bar = ();
77 //     let Bar { .. } = ();
78 //     let Bar(..) = ();
79 // }
80 fn path_pat(p: &mut Parser) -> CompletedMarker {
81     assert!(paths::is_path_start(p));
82     let m = p.start();
83     paths::expr_path(p);
84     let kind = match p.current() {
85         L_PAREN => {
86             tuple_pat_fields(p);
87             TUPLE_STRUCT_PAT
88         }
89         L_CURLY => {
90             field_pat_list(p);
91             STRUCT_PAT
92         }
93         _ => PATH_PAT,
94     };
95     m.complete(p, kind)
96 }
97
98 // test tuple_pat_fields
99 // fn foo() {
100 //     let S() = ();
101 //     let S(_) = ();
102 //     let S(_,) = ();
103 //     let S(_, .. , x) = ();
104 // }
105 fn tuple_pat_fields(p: &mut Parser) {
106     assert!(p.at(L_PAREN));
107     p.bump();
108     pat_list(p, R_PAREN);
109     p.expect(R_PAREN);
110 }
111
112 // test field_pat_list
113 // fn foo() {
114 //     let S {} = ();
115 //     let S { f, ref mut g } = ();
116 //     let S { h: _, ..} = ();
117 //     let S { h: _, } = ();
118 // }
119 fn field_pat_list(p: &mut Parser) {
120     assert!(p.at(L_CURLY));
121     let m = p.start();
122     p.bump();
123     while !p.at(EOF) && !p.at(R_CURLY) {
124         match p.current() {
125             DOTDOT => p.bump(),
126             IDENT if p.nth(1) == COLON => {
127                 p.bump();
128                 p.bump();
129                 pattern(p);
130             }
131             L_CURLY => error_block(p, "expected ident"),
132             _ => {
133                 bind_pat(p, false);
134             }
135         }
136         if !p.at(R_CURLY) {
137             p.expect(COMMA);
138         }
139     }
140     p.expect(R_CURLY);
141     m.complete(p, FIELD_PAT_LIST);
142 }
143
144 // test placeholder_pat
145 // fn main() { let _ = (); }
146 fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
147     assert!(p.at(UNDERSCORE));
148     let m = p.start();
149     p.bump();
150     m.complete(p, PLACEHOLDER_PAT)
151 }
152
153 // test ref_pat
154 // fn main() {
155 //     let &a = ();
156 //     let &mut b = ();
157 // }
158 fn ref_pat(p: &mut Parser) -> CompletedMarker {
159     assert!(p.at(AMP));
160     let m = p.start();
161     p.bump();
162     p.eat(MUT_KW);
163     pattern(p);
164     m.complete(p, REF_PAT)
165 }
166
167 // test tuple_pat
168 // fn main() {
169 //     let (a, b, ..) = ();
170 // }
171 fn tuple_pat(p: &mut Parser) -> CompletedMarker {
172     assert!(p.at(L_PAREN));
173     let m = p.start();
174     tuple_pat_fields(p);
175     m.complete(p, TUPLE_PAT)
176 }
177
178 // test slice_pat
179 // fn main() {
180 //     let [a, b, ..] = [];
181 // }
182 fn slice_pat(p: &mut Parser) -> CompletedMarker {
183     assert!(p.at(L_BRACK));
184     let m = p.start();
185     p.bump();
186     pat_list(p, R_BRACK);
187     p.expect(R_BRACK);
188     m.complete(p, SLICE_PAT)
189 }
190
191 fn pat_list(p: &mut Parser, ket: SyntaxKind) {
192     while !p.at(EOF) && !p.at(ket) {
193         match p.current() {
194             DOTDOT => p.bump(),
195             _ => {
196                 if !p.at_ts(PATTERN_FIRST) {
197                     p.error("expected a pattern");
198                     break;
199                 }
200                 pattern(p)
201             }
202         }
203         if !p.at(ket) {
204             p.expect(COMMA);
205         }
206     }
207 }
208
209 // test bind_pat
210 // fn main() {
211 //     let a = ();
212 //     let mut b = ();
213 //     let ref c = ();
214 //     let ref mut d = ();
215 //     let e @ _ = ();
216 //     let ref mut f @ g @ _ = ();
217 // }
218 fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
219     let m = p.start();
220     p.eat(REF_KW);
221     p.eat(MUT_KW);
222     name(p);
223     if with_at && p.eat(AT) {
224         pattern(p);
225     }
226     m.complete(p, BIND_PAT)
227 }