]> git.lizzy.rs Git - rust.git/blob - crates/parser/src/grammar/items.rs
Add support for new `where` clause location in associated types.
[rust.git] / crates / parser / src / grammar / items.rs
1 mod consts;
2 mod adt;
3 mod traits;
4 mod use_item;
5
6 pub(crate) use self::{
7     adt::{record_field_list, variant_list},
8     expressions::{match_arm_list, record_expr_field_list},
9     traits::assoc_item_list,
10     use_item::use_tree_list,
11 };
12 use super::*;
13
14 // test mod_contents
15 // fn foo() {}
16 // macro_rules! foo {}
17 // foo::bar!();
18 // super::baz! {}
19 // struct S;
20 pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
21     attributes::inner_attrs(p);
22     while !p.at(EOF) && !(p.at(T!['}']) && stop_on_r_curly) {
23         item_or_macro(p, stop_on_r_curly);
24     }
25 }
26
27 pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[
28     T![fn],
29     T![struct],
30     T![enum],
31     T![impl],
32     T![trait],
33     T![const],
34     T![static],
35     T![let],
36     T![mod],
37     T![pub],
38     T![crate],
39     T![use],
40     T![macro],
41     T![;],
42 ]);
43
44 pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) {
45     let m = p.start();
46     attributes::outer_attrs(p);
47
48     let m = match opt_item(p, m) {
49         Ok(()) => {
50             if p.at(T![;]) {
51                 p.err_and_bump(
52                     "expected item, found `;`\n\
53                      consider removing this semicolon",
54                 );
55             }
56             return;
57         }
58         Err(m) => m,
59     };
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         return;
70     }
71
72     m.abandon(p);
73     match p.current() {
74         T!['{'] => error_block(p, "expected an item"),
75         T!['}'] if !stop_on_r_curly => {
76             let e = p.start();
77             p.error("unmatched `}`");
78             p.bump(T!['}']);
79             e.complete(p, ERROR);
80         }
81         EOF | T!['}'] => p.error("expected an item"),
82         _ => p.err_and_bump("expected an item"),
83     }
84 }
85
86 /// Try to parse an item, completing `m` in case of success.
87 pub(super) fn opt_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
88     // test_err pub_expr
89     // fn foo() { pub 92; }
90     let has_visibility = opt_visibility(p, false);
91
92     let m = match opt_item_without_modifiers(p, m) {
93         Ok(()) => return Ok(()),
94         Err(m) => m,
95     };
96
97     let mut has_mods = false;
98     let mut has_extern = false;
99
100     // modifiers
101     if p.at(T![const]) && p.nth(1) != T!['{'] {
102         p.eat(T![const]);
103         has_mods = true;
104     }
105
106     // test_err async_without_semicolon
107     // fn foo() { let _ = async {} }
108     if p.at(T![async]) && !matches!(p.nth(1), T!['{'] | T![move] | T![|]) {
109         p.eat(T![async]);
110         has_mods = true;
111     }
112
113     // test_err unsafe_block_in_mod
114     // fn foo(){} unsafe { } fn bar(){}
115     if p.at(T![unsafe]) && p.nth(1) != T!['{'] {
116         p.eat(T![unsafe]);
117         has_mods = true;
118     }
119
120     if p.at(T![extern]) {
121         has_extern = true;
122         has_mods = true;
123         abi(p);
124     }
125     if p.at_contextual_kw(T![auto]) && p.nth(1) == T![trait] {
126         p.bump_remap(T![auto]);
127         has_mods = true;
128     }
129
130     // test default_item
131     // default impl T for Foo {}
132     if p.at_contextual_kw(T![default]) {
133         match p.nth(1) {
134             T![fn] | T![type] | T![const] | T![impl] => {
135                 p.bump_remap(T![default]);
136                 has_mods = true;
137             }
138             // test default_unsafe_item
139             // default unsafe impl T for Foo {
140             //     default unsafe fn foo() {}
141             // }
142             T![unsafe] if matches!(p.nth(2), T![impl] | T![fn]) => {
143                 p.bump_remap(T![default]);
144                 p.bump(T![unsafe]);
145                 has_mods = true;
146             }
147             // test default_async_fn
148             // impl T for Foo {
149             //     default async fn foo() {}
150             // }
151             T![async] => {
152                 let mut maybe_fn = p.nth(2);
153                 let is_unsafe = if matches!(maybe_fn, T![unsafe]) {
154                     // test default_async_unsafe_fn
155                     // impl T for Foo {
156                     //     default async unsafe fn foo() {}
157                     // }
158                     maybe_fn = p.nth(3);
159                     true
160                 } else {
161                     false
162                 };
163
164                 if matches!(maybe_fn, T![fn]) {
165                     p.bump_remap(T![default]);
166                     p.bump(T![async]);
167                     if is_unsafe {
168                         p.bump(T![unsafe]);
169                     }
170                     has_mods = true;
171                 }
172             }
173             _ => (),
174         }
175     }
176
177     // test existential_type
178     // existential type Foo: Fn() -> usize;
179     if p.at_contextual_kw(T![existential]) && p.nth(1) == T![type] {
180         p.bump_remap(T![existential]);
181         has_mods = true;
182     }
183
184     // items
185     match p.current() {
186         T![fn] => fn_(p, m),
187
188         T![const] if p.nth(1) != T!['{'] => consts::konst(p, m),
189
190         T![trait] => traits::trait_(p, m),
191         T![impl] => traits::impl_(p, m),
192
193         T![type] => type_alias(p, m),
194
195         // test extern_block
196         // unsafe extern "C" {}
197         // extern {}
198         T!['{'] if has_extern => {
199             extern_item_list(p);
200             m.complete(p, EXTERN_BLOCK);
201         }
202
203         _ if has_visibility || has_mods => {
204             if has_mods {
205                 p.error("expected existential, fn, trait or impl");
206             } else {
207                 p.error("expected an item");
208             }
209             m.complete(p, ERROR);
210         }
211
212         _ => return Err(m),
213     }
214     Ok(())
215 }
216
217 fn opt_item_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
218     let la = p.nth(1);
219     match p.current() {
220         T![extern] if la == T![crate] => extern_crate(p, m),
221         T![use] => use_item::use_(p, m),
222         T![mod] => mod_item(p, m),
223
224         T![type] => type_alias(p, m),
225         T![struct] => adt::strukt(p, m),
226         T![enum] => adt::enum_(p, m),
227         IDENT if p.at_contextual_kw(T![union]) && p.nth(1) == IDENT => adt::union(p, m),
228
229         T![macro] => macro_def(p, m),
230         IDENT if p.at_contextual_kw(T![macro_rules]) && p.nth(1) == BANG => macro_rules(p, m),
231
232         T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m),
233         T![static] if (la == IDENT || la == T![_] || la == T![mut]) => consts::static_(p, m),
234
235         _ => return Err(m),
236     };
237     Ok(())
238 }
239
240 // test extern_crate
241 // extern crate foo;
242 fn extern_crate(p: &mut Parser, m: Marker) {
243     p.bump(T![extern]);
244     p.bump(T![crate]);
245
246     if p.at(T![self]) {
247         // test extern_crate_self
248         // extern crate self;
249         let m = p.start();
250         p.bump(T![self]);
251         m.complete(p, NAME_REF);
252     } else {
253         name_ref(p);
254     }
255
256     // test extern_crate_rename
257     // extern crate foo as bar;
258     opt_rename(p);
259     p.expect(T![;]);
260     m.complete(p, EXTERN_CRATE);
261 }
262
263 // test mod_item
264 // mod a;
265 pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
266     p.bump(T![mod]);
267     name(p);
268     if p.at(T!['{']) {
269         // test mod_item_curly
270         // mod b { }
271         item_list(p);
272     } else if !p.eat(T![;]) {
273         p.error("expected `;` or `{`");
274     }
275     m.complete(p, MODULE);
276 }
277
278 // test type_alias
279 // type Foo = Bar;
280 fn type_alias(p: &mut Parser, m: Marker) {
281     p.bump(T![type]);
282
283     name(p);
284
285     // test type_item_type_params
286     // type Result<T> = ();
287     generic_params::opt_generic_param_list(p);
288
289     if p.at(T![:]) {
290         generic_params::bounds(p);
291     }
292
293     // test type_item_where_clause_deprecated
294     // type Foo where Foo: Copy = ();
295     generic_params::opt_where_clause(p);
296     if p.eat(T![=]) {
297         types::type_(p);
298     }
299
300     // test type_item_where_clause
301     // type Foo = () where Foo: Copy;
302     generic_params::opt_where_clause(p);
303
304     p.expect(T![;]);
305     m.complete(p, TYPE_ALIAS);
306 }
307
308 pub(crate) fn item_list(p: &mut Parser) {
309     assert!(p.at(T!['{']));
310     let m = p.start();
311     p.bump(T!['{']);
312     mod_contents(p, true);
313     p.expect(T!['}']);
314     m.complete(p, ITEM_LIST);
315 }
316
317 pub(crate) fn extern_item_list(p: &mut Parser) {
318     assert!(p.at(T!['{']));
319     let m = p.start();
320     p.bump(T!['{']);
321     mod_contents(p, true);
322     p.expect(T!['}']);
323     m.complete(p, EXTERN_ITEM_LIST);
324 }
325
326 fn macro_rules(p: &mut Parser, m: Marker) {
327     assert!(p.at_contextual_kw(T![macro_rules]));
328     p.bump_remap(T![macro_rules]);
329     p.expect(T![!]);
330
331     if p.at(IDENT) {
332         name(p);
333     }
334     // Special-case `macro_rules! try`.
335     // This is a hack until we do proper edition support
336
337     // test try_macro_rules
338     // macro_rules! try { () => {} }
339     if p.at(T![try]) {
340         let m = p.start();
341         p.bump_remap(IDENT);
342         m.complete(p, NAME);
343     }
344
345     match p.current() {
346         // test macro_rules_non_brace
347         // macro_rules! m ( ($i:ident) => {} );
348         // macro_rules! m [ ($i:ident) => {} ];
349         T!['['] | T!['('] => {
350             token_tree(p);
351             p.expect(T![;]);
352         }
353         T!['{'] => token_tree(p),
354         _ => p.error("expected `{`, `[`, `(`"),
355     }
356     m.complete(p, MACRO_RULES);
357 }
358
359 // test macro_def
360 // macro m($i:ident) {}
361 fn macro_def(p: &mut Parser, m: Marker) {
362     p.expect(T![macro]);
363     name_r(p, ITEM_RECOVERY_SET);
364     if p.at(T!['{']) {
365         // test macro_def_curly
366         // macro m { ($i:ident) => {} }
367         token_tree(p);
368     } else if p.at(T!['(']) {
369         let m = p.start();
370         token_tree(p);
371         match p.current() {
372             T!['{'] | T!['['] | T!['('] => token_tree(p),
373             _ => p.error("expected `{`, `[`, `(`"),
374         }
375         m.complete(p, TOKEN_TREE);
376     } else {
377         p.error("unmatched `(`");
378     }
379
380     m.complete(p, MACRO_DEF);
381 }
382
383 // test fn
384 // fn foo() {}
385 fn fn_(p: &mut Parser, m: Marker) {
386     p.bump(T![fn]);
387
388     name_r(p, ITEM_RECOVERY_SET);
389     // test function_type_params
390     // fn foo<T: Clone + Copy>(){}
391     generic_params::opt_generic_param_list(p);
392
393     if p.at(T!['(']) {
394         params::param_list_fn_def(p);
395     } else {
396         p.error("expected function arguments");
397     }
398     // test function_ret_type
399     // fn foo() {}
400     // fn bar() -> () {}
401     opt_ret_type(p);
402
403     // test function_where_clause
404     // fn foo<T>() where T: Copy {}
405     generic_params::opt_where_clause(p);
406
407     if p.at(T![;]) {
408         // test fn_decl
409         // trait T { fn foo(); }
410         p.bump(T![;]);
411     } else {
412         expressions::block_expr(p);
413     }
414     m.complete(p, FN);
415 }
416
417 fn macro_call(p: &mut Parser) -> BlockLike {
418     assert!(paths::is_use_path_start(p));
419     paths::use_path(p);
420     macro_call_after_excl(p)
421 }
422
423 pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
424     p.expect(T![!]);
425
426     match p.current() {
427         T!['{'] => {
428             token_tree(p);
429             BlockLike::Block
430         }
431         T!['('] | T!['['] => {
432             token_tree(p);
433             BlockLike::NotBlock
434         }
435         _ => {
436             p.error("expected `{`, `[`, `(`");
437             BlockLike::NotBlock
438         }
439     }
440 }
441
442 pub(crate) fn token_tree(p: &mut Parser) {
443     let closing_paren_kind = match p.current() {
444         T!['{'] => T!['}'],
445         T!['('] => T![')'],
446         T!['['] => T![']'],
447         _ => unreachable!(),
448     };
449     let m = p.start();
450     p.bump_any();
451     while !p.at(EOF) && !p.at(closing_paren_kind) {
452         match p.current() {
453             T!['{'] | T!['('] | T!['['] => token_tree(p),
454             T!['}'] => {
455                 p.error("unmatched `}`");
456                 m.complete(p, TOKEN_TREE);
457                 return;
458             }
459             T![')'] | T![']'] => p.err_and_bump("unmatched brace"),
460             _ => p.bump_any(),
461         }
462     }
463     p.expect(closing_paren_kind);
464     m.complete(p, TOKEN_TREE);
465 }