aboutsummaryrefslogtreecommitdiff
path: root/crates/libsyntax2/src/grammar/items
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-10 20:33:29 +0100
committerAleksey Kladov <[email protected]>2018-08-10 20:33:29 +0100
commit7c67612b8a894187fa3b64725531a5459f9211bf (patch)
tree9e2a536efa0c880d921fd8d4d74423afc9451fd4 /crates/libsyntax2/src/grammar/items
parent26262aaf05983c5b7f41cc438e287523268fe1eb (diff)
organizize
Diffstat (limited to 'crates/libsyntax2/src/grammar/items')
-rw-r--r--crates/libsyntax2/src/grammar/items/consts.rs21
-rw-r--r--crates/libsyntax2/src/grammar/items/mod.rs332
-rw-r--r--crates/libsyntax2/src/grammar/items/structs.rs116
-rw-r--r--crates/libsyntax2/src/grammar/items/traits.rs87
-rw-r--r--crates/libsyntax2/src/grammar/items/use_item.rs66
5 files changed, 622 insertions, 0 deletions
diff --git a/crates/libsyntax2/src/grammar/items/consts.rs b/crates/libsyntax2/src/grammar/items/consts.rs
new file mode 100644
index 000000000..b11949b49
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/consts.rs
@@ -0,0 +1,21 @@
1use super::*;
2
3pub(super) fn static_item(p: &mut Parser) {
4 const_or_static(p, STATIC_KW)
5}
6
7pub(super) fn const_item(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/libsyntax2/src/grammar/items/mod.rs b/crates/libsyntax2/src/grammar/items/mod.rs
new file mode 100644
index 000000000..3bf906f85
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/mod.rs
@@ -0,0 +1,332 @@
1use super::*;
2
3mod consts;
4mod structs;
5mod traits;
6mod use_item;
7
8// test mod_contents
9// fn foo() {}
10// macro_rules! foo {}
11// foo::bar!();
12// super::baz! {}
13// struct S;
14pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
15 attributes::inner_attributes(p);
16 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
17 item_or_macro(p, stop_on_r_curly)
18 }
19}
20
21pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) {
22 let m = p.start();
23 match maybe_item(p) {
24 MaybeItem::Item(kind) => {
25 m.complete(p, kind);
26 }
27 MaybeItem::None => {
28 if paths::is_path_start(p) {
29 match macro_call(p) {
30 BlockLike::Block => (),
31 BlockLike::NotBlock => {
32 p.expect(SEMI);
33 }
34 }
35 m.complete(p, MACRO_CALL);
36 } else {
37 m.abandon(p);
38 if p.at(L_CURLY) {
39 error_block(p, "expected an item");
40 } else if !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
41 p.err_and_bump("expected an item");
42 } else {
43 p.error("expected an item");
44 }
45 }
46 }
47 MaybeItem::Modifiers => {
48 p.error("expected fn, trait or impl");
49 m.complete(p, ERROR);
50 }
51 }
52}
53
54pub(super) const ITEM_FIRST: TokenSet =
55 token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
56
57pub(super) enum MaybeItem {
58 None,
59 Item(SyntaxKind),
60 Modifiers,
61}
62
63pub(super) fn maybe_item(p: &mut Parser) -> MaybeItem {
64 attributes::outer_attributes(p);
65 visibility(p);
66 if let Some(kind) = items_without_modifiers(p) {
67 return MaybeItem::Item(kind);
68 }
69
70 let mut has_mods = false;
71 // modifiers
72 has_mods |= p.eat(CONST_KW);
73
74 // test unsafe_block_in_mod
75 // fn foo(){} unsafe { } fn bar(){}
76 if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY {
77 p.eat(UNSAFE_KW);
78 has_mods = true;
79 }
80 if p.at(EXTERN_KW) {
81 has_mods = true;
82 abi(p);
83 }
84 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
85 p.bump_remap(AUTO_KW);
86 has_mods = true;
87 }
88 if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
89 p.bump_remap(DEFAULT_KW);
90 has_mods = true;
91 }
92
93 // items
94 let kind = match p.current() {
95 // test extern_fn
96 // extern fn foo() {}
97
98 // test const_fn
99 // const fn foo() {}
100
101 // test const_unsafe_fn
102 // const unsafe fn foo() {}
103
104 // test unsafe_extern_fn
105 // unsafe extern "C" fn foo() {}
106
107 // test unsafe_fn
108 // unsafe fn foo() {}
109 FN_KW => {
110 function(p);
111 FUNCTION
112 }
113
114 // test unsafe_trait
115 // unsafe trait T {}
116
117 // test auto_trait
118 // auto trait T {}
119
120 // test unsafe_auto_trait
121 // unsafe auto trait T {}
122 TRAIT_KW => {
123 traits::trait_item(p);
124 TRAIT_ITEM
125 }
126
127 // test unsafe_impl
128 // unsafe impl Foo {}
129
130 // test default_impl
131 // default impl Foo {}
132
133 // test unsafe_default_impl
134 // unsafe default impl Foo {}
135 IMPL_KW => {
136 traits::impl_item(p);
137 IMPL_ITEM
138 }
139 _ => return if has_mods {
140 MaybeItem::Modifiers
141 } else {
142 MaybeItem::None
143 }
144 };
145
146 MaybeItem::Item(kind)
147}
148
149fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
150 let la = p.nth(1);
151 let kind = match p.current() {
152 // test extern_crate
153 // extern crate foo;
154 EXTERN_KW if la == CRATE_KW => {
155 extern_crate_item(p);
156 EXTERN_CRATE_ITEM
157 }
158 TYPE_KW => {
159 type_item(p);
160 TYPE_ITEM
161 }
162 MOD_KW => {
163 mod_item(p);
164 MOD_ITEM
165 }
166 STRUCT_KW => {
167 structs::struct_item(p);
168 if p.at(SEMI) {
169 p.err_and_bump(
170 "expected item, found `;`\n\
171 consider removing this semicolon"
172 );
173 }
174 STRUCT_ITEM
175 }
176 ENUM_KW => {
177 structs::enum_item(p);
178 ENUM_ITEM
179 }
180 USE_KW => {
181 use_item::use_item(p);
182 USE_ITEM
183 }
184 CONST_KW if (la == IDENT || la == MUT_KW) => {
185 consts::const_item(p);
186 CONST_ITEM
187 }
188 STATIC_KW => {
189 consts::static_item(p);
190 STATIC_ITEM
191 }
192 // test extern_block
193 // extern {}
194 EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => {
195 abi(p);
196 extern_block(p);
197 EXTERN_BLOCK_EXPR
198 }
199 _ => return None,
200 };
201 Some(kind)
202}
203
204fn extern_crate_item(p: &mut Parser) {
205 assert!(p.at(EXTERN_KW));
206 p.bump();
207 assert!(p.at(CRATE_KW));
208 p.bump();
209 name(p);
210 alias(p);
211 p.expect(SEMI);
212}
213
214fn extern_block(p: &mut Parser) {
215 assert!(p.at(L_CURLY));
216 p.bump();
217 p.expect(R_CURLY);
218}
219
220fn function(p: &mut Parser) {
221 assert!(p.at(FN_KW));
222 p.bump();
223
224 name(p);
225 // test function_type_params
226 // fn foo<T: Clone + Copy>(){}
227 type_params::type_param_list(p);
228
229 if p.at(L_PAREN) {
230 params::param_list(p);
231 } else {
232 p.error("expected function arguments");
233 }
234 // test function_ret_type
235 // fn foo() {}
236 // fn bar() -> () {}
237 fn_ret_type(p);
238
239 // test function_where_clause
240 // fn foo<T>() where T: Copy {}
241 type_params::where_clause(p);
242
243 // test fn_decl
244 // trait T { fn foo(); }
245 if !p.eat(SEMI) {
246 expressions::block(p);
247 }
248}
249
250// test type_item
251// type Foo = Bar;
252fn type_item(p: &mut Parser) {
253 assert!(p.at(TYPE_KW));
254 p.bump();
255
256 name(p);
257
258 // test type_item_type_params
259 // type Result<T> = ();
260 type_params::type_param_list(p);
261
262 if p.at(COLON) {
263 type_params::bounds(p);
264 }
265
266 // test type_item_where_clause
267 // type Foo where Foo: Copy = ();
268 type_params::where_clause(p);
269
270 if p.eat(EQ) {
271 types::type_(p);
272 }
273 p.expect(SEMI);
274}
275
276fn mod_item(p: &mut Parser) {
277 assert!(p.at(MOD_KW));
278 p.bump();
279
280 name(p);
281 if !p.eat(SEMI) {
282 if p.expect(L_CURLY) {
283 mod_contents(p, true);
284 p.expect(R_CURLY);
285 }
286 }
287}
288
289fn macro_call(p: &mut Parser) -> BlockLike {
290 assert!(paths::is_path_start(p));
291 paths::use_path(p);
292 macro_call_after_excl(p)
293}
294
295pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
296 p.expect(EXCL);
297 p.eat(IDENT);
298 let flavor = match p.current() {
299 L_CURLY => {
300 token_tree(p);
301 BlockLike::Block
302 }
303 L_PAREN | L_BRACK => {
304 token_tree(p);
305 BlockLike::NotBlock
306 }
307 _ => {
308 p.error("expected `{`, `[`, `(`");
309 BlockLike::NotBlock
310 },
311 };
312
313 flavor
314}
315
316fn token_tree(p: &mut Parser) {
317 let closing_paren_kind = match p.current() {
318 L_CURLY => R_CURLY,
319 L_PAREN => R_PAREN,
320 L_BRACK => R_BRACK,
321 _ => unreachable!(),
322 };
323 p.bump();
324 while !p.at(EOF) && !p.at(closing_paren_kind) {
325 match p.current() {
326 L_CURLY | L_PAREN | L_BRACK => token_tree(p),
327 R_CURLY | R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"),
328 _ => p.bump()
329 }
330 };
331 p.expect(closing_paren_kind);
332}
diff --git a/crates/libsyntax2/src/grammar/items/structs.rs b/crates/libsyntax2/src/grammar/items/structs.rs
new file mode 100644
index 000000000..67616eaad
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/structs.rs
@@ -0,0 +1,116 @@
1use super::*;
2
3pub(super) fn struct_item(p: &mut Parser) {
4 assert!(p.at(STRUCT_KW));
5 p.bump();
6
7 name(p);
8 type_params::type_param_list(p);
9 match p.current() {
10 WHERE_KW => {
11 type_params::where_clause(p);
12 match p.current() {
13 SEMI => {
14 p.bump();
15 return;
16 }
17 L_CURLY => named_fields(p),
18 _ => {
19 //TODO: special case `(` error message
20 p.error("expected `;` or `{`");
21 return;
22 }
23 }
24 }
25 SEMI => {
26 p.bump();
27 return;
28 }
29 L_CURLY => named_fields(p),
30 L_PAREN => {
31 pos_fields(p);
32 p.expect(SEMI);
33 }
34 _ => {
35 p.error("expected `;`, `{`, or `(`");
36 return;
37 }
38 }
39}
40
41pub(super) fn enum_item(p: &mut Parser) {
42 assert!(p.at(ENUM_KW));
43 p.bump();
44 name(p);
45 type_params::type_param_list(p);
46 type_params::where_clause(p);
47 if p.expect(L_CURLY) {
48 while !p.at(EOF) && !p.at(R_CURLY) {
49 let var = p.start();
50 attributes::outer_attributes(p);
51 if p.at(IDENT) {
52 name(p);
53 match p.current() {
54 L_CURLY => named_fields(p),
55 L_PAREN => pos_fields(p),
56 EQ => {
57 p.bump();
58 expressions::expr(p);
59 }
60 _ => (),
61 }
62 var.complete(p, ENUM_VARIANT);
63 } else {
64 var.abandon(p);
65 p.err_and_bump("expected enum variant");
66 }
67 if !p.at(R_CURLY) {
68 p.expect(COMMA);
69 }
70 }
71 p.expect(R_CURLY);
72 }
73}
74
75fn named_fields(p: &mut Parser) {
76 assert!(p.at(L_CURLY));
77 p.bump();
78 while !p.at(R_CURLY) && !p.at(EOF) {
79 named_field(p);
80 if !p.at(R_CURLY) {
81 p.expect(COMMA);
82 }
83 }
84 p.expect(R_CURLY);
85
86 fn named_field(p: &mut Parser) {
87 let field = p.start();
88 visibility(p);
89 if p.at(IDENT) {
90 name(p);
91 p.expect(COLON);
92 types::type_(p);
93 field.complete(p, NAMED_FIELD);
94 } else {
95 field.abandon(p);
96 p.err_and_bump("expected field declaration");
97 }
98 }
99}
100
101fn pos_fields(p: &mut Parser) {
102 if !p.expect(L_PAREN) {
103 return;
104 }
105 while !p.at(R_PAREN) && !p.at(EOF) {
106 let pos_field = p.start();
107 visibility(p);
108 types::type_(p);
109 pos_field.complete(p, POS_FIELD);
110
111 if !p.at(R_PAREN) {
112 p.expect(COMMA);
113 }
114 }
115 p.expect(R_PAREN);
116}
diff --git a/crates/libsyntax2/src/grammar/items/traits.rs b/crates/libsyntax2/src/grammar/items/traits.rs
new file mode 100644
index 000000000..0b9fb2b0b
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/traits.rs
@@ -0,0 +1,87 @@
1use super::*;
2
3// test trait_item
4// trait T<U>: Hash + Clone where U: Copy {}
5pub(super) fn trait_item(p: &mut Parser) {
6 assert!(p.at(TRAIT_KW));
7 p.bump();
8 name(p);
9 type_params::type_param_list(p);
10 if p.at(COLON) {
11 type_params::bounds(p);
12 }
13 type_params::where_clause(p);
14 p.expect(L_CURLY);
15 // test trait_item_items
16 // impl F {
17 // type A: Clone;
18 // const B: i32;
19 // fn foo() {}
20 // fn bar(&self);
21 // }
22 while !p.at(EOF) && !p.at(R_CURLY) {
23 item_or_macro(p, true);
24 }
25 p.expect(R_CURLY);
26}
27
28// test impl_item
29// impl Foo {}
30pub(super) fn impl_item(p: &mut Parser) {
31 assert!(p.at(IMPL_KW));
32 p.bump();
33 if choose_type_params_over_qpath(p) {
34 type_params::type_param_list(p);
35 }
36
37 // TODO: never type
38 // impl ! {}
39
40 // test impl_item_neg
41 // impl !Send for X {}
42 p.eat(EXCL);
43 types::type_(p);
44 if p.eat(FOR_KW) {
45 types::type_(p);
46 }
47 type_params::where_clause(p);
48 p.expect(L_CURLY);
49
50 // test impl_item_items
51 // impl F {
52 // type A = i32;
53 // const B: i32 = 92;
54 // fn foo() {}
55 // fn bar(&self) {}
56 // }
57 while !p.at(EOF) && !p.at(R_CURLY) {
58 item_or_macro(p, true);
59 }
60 p.expect(R_CURLY);
61}
62
63fn choose_type_params_over_qpath(p: &Parser) -> bool {
64 // There's an ambiguity between generic parameters and qualified paths in impls.
65 // If we see `<` it may start both, so we have to inspect some following tokens.
66 // The following combinations can only start generics,
67 // but not qualified paths (with one exception):
68 // `<` `>` - empty generic parameters
69 // `<` `#` - generic parameters with attributes
70 // `<` (LIFETIME|IDENT) `>` - single generic parameter
71 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
72 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
73 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
74 // The only truly ambiguous case is
75 // `<` IDENT `>` `::` IDENT ...
76 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
77 // because this is what almost always expected in practice, qualified paths in impls
78 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
79 if !p.at(L_ANGLE) {
80 return false;
81 }
82 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
83 return true;
84 }
85 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
86 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
87}
diff --git a/crates/libsyntax2/src/grammar/items/use_item.rs b/crates/libsyntax2/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..a3f7f0da8
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/use_item.rs
@@ -0,0 +1,66 @@
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 nested_trees(p);
24 }
25 _ if paths::is_path_start(p) => {
26 paths::use_path(p);
27 match p.current() {
28 AS_KW => {
29 alias(p);
30 }
31 COLONCOLON => {
32 p.bump();
33 match p.current() {
34 STAR => {
35 p.bump();
36 }
37 L_CURLY => nested_trees(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
56fn nested_trees(p: &mut Parser) {
57 assert!(p.at(L_CURLY));
58 p.bump();
59 while !p.at(EOF) && !p.at(R_CURLY) {
60 use_tree(p);
61 if !p.at(R_CURLY) {
62 p.expect(COMMA);
63 }
64 }
65 p.expect(R_CURLY);
66}