diff options
Diffstat (limited to 'crates/ra_syntax/src/grammar/patterns.rs')
-rw-r--r-- | crates/ra_syntax/src/grammar/patterns.rs | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/grammar/patterns.rs b/crates/ra_syntax/src/grammar/patterns.rs new file mode 100644 index 000000000..420bae7a7 --- /dev/null +++ b/crates/ra_syntax/src/grammar/patterns.rs | |||
@@ -0,0 +1,224 @@ | |||
1 | use super::*; | ||
2 | |||
3 | pub(super) const PATTERN_FIRST: TokenSet = | ||
4 | token_set_union![ | ||
5 | token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE], | ||
6 | expressions::LITERAL_FIRST, | ||
7 | paths::PATH_FIRST, | ||
8 | ]; | ||
9 | |||
10 | pub(super) fn pattern(p: &mut Parser) { | ||
11 | pattern_r(p, PAT_RECOVERY_SET) | ||
12 | } | ||
13 | |||
14 | pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) { | ||
15 | if let Some(lhs) = atom_pat(p, recovery_set) { | ||
16 | // test range_pat | ||
17 | // fn main() { | ||
18 | // match 92 { 0 ... 100 => () } | ||
19 | // } | ||
20 | if p.at(DOTDOTDOT) { | ||
21 | let m = lhs.precede(p); | ||
22 | p.bump(); | ||
23 | atom_pat(p, recovery_set); | ||
24 | m.complete(p, RANGE_PAT); | ||
25 | } | ||
26 | } | ||
27 | } | ||
28 | |||
29 | const PAT_RECOVERY_SET: TokenSet = | ||
30 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; | ||
31 | |||
32 | |||
33 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | ||
34 | let la0 = p.nth(0); | ||
35 | let la1 = p.nth(1); | ||
36 | if la0 == REF_KW || la0 == MUT_KW | ||
37 | || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY)) { | ||
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 | } | ||