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