diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-08-12 16:15:00 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-08-12 16:15:00 +0100 |
commit | 3d6889cba72a9d02199f7adaa2ecc69bc30af834 (patch) | |
tree | a17351b1e3addea0a719f38990fea9289b6ef65e /crates/parser/src/grammar/items.rs | |
parent | a573e088ac64eeeb19e4fc74be2ff019be510477 (diff) | |
parent | 50a02eb3593591a02677e1b56f24d7ff0459b9d0 (diff) |
Merge #5727
5727: Rename ra_parser -> parser
r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/parser/src/grammar/items.rs')
-rw-r--r-- | crates/parser/src/grammar/items.rs | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs new file mode 100644 index 000000000..d091b0fbb --- /dev/null +++ b/crates/parser/src/grammar/items.rs | |||
@@ -0,0 +1,432 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | mod consts; | ||
4 | mod adt; | ||
5 | mod traits; | ||
6 | mod use_item; | ||
7 | |||
8 | pub(crate) use self::{ | ||
9 | adt::{enum_variant_list, record_field_def_list}, | ||
10 | expressions::{match_arm_list, record_field_list}, | ||
11 | traits::{impl_item_list, trait_item_list}, | ||
12 | use_item::use_tree_list, | ||
13 | }; | ||
14 | use super::*; | ||
15 | |||
16 | // test mod_contents | ||
17 | // fn foo() {} | ||
18 | // macro_rules! foo {} | ||
19 | // foo::bar!(); | ||
20 | // super::baz! {} | ||
21 | // struct S; | ||
22 | pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { | ||
23 | attributes::inner_attributes(p); | ||
24 | while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) { | ||
25 | item_or_macro(p, stop_on_r_curly) | ||
26 | } | ||
27 | } | ||
28 | |||
29 | pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ | ||
30 | FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, | ||
31 | CRATE_KW, USE_KW, MACRO_KW | ||
32 | ]; | ||
33 | |||
34 | pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) { | ||
35 | let m = p.start(); | ||
36 | attributes::outer_attributes(p); | ||
37 | let m = match maybe_item(p, m) { | ||
38 | Ok(()) => { | ||
39 | if p.at(T![;]) { | ||
40 | p.err_and_bump( | ||
41 | "expected item, found `;`\n\ | ||
42 | consider removing this semicolon", | ||
43 | ); | ||
44 | } | ||
45 | return; | ||
46 | } | ||
47 | Err(m) => m, | ||
48 | }; | ||
49 | if paths::is_use_path_start(p) { | ||
50 | match macro_call(p) { | ||
51 | BlockLike::Block => (), | ||
52 | BlockLike::NotBlock => { | ||
53 | p.expect(T![;]); | ||
54 | } | ||
55 | } | ||
56 | m.complete(p, MACRO_CALL); | ||
57 | } else { | ||
58 | m.abandon(p); | ||
59 | if p.at(T!['{']) { | ||
60 | error_block(p, "expected an item"); | ||
61 | } else if p.at(T!['}']) && !stop_on_r_curly { | ||
62 | let e = p.start(); | ||
63 | p.error("unmatched `}`"); | ||
64 | p.bump(T!['}']); | ||
65 | e.complete(p, ERROR); | ||
66 | } else if !p.at(EOF) && !p.at(T!['}']) { | ||
67 | p.err_and_bump("expected an item"); | ||
68 | } else { | ||
69 | p.error("expected an item"); | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { | ||
75 | // test_err pub_expr | ||
76 | // fn foo() { pub 92; } | ||
77 | let has_visibility = opt_visibility(p); | ||
78 | |||
79 | let m = match items_without_modifiers(p, m) { | ||
80 | Ok(()) => return Ok(()), | ||
81 | Err(m) => m, | ||
82 | }; | ||
83 | |||
84 | let mut has_mods = false; | ||
85 | |||
86 | // modifiers | ||
87 | has_mods |= p.eat(T![const]); | ||
88 | |||
89 | // test_err async_without_semicolon | ||
90 | // fn foo() { let _ = async {} } | ||
91 | if p.at(T![async]) && p.nth(1) != T!['{'] && p.nth(1) != T![move] && p.nth(1) != T![|] { | ||
92 | p.eat(T![async]); | ||
93 | has_mods = true; | ||
94 | } | ||
95 | |||
96 | // test_err unsafe_block_in_mod | ||
97 | // fn foo(){} unsafe { } fn bar(){} | ||
98 | if p.at(T![unsafe]) && p.nth(1) != T!['{'] { | ||
99 | p.eat(T![unsafe]); | ||
100 | has_mods = true; | ||
101 | } | ||
102 | |||
103 | if p.at(T![extern]) { | ||
104 | has_mods = true; | ||
105 | abi(p); | ||
106 | } | ||
107 | if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == T![trait] { | ||
108 | p.bump_remap(T![auto]); | ||
109 | has_mods = true; | ||
110 | } | ||
111 | |||
112 | // test default_item | ||
113 | // default impl T for Foo {} | ||
114 | if p.at(IDENT) && p.at_contextual_kw("default") { | ||
115 | match p.nth(1) { | ||
116 | T![fn] | T![type] | T![const] | T![impl] => { | ||
117 | p.bump_remap(T![default]); | ||
118 | has_mods = true; | ||
119 | } | ||
120 | T![unsafe] => { | ||
121 | // test default_unsafe_item | ||
122 | // default unsafe impl T for Foo { | ||
123 | // default unsafe fn foo() {} | ||
124 | // } | ||
125 | if matches!(p.nth(2), T![impl] | T![fn]) { | ||
126 | p.bump_remap(T![default]); | ||
127 | p.bump(T![unsafe]); | ||
128 | has_mods = true; | ||
129 | } | ||
130 | } | ||
131 | _ => (), | ||
132 | } | ||
133 | } | ||
134 | |||
135 | // test existential_type | ||
136 | // existential type Foo: Fn() -> usize; | ||
137 | if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] { | ||
138 | p.bump_remap(T![existential]); | ||
139 | has_mods = true; | ||
140 | } | ||
141 | |||
142 | // items | ||
143 | match p.current() { | ||
144 | // test fn | ||
145 | // fn foo() {} | ||
146 | T![fn] => { | ||
147 | fn_def(p); | ||
148 | m.complete(p, FN); | ||
149 | } | ||
150 | |||
151 | // test trait | ||
152 | // trait T {} | ||
153 | T![trait] => { | ||
154 | traits::trait_def(p); | ||
155 | m.complete(p, TRAIT); | ||
156 | } | ||
157 | |||
158 | T![const] => { | ||
159 | consts::const_def(p, m); | ||
160 | } | ||
161 | |||
162 | // test impl | ||
163 | // impl T for S {} | ||
164 | T![impl] => { | ||
165 | traits::impl_def(p); | ||
166 | m.complete(p, IMPL); | ||
167 | } | ||
168 | |||
169 | T![type] => { | ||
170 | type_def(p, m); | ||
171 | } | ||
172 | _ => { | ||
173 | if !has_visibility && !has_mods { | ||
174 | return Err(m); | ||
175 | } else { | ||
176 | if has_mods { | ||
177 | p.error("expected existential, fn, trait or impl"); | ||
178 | } else { | ||
179 | p.error("expected an item"); | ||
180 | } | ||
181 | m.complete(p, ERROR); | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | Ok(()) | ||
186 | } | ||
187 | |||
188 | fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { | ||
189 | let la = p.nth(1); | ||
190 | match p.current() { | ||
191 | // test extern_crate | ||
192 | // extern crate foo; | ||
193 | T![extern] if la == T![crate] => extern_crate_item(p, m), | ||
194 | T![type] => { | ||
195 | type_def(p, m); | ||
196 | } | ||
197 | T![mod] => mod_item(p, m), | ||
198 | T![struct] => { | ||
199 | // test struct_items | ||
200 | // struct Foo; | ||
201 | // struct Foo {} | ||
202 | // struct Foo(); | ||
203 | // struct Foo(String, usize); | ||
204 | // struct Foo { | ||
205 | // a: i32, | ||
206 | // b: f32, | ||
207 | // } | ||
208 | adt::struct_def(p, m); | ||
209 | } | ||
210 | // test pub_macro_def | ||
211 | // pub macro m($:ident) {} | ||
212 | T![macro] => { | ||
213 | macro_def(p, m); | ||
214 | } | ||
215 | IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => { | ||
216 | // test union_items | ||
217 | // union Foo {} | ||
218 | // union Foo { | ||
219 | // a: i32, | ||
220 | // b: f32, | ||
221 | // } | ||
222 | adt::union_def(p, m); | ||
223 | } | ||
224 | T![enum] => adt::enum_def(p, m), | ||
225 | T![use] => use_item::use_item(p, m), | ||
226 | T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::const_def(p, m), | ||
227 | T![static] => consts::static_def(p, m), | ||
228 | // test extern_block | ||
229 | // extern {} | ||
230 | T![extern] | ||
231 | if la == T!['{'] || ((la == STRING || la == RAW_STRING) && p.nth(2) == T!['{']) => | ||
232 | { | ||
233 | abi(p); | ||
234 | extern_item_list(p); | ||
235 | m.complete(p, EXTERN_BLOCK); | ||
236 | } | ||
237 | _ => return Err(m), | ||
238 | }; | ||
239 | Ok(()) | ||
240 | } | ||
241 | |||
242 | fn extern_crate_item(p: &mut Parser, m: Marker) { | ||
243 | assert!(p.at(T![extern])); | ||
244 | p.bump(T![extern]); | ||
245 | assert!(p.at(T![crate])); | ||
246 | p.bump(T![crate]); | ||
247 | |||
248 | if p.at(T![self]) { | ||
249 | p.bump(T![self]); | ||
250 | } else { | ||
251 | name_ref(p); | ||
252 | } | ||
253 | |||
254 | opt_alias(p); | ||
255 | p.expect(T![;]); | ||
256 | m.complete(p, EXTERN_CRATE); | ||
257 | } | ||
258 | |||
259 | pub(crate) fn extern_item_list(p: &mut Parser) { | ||
260 | assert!(p.at(T!['{'])); | ||
261 | let m = p.start(); | ||
262 | p.bump(T!['{']); | ||
263 | mod_contents(p, true); | ||
264 | p.expect(T!['}']); | ||
265 | m.complete(p, EXTERN_ITEM_LIST); | ||
266 | } | ||
267 | |||
268 | fn fn_def(p: &mut Parser) { | ||
269 | assert!(p.at(T![fn])); | ||
270 | p.bump(T![fn]); | ||
271 | |||
272 | name_r(p, ITEM_RECOVERY_SET); | ||
273 | // test function_type_params | ||
274 | // fn foo<T: Clone + Copy>(){} | ||
275 | type_params::opt_type_param_list(p); | ||
276 | |||
277 | if p.at(T!['(']) { | ||
278 | params::param_list_fn_def(p); | ||
279 | } else { | ||
280 | p.error("expected function arguments"); | ||
281 | } | ||
282 | // test function_ret_type | ||
283 | // fn foo() {} | ||
284 | // fn bar() -> () {} | ||
285 | opt_fn_ret_type(p); | ||
286 | |||
287 | // test function_where_clause | ||
288 | // fn foo<T>() where T: Copy {} | ||
289 | type_params::opt_where_clause(p); | ||
290 | |||
291 | // test fn_decl | ||
292 | // trait T { fn foo(); } | ||
293 | if p.at(T![;]) { | ||
294 | p.bump(T![;]); | ||
295 | } else { | ||
296 | expressions::block_expr(p) | ||
297 | } | ||
298 | } | ||
299 | |||
300 | // test type_item | ||
301 | // type Foo = Bar; | ||
302 | fn type_def(p: &mut Parser, m: Marker) { | ||
303 | assert!(p.at(T![type])); | ||
304 | p.bump(T![type]); | ||
305 | |||
306 | name(p); | ||
307 | |||
308 | // test type_item_type_params | ||
309 | // type Result<T> = (); | ||
310 | type_params::opt_type_param_list(p); | ||
311 | |||
312 | if p.at(T![:]) { | ||
313 | type_params::bounds(p); | ||
314 | } | ||
315 | |||
316 | // test type_item_where_clause | ||
317 | // type Foo where Foo: Copy = (); | ||
318 | type_params::opt_where_clause(p); | ||
319 | if p.eat(T![=]) { | ||
320 | types::type_(p); | ||
321 | } | ||
322 | p.expect(T![;]); | ||
323 | m.complete(p, TYPE_ALIAS); | ||
324 | } | ||
325 | |||
326 | pub(crate) fn mod_item(p: &mut Parser, m: Marker) { | ||
327 | assert!(p.at(T![mod])); | ||
328 | p.bump(T![mod]); | ||
329 | |||
330 | name(p); | ||
331 | if p.at(T!['{']) { | ||
332 | mod_item_list(p); | ||
333 | } else if !p.eat(T![;]) { | ||
334 | p.error("expected `;` or `{`"); | ||
335 | } | ||
336 | m.complete(p, MODULE); | ||
337 | } | ||
338 | |||
339 | pub(crate) fn mod_item_list(p: &mut Parser) { | ||
340 | assert!(p.at(T!['{'])); | ||
341 | let m = p.start(); | ||
342 | p.bump(T!['{']); | ||
343 | mod_contents(p, true); | ||
344 | p.expect(T!['}']); | ||
345 | m.complete(p, ITEM_LIST); | ||
346 | } | ||
347 | |||
348 | // test macro_def | ||
349 | // macro m { ($i:ident) => {} } | ||
350 | // macro m($i:ident) {} | ||
351 | fn macro_def(p: &mut Parser, m: Marker) { | ||
352 | p.expect(T![macro]); | ||
353 | name_r(p, ITEM_RECOVERY_SET); | ||
354 | if p.at(T!['{']) { | ||
355 | token_tree(p); | ||
356 | } else if !p.at(T!['(']) { | ||
357 | p.error("unmatched `(`"); | ||
358 | } else { | ||
359 | let m = p.start(); | ||
360 | token_tree(p); | ||
361 | match p.current() { | ||
362 | T!['{'] | T!['['] | T!['('] => token_tree(p), | ||
363 | _ => p.error("expected `{`, `[`, `(`"), | ||
364 | } | ||
365 | m.complete(p, TOKEN_TREE); | ||
366 | } | ||
367 | |||
368 | m.complete(p, MACRO_DEF); | ||
369 | } | ||
370 | |||
371 | fn macro_call(p: &mut Parser) -> BlockLike { | ||
372 | assert!(paths::is_use_path_start(p)); | ||
373 | paths::use_path(p); | ||
374 | macro_call_after_excl(p) | ||
375 | } | ||
376 | |||
377 | pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike { | ||
378 | p.expect(T![!]); | ||
379 | if p.at(IDENT) { | ||
380 | name(p); | ||
381 | } | ||
382 | // Special-case `macro_rules! try`. | ||
383 | // This is a hack until we do proper edition support | ||
384 | |||
385 | // test try_macro_rules | ||
386 | // macro_rules! try { () => {} } | ||
387 | if p.at(T![try]) { | ||
388 | let m = p.start(); | ||
389 | p.bump_remap(IDENT); | ||
390 | m.complete(p, NAME); | ||
391 | } | ||
392 | |||
393 | match p.current() { | ||
394 | T!['{'] => { | ||
395 | token_tree(p); | ||
396 | BlockLike::Block | ||
397 | } | ||
398 | T!['('] | T!['['] => { | ||
399 | token_tree(p); | ||
400 | BlockLike::NotBlock | ||
401 | } | ||
402 | _ => { | ||
403 | p.error("expected `{`, `[`, `(`"); | ||
404 | BlockLike::NotBlock | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | |||
409 | pub(crate) fn token_tree(p: &mut Parser) { | ||
410 | let closing_paren_kind = match p.current() { | ||
411 | T!['{'] => T!['}'], | ||
412 | T!['('] => T![')'], | ||
413 | T!['['] => T![']'], | ||
414 | _ => unreachable!(), | ||
415 | }; | ||
416 | let m = p.start(); | ||
417 | p.bump_any(); | ||
418 | while !p.at(EOF) && !p.at(closing_paren_kind) { | ||
419 | match p.current() { | ||
420 | T!['{'] | T!['('] | T!['['] => token_tree(p), | ||
421 | T!['}'] => { | ||
422 | p.error("unmatched `}`"); | ||
423 | m.complete(p, TOKEN_TREE); | ||
424 | return; | ||
425 | } | ||
426 | T![')'] | T![']'] => p.err_and_bump("unmatched brace"), | ||
427 | _ => p.bump_any(), | ||
428 | } | ||
429 | } | ||
430 | p.expect(closing_paren_kind); | ||
431 | m.complete(p, TOKEN_TREE); | ||
432 | } | ||