aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/grammar/items
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-09-16 10:54:24 +0100
committerAleksey Kladov <[email protected]>2018-09-16 11:07:39 +0100
commitb5021411a84822cb3f1e3aeffad9550dd15bdeb6 (patch)
tree9dca564f8e51b298dced01c4ce669c756dce3142 /crates/ra_syntax/src/grammar/items
parentba0bfeee12e19da40b5eabc8d0408639af10e96f (diff)
rename all things
Diffstat (limited to 'crates/ra_syntax/src/grammar/items')
-rw-r--r--crates/ra_syntax/src/grammar/items/consts.rs21
-rw-r--r--crates/ra_syntax/src/grammar/items/mod.rs393
-rw-r--r--crates/ra_syntax/src/grammar/items/nominal.rs154
-rw-r--r--crates/ra_syntax/src/grammar/items/traits.rs117
-rw-r--r--crates/ra_syntax/src/grammar/items/use_item.rs68
5 files changed, 753 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/grammar/items/consts.rs b/crates/ra_syntax/src/grammar/items/consts.rs
new file mode 100644
index 000000000..5a5852f83
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/consts.rs
@@ -0,0 +1,21 @@
1use super::*;
2
3pub(super) fn static_def(p: &mut Parser) {
4 const_or_static(p, STATIC_KW)
5}
6
7pub(super) fn const_def(p: &mut Parser) {
8 const_or_static(p, CONST_KW)
9}
10
11fn const_or_static(p: &mut Parser, kw: SyntaxKind) {
12 assert!(p.at(kw));
13 p.bump();
14 p.eat(MUT_KW); // TODO: validator to forbid const mut
15 name(p);
16 types::ascription(p);
17 if p.eat(EQ) {
18 expressions::expr(p);
19 }
20 p.expect(SEMI);
21}
diff --git a/crates/ra_syntax/src/grammar/items/mod.rs b/crates/ra_syntax/src/grammar/items/mod.rs
new file mode 100644
index 000000000..2567313ab
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/mod.rs
@@ -0,0 +1,393 @@
1
2mod consts;
3mod nominal;
4mod traits;
5mod use_item;
6
7use super::*;
8pub(crate) use self::{
9 expressions::{named_field_list, match_arm_list},
10 nominal::{enum_variant_list, named_field_def_list},
11 traits::{trait_item_list, impl_item_list},
12 use_item::use_tree_list,
13};
14
15// test mod_contents
16// fn foo() {}
17// macro_rules! foo {}
18// foo::bar!();
19// super::baz! {}
20// struct S;
21pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
22 attributes::inner_attributes(p);
23 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
24 item_or_macro(p, stop_on_r_curly, ItemFlavor::Mod)
25 }
26}
27
28pub(super) enum ItemFlavor {
29 Mod, Trait
30}
31
32const ITEM_RECOVERY_SET: TokenSet =
33 token_set![FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW,
34 MOD_KW, PUB_KW, CRATE_KW];
35
36pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
37 let m = p.start();
38 match maybe_item(p, flavor) {
39 MaybeItem::Item(kind) => {
40 m.complete(p, kind);
41 }
42 MaybeItem::None => {
43 if paths::is_path_start(p) {
44 match macro_call(p) {
45 BlockLike::Block => (),
46 BlockLike::NotBlock => {
47 p.expect(SEMI);
48 }
49 }
50 m.complete(p, MACRO_CALL);
51 } else {
52 m.abandon(p);
53 if p.at(L_CURLY) {
54 error_block(p, "expected an item");
55 } else if p.at(R_CURLY) && !stop_on_r_curly {
56 let e = p.start();
57 p.error("unmatched `}`");
58 p.bump();
59 e.complete(p, ERROR);
60 } else if !p.at(EOF) && !p.at(R_CURLY) {
61 p.err_and_bump("expected an item");
62 } else {
63 p.error("expected an item");
64 }
65 }
66 }
67 MaybeItem::Modifiers => {
68 p.error("expected fn, trait or impl");
69 m.complete(p, ERROR);
70 }
71 }
72}
73
74pub(super) enum MaybeItem {
75 None,
76 Item(SyntaxKind),
77 Modifiers,
78}
79
80pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem {
81 attributes::outer_attributes(p);
82 opt_visibility(p);
83 if let Some(kind) = items_without_modifiers(p) {
84 return MaybeItem::Item(kind);
85 }
86
87 let mut has_mods = false;
88 // modifiers
89 has_mods |= p.eat(CONST_KW);
90
91 // test unsafe_block_in_mod
92 // fn foo(){} unsafe { } fn bar(){}
93 if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY {
94 p.eat(UNSAFE_KW);
95 has_mods = true;
96 }
97 if p.at(EXTERN_KW) {
98 has_mods = true;
99 abi(p);
100 }
101 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
102 p.bump_remap(AUTO_KW);
103 has_mods = true;
104 }
105 if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
106 p.bump_remap(DEFAULT_KW);
107 has_mods = true;
108 }
109
110 // items
111 let kind = match p.current() {
112 // test extern_fn
113 // extern fn foo() {}
114
115 // test const_fn
116 // const fn foo() {}
117
118 // test const_unsafe_fn
119 // const unsafe fn foo() {}
120
121 // test unsafe_extern_fn
122 // unsafe extern "C" fn foo() {}
123
124 // test unsafe_fn
125 // unsafe fn foo() {}
126 FN_KW => {
127 fn_def(p, flavor);
128 FN_DEF
129 }
130
131 // test unsafe_trait
132 // unsafe trait T {}
133
134 // test auto_trait
135 // auto trait T {}
136
137 // test unsafe_auto_trait
138 // unsafe auto trait T {}
139 TRAIT_KW => {
140 traits::trait_def(p);
141 TRAIT_DEF
142 }
143
144 // test unsafe_impl
145 // unsafe impl Foo {}
146
147 // test default_impl
148 // default impl Foo {}
149
150 // test unsafe_default_impl
151 // unsafe default impl Foo {}
152 IMPL_KW => {
153 traits::impl_item(p);
154 IMPL_ITEM
155 }
156 _ => return if has_mods {
157 MaybeItem::Modifiers
158 } else {
159 MaybeItem::None
160 }
161 };
162
163 MaybeItem::Item(kind)
164}
165
166fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
167 let la = p.nth(1);
168 let kind = match p.current() {
169 // test extern_crate
170 // extern crate foo;
171 EXTERN_KW if la == CRATE_KW => {
172 extern_crate_item(p);
173 EXTERN_CRATE_ITEM
174 }
175 TYPE_KW => {
176 type_def(p);
177 TYPE_DEF
178 }
179 MOD_KW => {
180 mod_item(p);
181 MODULE
182 }
183 STRUCT_KW => {
184 // test struct_items
185 // struct Foo;
186 // struct Foo {}
187 // struct Foo();
188 // struct Foo(String, usize);
189 // struct Foo {
190 // a: i32,
191 // b: f32,
192 // }
193 nominal::struct_def(p, STRUCT_KW);
194 if p.at(SEMI) {
195 p.err_and_bump(
196 "expected item, found `;`\n\
197 consider removing this semicolon"
198 );
199 }
200 STRUCT_DEF
201 }
202 IDENT if p.at_contextual_kw("union") => {
203 // test union_items
204 // union Foo {}
205 // union Foo {
206 // a: i32,
207 // b: f32,
208 // }
209 nominal::struct_def(p, UNION_KW);
210 STRUCT_DEF
211 }
212 ENUM_KW => {
213 nominal::enum_def(p);
214 ENUM_DEF
215 }
216 USE_KW => {
217 use_item::use_item(p);
218 USE_ITEM
219 }
220 CONST_KW if (la == IDENT || la == MUT_KW) => {
221 consts::const_def(p);
222 CONST_DEF
223 }
224 STATIC_KW => {
225 consts::static_def(p);
226 STATIC_DEF
227 }
228 // test extern_block
229 // extern {}
230 EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => {
231 abi(p);
232 extern_item_list(p);
233 EXTERN_BLOCK
234 }
235 _ => return None,
236 };
237 Some(kind)
238}
239
240fn extern_crate_item(p: &mut Parser) {
241 assert!(p.at(EXTERN_KW));
242 p.bump();
243 assert!(p.at(CRATE_KW));
244 p.bump();
245 name(p);
246 opt_alias(p);
247 p.expect(SEMI);
248}
249
250pub(crate) fn extern_item_list(p: &mut Parser) {
251 assert!(p.at(L_CURLY));
252 let m = p.start();
253 p.bump();
254 mod_contents(p, true);
255 p.expect(R_CURLY);
256 m.complete(p, EXTERN_ITEM_LIST);
257}
258
259fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
260 assert!(p.at(FN_KW));
261 p.bump();
262
263 name_r(p, ITEM_RECOVERY_SET);
264 // test function_type_params
265 // fn foo<T: Clone + Copy>(){}
266 type_params::opt_type_param_list(p);
267
268 if p.at(L_PAREN) {
269 match flavor {
270 ItemFlavor::Mod =>
271 params::param_list(p),
272 ItemFlavor::Trait =>
273 params::param_list_opt_patterns(p),
274 }
275 } else {
276 p.error("expected function arguments");
277 }
278 // test function_ret_type
279 // fn foo() {}
280 // fn bar() -> () {}
281 opt_fn_ret_type(p);
282
283 // test function_where_clause
284 // fn foo<T>() where T: Copy {}
285 type_params::opt_where_clause(p);
286
287 // test fn_decl
288 // trait T { fn foo(); }
289 if p.at(SEMI) {
290 p.bump();
291 } else {
292 expressions::block(p)
293 }
294}
295
296// test type_item
297// type Foo = Bar;
298fn type_def(p: &mut Parser) {
299 assert!(p.at(TYPE_KW));
300 p.bump();
301
302 name(p);
303
304 // test type_item_type_params
305 // type Result<T> = ();
306 type_params::opt_type_param_list(p);
307
308 if p.at(COLON) {
309 type_params::bounds(p);
310 }
311
312 // test type_item_where_clause
313 // type Foo where Foo: Copy = ();
314 type_params::opt_where_clause(p);
315
316 if p.eat(EQ) {
317 types::type_(p);
318 }
319 p.expect(SEMI);
320}
321
322pub(crate) fn mod_item(p: &mut Parser) {
323 assert!(p.at(MOD_KW));
324 p.bump();
325
326 name(p);
327 if p.at(L_CURLY) {
328 mod_item_list(p);
329 } else if !p.eat(SEMI) {
330 p.error("expected `;` or `{`");
331 }
332}
333
334pub(crate) fn mod_item_list(p: &mut Parser) {
335 assert!(p.at(L_CURLY));
336 let m = p.start();
337 p.bump();
338 mod_contents(p, true);
339 p.expect(R_CURLY);
340 m.complete(p, ITEM_LIST);
341}
342
343fn macro_call(p: &mut Parser) -> BlockLike {
344 assert!(paths::is_path_start(p));
345 paths::use_path(p);
346 macro_call_after_excl(p)
347}
348
349pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
350 p.expect(EXCL);
351 p.eat(IDENT);
352 let flavor = match p.current() {
353 L_CURLY => {
354 token_tree(p);
355 BlockLike::Block
356 }
357 L_PAREN | L_BRACK => {
358 token_tree(p);
359 BlockLike::NotBlock
360 }
361 _ => {
362 p.error("expected `{`, `[`, `(`");
363 BlockLike::NotBlock
364 },
365 };
366
367 flavor
368}
369
370pub(crate) fn token_tree(p: &mut Parser) {
371 let closing_paren_kind = match p.current() {
372 L_CURLY => R_CURLY,
373 L_PAREN => R_PAREN,
374 L_BRACK => R_BRACK,
375 _ => unreachable!(),
376 };
377 let m = p.start();
378 p.bump();
379 while !p.at(EOF) && !p.at(closing_paren_kind) {
380 match p.current() {
381 L_CURLY | L_PAREN | L_BRACK => token_tree(p),
382 R_CURLY => {
383 p.error("unmatched `}`");
384 m.complete(p, TOKEN_TREE);
385 return;
386 }
387 R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"),
388 _ => p.bump()
389 }
390 };
391 p.expect(closing_paren_kind);
392 m.complete(p, TOKEN_TREE);
393}
diff --git a/crates/ra_syntax/src/grammar/items/nominal.rs b/crates/ra_syntax/src/grammar/items/nominal.rs
new file mode 100644
index 000000000..8d02ad555
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/nominal.rs
@@ -0,0 +1,154 @@
1use super::*;
2
3pub(super) fn struct_def(p: &mut Parser, kind: SyntaxKind) {
4 assert!(p.at(STRUCT_KW) || p.at_contextual_kw("union"));
5 p.bump_remap(kind);
6
7 name_r(p, ITEM_RECOVERY_SET);
8 type_params::opt_type_param_list(p);
9 match p.current() {
10 WHERE_KW => {
11 type_params::opt_where_clause(p);
12 match p.current() {
13 SEMI => {
14 p.bump();
15 return;
16 }
17 L_CURLY => named_field_def_list(p),
18 _ => {
19 //TODO: special case `(` error message
20 p.error("expected `;` or `{`");
21 return;
22 }
23 }
24 }
25 SEMI if kind == STRUCT_KW => {
26 p.bump();
27 return;
28 }
29 L_CURLY => named_field_def_list(p),
30 L_PAREN if kind == STRUCT_KW => {
31 pos_field_list(p);
32 p.expect(SEMI);
33 }
34 _ if kind == STRUCT_KW => {
35 p.error("expected `;`, `{`, or `(`");
36 return;
37 }
38 _ => {
39 p.error("expected `{`");
40 return;
41 }
42 }
43}
44
45pub(super) fn enum_def(p: &mut Parser) {
46 assert!(p.at(ENUM_KW));
47 p.bump();
48 name_r(p, ITEM_RECOVERY_SET);
49 type_params::opt_type_param_list(p);
50 type_params::opt_where_clause(p);
51 if p.at(L_CURLY) {
52 enum_variant_list(p);
53 } else {
54 p.error("expected `{`")
55 }
56}
57
58pub(crate) fn enum_variant_list(p: &mut Parser) {
59 assert!(p.at(L_CURLY));
60 let m = p.start();
61 p.bump();
62 while !p.at(EOF) && !p.at(R_CURLY) {
63 if p.at(L_CURLY) {
64 error_block(p, "expected enum variant");
65 continue;
66 }
67 let var = p.start();
68 attributes::outer_attributes(p);
69 if p.at(IDENT) {
70 name(p);
71 match p.current() {
72 L_CURLY => named_field_def_list(p),
73 L_PAREN => pos_field_list(p),
74 EQ => {
75 p.bump();
76 expressions::expr(p);
77 }
78 _ => (),
79 }
80 var.complete(p, ENUM_VARIANT);
81 } else {
82 var.abandon(p);
83 p.err_and_bump("expected enum variant");
84 }
85 if !p.at(R_CURLY) {
86 p.expect(COMMA);
87 }
88 }
89 p.expect(R_CURLY);
90 m.complete(p, ENUM_VARIANT_LIST);
91}
92
93pub(crate) fn named_field_def_list(p: &mut Parser) {
94 assert!(p.at(L_CURLY));
95 let m = p.start();
96 p.bump();
97 while !p.at(R_CURLY) && !p.at(EOF) {
98 if p.at(L_CURLY) {
99 error_block(p, "expected field");
100 continue;
101 }
102 named_field_def(p);
103 if !p.at(R_CURLY) {
104 p.expect(COMMA);
105 }
106 }
107 p.expect(R_CURLY);
108 m.complete(p, NAMED_FIELD_DEF_LIST);
109
110 fn named_field_def(p: &mut Parser) {
111 let m = p.start();
112 // test field_attrs
113 // struct S {
114 // #[serde(with = "url_serde")]
115 // pub uri: Uri,
116 // }
117 attributes::outer_attributes(p);
118 opt_visibility(p);
119 if p.at(IDENT) {
120 name(p);
121 p.expect(COLON);
122 types::type_(p);
123 m.complete(p, NAMED_FIELD_DEF);
124 } else {
125 m.abandon(p);
126 p.err_and_bump("expected field declaration");
127 }
128 }
129}
130
131fn pos_field_list(p: &mut Parser) {
132 assert!(p.at(L_PAREN));
133 let m = p.start();
134 if !p.expect(L_PAREN) {
135 return;
136 }
137 while !p.at(R_PAREN) && !p.at(EOF) {
138 let m = p.start();
139 opt_visibility(p);
140 if !p.at_ts(types::TYPE_FIRST) {
141 p.error("expected a type");
142 m.complete(p, ERROR);
143 break;
144 }
145 types::type_(p);
146 m.complete(p, POS_FIELD);
147
148 if !p.at(R_PAREN) {
149 p.expect(COMMA);
150 }
151 }
152 p.expect(R_PAREN);
153 m.complete(p, POS_FIELD_LIST);
154}
diff --git a/crates/ra_syntax/src/grammar/items/traits.rs b/crates/ra_syntax/src/grammar/items/traits.rs
new file mode 100644
index 000000000..c21cfb1a9
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/traits.rs
@@ -0,0 +1,117 @@
1use super::*;
2
3// test trait_item
4// trait T<U>: Hash + Clone where U: Copy {}
5pub(super) fn trait_def(p: &mut Parser) {
6 assert!(p.at(TRAIT_KW));
7 p.bump();
8 name_r(p, ITEM_RECOVERY_SET);
9 type_params::opt_type_param_list(p);
10 if p.at(COLON) {
11 type_params::bounds(p);
12 }
13 type_params::opt_where_clause(p);
14 if p.at(L_CURLY) {
15 trait_item_list(p);
16 } else {
17 p.error("expected `{`");
18 }
19}
20
21// test trait_item_list
22// impl F {
23// type A: Clone;
24// const B: i32;
25// fn foo() {}
26// fn bar(&self);
27// }
28pub(crate) fn trait_item_list(p: &mut Parser) {
29 assert!(p.at(L_CURLY));
30 let m = p.start();
31 p.bump();
32 while !p.at(EOF) && !p.at(R_CURLY) {
33 if p.at(L_CURLY) {
34 error_block(p, "expected an item");
35 continue;
36 }
37 item_or_macro(p, true, ItemFlavor::Trait);
38 }
39 p.expect(R_CURLY);
40 m.complete(p, ITEM_LIST);
41}
42
43// test impl_item
44// impl Foo {}
45pub(super) fn impl_item(p: &mut Parser) {
46 assert!(p.at(IMPL_KW));
47 p.bump();
48 if choose_type_params_over_qpath(p) {
49 type_params::opt_type_param_list(p);
50 }
51
52 // TODO: never type
53 // impl ! {}
54
55 // test impl_item_neg
56 // impl !Send for X {}
57 p.eat(EXCL);
58 types::type_(p);
59 if p.eat(FOR_KW) {
60 types::type_(p);
61 }
62 type_params::opt_where_clause(p);
63 if p.at(L_CURLY) {
64 impl_item_list(p);
65 } else {
66 p.error("expected `{`");
67 }
68}
69
70// test impl_item_list
71// impl F {
72// type A = i32;
73// const B: i32 = 92;
74// fn foo() {}
75// fn bar(&self) {}
76// }
77pub(crate) fn impl_item_list(p: &mut Parser) {
78 assert!(p.at(L_CURLY));
79 let m = p.start();
80 p.bump();
81
82 while !p.at(EOF) && !p.at(R_CURLY) {
83 if p.at(L_CURLY) {
84 error_block(p, "expected an item");
85 continue;
86 }
87 item_or_macro(p, true, ItemFlavor::Mod);
88 }
89 p.expect(R_CURLY);
90 m.complete(p, ITEM_LIST);
91}
92
93fn choose_type_params_over_qpath(p: &Parser) -> bool {
94 // There's an ambiguity between generic parameters and qualified paths in impls.
95 // If we see `<` it may start both, so we have to inspect some following tokens.
96 // The following combinations can only start generics,
97 // but not qualified paths (with one exception):
98 // `<` `>` - empty generic parameters
99 // `<` `#` - generic parameters with attributes
100 // `<` (LIFETIME|IDENT) `>` - single generic parameter
101 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
102 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
103 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
104 // The only truly ambiguous case is
105 // `<` IDENT `>` `::` IDENT ...
106 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
107 // because this is what almost always expected in practice, qualified paths in impls
108 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
109 if !p.at(L_ANGLE) {
110 return false;
111 }
112 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
113 return true;
114 }
115 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
116 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
117}
diff --git a/crates/ra_syntax/src/grammar/items/use_item.rs b/crates/ra_syntax/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..1ee4349fd
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/use_item.rs
@@ -0,0 +1,68 @@
1use super::*;
2
3pub(super) fn use_item(p: &mut Parser) {
4 assert!(p.at(USE_KW));
5 p.bump();
6 use_tree(p);
7 p.expect(SEMI);
8}
9
10fn use_tree(p: &mut Parser) {
11 let la = p.nth(1);
12 let m = p.start();
13 match (p.current(), la) {
14 (STAR, _) => p.bump(),
15 (COLONCOLON, STAR) => {
16 p.bump();
17 p.bump();
18 }
19 (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
20 if p.at(COLONCOLON) {
21 p.bump();
22 }
23 use_tree_list(p);
24 }
25 _ if paths::is_path_start(p) => {
26 paths::use_path(p);
27 match p.current() {
28 AS_KW => {
29 opt_alias(p);
30 }
31 COLONCOLON => {
32 p.bump();
33 match p.current() {
34 STAR => {
35 p.bump();
36 }
37 L_CURLY => use_tree_list(p),
38 _ => {
39 // is this unreachable?
40 p.error("expected `{` or `*`");
41 }
42 }
43 }
44 _ => (),
45 }
46 }
47 _ => {
48 m.abandon(p);
49 p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
50 return;
51 }
52 }
53 m.complete(p, USE_TREE);
54}
55
56pub(crate) fn use_tree_list(p: &mut Parser) {
57 assert!(p.at(L_CURLY));
58 let m = p.start();
59 p.bump();
60 while !p.at(EOF) && !p.at(R_CURLY) {
61 use_tree(p);
62 if !p.at(R_CURLY) {
63 p.expect(COMMA);
64 }
65 }
66 p.expect(R_CURLY);
67 m.complete(p, USE_TREE_LIST);
68}