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