]> git.lizzy.rs Git - rust.git/blob - crates/ra_parser/src/grammar/items.rs
7e345f733d2d15e048b91d25b51fb57df364986c
[rust.git] / crates / ra_parser / src / grammar / items.rs
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 !p.at(EOF) && !(stop_on_r_curly && p.at(T!['}'])) {
25         item_or_macro(p, stop_on_r_curly, ItemFlavor::Mod)
26     }
27 }
28
29 pub(super) enum ItemFlavor {
30     Mod,
31     Trait,
32 }
33
34 pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
35     FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
36     CRATE_KW, USE_KW
37 ];
38
39 pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
40     let m = p.start();
41     attributes::outer_attributes(p);
42     let m = match maybe_item(p, m, flavor) {
43         Ok(()) => {
44             if p.at(T![;]) {
45                 p.err_and_bump(
46                     "expected item, found `;`\n\
47                      consider removing this semicolon",
48                 );
49             }
50             return;
51         }
52         Err(m) => m,
53     };
54     if paths::is_use_path_start(p) {
55         match macro_call(p) {
56             BlockLike::Block => (),
57             BlockLike::NotBlock => {
58                 p.expect(T![;]);
59             }
60         }
61         m.complete(p, MACRO_CALL);
62     } else {
63         m.abandon(p);
64         if p.at(T!['{']) {
65             error_block(p, "expected an item");
66         } else if p.at(T!['}']) && !stop_on_r_curly {
67             let e = p.start();
68             p.error("unmatched `}`");
69             p.bump(T!['}']);
70             e.complete(p, ERROR);
71         } else if !p.at(EOF) && !p.at(T!['}']) {
72             p.err_and_bump("expected an item");
73         } else {
74             p.error("expected an item");
75         }
76     }
77 }
78
79 pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Result<(), Marker> {
80     // test_err pub_expr
81     // fn foo() { pub 92; }
82     let has_visibility = opt_visibility(p);
83
84     let m = match items_without_modifiers(p, m) {
85         Ok(()) => return Ok(()),
86         Err(m) => m,
87     };
88
89     let mut has_mods = false;
90
91     // modifiers
92     has_mods |= p.eat(T![const]);
93
94     // test_err unsafe_block_in_mod
95     // fn foo(){} unsafe { } fn bar(){}
96     if p.at(T![unsafe]) && p.nth(1) != T!['{'] {
97         p.eat(T![unsafe]);
98         has_mods = true;
99     }
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     if p.at(T![extern]) {
109         has_mods = true;
110         abi(p);
111     }
112     if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == T![trait] {
113         p.bump_remap(T![auto]);
114         has_mods = true;
115     }
116
117     if p.at(IDENT)
118         && p.at_contextual_kw("default")
119         && (match p.nth(1) {
120             T![impl] => true,
121             T![fn] | T![type] => {
122                 if let ItemFlavor::Mod = flavor {
123                     true
124                 } else {
125                     false
126                 }
127             }
128             _ => false,
129         })
130     {
131         p.bump_remap(T![default]);
132         has_mods = true;
133     }
134     if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] {
135         p.bump_remap(T![existential]);
136         has_mods = true;
137     }
138
139     // items
140     match p.current() {
141         // test async_fn
142         // async fn foo() {}
143
144         // test extern_fn
145         // extern fn foo() {}
146
147         // test const_fn
148         // const fn foo() {}
149
150         // test const_unsafe_fn
151         // const unsafe fn foo() {}
152
153         // test unsafe_extern_fn
154         // unsafe extern "C" fn foo() {}
155
156         // test unsafe_fn
157         // unsafe fn foo() {}
158
159         // test combined_fns
160         // unsafe async fn foo() {}
161         // const unsafe fn bar() {}
162
163         // test_err wrong_order_fns
164         // async unsafe fn foo() {}
165         // unsafe const fn bar() {}
166         T![fn] => {
167             fn_def(p, flavor);
168             m.complete(p, FN_DEF);
169         }
170
171         // test unsafe_trait
172         // unsafe trait T {}
173
174         // test auto_trait
175         // auto trait T {}
176
177         // test unsafe_auto_trait
178         // unsafe auto trait T {}
179         T![trait] => {
180             traits::trait_def(p);
181             m.complete(p, TRAIT_DEF);
182         }
183
184         // test unsafe_impl
185         // unsafe impl Foo {}
186
187         // test default_impl
188         // default impl Foo {}
189
190         // test_err default_fn_type
191         // trait T {
192         //     default type T = Bar;
193         //     default fn foo() {}
194         // }
195
196         // test default_fn_type
197         // impl T for Foo {
198         //     default type T = Bar;
199         //     default fn foo() {}
200         // }
201
202         // test unsafe_default_impl
203         // unsafe default impl Foo {}
204         T![impl] => {
205             traits::impl_block(p);
206             m.complete(p, IMPL_BLOCK);
207         }
208
209         // test existential_type
210         // existential type Foo: Fn() -> usize;
211         T![type] => {
212             type_def(p, m);
213         }
214         _ => {
215             if !has_visibility && !has_mods {
216                 return Err(m);
217             } else {
218                 if has_mods {
219                     p.error("expected existential, fn, trait or impl");
220                 } else {
221                     p.error("expected an item");
222                 }
223                 m.complete(p, ERROR);
224             }
225         }
226     }
227     Ok(())
228 }
229
230 fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
231     let la = p.nth(1);
232     match p.current() {
233         // test extern_crate
234         // extern crate foo;
235         T![extern] if la == T![crate] => extern_crate_item(p, m),
236         T![type] => {
237             type_def(p, m);
238         }
239         T![mod] => mod_item(p, m),
240         T![struct] => {
241             // test struct_items
242             // struct Foo;
243             // struct Foo {}
244             // struct Foo();
245             // struct Foo(String, usize);
246             // struct Foo {
247             //     a: i32,
248             //     b: f32,
249             // }
250             adt::struct_def(p, m);
251         }
252         // test pub_macro_def
253         // pub macro m($:ident) {}
254         T![macro] => {
255             macro_def(p, m);
256         }
257         IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
258             // test union_items
259             // union Foo {}
260             // union Foo {
261             //     a: i32,
262             //     b: f32,
263             // }
264             adt::union_def(p, m);
265         }
266         T![enum] => adt::enum_def(p, m),
267         T![use] => use_item::use_item(p, m),
268         T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::const_def(p, m),
269         T![static] => consts::static_def(p, m),
270         // test extern_block
271         // extern {}
272         T![extern]
273             if la == T!['{'] || ((la == STRING || la == RAW_STRING) && p.nth(2) == T!['{']) =>
274         {
275             abi(p);
276             extern_item_list(p);
277             m.complete(p, EXTERN_BLOCK);
278         }
279         _ => return Err(m),
280     };
281     Ok(())
282 }
283
284 fn extern_crate_item(p: &mut Parser, m: Marker) {
285     assert!(p.at(T![extern]));
286     p.bump(T![extern]);
287     assert!(p.at(T![crate]));
288     p.bump(T![crate]);
289     name_ref(p);
290     opt_alias(p);
291     p.expect(T![;]);
292     m.complete(p, EXTERN_CRATE_ITEM);
293 }
294
295 pub(crate) fn extern_item_list(p: &mut Parser) {
296     assert!(p.at(T!['{']));
297     let m = p.start();
298     p.bump(T!['{']);
299     mod_contents(p, true);
300     p.expect(T!['}']);
301     m.complete(p, EXTERN_ITEM_LIST);
302 }
303
304 fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
305     assert!(p.at(T![fn]));
306     p.bump(T![fn]);
307
308     name_r(p, ITEM_RECOVERY_SET);
309     // test function_type_params
310     // fn foo<T: Clone + Copy>(){}
311     type_params::opt_type_param_list(p);
312
313     if p.at(T!['(']) {
314         match flavor {
315             ItemFlavor::Mod => params::param_list(p),
316             ItemFlavor::Trait => params::param_list_opt_patterns(p),
317         }
318     } else {
319         p.error("expected function arguments");
320     }
321     // test function_ret_type
322     // fn foo() {}
323     // fn bar() -> () {}
324     opt_fn_ret_type(p);
325
326     // test function_where_clause
327     // fn foo<T>() where T: Copy {}
328     type_params::opt_where_clause(p);
329
330     // test fn_decl
331     // trait T { fn foo(); }
332     if p.at(T![;]) {
333         p.bump(T![;]);
334     } else {
335         expressions::block(p)
336     }
337 }
338
339 // test type_item
340 // type Foo = Bar;
341 fn type_def(p: &mut Parser, m: Marker) {
342     assert!(p.at(T![type]));
343     p.bump(T![type]);
344
345     name(p);
346
347     // test type_item_type_params
348     // type Result<T> = ();
349     type_params::opt_type_param_list(p);
350
351     if p.at(T![:]) {
352         type_params::bounds(p);
353     }
354
355     // test type_item_where_clause
356     // type Foo where Foo: Copy = ();
357     type_params::opt_where_clause(p);
358     if p.eat(T![=]) {
359         types::type_(p);
360     }
361     p.expect(T![;]);
362     m.complete(p, TYPE_ALIAS_DEF);
363 }
364
365 pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
366     assert!(p.at(T![mod]));
367     p.bump(T![mod]);
368
369     name(p);
370     if p.at(T!['{']) {
371         mod_item_list(p);
372     } else if !p.eat(T![;]) {
373         p.error("expected `;` or `{`");
374     }
375     m.complete(p, MODULE);
376 }
377
378 pub(crate) fn mod_item_list(p: &mut Parser) {
379     assert!(p.at(T!['{']));
380     let m = p.start();
381     p.bump(T!['{']);
382     mod_contents(p, true);
383     p.expect(T!['}']);
384     m.complete(p, ITEM_LIST);
385 }
386
387 // test macro_def
388 // macro m { ($i:ident) => {} }
389 // macro m($i:ident) {}
390 fn macro_def(p: &mut Parser, m: Marker) {
391     p.expect(T![macro]);
392     p.expect(IDENT);
393     if p.at(T!['{']) {
394         token_tree(p);
395     } else if !p.at(T!['(']) {
396         p.error("unmatched `(`");
397     } else {
398         let m = p.start();
399         token_tree(p);
400         match p.current() {
401             T!['{'] | T!['['] | T!['('] => token_tree(p),
402             _ => p.error("expected `{`, `[`, `(`"),
403         }
404         m.complete(p, TOKEN_TREE);
405     }
406
407     m.complete(p, MACRO_DEF);
408 }
409
410 fn macro_call(p: &mut Parser) -> BlockLike {
411     assert!(paths::is_use_path_start(p));
412     paths::use_path(p);
413     macro_call_after_excl(p)
414 }
415
416 pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
417     p.expect(T![!]);
418     if p.at(IDENT) {
419         name(p);
420     }
421     match p.current() {
422         T!['{'] => {
423             token_tree(p);
424             BlockLike::Block
425         }
426         T!['('] | T!['['] => {
427             token_tree(p);
428             BlockLike::NotBlock
429         }
430         _ => {
431             p.error("expected `{`, `[`, `(`");
432             BlockLike::NotBlock
433         }
434     }
435 }
436
437 pub(crate) fn token_tree(p: &mut Parser) {
438     let closing_paren_kind = match p.current() {
439         T!['{'] => T!['}'],
440         T!['('] => T![')'],
441         T!['['] => T![']'],
442         _ => unreachable!(),
443     };
444     let m = p.start();
445     p.bump_any();
446     while !p.at(EOF) && !p.at(closing_paren_kind) {
447         match p.current() {
448             T!['{'] | T!['('] | T!['['] => token_tree(p),
449             T!['}'] => {
450                 p.error("unmatched `}`");
451                 m.complete(p, TOKEN_TREE);
452                 return;
453             }
454             T![')'] | T![']'] => p.err_and_bump("unmatched brace"),
455             _ => p.bump_any(),
456         }
457     }
458     p.expect(closing_paren_kind);
459     m.complete(p, TOKEN_TREE);
460 }