aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/grammar/items.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/grammar/items.rs')
-rw-r--r--crates/ra_syntax/src/grammar/items.rs394
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 @@
1mod consts;
2mod nominal;
3mod traits;
4mod use_item;
5
6pub(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};
12use super::*;
13
14// test mod_contents
15// fn foo() {}
16// macro_rules! foo {}
17// foo::bar!();
18// super::baz! {}
19// struct S;
20pub(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
27pub(super) enum ItemFlavor {
28 Mod,
29 Trait,
30}
31
32pub(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
37pub(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
75pub(super) enum MaybeItem {
76 None,
77 Item(SyntaxKind),
78 Modifiers,
79}
80
81pub(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
169fn 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
245fn 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
255pub(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
264fn 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;
301fn 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
325pub(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
337pub(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
346fn 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
352pub(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
371pub(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}