aboutsummaryrefslogtreecommitdiff
path: root/src/grammar/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/grammar/items')
-rw-r--r--src/grammar/items/consts.rs20
-rw-r--r--src/grammar/items/mod.rs290
-rw-r--r--src/grammar/items/structs.rs116
-rw-r--r--src/grammar/items/traits.rs77
-rw-r--r--src/grammar/items/use_item.rs66
5 files changed, 569 insertions, 0 deletions
diff --git a/src/grammar/items/consts.rs b/src/grammar/items/consts.rs
new file mode 100644
index 000000000..ca26a7814
--- /dev/null
+++ b/src/grammar/items/consts.rs
@@ -0,0 +1,20 @@
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 p.expect(EQ);
18 expressions::expr(p);
19 p.expect(SEMI);
20}
diff --git a/src/grammar/items/mod.rs b/src/grammar/items/mod.rs
new file mode 100644
index 000000000..d5f75f13d
--- /dev/null
+++ b/src/grammar/items/mod.rs
@@ -0,0 +1,290 @@
1use super::*;
2
3mod consts;
4mod structs;
5mod traits;
6mod use_item;
7
8pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
9 attributes::inner_attributes(p);
10 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
11 item(p);
12 }
13}
14
15pub(super) const ITEM_FIRST: TokenSet =
16 token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
17
18pub(super) fn item(p: &mut Parser) {
19 let item = p.start();
20 attributes::outer_attributes(p);
21 visibility(p);
22 let la = p.nth(1);
23 let item_kind = match p.current() {
24 USE_KW => {
25 use_item::use_item(p);
26 USE_ITEM
27 }
28 // test extern_crate
29 // extern crate foo;
30 EXTERN_KW if la == CRATE_KW => {
31 extern_crate_item(p);
32 EXTERN_CRATE_ITEM
33 }
34 EXTERN_KW => {
35 abi(p);
36 match p.current() {
37 // test extern_fn
38 // extern fn foo() {}
39 FN_KW => {
40 fn_item(p);
41 FN_ITEM
42 }
43 // test extern_block
44 // extern {}
45 L_CURLY => {
46 extern_block(p);
47 EXTERN_BLOCK
48 }
49 // test extern_struct
50 // extern struct Foo;
51 _ => {
52 item.abandon(p);
53 p.error("expected `fn` or `{`");
54 return;
55 }
56 }
57 }
58 STATIC_KW => {
59 consts::static_item(p);
60 STATIC_ITEM
61 }
62 CONST_KW => match p.nth(1) {
63 // test const_fn
64 // const fn foo() {}
65 FN_KW => {
66 p.bump();
67 fn_item(p);
68 FN_ITEM
69 }
70 // test const_unsafe_fn
71 // const unsafe fn foo() {}
72 UNSAFE_KW if p.nth(2) == FN_KW => {
73 p.bump();
74 p.bump();
75 fn_item(p);
76 FN_ITEM
77 }
78 _ => {
79 consts::const_item(p);
80 CONST_ITEM
81 }
82 },
83 UNSAFE_KW => {
84 p.bump();
85 let la = p.nth(1);
86 match p.current() {
87 // test unsafe_trait
88 // unsafe trait T {}
89 TRAIT_KW => {
90 traits::trait_item(p);
91 TRAIT_ITEM
92 }
93
94 // test unsafe_auto_trait
95 // unsafe auto trait T {}
96 IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => {
97 p.bump_remap(AUTO_KW);
98 traits::trait_item(p);
99 TRAIT_ITEM
100 }
101
102 // test unsafe_impl
103 // unsafe impl Foo {}
104 IMPL_KW => {
105 traits::impl_item(p);
106 IMPL_ITEM
107 }
108
109 // test unsafe_default_impl
110 // unsafe default impl Foo {}
111 IDENT if p.at_contextual_kw("default") && la == IMPL_KW => {
112 p.bump_remap(DEFAULT_KW);
113 traits::impl_item(p);
114 IMPL_ITEM
115 }
116
117 // test unsafe_extern_fn
118 // unsafe extern "C" fn foo() {}
119 EXTERN_KW => {
120 abi(p);
121 if !p.at(FN_KW) {
122 item.abandon(p);
123 p.error("expected function");
124 return;
125 }
126 fn_item(p);
127 FN_ITEM
128 }
129
130 // test unsafe_fn
131 // unsafe fn foo() {}
132 FN_KW => {
133 fn_item(p);
134 FN_ITEM
135 }
136
137 t => {
138 item.abandon(p);
139 let message = "expected `trait`, `impl` or `fn`";
140
141 // test unsafe_block_in_mod
142 // fn foo(){} unsafe { } fn bar(){}
143 if t == L_CURLY {
144 error_block(p, message);
145 } else {
146 p.error(message);
147 }
148 return;
149 }
150 }
151 }
152 TRAIT_KW => {
153 traits::trait_item(p);
154 TRAIT_ITEM
155 }
156 // test auto_trait
157 // auto trait T {}
158 IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => {
159 p.bump_remap(AUTO_KW);
160 traits::trait_item(p);
161 TRAIT_ITEM
162 }
163 IMPL_KW => {
164 traits::impl_item(p);
165 IMPL_ITEM
166 }
167 // test default_impl
168 // default impl Foo {}
169 IDENT if p.at_contextual_kw("default") && la == IMPL_KW => {
170 p.bump_remap(DEFAULT_KW);
171 traits::impl_item(p);
172 IMPL_ITEM
173 }
174
175 FN_KW => {
176 fn_item(p);
177 FN_ITEM
178 }
179 TYPE_KW => {
180 type_item(p);
181 TYPE_ITEM
182 }
183 MOD_KW => {
184 mod_item(p);
185 MOD_ITEM
186 }
187 STRUCT_KW => {
188 structs::struct_item(p);
189 STRUCT_ITEM
190 }
191 ENUM_KW => {
192 structs::enum_item(p);
193 ENUM_ITEM
194 }
195 L_CURLY => {
196 item.abandon(p);
197 error_block(p, "expected item");
198 return;
199 }
200 err_token => {
201 item.abandon(p);
202 let message = if err_token == SEMI {
203 //TODO: if the item is incomplete, this message is misleading
204 "expected item, found `;`\n\
205 consider removing this semicolon"
206 } else {
207 "expected item"
208 };
209 p.err_and_bump(message);
210 return;
211 }
212 };
213 item.complete(p, item_kind);
214}
215
216fn extern_crate_item(p: &mut Parser) {
217 assert!(p.at(EXTERN_KW));
218 p.bump();
219 assert!(p.at(CRATE_KW));
220 p.bump();
221 name(p);
222 alias(p);
223 p.expect(SEMI);
224}
225
226fn extern_block(p: &mut Parser) {
227 assert!(p.at(L_CURLY));
228 p.bump();
229 p.expect(R_CURLY);
230}
231
232fn fn_item(p: &mut Parser) {
233 assert!(p.at(FN_KW));
234 p.bump();
235
236 name(p);
237 // test fn_item_type_params
238 // fn foo<T: Clone + Copy>(){}
239 type_params::type_param_list(p);
240
241 if p.at(L_PAREN) {
242 params::param_list(p);
243 } else {
244 p.error("expected function arguments");
245 }
246 // test fn_item_ret_type
247 // fn foo() {}
248 // fn bar() -> () {}
249 fn_ret_type(p);
250
251 // test fn_item_where_clause
252 // fn foo<T>() where T: Copy {}
253 type_params::where_clause(p);
254
255 expressions::block(p);
256}
257
258// test type_item
259// type Foo = Bar;
260fn type_item(p: &mut Parser) {
261 assert!(p.at(TYPE_KW));
262 p.bump();
263
264 name(p);
265
266 // test type_item_type_params
267 // type Result<T> = ();
268 type_params::type_param_list(p);
269
270 // test type_item_where_clause
271 // type Foo where Foo: Copy = ();
272 type_params::where_clause(p);
273
274 p.expect(EQ);
275 types::type_(p);
276 p.expect(SEMI);
277}
278
279fn mod_item(p: &mut Parser) {
280 assert!(p.at(MOD_KW));
281 p.bump();
282
283 name(p);
284 if !p.eat(SEMI) {
285 if p.expect(L_CURLY) {
286 mod_contents(p, true);
287 p.expect(R_CURLY);
288 }
289 }
290}
diff --git a/src/grammar/items/structs.rs b/src/grammar/items/structs.rs
new file mode 100644
index 000000000..7ced542a4
--- /dev/null
+++ b/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 p.bump();
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/src/grammar/items/traits.rs b/src/grammar/items/traits.rs
new file mode 100644
index 000000000..bda13e565
--- /dev/null
+++ b/src/grammar/items/traits.rs
@@ -0,0 +1,77 @@
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 p.expect(R_CURLY);
16}
17
18// test impl_item
19// impl Foo {}
20pub(super) fn impl_item(p: &mut Parser) {
21 assert!(p.at(IMPL_KW));
22 p.bump();
23 if choose_type_params_over_qpath(p) {
24 type_params::type_param_list(p);
25 }
26
27 // TODO: never type
28 // impl ! {}
29
30 // test impl_item_neg
31 // impl !Send for X {}
32 p.eat(EXCL);
33 types::type_(p);
34 if p.eat(FOR_KW) {
35 types::type_(p);
36 }
37 type_params::where_clause(p);
38 p.expect(L_CURLY);
39
40 // test impl_item_items
41 // impl F {
42 // type A = i32;
43 // const B: i32 = 92;
44 // fn foo() {}
45 // fn bar(&self) {}
46 // }
47 while !p.at(EOF) && !p.at(R_CURLY) {
48 item(p);
49 }
50 p.expect(R_CURLY);
51}
52
53fn choose_type_params_over_qpath(p: &Parser) -> bool {
54 // There's an ambiguity between generic parameters and qualified paths in impls.
55 // If we see `<` it may start both, so we have to inspect some following tokens.
56 // The following combinations can only start generics,
57 // but not qualified paths (with one exception):
58 // `<` `>` - empty generic parameters
59 // `<` `#` - generic parameters with attributes
60 // `<` (LIFETIME|IDENT) `>` - single generic parameter
61 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
62 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
63 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
64 // The only truly ambiguous case is
65 // `<` IDENT `>` `::` IDENT ...
66 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
67 // because this is what almost always expected in practice, qualified paths in impls
68 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
69 if !p.at(L_ANGLE) {
70 return false;
71 }
72 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
73 return true;
74 }
75 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
76 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
77}
diff --git a/src/grammar/items/use_item.rs b/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..a3f7f0da8
--- /dev/null
+++ b/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}