diff options
Diffstat (limited to 'crates/ra_syntax/src/grammar/items.rs')
-rw-r--r-- | crates/ra_syntax/src/grammar/items.rs | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/grammar/items.rs b/crates/ra_syntax/src/grammar/items.rs new file mode 100644 index 000000000..4473c2fab --- /dev/null +++ b/crates/ra_syntax/src/grammar/items.rs | |||
@@ -0,0 +1,394 @@ | |||
1 | mod consts; | ||
2 | mod nominal; | ||
3 | mod traits; | ||
4 | mod use_item; | ||
5 | |||
6 | pub(crate) use self::{ | ||
7 | expressions::{match_arm_list, named_field_list}, | ||
8 | nominal::{enum_variant_list, named_field_def_list}, | ||
9 | traits::{impl_item_list, trait_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_attributes(p); | ||
22 | while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) { | ||
23 | item_or_macro(p, stop_on_r_curly, ItemFlavor::Mod) | ||
24 | } | ||
25 | } | ||
26 | |||
27 | pub(super) enum ItemFlavor { | ||
28 | Mod, | ||
29 | Trait, | ||
30 | } | ||
31 | |||
32 | pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ | ||
33 | FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, | ||
34 | CRATE_KW | ||
35 | ]; | ||
36 | |||
37 | pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { | ||
38 | let m = p.start(); | ||
39 | match maybe_item(p, flavor) { | ||
40 | MaybeItem::Item(kind) => { | ||
41 | m.complete(p, kind); | ||
42 | } | ||
43 | MaybeItem::None => { | ||
44 | if paths::is_path_start(p) { | ||
45 | match macro_call(p) { | ||
46 | BlockLike::Block => (), | ||
47 | BlockLike::NotBlock => { | ||
48 | p.expect(SEMI); | ||
49 | } | ||
50 | } | ||
51 | m.complete(p, MACRO_CALL); | ||
52 | } else { | ||
53 | m.abandon(p); | ||
54 | if p.at(L_CURLY) { | ||
55 | error_block(p, "expected an item"); | ||
56 | } else if p.at(R_CURLY) && !stop_on_r_curly { | ||
57 | let e = p.start(); | ||
58 | p.error("unmatched `}`"); | ||
59 | p.bump(); | ||
60 | e.complete(p, ERROR); | ||
61 | } else if !p.at(EOF) && !p.at(R_CURLY) { | ||
62 | p.err_and_bump("expected an item"); | ||
63 | } else { | ||
64 | p.error("expected an item"); | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | MaybeItem::Modifiers => { | ||
69 | p.error("expected fn, trait or impl"); | ||
70 | m.complete(p, ERROR); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | pub(super) enum MaybeItem { | ||
76 | None, | ||
77 | Item(SyntaxKind), | ||
78 | Modifiers, | ||
79 | } | ||
80 | |||
81 | pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem { | ||
82 | attributes::outer_attributes(p); | ||
83 | opt_visibility(p); | ||
84 | if let Some(kind) = items_without_modifiers(p) { | ||
85 | return MaybeItem::Item(kind); | ||
86 | } | ||
87 | |||
88 | let mut has_mods = false; | ||
89 | // modifiers | ||
90 | has_mods |= p.eat(CONST_KW); | ||
91 | |||
92 | // test unsafe_block_in_mod | ||
93 | // fn foo(){} unsafe { } fn bar(){} | ||
94 | if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY { | ||
95 | p.eat(UNSAFE_KW); | ||
96 | has_mods = true; | ||
97 | } | ||
98 | if p.at(EXTERN_KW) { | ||
99 | has_mods = true; | ||
100 | abi(p); | ||
101 | } | ||
102 | if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW { | ||
103 | p.bump_remap(AUTO_KW); | ||
104 | has_mods = true; | ||
105 | } | ||
106 | if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW { | ||
107 | p.bump_remap(DEFAULT_KW); | ||
108 | has_mods = true; | ||
109 | } | ||
110 | |||
111 | // items | ||
112 | let kind = match p.current() { | ||
113 | // test extern_fn | ||
114 | // extern fn foo() {} | ||
115 | |||
116 | // test const_fn | ||
117 | // const fn foo() {} | ||
118 | |||
119 | // test const_unsafe_fn | ||
120 | // const unsafe fn foo() {} | ||
121 | |||
122 | // test unsafe_extern_fn | ||
123 | // unsafe extern "C" fn foo() {} | ||
124 | |||
125 | // test unsafe_fn | ||
126 | // unsafe fn foo() {} | ||
127 | FN_KW => { | ||
128 | fn_def(p, flavor); | ||
129 | FN_DEF | ||
130 | } | ||
131 | |||
132 | // test unsafe_trait | ||
133 | // unsafe trait T {} | ||
134 | |||
135 | // test auto_trait | ||
136 | // auto trait T {} | ||
137 | |||
138 | // test unsafe_auto_trait | ||
139 | // unsafe auto trait T {} | ||
140 | TRAIT_KW => { | ||
141 | traits::trait_def(p); | ||
142 | TRAIT_DEF | ||
143 | } | ||
144 | |||
145 | // test unsafe_impl | ||
146 | // unsafe impl Foo {} | ||
147 | |||
148 | // test default_impl | ||
149 | // default impl Foo {} | ||
150 | |||
151 | // test unsafe_default_impl | ||
152 | // unsafe default impl Foo {} | ||
153 | IMPL_KW => { | ||
154 | traits::impl_item(p); | ||
155 | IMPL_ITEM | ||
156 | } | ||
157 | _ => { | ||
158 | return if has_mods { | ||
159 | MaybeItem::Modifiers | ||
160 | } else { | ||
161 | MaybeItem::None | ||
162 | }; | ||
163 | } | ||
164 | }; | ||
165 | |||
166 | MaybeItem::Item(kind) | ||
167 | } | ||
168 | |||
169 | fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> { | ||
170 | let la = p.nth(1); | ||
171 | let kind = match p.current() { | ||
172 | // test extern_crate | ||
173 | // extern crate foo; | ||
174 | EXTERN_KW if la == CRATE_KW => { | ||
175 | extern_crate_item(p); | ||
176 | EXTERN_CRATE_ITEM | ||
177 | } | ||
178 | TYPE_KW => { | ||
179 | type_def(p); | ||
180 | TYPE_DEF | ||
181 | } | ||
182 | MOD_KW => { | ||
183 | mod_item(p); | ||
184 | MODULE | ||
185 | } | ||
186 | STRUCT_KW => { | ||
187 | // test struct_items | ||
188 | // struct Foo; | ||
189 | // struct Foo {} | ||
190 | // struct Foo(); | ||
191 | // struct Foo(String, usize); | ||
192 | // struct Foo { | ||
193 | // a: i32, | ||
194 | // b: f32, | ||
195 | // } | ||
196 | nominal::struct_def(p, STRUCT_KW); | ||
197 | if p.at(SEMI) { | ||
198 | p.err_and_bump( | ||
199 | "expected item, found `;`\n\ | ||
200 | consider removing this semicolon", | ||
201 | ); | ||
202 | } | ||
203 | STRUCT_DEF | ||
204 | } | ||
205 | IDENT if p.at_contextual_kw("union") => { | ||
206 | // test union_items | ||
207 | // union Foo {} | ||
208 | // union Foo { | ||
209 | // a: i32, | ||
210 | // b: f32, | ||
211 | // } | ||
212 | nominal::struct_def(p, UNION_KW); | ||
213 | STRUCT_DEF | ||
214 | } | ||
215 | ENUM_KW => { | ||
216 | nominal::enum_def(p); | ||
217 | ENUM_DEF | ||
218 | } | ||
219 | USE_KW => { | ||
220 | use_item::use_item(p); | ||
221 | USE_ITEM | ||
222 | } | ||
223 | CONST_KW if (la == IDENT || la == MUT_KW) => { | ||
224 | consts::const_def(p); | ||
225 | CONST_DEF | ||
226 | } | ||
227 | STATIC_KW => { | ||
228 | consts::static_def(p); | ||
229 | STATIC_DEF | ||
230 | } | ||
231 | // test extern_block | ||
232 | // extern {} | ||
233 | EXTERN_KW | ||
234 | if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => | ||
235 | { | ||
236 | abi(p); | ||
237 | extern_item_list(p); | ||
238 | EXTERN_BLOCK | ||
239 | } | ||
240 | _ => return None, | ||
241 | }; | ||
242 | Some(kind) | ||
243 | } | ||
244 | |||
245 | fn extern_crate_item(p: &mut Parser) { | ||
246 | assert!(p.at(EXTERN_KW)); | ||
247 | p.bump(); | ||
248 | assert!(p.at(CRATE_KW)); | ||
249 | p.bump(); | ||
250 | name(p); | ||
251 | opt_alias(p); | ||
252 | p.expect(SEMI); | ||
253 | } | ||
254 | |||
255 | pub(crate) fn extern_item_list(p: &mut Parser) { | ||
256 | assert!(p.at(L_CURLY)); | ||
257 | let m = p.start(); | ||
258 | p.bump(); | ||
259 | mod_contents(p, true); | ||
260 | p.expect(R_CURLY); | ||
261 | m.complete(p, EXTERN_ITEM_LIST); | ||
262 | } | ||
263 | |||
264 | fn fn_def(p: &mut Parser, flavor: ItemFlavor) { | ||
265 | assert!(p.at(FN_KW)); | ||
266 | p.bump(); | ||
267 | |||
268 | name_r(p, ITEM_RECOVERY_SET); | ||
269 | // test function_type_params | ||
270 | // fn foo<T: Clone + Copy>(){} | ||
271 | type_params::opt_type_param_list(p); | ||
272 | |||
273 | if p.at(L_PAREN) { | ||
274 | match flavor { | ||
275 | ItemFlavor::Mod => params::param_list(p), | ||
276 | ItemFlavor::Trait => params::param_list_opt_patterns(p), | ||
277 | } | ||
278 | } else { | ||
279 | p.error("expected function arguments"); | ||
280 | } | ||
281 | // test function_ret_type | ||
282 | // fn foo() {} | ||
283 | // fn bar() -> () {} | ||
284 | opt_fn_ret_type(p); | ||
285 | |||
286 | // test function_where_clause | ||
287 | // fn foo<T>() where T: Copy {} | ||
288 | type_params::opt_where_clause(p); | ||
289 | |||
290 | // test fn_decl | ||
291 | // trait T { fn foo(); } | ||
292 | if p.at(SEMI) { | ||
293 | p.bump(); | ||
294 | } else { | ||
295 | expressions::block(p) | ||
296 | } | ||
297 | } | ||
298 | |||
299 | // test type_item | ||
300 | // type Foo = Bar; | ||
301 | fn type_def(p: &mut Parser) { | ||
302 | assert!(p.at(TYPE_KW)); | ||
303 | p.bump(); | ||
304 | |||
305 | name(p); | ||
306 | |||
307 | // test type_item_type_params | ||
308 | // type Result<T> = (); | ||
309 | type_params::opt_type_param_list(p); | ||
310 | |||
311 | if p.at(COLON) { | ||
312 | type_params::bounds(p); | ||
313 | } | ||
314 | |||
315 | // test type_item_where_clause | ||
316 | // type Foo where Foo: Copy = (); | ||
317 | type_params::opt_where_clause(p); | ||
318 | |||
319 | if p.eat(EQ) { | ||
320 | types::type_(p); | ||
321 | } | ||
322 | p.expect(SEMI); | ||
323 | } | ||
324 | |||
325 | pub(crate) fn mod_item(p: &mut Parser) { | ||
326 | assert!(p.at(MOD_KW)); | ||
327 | p.bump(); | ||
328 | |||
329 | name(p); | ||
330 | if p.at(L_CURLY) { | ||
331 | mod_item_list(p); | ||
332 | } else if !p.eat(SEMI) { | ||
333 | p.error("expected `;` or `{`"); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | pub(crate) fn mod_item_list(p: &mut Parser) { | ||
338 | assert!(p.at(L_CURLY)); | ||
339 | let m = p.start(); | ||
340 | p.bump(); | ||
341 | mod_contents(p, true); | ||
342 | p.expect(R_CURLY); | ||
343 | m.complete(p, ITEM_LIST); | ||
344 | } | ||
345 | |||
346 | fn macro_call(p: &mut Parser) -> BlockLike { | ||
347 | assert!(paths::is_path_start(p)); | ||
348 | paths::use_path(p); | ||
349 | macro_call_after_excl(p) | ||
350 | } | ||
351 | |||
352 | pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike { | ||
353 | p.expect(EXCL); | ||
354 | p.eat(IDENT); | ||
355 | match p.current() { | ||
356 | L_CURLY => { | ||
357 | token_tree(p); | ||
358 | BlockLike::Block | ||
359 | } | ||
360 | L_PAREN | L_BRACK => { | ||
361 | token_tree(p); | ||
362 | BlockLike::NotBlock | ||
363 | } | ||
364 | _ => { | ||
365 | p.error("expected `{`, `[`, `(`"); | ||
366 | BlockLike::NotBlock | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
371 | pub(crate) fn token_tree(p: &mut Parser) { | ||
372 | let closing_paren_kind = match p.current() { | ||
373 | L_CURLY => R_CURLY, | ||
374 | L_PAREN => R_PAREN, | ||
375 | L_BRACK => R_BRACK, | ||
376 | _ => unreachable!(), | ||
377 | }; | ||
378 | let m = p.start(); | ||
379 | p.bump(); | ||
380 | while !p.at(EOF) && !p.at(closing_paren_kind) { | ||
381 | match p.current() { | ||
382 | L_CURLY | L_PAREN | L_BRACK => token_tree(p), | ||
383 | R_CURLY => { | ||
384 | p.error("unmatched `}`"); | ||
385 | m.complete(p, TOKEN_TREE); | ||
386 | return; | ||
387 | } | ||
388 | R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"), | ||
389 | _ => p.bump(), | ||
390 | } | ||
391 | } | ||
392 | p.expect(closing_paren_kind); | ||
393 | m.complete(p, TOKEN_TREE); | ||
394 | } | ||