aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/items.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/grammar/items.rs')
-rw-r--r--crates/parser/src/grammar/items.rs444
1 files changed, 444 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
new file mode 100644
index 000000000..8fd8f3b80
--- /dev/null
+++ b/crates/parser/src/grammar/items.rs
@@ -0,0 +1,444 @@
1//! FIXME: write short doc here
2
3mod consts;
4mod adt;
5mod traits;
6mod use_item;
7
8pub(crate) use self::{
9 adt::{record_field_list, variant_list},
10 expressions::{match_arm_list, record_expr_field_list},
11 traits::assoc_item_list,
12 use_item::use_tree_list,
13};
14use super::*;
15
16// test mod_contents
17// fn foo() {}
18// macro_rules! foo {}
19// foo::bar!();
20// super::baz! {}
21// struct S;
22pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
23 attributes::inner_attrs(p);
24 while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) {
25 item_or_macro(p, stop_on_r_curly)
26 }
27}
28
29pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
30 FN_KW,
31 STRUCT_KW,
32 ENUM_KW,
33 IMPL_KW,
34 TRAIT_KW,
35 CONST_KW,
36 STATIC_KW,
37 LET_KW,
38 MOD_KW,
39 PUB_KW,
40 CRATE_KW,
41 USE_KW,
42 MACRO_KW,
43 T![;],
44];
45
46pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) {
47 let m = p.start();
48 attributes::outer_attrs(p);
49 let m = match maybe_item(p, m) {
50 Ok(()) => {
51 if p.at(T![;]) {
52 p.err_and_bump(
53 "expected item, found `;`\n\
54 consider removing this semicolon",
55 );
56 }
57 return;
58 }
59 Err(m) => m,
60 };
61 if paths::is_use_path_start(p) {
62 match macro_call(p) {
63 BlockLike::Block => (),
64 BlockLike::NotBlock => {
65 p.expect(T![;]);
66 }
67 }
68 m.complete(p, MACRO_CALL);
69 } else {
70 m.abandon(p);
71 if p.at(T!['{']) {
72 error_block(p, "expected an item");
73 } else if p.at(T!['}']) && !stop_on_r_curly {
74 let e = p.start();
75 p.error("unmatched `}`");
76 p.bump(T!['}']);
77 e.complete(p, ERROR);
78 } else if !p.at(EOF) && !p.at(T!['}']) {
79 p.err_and_bump("expected an item");
80 } else {
81 p.error("expected an item");
82 }
83 }
84}
85
86pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
87 // test_err pub_expr
88 // fn foo() { pub 92; }
89 let has_visibility = opt_visibility(p);
90
91 let m = match items_without_modifiers(p, m) {
92 Ok(()) => return Ok(()),
93 Err(m) => m,
94 };
95
96 let mut has_mods = false;
97
98 // modifiers
99 has_mods |= p.eat(T![const]);
100
101 // test_err async_without_semicolon
102 // fn foo() { let _ = async {} }
103 if p.at(T![async]) && p.nth(1) != T!['{'] && p.nth(1) != T![move] && p.nth(1) != T![|] {
104 p.eat(T![async]);
105 has_mods = true;
106 }
107
108 // test_err unsafe_block_in_mod
109 // fn foo(){} unsafe { } fn bar(){}
110 if p.at(T![unsafe]) && p.nth(1) != T!['{'] {
111 p.eat(T![unsafe]);
112 has_mods = true;
113 }
114
115 if p.at(T![extern]) {
116 has_mods = true;
117 abi(p);
118 }
119 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == T![trait] {
120 p.bump_remap(T![auto]);
121 has_mods = true;
122 }
123
124 // test default_item
125 // default impl T for Foo {}
126 if p.at(IDENT) && p.at_contextual_kw("default") {
127 match p.nth(1) {
128 T![fn] | T![type] | T![const] | T![impl] => {
129 p.bump_remap(T![default]);
130 has_mods = true;
131 }
132 T![unsafe] => {
133 // test default_unsafe_item
134 // default unsafe impl T for Foo {
135 // default unsafe fn foo() {}
136 // }
137 if matches!(p.nth(2), T![impl] | T![fn]) {
138 p.bump_remap(T![default]);
139 p.bump(T![unsafe]);
140 has_mods = true;
141 }
142 }
143 _ => (),
144 }
145 }
146
147 // test existential_type
148 // existential type Foo: Fn() -> usize;
149 if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] {
150 p.bump_remap(T![existential]);
151 has_mods = true;
152 }
153
154 // items
155 match p.current() {
156 // test fn
157 // fn foo() {}
158 T![fn] => {
159 fn_(p);
160 m.complete(p, FN);
161 }
162
163 // test trait
164 // trait T {}
165 T![trait] => {
166 traits::trait_(p);
167 m.complete(p, TRAIT);
168 }
169
170 T![const] => {
171 consts::konst(p, m);
172 }
173
174 // test impl
175 // impl T for S {}
176 T![impl] => {
177 traits::impl_(p);
178 m.complete(p, IMPL);
179 }
180
181 T![type] => {
182 type_alias(p, m);
183 }
184 _ => {
185 if !has_visibility && !has_mods {
186 return Err(m);
187 } else {
188 if has_mods {
189 p.error("expected existential, fn, trait or impl");
190 } else {
191 p.error("expected an item");
192 }
193 m.complete(p, ERROR);
194 }
195 }
196 }
197 Ok(())
198}
199
200fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
201 let la = p.nth(1);
202 match p.current() {
203 // test extern_crate
204 // extern crate foo;
205 T![extern] if la == T![crate] => extern_crate(p, m),
206 T![type] => {
207 type_alias(p, m);
208 }
209 T![mod] => mod_item(p, m),
210 T![struct] => {
211 // test struct_items
212 // struct Foo;
213 // struct Foo {}
214 // struct Foo();
215 // struct Foo(String, usize);
216 // struct Foo {
217 // a: i32,
218 // b: f32,
219 // }
220 adt::strukt(p, m);
221 }
222 // test pub_macro_def
223 // pub macro m($:ident) {}
224 T![macro] => {
225 macro_def(p, m);
226 }
227 IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
228 // test union_items
229 // union Foo {}
230 // union Foo {
231 // a: i32,
232 // b: f32,
233 // }
234 adt::union(p, m);
235 }
236 T![enum] => adt::enum_(p, m),
237 T![use] => use_item::use_(p, m),
238 T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m),
239 T![static] => consts::static_(p, m),
240 // test extern_block
241 // extern {}
242 T![extern]
243 if la == T!['{'] || ((la == STRING || la == RAW_STRING) && p.nth(2) == T!['{']) =>
244 {
245 abi(p);
246 extern_item_list(p);
247 m.complete(p, EXTERN_BLOCK);
248 }
249 _ => return Err(m),
250 };
251 Ok(())
252}
253
254fn extern_crate(p: &mut Parser, m: Marker) {
255 assert!(p.at(T![extern]));
256 p.bump(T![extern]);
257 assert!(p.at(T![crate]));
258 p.bump(T![crate]);
259
260 if p.at(T![self]) {
261 p.bump(T![self]);
262 } else {
263 name_ref(p);
264 }
265
266 opt_rename(p);
267 p.expect(T![;]);
268 m.complete(p, EXTERN_CRATE);
269}
270
271pub(crate) fn extern_item_list(p: &mut Parser) {
272 assert!(p.at(T!['{']));
273 let m = p.start();
274 p.bump(T!['{']);
275 mod_contents(p, true);
276 p.expect(T!['}']);
277 m.complete(p, EXTERN_ITEM_LIST);
278}
279
280fn fn_(p: &mut Parser) {
281 assert!(p.at(T![fn]));
282 p.bump(T![fn]);
283
284 name_r(p, ITEM_RECOVERY_SET);
285 // test function_type_params
286 // fn foo<T: Clone + Copy>(){}
287 type_params::opt_generic_param_list(p);
288
289 if p.at(T!['(']) {
290 params::param_list_fn_def(p);
291 } else {
292 p.error("expected function arguments");
293 }
294 // test function_ret_type
295 // fn foo() {}
296 // fn bar() -> () {}
297 opt_ret_type(p);
298
299 // test function_where_clause
300 // fn foo<T>() where T: Copy {}
301 type_params::opt_where_clause(p);
302
303 // test fn_decl
304 // trait T { fn foo(); }
305 if p.at(T![;]) {
306 p.bump(T![;]);
307 } else {
308 expressions::block_expr(p)
309 }
310}
311
312// test type_item
313// type Foo = Bar;
314fn type_alias(p: &mut Parser, m: Marker) {
315 assert!(p.at(T![type]));
316 p.bump(T![type]);
317
318 name(p);
319
320 // test type_item_type_params
321 // type Result<T> = ();
322 type_params::opt_generic_param_list(p);
323
324 if p.at(T![:]) {
325 type_params::bounds(p);
326 }
327
328 // test type_item_where_clause
329 // type Foo where Foo: Copy = ();
330 type_params::opt_where_clause(p);
331 if p.eat(T![=]) {
332 types::type_(p);
333 }
334 p.expect(T![;]);
335 m.complete(p, TYPE_ALIAS);
336}
337
338pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
339 assert!(p.at(T![mod]));
340 p.bump(T![mod]);
341
342 name(p);
343 if p.at(T!['{']) {
344 item_list(p);
345 } else if !p.eat(T![;]) {
346 p.error("expected `;` or `{`");
347 }
348 m.complete(p, MODULE);
349}
350
351pub(crate) fn item_list(p: &mut Parser) {
352 assert!(p.at(T!['{']));
353 let m = p.start();
354 p.bump(T!['{']);
355 mod_contents(p, true);
356 p.expect(T!['}']);
357 m.complete(p, ITEM_LIST);
358}
359
360// test macro_def
361// macro m { ($i:ident) => {} }
362// macro m($i:ident) {}
363fn macro_def(p: &mut Parser, m: Marker) {
364 p.expect(T![macro]);
365 name_r(p, ITEM_RECOVERY_SET);
366 if p.at(T!['{']) {
367 token_tree(p);
368 } else if !p.at(T!['(']) {
369 p.error("unmatched `(`");
370 } else {
371 let m = p.start();
372 token_tree(p);
373 match p.current() {
374 T!['{'] | T!['['] | T!['('] => token_tree(p),
375 _ => p.error("expected `{`, `[`, `(`"),
376 }
377 m.complete(p, TOKEN_TREE);
378 }
379
380 m.complete(p, MACRO_DEF);
381}
382
383fn macro_call(p: &mut Parser) -> BlockLike {
384 assert!(paths::is_use_path_start(p));
385 paths::use_path(p);
386 macro_call_after_excl(p)
387}
388
389pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
390 p.expect(T![!]);
391 if p.at(IDENT) {
392 name(p);
393 }
394 // Special-case `macro_rules! try`.
395 // This is a hack until we do proper edition support
396
397 // test try_macro_rules
398 // macro_rules! try { () => {} }
399 if p.at(T![try]) {
400 let m = p.start();
401 p.bump_remap(IDENT);
402 m.complete(p, NAME);
403 }
404
405 match p.current() {
406 T!['{'] => {
407 token_tree(p);
408 BlockLike::Block
409 }
410 T!['('] | T!['['] => {
411 token_tree(p);
412 BlockLike::NotBlock
413 }
414 _ => {
415 p.error("expected `{`, `[`, `(`");
416 BlockLike::NotBlock
417 }
418 }
419}
420
421pub(crate) fn token_tree(p: &mut Parser) {
422 let closing_paren_kind = match p.current() {
423 T!['{'] => T!['}'],
424 T!['('] => T![')'],
425 T!['['] => T![']'],
426 _ => unreachable!(),
427 };
428 let m = p.start();
429 p.bump_any();
430 while !p.at(EOF) && !p.at(closing_paren_kind) {
431 match p.current() {
432 T!['{'] | T!['('] | T!['['] => token_tree(p),
433 T!['}'] => {
434 p.error("unmatched `}`");
435 m.complete(p, TOKEN_TREE);
436 return;
437 }
438 T![')'] | T![']'] => p.err_and_bump("unmatched brace"),
439 _ => p.bump_any(),
440 }
441 }
442 p.expect(closing_paren_kind);
443 m.complete(p, TOKEN_TREE);
444}