aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/grammar')
-rw-r--r--crates/parser/src/grammar/attributes.rs48
-rw-r--r--crates/parser/src/grammar/expressions.rs651
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs611
-rw-r--r--crates/parser/src/grammar/items.rs444
-rw-r--r--crates/parser/src/grammar/items/adt.rs178
-rw-r--r--crates/parser/src/grammar/items/consts.rs33
-rw-r--r--crates/parser/src/grammar/items/traits.rs131
-rw-r--r--crates/parser/src/grammar/items/use_item.rs132
-rw-r--r--crates/parser/src/grammar/params.rs188
-rw-r--r--crates/parser/src/grammar/paths.rs115
-rw-r--r--crates/parser/src/grammar/patterns.rs379
-rw-r--r--crates/parser/src/grammar/type_args.rs63
-rw-r--r--crates/parser/src/grammar/type_params.rs209
-rw-r--r--crates/parser/src/grammar/types.rs324
14 files changed, 3506 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs
new file mode 100644
index 000000000..dab0f62c3
--- /dev/null
+++ b/crates/parser/src/grammar/attributes.rs
@@ -0,0 +1,48 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn inner_attrs(p: &mut Parser) {
6 while p.at(T![#]) && p.nth(1) == T![!] {
7 attr(p, true)
8 }
9}
10
11pub(super) fn outer_attrs(p: &mut Parser) {
12 while p.at(T![#]) {
13 attr(p, false)
14 }
15}
16
17fn attr(p: &mut Parser, inner: bool) {
18 let attr = p.start();
19 assert!(p.at(T![#]));
20 p.bump(T![#]);
21
22 if inner {
23 assert!(p.at(T![!]));
24 p.bump(T![!]);
25 }
26
27 if p.eat(T!['[']) {
28 paths::use_path(p);
29
30 match p.current() {
31 T![=] => {
32 p.bump(T![=]);
33 if expressions::literal(p).is_none() {
34 p.error("expected literal");
35 }
36 }
37 T!['('] | T!['['] | T!['{'] => items::token_tree(p),
38 _ => {}
39 }
40
41 if !p.eat(T![']']) {
42 p.error("expected `]`");
43 }
44 } else {
45 p.error("expected `[`");
46 }
47 attr.complete(p, ATTR);
48}
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
new file mode 100644
index 000000000..e72929f8c
--- /dev/null
+++ b/crates/parser/src/grammar/expressions.rs
@@ -0,0 +1,651 @@
1//! FIXME: write short doc here
2
3mod atom;
4
5pub(crate) use self::atom::{block_expr, match_arm_list};
6pub(super) use self::atom::{literal, LITERAL_FIRST};
7use super::*;
8
9pub(super) enum StmtWithSemi {
10 Yes,
11 No,
12 Optional,
13}
14
15const EXPR_FIRST: TokenSet = LHS_FIRST;
16
17pub(super) fn expr(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
18 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
19 expr_bp(p, r, 1)
20}
21
22pub(super) fn expr_with_attrs(p: &mut Parser) -> bool {
23 let m = p.start();
24 let has_attrs = p.at(T![#]);
25 attributes::outer_attrs(p);
26
27 let (cm, _block_like) = expr(p);
28 let success = cm.is_some();
29
30 match (has_attrs, cm) {
31 (true, Some(cm)) => {
32 let kind = cm.kind();
33 cm.undo_completion(p).abandon(p);
34 m.complete(p, kind);
35 }
36 _ => m.abandon(p),
37 }
38
39 success
40}
41
42pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
43 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
44 expr_bp(p, r, 1)
45}
46
47fn expr_no_struct(p: &mut Parser) {
48 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
49 expr_bp(p, r, 1);
50}
51
52fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
53 let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR);
54 !forbid
55}
56
57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
58 let m = p.start();
59 // test attr_on_expr_stmt
60 // fn foo() {
61 // #[A] foo();
62 // #[B] bar!{}
63 // #[C] #[D] {}
64 // #[D] return ();
65 // }
66 let has_attrs = p.at(T![#]);
67 attributes::outer_attrs(p);
68
69 if p.at(T![let]) {
70 let_stmt(p, m, with_semi);
71 return;
72 }
73
74 // test block_items
75 // fn a() { fn b() {} }
76 let m = match items::maybe_item(p, m) {
77 Ok(()) => return,
78 Err(m) => m,
79 };
80
81 let (cm, blocklike) = expr_stmt(p);
82 let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);
83
84 if has_attrs && !is_expr_stmt_attr_allowed(kind) {
85 // test_err attr_on_expr_not_allowed
86 // fn foo() {
87 // #[A] 1 + 2;
88 // #[B] if true {};
89 // }
90 p.error(format!("attributes are not allowed on {:?}", kind));
91 }
92
93 if p.at(T!['}']) {
94 // test attr_on_last_expr_in_block
95 // fn foo() {
96 // { #[A] bar!()? }
97 // #[B] &()
98 // }
99 if let Some(cm) = cm {
100 cm.undo_completion(p).abandon(p);
101 m.complete(p, kind);
102 } else {
103 m.abandon(p);
104 }
105 } else {
106 // test no_semi_after_block
107 // fn foo() {
108 // if true {}
109 // loop {}
110 // match () {}
111 // while true {}
112 // for _ in () {}
113 // {}
114 // {}
115 // macro_rules! test {
116 // () => {}
117 // }
118 // test!{}
119 // }
120
121 match with_semi {
122 StmtWithSemi::Yes => {
123 if blocklike.is_block() {
124 p.eat(T![;]);
125 } else {
126 p.expect(T![;]);
127 }
128 }
129 StmtWithSemi::No => {}
130 StmtWithSemi::Optional => {
131 if p.at(T![;]) {
132 p.eat(T![;]);
133 }
134 }
135 }
136
137 m.complete(p, EXPR_STMT);
138 }
139
140 // test let_stmt
141 // fn foo() {
142 // let a;
143 // let b: i32;
144 // let c = 92;
145 // let d: i32 = 92;
146 // let e: !;
147 // let _: ! = {};
148 // let f = #[attr]||{};
149 // }
150 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
151 assert!(p.at(T![let]));
152 p.bump(T![let]);
153 patterns::pattern(p);
154 if p.at(T![:]) {
155 types::ascription(p);
156 }
157 if p.eat(T![=]) {
158 expressions::expr_with_attrs(p);
159 }
160
161 match with_semi {
162 StmtWithSemi::Yes => {
163 p.expect(T![;]);
164 }
165 StmtWithSemi::No => {}
166 StmtWithSemi::Optional => {
167 if p.at(T![;]) {
168 p.eat(T![;]);
169 }
170 }
171 }
172 m.complete(p, LET_STMT);
173 }
174}
175
176pub(super) fn expr_block_contents(p: &mut Parser) {
177 // This is checked by a validator
178 attributes::inner_attrs(p);
179
180 while !p.at(EOF) && !p.at(T!['}']) {
181 // test nocontentexpr
182 // fn foo(){
183 // ;;;some_expr();;;;{;;;};;;;Ok(())
184 // }
185
186 // test nocontentexpr_after_item
187 // fn simple_function() {
188 // enum LocalEnum {
189 // One,
190 // Two,
191 // };
192 // fn f() {};
193 // struct S {};
194 // }
195
196 if p.at(T![;]) {
197 p.bump(T![;]);
198 continue;
199 }
200
201 stmt(p, StmtWithSemi::Yes)
202 }
203}
204
205#[derive(Clone, Copy)]
206struct Restrictions {
207 forbid_structs: bool,
208 prefer_stmt: bool,
209}
210
211/// Binding powers of operators for a Pratt parser.
212///
213/// See https://www.oilshell.org/blog/2016/11/03.html
214#[rustfmt::skip]
215fn current_op(p: &Parser) -> (u8, SyntaxKind) {
216 const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]);
217 match p.current() {
218 T![|] if p.at(T![||]) => (3, T![||]),
219 T![|] if p.at(T![|=]) => (1, T![|=]),
220 T![|] => (6, T![|]),
221 T![>] if p.at(T![>>=]) => (1, T![>>=]),
222 T![>] if p.at(T![>>]) => (9, T![>>]),
223 T![>] if p.at(T![>=]) => (5, T![>=]),
224 T![>] => (5, T![>]),
225 T![=] if p.at(T![=>]) => NOT_AN_OP,
226 T![=] if p.at(T![==]) => (5, T![==]),
227 T![=] => (1, T![=]),
228 T![<] if p.at(T![<=]) => (5, T![<=]),
229 T![<] if p.at(T![<<=]) => (1, T![<<=]),
230 T![<] if p.at(T![<<]) => (9, T![<<]),
231 T![<] => (5, T![<]),
232 T![+] if p.at(T![+=]) => (1, T![+=]),
233 T![+] => (10, T![+]),
234 T![^] if p.at(T![^=]) => (1, T![^=]),
235 T![^] => (7, T![^]),
236 T![%] if p.at(T![%=]) => (1, T![%=]),
237 T![%] => (11, T![%]),
238 T![&] if p.at(T![&=]) => (1, T![&=]),
239 T![&] if p.at(T![&&]) => (4, T![&&]),
240 T![&] => (8, T![&]),
241 T![/] if p.at(T![/=]) => (1, T![/=]),
242 T![/] => (11, T![/]),
243 T![*] if p.at(T![*=]) => (1, T![*=]),
244 T![*] => (11, T![*]),
245 T![.] if p.at(T![..=]) => (2, T![..=]),
246 T![.] if p.at(T![..]) => (2, T![..]),
247 T![!] if p.at(T![!=]) => (5, T![!=]),
248 T![-] if p.at(T![-=]) => (1, T![-=]),
249 T![-] => (10, T![-]),
250 T![as] => (12, T![as]),
251
252 _ => NOT_AN_OP
253 }
254}
255
256// Parses expression with binding power of at least bp.
257fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
258 let mut lhs = match lhs(p, r) {
259 Some((lhs, blocklike)) => {
260 // test stmt_bin_expr_ambiguity
261 // fn foo() {
262 // let _ = {1} & 2;
263 // {1} &2;
264 // }
265 if r.prefer_stmt && blocklike.is_block() {
266 return (Some(lhs), BlockLike::Block);
267 }
268 lhs
269 }
270 None => return (None, BlockLike::NotBlock),
271 };
272
273 loop {
274 let is_range = p.at(T![..]) || p.at(T![..=]);
275 let (op_bp, op) = current_op(p);
276 if op_bp < bp {
277 break;
278 }
279 // test as_precedence
280 // fn foo() {
281 // let _ = &1 as *const i32;
282 // }
283 if p.at(T![as]) {
284 lhs = cast_expr(p, lhs);
285 continue;
286 }
287 let m = lhs.precede(p);
288 p.bump(op);
289
290 // test binop_resets_statementness
291 // fn foo() {
292 // v = {1}&2;
293 // }
294 r = Restrictions { prefer_stmt: false, ..r };
295
296 if is_range {
297 // test postfix_range
298 // fn foo() {
299 // let x = 1..;
300 // match 1.. { _ => () };
301 // match a.b()..S { _ => () };
302 // }
303 let has_trailing_expression =
304 p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{']));
305 if !has_trailing_expression {
306 // no RHS
307 lhs = m.complete(p, RANGE_EXPR);
308 break;
309 }
310 }
311
312 expr_bp(p, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
313 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
314 }
315 (Some(lhs), BlockLike::NotBlock)
316}
317
318const LHS_FIRST: TokenSet =
319 atom::ATOM_EXPR_FIRST.union(token_set![T![&], T![*], T![!], T![.], T![-]]);
320
321fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
322 let m;
323 let kind = match p.current() {
324 // test ref_expr
325 // fn foo() {
326 // // reference operator
327 // let _ = &1;
328 // let _ = &mut &f();
329 // let _ = &raw;
330 // let _ = &raw.0;
331 // // raw reference operator
332 // let _ = &raw mut foo;
333 // let _ = &raw const foo;
334 // }
335 T![&] => {
336 m = p.start();
337 p.bump(T![&]);
338 if p.at(IDENT)
339 && p.at_contextual_kw("raw")
340 && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const]))
341 {
342 p.bump_remap(T![raw]);
343 p.bump_any();
344 } else {
345 p.eat(T![mut]);
346 }
347 REF_EXPR
348 }
349 // test unary_expr
350 // fn foo() {
351 // **&1;
352 // !!true;
353 // --1;
354 // }
355 T![*] | T![!] | T![-] => {
356 m = p.start();
357 p.bump_any();
358 PREFIX_EXPR
359 }
360 _ => {
361 // test full_range_expr
362 // fn foo() { xs[..]; }
363 for &op in [T![..=], T![..]].iter() {
364 if p.at(op) {
365 m = p.start();
366 p.bump(op);
367 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
368 expr_bp(p, r, 2);
369 }
370 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
371 }
372 }
373
374 // test expression_after_block
375 // fn foo() {
376 // let mut p = F{x: 5};
377 // {p}.x = 10;
378 // }
379 //
380 let (lhs, blocklike) = atom::atom_expr(p, r)?;
381 return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())));
382 }
383 };
384 // parse the interior of the unary expression
385 expr_bp(p, r, 255);
386 Some((m.complete(p, kind), BlockLike::NotBlock))
387}
388
389fn postfix_expr(
390 p: &mut Parser,
391 mut lhs: CompletedMarker,
392 // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
393 // E.g. `while true {break}();` is parsed as
394 // `while true {break}; ();`
395 mut block_like: BlockLike,
396 mut allow_calls: bool,
397) -> (CompletedMarker, BlockLike) {
398 loop {
399 lhs = match p.current() {
400 // test stmt_postfix_expr_ambiguity
401 // fn foo() {
402 // match () {
403 // _ => {}
404 // () => {}
405 // [] => {}
406 // }
407 // }
408 T!['('] if allow_calls => call_expr(p, lhs),
409 T!['['] if allow_calls => index_expr(p, lhs),
410 T![.] => match postfix_dot_expr(p, lhs) {
411 Ok(it) => it,
412 Err(it) => {
413 lhs = it;
414 break;
415 }
416 },
417 T![?] => try_expr(p, lhs),
418 _ => break,
419 };
420 allow_calls = true;
421 block_like = BlockLike::NotBlock;
422 }
423 return (lhs, block_like);
424
425 fn postfix_dot_expr(
426 p: &mut Parser,
427 lhs: CompletedMarker,
428 ) -> Result<CompletedMarker, CompletedMarker> {
429 assert!(p.at(T![.]));
430 if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
431 return Ok(method_call_expr(p, lhs));
432 }
433
434 // test await_expr
435 // fn foo() {
436 // x.await;
437 // x.0.await;
438 // x.0().await?.hello();
439 // }
440 if p.nth(1) == T![await] {
441 let m = lhs.precede(p);
442 p.bump(T![.]);
443 p.bump(T![await]);
444 return Ok(m.complete(p, AWAIT_EXPR));
445 }
446
447 if p.at(T![..=]) || p.at(T![..]) {
448 return Err(lhs);
449 }
450
451 Ok(field_expr(p, lhs))
452 }
453}
454
455// test call_expr
456// fn foo() {
457// let _ = f();
458// let _ = f()(1)(1, 2,);
459// let _ = f(<Foo>::func());
460// f(<Foo as Trait>::func());
461// }
462fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
463 assert!(p.at(T!['(']));
464 let m = lhs.precede(p);
465 arg_list(p);
466 m.complete(p, CALL_EXPR)
467}
468
469// test index_expr
470// fn foo() {
471// x[1][2];
472// }
473fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
474 assert!(p.at(T!['[']));
475 let m = lhs.precede(p);
476 p.bump(T!['[']);
477 expr(p);
478 p.expect(T![']']);
479 m.complete(p, INDEX_EXPR)
480}
481
482// test method_call_expr
483// fn foo() {
484// x.foo();
485// y.bar::<T>(1, 2,);
486// }
487fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
488 assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])));
489 let m = lhs.precede(p);
490 p.bump_any();
491 name_ref(p);
492 type_args::opt_generic_arg_list(p, true);
493 if p.at(T!['(']) {
494 arg_list(p);
495 }
496 m.complete(p, METHOD_CALL_EXPR)
497}
498
499// test field_expr
500// fn foo() {
501// x.foo;
502// x.0.bar;
503// x.0();
504// }
505
506// test_err bad_tuple_index_expr
507// fn foo() {
508// x.0.;
509// x.1i32;
510// x.0x01;
511// }
512fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
513 assert!(p.at(T![.]));
514 let m = lhs.precede(p);
515 p.bump(T![.]);
516 if p.at(IDENT) || p.at(INT_NUMBER) {
517 name_ref_or_index(p)
518 } else if p.at(FLOAT_NUMBER) {
519 // FIXME: How to recover and instead parse INT + T![.]?
520 p.bump_any();
521 } else {
522 p.error("expected field name or number")
523 }
524 m.complete(p, FIELD_EXPR)
525}
526
527// test try_expr
528// fn foo() {
529// x?;
530// }
531fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
532 assert!(p.at(T![?]));
533 let m = lhs.precede(p);
534 p.bump(T![?]);
535 m.complete(p, TRY_EXPR)
536}
537
538// test cast_expr
539// fn foo() {
540// 82 as i32;
541// 81 as i8 + 1;
542// 79 as i16 - 1;
543// 0x36 as u8 <= 0x37;
544// }
545fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
546 assert!(p.at(T![as]));
547 let m = lhs.precede(p);
548 p.bump(T![as]);
549 // Use type_no_bounds(), because cast expressions are not
550 // allowed to have bounds.
551 types::type_no_bounds(p);
552 m.complete(p, CAST_EXPR)
553}
554
555fn arg_list(p: &mut Parser) {
556 assert!(p.at(T!['(']));
557 let m = p.start();
558 p.bump(T!['(']);
559 while !p.at(T![')']) && !p.at(EOF) {
560 // test arg_with_attr
561 // fn main() {
562 // foo(#[attr] 92)
563 // }
564 if !expr_with_attrs(p) {
565 break;
566 }
567 if !p.at(T![')']) && !p.expect(T![,]) {
568 break;
569 }
570 }
571 p.eat(T![')']);
572 m.complete(p, ARG_LIST);
573}
574
575// test path_expr
576// fn foo() {
577// let _ = a;
578// let _ = a::b;
579// let _ = ::a::<b>;
580// let _ = format!();
581// }
582fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
583 assert!(paths::is_path_start(p));
584 let m = p.start();
585 paths::expr_path(p);
586 match p.current() {
587 T!['{'] if !r.forbid_structs => {
588 record_expr_field_list(p);
589 (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
590 }
591 T![!] if !p.at(T![!=]) => {
592 let block_like = items::macro_call_after_excl(p);
593 (m.complete(p, MACRO_CALL), block_like)
594 }
595 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
596 }
597}
598
599// test record_lit
600// fn foo() {
601// S {};
602// S { x, y: 32, };
603// S { x, y: 32, ..Default::default() };
604// TupleStruct { 0: 1 };
605// }
606pub(crate) fn record_expr_field_list(p: &mut Parser) {
607 assert!(p.at(T!['{']));
608 let m = p.start();
609 p.bump(T!['{']);
610 while !p.at(EOF) && !p.at(T!['}']) {
611 let m = p.start();
612 // test record_literal_field_with_attr
613 // fn main() {
614 // S { #[cfg(test)] field: 1 }
615 // }
616 attributes::outer_attrs(p);
617
618 match p.current() {
619 IDENT | INT_NUMBER => {
620 // test_err record_literal_before_ellipsis_recovery
621 // fn main() {
622 // S { field ..S::default() }
623 // }
624 if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
625 name_ref_or_index(p);
626 p.expect(T![:]);
627 }
628 expr(p);
629 m.complete(p, RECORD_EXPR_FIELD);
630 }
631 T![.] if p.at(T![..]) => {
632 m.abandon(p);
633 p.bump(T![..]);
634 expr(p);
635 }
636 T!['{'] => {
637 error_block(p, "expected a field");
638 m.abandon(p);
639 }
640 _ => {
641 p.err_and_bump("expected identifier");
642 m.abandon(p);
643 }
644 }
645 if !p.at(T!['}']) {
646 p.expect(T![,]);
647 }
648 }
649 p.expect(T!['}']);
650 m.complete(p, RECORD_EXPR_FIELD_LIST);
651}
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..ba6dd2fbc
--- /dev/null
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -0,0 +1,611 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5// test expr_literals
6// fn foo() {
7// let _ = true;
8// let _ = false;
9// let _ = 1;
10// let _ = 2.0;
11// let _ = b'a';
12// let _ = 'b';
13// let _ = "c";
14// let _ = r"d";
15// let _ = b"e";
16// let _ = br"f";
17// }
18pub(crate) const LITERAL_FIRST: TokenSet = token_set![
19 TRUE_KW,
20 FALSE_KW,
21 INT_NUMBER,
22 FLOAT_NUMBER,
23 BYTE,
24 CHAR,
25 STRING,
26 RAW_STRING,
27 BYTE_STRING,
28 RAW_BYTE_STRING
29];
30
31pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
32 if !p.at_ts(LITERAL_FIRST) {
33 return None;
34 }
35 let m = p.start();
36 p.bump_any();
37 Some(m.complete(p, LITERAL))
38}
39
40// E.g. for after the break in `if break {}`, this should not match
41pub(super) const ATOM_EXPR_FIRST: TokenSet =
42 LITERAL_FIRST.union(paths::PATH_FIRST).union(token_set![
43 T!['('],
44 T!['{'],
45 T!['['],
46 L_DOLLAR,
47 T![|],
48 T![move],
49 T![box],
50 T![if],
51 T![while],
52 T![match],
53 T![unsafe],
54 T![return],
55 T![break],
56 T![continue],
57 T![async],
58 T![try],
59 T![loop],
60 T![for],
61 LIFETIME,
62 ]);
63
64const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW, R_DOLLAR];
65
66pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
67 if let Some(m) = literal(p) {
68 return Some((m, BlockLike::NotBlock));
69 }
70 if paths::is_path_start(p) {
71 return Some(path_expr(p, r));
72 }
73 let la = p.nth(1);
74 let done = match p.current() {
75 T!['('] => tuple_expr(p),
76 T!['['] => array_expr(p),
77 L_DOLLAR => meta_var_expr(p),
78 T![|] => closure_expr(p),
79 T![move] if la == T![|] => closure_expr(p),
80 T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => closure_expr(p),
81 T![if] => if_expr(p),
82
83 T![loop] => loop_expr(p, None),
84 T![box] => box_expr(p, None),
85 T![for] => for_expr(p, None),
86 T![while] => while_expr(p, None),
87 T![try] => try_block_expr(p, None),
88 LIFETIME if la == T![:] => {
89 let m = p.start();
90 label(p);
91 match p.current() {
92 T![loop] => loop_expr(p, Some(m)),
93 T![for] => for_expr(p, Some(m)),
94 T![while] => while_expr(p, Some(m)),
95 // test labeled_block
96 // fn f() { 'label: {}; }
97 T!['{'] => {
98 block_expr(p);
99 m.complete(p, EFFECT_EXPR)
100 }
101 _ => {
102 // test_err misplaced_label_err
103 // fn main() {
104 // 'loop: impl
105 // }
106 p.error("expected a loop");
107 m.complete(p, ERROR);
108 return None;
109 }
110 }
111 }
112 T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => {
113 let m = p.start();
114 p.bump(T![async]);
115 p.eat(T![move]);
116 block_expr(p);
117 m.complete(p, EFFECT_EXPR)
118 }
119 T![match] => match_expr(p),
120 // test unsafe_block
121 // fn f() { unsafe { } }
122 T![unsafe] if la == T!['{'] => {
123 let m = p.start();
124 p.bump(T![unsafe]);
125 block_expr(p);
126 m.complete(p, EFFECT_EXPR)
127 }
128 T!['{'] => {
129 // test for_range_from
130 // fn foo() {
131 // for x in 0 .. {
132 // break;
133 // }
134 // }
135 block_expr_unchecked(p)
136 }
137 T![return] => return_expr(p),
138 T![continue] => continue_expr(p),
139 T![break] => break_expr(p, r),
140 _ => {
141 p.err_recover("expected expression", EXPR_RECOVERY_SET);
142 return None;
143 }
144 };
145 let blocklike = match done.kind() {
146 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | EFFECT_EXPR => {
147 BlockLike::Block
148 }
149 _ => BlockLike::NotBlock,
150 };
151 Some((done, blocklike))
152}
153
154// test tuple_expr
155// fn foo() {
156// ();
157// (1);
158// (1,);
159// }
160fn tuple_expr(p: &mut Parser) -> CompletedMarker {
161 assert!(p.at(T!['(']));
162 let m = p.start();
163 p.expect(T!['(']);
164
165 let mut saw_comma = false;
166 let mut saw_expr = false;
167 while !p.at(EOF) && !p.at(T![')']) {
168 saw_expr = true;
169 if !p.at_ts(EXPR_FIRST) {
170 p.error("expected expression");
171 break;
172 }
173 expr(p);
174 if !p.at(T![')']) {
175 saw_comma = true;
176 p.expect(T![,]);
177 }
178 }
179 p.expect(T![')']);
180 m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
181}
182
183// test array_expr
184// fn foo() {
185// [];
186// [1];
187// [1, 2,];
188// [1; 2];
189// }
190fn array_expr(p: &mut Parser) -> CompletedMarker {
191 assert!(p.at(T!['[']));
192 let m = p.start();
193
194 let mut n_exprs = 0u32;
195 let mut has_semi = false;
196
197 p.bump(T!['[']);
198 while !p.at(EOF) && !p.at(T![']']) {
199 n_exprs += 1;
200
201 // test array_attrs
202 // const A: &[i64] = &[1, #[cfg(test)] 2];
203 if !expr_with_attrs(p) {
204 break;
205 }
206
207 if n_exprs == 1 && p.eat(T![;]) {
208 has_semi = true;
209 continue;
210 }
211
212 if has_semi || !p.at(T![']']) && !p.expect(T![,]) {
213 break;
214 }
215 }
216 p.expect(T![']']);
217
218 m.complete(p, ARRAY_EXPR)
219}
220
221// test lambda_expr
222// fn foo() {
223// || ();
224// || -> i32 { 92 };
225// |x| x;
226// move |x: i32,| x;
227// async || {};
228// move || {};
229// async move || {};
230// }
231fn closure_expr(p: &mut Parser) -> CompletedMarker {
232 assert!(
233 p.at(T![|])
234 || (p.at(T![move]) && p.nth(1) == T![|])
235 || (p.at(T![async]) && p.nth(1) == T![|])
236 || (p.at(T![async]) && p.nth(1) == T![move] && p.nth(2) == T![|])
237 );
238 let m = p.start();
239 p.eat(T![async]);
240 p.eat(T![move]);
241 params::param_list_closure(p);
242 if opt_ret_type(p) {
243 // test lambda_ret_block
244 // fn main() { || -> i32 { 92 }(); }
245 block_expr(p);
246 } else {
247 if p.at_ts(EXPR_FIRST) {
248 expr(p);
249 } else {
250 p.error("expected expression");
251 }
252 }
253 m.complete(p, CLOSURE_EXPR)
254}
255
256// test if_expr
257// fn foo() {
258// if true {};
259// if true {} else {};
260// if true {} else if false {} else {};
261// if S {};
262// if { true } { } else { };
263// }
264fn if_expr(p: &mut Parser) -> CompletedMarker {
265 assert!(p.at(T![if]));
266 let m = p.start();
267 p.bump(T![if]);
268 condition(p);
269 block_expr(p);
270 if p.at(T![else]) {
271 p.bump(T![else]);
272 if p.at(T![if]) {
273 if_expr(p);
274 } else {
275 block_expr(p);
276 }
277 }
278 m.complete(p, IF_EXPR)
279}
280
281// test label
282// fn foo() {
283// 'a: loop {}
284// 'b: while true {}
285// 'c: for x in () {}
286// }
287fn label(p: &mut Parser) {
288 assert!(p.at(LIFETIME) && p.nth(1) == T![:]);
289 let m = p.start();
290 p.bump(LIFETIME);
291 p.bump_any();
292 m.complete(p, LABEL);
293}
294
295// test loop_expr
296// fn foo() {
297// loop {};
298// }
299fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
300 assert!(p.at(T![loop]));
301 let m = m.unwrap_or_else(|| p.start());
302 p.bump(T![loop]);
303 block_expr(p);
304 m.complete(p, LOOP_EXPR)
305}
306
307// test while_expr
308// fn foo() {
309// while true {};
310// while let Some(x) = it.next() {};
311// while { true } {};
312// }
313fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
314 assert!(p.at(T![while]));
315 let m = m.unwrap_or_else(|| p.start());
316 p.bump(T![while]);
317 condition(p);
318 block_expr(p);
319 m.complete(p, WHILE_EXPR)
320}
321
322// test for_expr
323// fn foo() {
324// for x in [] {};
325// }
326fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
327 assert!(p.at(T![for]));
328 let m = m.unwrap_or_else(|| p.start());
329 p.bump(T![for]);
330 patterns::pattern(p);
331 p.expect(T![in]);
332 expr_no_struct(p);
333 block_expr(p);
334 m.complete(p, FOR_EXPR)
335}
336
337// test cond
338// fn foo() { if let Some(_) = None {} }
339// fn bar() {
340// if let Some(_) | Some(_) = None {}
341// if let | Some(_) = None {}
342// while let Some(_) | Some(_) = None {}
343// while let | Some(_) = None {}
344// }
345fn condition(p: &mut Parser) {
346 let m = p.start();
347 if p.eat(T![let]) {
348 patterns::pattern_top(p);
349 p.expect(T![=]);
350 }
351 expr_no_struct(p);
352 m.complete(p, CONDITION);
353}
354
355// test match_expr
356// fn foo() {
357// match () { };
358// match S {};
359// match { } { _ => () };
360// match { S {} } {};
361// }
362fn match_expr(p: &mut Parser) -> CompletedMarker {
363 assert!(p.at(T![match]));
364 let m = p.start();
365 p.bump(T![match]);
366 expr_no_struct(p);
367 if p.at(T!['{']) {
368 match_arm_list(p);
369 } else {
370 p.error("expected `{`")
371 }
372 m.complete(p, MATCH_EXPR)
373}
374
375pub(crate) fn match_arm_list(p: &mut Parser) {
376 assert!(p.at(T!['{']));
377 let m = p.start();
378 p.eat(T!['{']);
379
380 // test match_arms_inner_attribute
381 // fn foo() {
382 // match () {
383 // #![doc("Inner attribute")]
384 // #![doc("Can be")]
385 // #![doc("Stacked")]
386 // _ => (),
387 // }
388 // }
389 attributes::inner_attrs(p);
390
391 while !p.at(EOF) && !p.at(T!['}']) {
392 if p.at(T!['{']) {
393 error_block(p, "expected match arm");
394 continue;
395 }
396
397 // test match_arms_commas
398 // fn foo() {
399 // match () {
400 // _ => (),
401 // _ => {}
402 // _ => ()
403 // }
404 // }
405 if match_arm(p).is_block() {
406 p.eat(T![,]);
407 } else if !p.at(T!['}']) {
408 p.expect(T![,]);
409 }
410 }
411 p.expect(T!['}']);
412 m.complete(p, MATCH_ARM_LIST);
413}
414
415// test match_arm
416// fn foo() {
417// match () {
418// _ => (),
419// _ if Test > Test{field: 0} => (),
420// X | Y if Z => (),
421// | X | Y if Z => (),
422// | X => (),
423// };
424// }
425fn match_arm(p: &mut Parser) -> BlockLike {
426 let m = p.start();
427 // test match_arms_outer_attributes
428 // fn foo() {
429 // match () {
430 // #[cfg(feature = "some")]
431 // _ => (),
432 // #[cfg(feature = "other")]
433 // _ => (),
434 // #[cfg(feature = "many")]
435 // #[cfg(feature = "attributes")]
436 // #[cfg(feature = "before")]
437 // _ => (),
438 // }
439 // }
440 attributes::outer_attrs(p);
441
442 patterns::pattern_top_r(p, TokenSet::EMPTY);
443 if p.at(T![if]) {
444 match_guard(p);
445 }
446 p.expect(T![=>]);
447 let blocklike = expr_stmt(p).1;
448 m.complete(p, MATCH_ARM);
449 blocklike
450}
451
452// test match_guard
453// fn foo() {
454// match () {
455// _ if foo => (),
456// }
457// }
458fn match_guard(p: &mut Parser) -> CompletedMarker {
459 assert!(p.at(T![if]));
460 let m = p.start();
461 p.bump(T![if]);
462 expr(p);
463 m.complete(p, MATCH_GUARD)
464}
465
466// test block
467// fn a() {}
468// fn b() { let _ = 1; }
469// fn c() { 1; 2; }
470// fn d() { 1; 2 }
471pub(crate) fn block_expr(p: &mut Parser) {
472 if !p.at(T!['{']) {
473 p.error("expected a block");
474 return;
475 }
476 block_expr_unchecked(p);
477}
478
479fn block_expr_unchecked(p: &mut Parser) -> CompletedMarker {
480 assert!(p.at(T!['{']));
481 let m = p.start();
482 p.bump(T!['{']);
483 expr_block_contents(p);
484 p.expect(T!['}']);
485 m.complete(p, BLOCK_EXPR)
486}
487
488// test return_expr
489// fn foo() {
490// return;
491// return 92;
492// }
493fn return_expr(p: &mut Parser) -> CompletedMarker {
494 assert!(p.at(T![return]));
495 let m = p.start();
496 p.bump(T![return]);
497 if p.at_ts(EXPR_FIRST) {
498 expr(p);
499 }
500 m.complete(p, RETURN_EXPR)
501}
502
503// test continue_expr
504// fn foo() {
505// loop {
506// continue;
507// continue 'l;
508// }
509// }
510fn continue_expr(p: &mut Parser) -> CompletedMarker {
511 assert!(p.at(T![continue]));
512 let m = p.start();
513 p.bump(T![continue]);
514 p.eat(LIFETIME);
515 m.complete(p, CONTINUE_EXPR)
516}
517
518// test break_expr
519// fn foo() {
520// loop {
521// break;
522// break 'l;
523// break 92;
524// break 'l 92;
525// }
526// }
527fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
528 assert!(p.at(T![break]));
529 let m = p.start();
530 p.bump(T![break]);
531 p.eat(LIFETIME);
532 // test break_ambiguity
533 // fn foo(){
534 // if break {}
535 // while break {}
536 // for i in break {}
537 // match break {}
538 // }
539 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
540 expr(p);
541 }
542 m.complete(p, BREAK_EXPR)
543}
544
545// test try_block_expr
546// fn foo() {
547// let _ = try {};
548// }
549fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
550 assert!(p.at(T![try]));
551 let m = m.unwrap_or_else(|| p.start());
552 // Special-case `try!` as macro.
553 // This is a hack until we do proper edition support
554 if p.nth_at(1, T![!]) {
555 // test try_macro_fallback
556 // fn foo() { try!(Ok(())); }
557 let path = p.start();
558 let path_segment = p.start();
559 let name_ref = p.start();
560 p.bump_remap(IDENT);
561 name_ref.complete(p, NAME_REF);
562 path_segment.complete(p, PATH_SEGMENT);
563 path.complete(p, PATH);
564 let _block_like = items::macro_call_after_excl(p);
565 return m.complete(p, MACRO_CALL);
566 }
567
568 p.bump(T![try]);
569 block_expr(p);
570 m.complete(p, EFFECT_EXPR)
571}
572
573// test box_expr
574// fn foo() {
575// let x = box 1i32;
576// let y = (box 1i32, box 2i32);
577// let z = Foo(box 1i32, box 2i32);
578// }
579fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
580 assert!(p.at(T![box]));
581 let m = m.unwrap_or_else(|| p.start());
582 p.bump(T![box]);
583 if p.at_ts(EXPR_FIRST) {
584 expr(p);
585 }
586 m.complete(p, BOX_EXPR)
587}
588
589/// Expression from `$var` macro expansion, wrapped in dollars
590fn meta_var_expr(p: &mut Parser) -> CompletedMarker {
591 assert!(p.at(L_DOLLAR));
592 let m = p.start();
593 p.bump(L_DOLLAR);
594 let (completed, _is_block) =
595 expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
596
597 match (completed, p.current()) {
598 (Some(it), R_DOLLAR) => {
599 p.bump(R_DOLLAR);
600 m.abandon(p);
601 it
602 }
603 _ => {
604 while !p.at(R_DOLLAR) {
605 p.bump_any()
606 }
607 p.bump(R_DOLLAR);
608 m.complete(p, ERROR)
609 }
610 }
611}
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}
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs
new file mode 100644
index 000000000..67c0c5697
--- /dev/null
+++ b/crates/parser/src/grammar/items/adt.rs
@@ -0,0 +1,178 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn strukt(p: &mut Parser, m: Marker) {
6 assert!(p.at(T![struct]));
7 p.bump(T![struct]);
8 struct_or_union(p, m, T![struct], STRUCT);
9}
10
11pub(super) fn union(p: &mut Parser, m: Marker) {
12 assert!(p.at_contextual_kw("union"));
13 p.bump_remap(T![union]);
14 struct_or_union(p, m, T![union], UNION);
15}
16
17fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
18 name_r(p, ITEM_RECOVERY_SET);
19 type_params::opt_generic_param_list(p);
20 match p.current() {
21 T![where] => {
22 type_params::opt_where_clause(p);
23 match p.current() {
24 T![;] => {
25 p.bump(T![;]);
26 }
27 T!['{'] => record_field_list(p),
28 _ => {
29 //FIXME: special case `(` error message
30 p.error("expected `;` or `{`");
31 }
32 }
33 }
34 T![;] if kw == T![struct] => {
35 p.bump(T![;]);
36 }
37 T!['{'] => record_field_list(p),
38 T!['('] if kw == T![struct] => {
39 tuple_field_list(p);
40 // test tuple_struct_where
41 // struct Test<T>(T) where T: Clone;
42 // struct Test<T>(T);
43 type_params::opt_where_clause(p);
44 p.expect(T![;]);
45 }
46 _ if kw == T![struct] => {
47 p.error("expected `;`, `{`, or `(`");
48 }
49 _ => {
50 p.error("expected `{`");
51 }
52 }
53 m.complete(p, def);
54}
55
56pub(super) fn enum_(p: &mut Parser, m: Marker) {
57 assert!(p.at(T![enum]));
58 p.bump(T![enum]);
59 name_r(p, ITEM_RECOVERY_SET);
60 type_params::opt_generic_param_list(p);
61 type_params::opt_where_clause(p);
62 if p.at(T!['{']) {
63 variant_list(p);
64 } else {
65 p.error("expected `{`")
66 }
67 m.complete(p, ENUM);
68}
69
70pub(crate) fn variant_list(p: &mut Parser) {
71 assert!(p.at(T!['{']));
72 let m = p.start();
73 p.bump(T!['{']);
74 while !p.at(EOF) && !p.at(T!['}']) {
75 if p.at(T!['{']) {
76 error_block(p, "expected enum variant");
77 continue;
78 }
79 let var = p.start();
80 attributes::outer_attrs(p);
81 if p.at(IDENT) {
82 name(p);
83 match p.current() {
84 T!['{'] => record_field_list(p),
85 T!['('] => tuple_field_list(p),
86 _ => (),
87 }
88
89 // test variant_discriminant
90 // enum E { X(i32) = 10 }
91 if p.eat(T![=]) {
92 expressions::expr(p);
93 }
94 var.complete(p, VARIANT);
95 } else {
96 var.abandon(p);
97 p.err_and_bump("expected enum variant");
98 }
99 if !p.at(T!['}']) {
100 p.expect(T![,]);
101 }
102 }
103 p.expect(T!['}']);
104 m.complete(p, VARIANT_LIST);
105}
106
107pub(crate) fn record_field_list(p: &mut Parser) {
108 assert!(p.at(T!['{']));
109 let m = p.start();
110 p.bump(T!['{']);
111 while !p.at(T!['}']) && !p.at(EOF) {
112 if p.at(T!['{']) {
113 error_block(p, "expected field");
114 continue;
115 }
116 record_field_def(p);
117 if !p.at(T!['}']) {
118 p.expect(T![,]);
119 }
120 }
121 p.expect(T!['}']);
122 m.complete(p, RECORD_FIELD_LIST);
123
124 fn record_field_def(p: &mut Parser) {
125 let m = p.start();
126 // test record_field_attrs
127 // struct S {
128 // #[serde(with = "url_serde")]
129 // pub uri: Uri,
130 // }
131 attributes::outer_attrs(p);
132 opt_visibility(p);
133 if p.at(IDENT) {
134 name(p);
135 p.expect(T![:]);
136 types::type_(p);
137 m.complete(p, RECORD_FIELD);
138 } else {
139 m.abandon(p);
140 p.err_and_bump("expected field declaration");
141 }
142 }
143}
144
145fn tuple_field_list(p: &mut Parser) {
146 assert!(p.at(T!['(']));
147 let m = p.start();
148 if !p.expect(T!['(']) {
149 return;
150 }
151 while !p.at(T![')']) && !p.at(EOF) {
152 let m = p.start();
153 // test tuple_field_attrs
154 // struct S (
155 // #[serde(with = "url_serde")]
156 // pub Uri,
157 // );
158 //
159 // enum S {
160 // Uri(#[serde(with = "url_serde")] Uri),
161 // }
162 attributes::outer_attrs(p);
163 opt_visibility(p);
164 if !p.at_ts(types::TYPE_FIRST) {
165 p.error("expected a type");
166 m.complete(p, ERROR);
167 break;
168 }
169 types::type_(p);
170 m.complete(p, TUPLE_FIELD);
171
172 if !p.at(T![')']) {
173 p.expect(T![,]);
174 }
175 }
176 p.expect(T![')']);
177 m.complete(p, TUPLE_FIELD_LIST);
178}
diff --git a/crates/parser/src/grammar/items/consts.rs b/crates/parser/src/grammar/items/consts.rs
new file mode 100644
index 000000000..eb7d1f828
--- /dev/null
+++ b/crates/parser/src/grammar/items/consts.rs
@@ -0,0 +1,33 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn static_(p: &mut Parser, m: Marker) {
6 const_or_static(p, m, T![static], STATIC)
7}
8
9pub(super) fn konst(p: &mut Parser, m: Marker) {
10 const_or_static(p, m, T![const], CONST)
11}
12
13fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
14 assert!(p.at(kw));
15 p.bump(kw);
16 p.eat(T![mut]); // FIXME: validator to forbid const mut
17
18 // Allow `_` in place of an identifier in a `const`.
19 let is_const_underscore = kw == T![const] && p.eat(T![_]);
20 if !is_const_underscore {
21 name(p);
22 }
23
24 // test_err static_underscore
25 // static _: i32 = 5;
26
27 types::ascription(p);
28 if p.eat(T![=]) {
29 expressions::expr(p);
30 }
31 p.expect(T![;]);
32 m.complete(p, def);
33}
diff --git a/crates/parser/src/grammar/items/traits.rs b/crates/parser/src/grammar/items/traits.rs
new file mode 100644
index 000000000..8394020da
--- /dev/null
+++ b/crates/parser/src/grammar/items/traits.rs
@@ -0,0 +1,131 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5// test trait_item
6// trait T<U>: Hash + Clone where U: Copy {}
7// trait X<U: Debug + Display>: Hash + Clone where U: Copy {}
8pub(super) fn trait_(p: &mut Parser) {
9 assert!(p.at(T![trait]));
10 p.bump(T![trait]);
11 name_r(p, ITEM_RECOVERY_SET);
12 type_params::opt_generic_param_list(p);
13 // test trait_alias
14 // trait Z<U> = T<U>;
15 // trait Z<U> = T<U> where U: Copy;
16 // trait Z<U> = where Self: T<U>;
17 if p.eat(T![=]) {
18 type_params::bounds_without_colon(p);
19 type_params::opt_where_clause(p);
20 p.expect(T![;]);
21 return;
22 }
23 if p.at(T![:]) {
24 type_params::bounds(p);
25 }
26 type_params::opt_where_clause(p);
27 if p.at(T!['{']) {
28 assoc_item_list(p);
29 } else {
30 p.error("expected `{`");
31 }
32}
33
34// test impl_def
35// impl Foo {}
36pub(super) fn impl_(p: &mut Parser) {
37 assert!(p.at(T![impl]));
38 p.bump(T![impl]);
39 if choose_type_params_over_qpath(p) {
40 type_params::opt_generic_param_list(p);
41 }
42
43 // FIXME: never type
44 // impl ! {}
45
46 // test impl_def_neg
47 // impl !Send for X {}
48 p.eat(T![!]);
49 impl_type(p);
50 if p.eat(T![for]) {
51 impl_type(p);
52 }
53 type_params::opt_where_clause(p);
54 if p.at(T!['{']) {
55 assoc_item_list(p);
56 } else {
57 p.error("expected `{`");
58 }
59}
60
61// test impl_item_list
62// impl F {
63// type A = i32;
64// const B: i32 = 92;
65// fn foo() {}
66// fn bar(&self) {}
67// }
68pub(crate) fn assoc_item_list(p: &mut Parser) {
69 assert!(p.at(T!['{']));
70 let m = p.start();
71 p.bump(T!['{']);
72 // test impl_inner_attributes
73 // enum F{}
74 // impl F {
75 // //! This is a doc comment
76 // #![doc("This is also a doc comment")]
77 // }
78 attributes::inner_attrs(p);
79
80 while !p.at(EOF) && !p.at(T!['}']) {
81 if p.at(T!['{']) {
82 error_block(p, "expected an item");
83 continue;
84 }
85 item_or_macro(p, true);
86 }
87 p.expect(T!['}']);
88 m.complete(p, ASSOC_ITEM_LIST);
89}
90
91// test impl_type_params
92// impl<const N: u32> Bar<N> {}
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 // `<` `const` - const generic parameters
101 // `<` (LIFETIME|IDENT) `>` - single generic parameter
102 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
103 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
104 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
105 // The only truly ambiguous case is
106 // `<` IDENT `>` `::` IDENT ...
107 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
108 // because this is what almost always expected in practice, qualified paths in impls
109 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
110 if !p.at(T![<]) {
111 return false;
112 }
113 if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW {
114 return true;
115 }
116 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
117 && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=])
118}
119
120// test_err impl_type
121// impl Type {}
122// impl Trait1 for T {}
123// impl impl NotType {}
124// impl Trait2 for impl NotType {}
125pub(crate) fn impl_type(p: &mut Parser) {
126 if p.at(T![impl]) {
127 p.error("expected trait or type");
128 return;
129 }
130 types::type_(p);
131}
diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..20e6a13cf
--- /dev/null
+++ b/crates/parser/src/grammar/items/use_item.rs
@@ -0,0 +1,132 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn use_(p: &mut Parser, m: Marker) {
6 assert!(p.at(T![use]));
7 p.bump(T![use]);
8 use_tree(p, true);
9 p.expect(T![;]);
10 m.complete(p, USE);
11}
12
13/// Parse a use 'tree', such as `some::path` in `use some::path;`
14/// Note that this is called both by `use_item` and `use_tree_list`,
15/// so handles both `some::path::{inner::path}` and `inner::path` in
16/// `use some::path::{inner::path};`
17fn use_tree(p: &mut Parser, top_level: bool) {
18 let m = p.start();
19 match p.current() {
20 // Finish the use_tree for cases of e.g.
21 // `use some::path::{self, *};` or `use *;`
22 // This does not handle cases such as `use some::path::*`
23 // N.B. in Rust 2015 `use *;` imports all from crate root
24 // however in Rust 2018 `use *;` errors: ('cannot glob-import all possible crates')
25 // FIXME: Add this error (if not out of scope)
26
27 // test use_star
28 // use *;
29 // use ::*;
30 // use some::path::{*};
31 // use some::path::{::*};
32 T![*] => p.bump(T![*]),
33 T![:] if p.at(T![::]) && p.nth(2) == T![*] => {
34 // Parse `use ::*;`, which imports all from the crate root in Rust 2015
35 // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`)
36 // but still parses and errors later: ('crate root in paths can only be used in start position')
37 // FIXME: Add this error (if not out of scope)
38 // In Rust 2018, it is always invalid (see above)
39 p.bump(T![::]);
40 p.bump(T![*]);
41 }
42 // Open a use tree list
43 // Handles cases such as `use {some::path};` or `{inner::path}` in
44 // `use some::path::{{inner::path}, other::path}`
45
46 // test use_tree_list
47 // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`)
48 // use {path::from::root}; // Rust 2015
49 // use ::{some::arbritrary::path}; // Rust 2015
50 // use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting
51 T!['{'] => {
52 use_tree_list(p);
53 }
54 T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => {
55 p.bump(T![::]);
56 use_tree_list(p);
57 }
58 // Parse a 'standard' path.
59 // Also handles aliases (e.g. `use something as something_else`)
60
61 // test use_path
62 // use ::crate_name; // Rust 2018 - All flavours
63 // use crate_name; // Rust 2018 - Anchored paths
64 // use item_in_scope_or_crate_name; // Rust 2018 - Uniform Paths
65 //
66 // use self::module::Item;
67 // use crate::Item;
68 // use self::some::Struct;
69 // use crate_name::some_item;
70 _ if paths::is_use_path_start(p) => {
71 paths::use_path(p);
72 match p.current() {
73 T![as] => {
74 // test use_alias
75 // use some::path as some_name;
76 // use some::{
77 // other::path as some_other_name,
78 // different::path as different_name,
79 // yet::another::path,
80 // running::out::of::synonyms::for_::different::*
81 // };
82 // use Trait as _;
83 opt_rename(p);
84 }
85 T![:] if p.at(T![::]) => {
86 p.bump(T![::]);
87 match p.current() {
88 T![*] => {
89 p.bump(T![*]);
90 }
91 // test use_tree_list_after_path
92 // use crate::{Item};
93 // use self::{Item};
94 T!['{'] => use_tree_list(p),
95 _ => {
96 // is this unreachable?
97 p.error("expected `{` or `*`");
98 }
99 }
100 }
101 _ => (),
102 }
103 }
104 _ => {
105 m.abandon(p);
106 let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier";
107 if top_level {
108 p.err_recover(msg, ITEM_RECOVERY_SET);
109 } else {
110 // if we are parsing a nested tree, we have to eat a token to
111 // main balanced `{}`
112 p.err_and_bump(msg);
113 }
114 return;
115 }
116 }
117 m.complete(p, USE_TREE);
118}
119
120pub(crate) fn use_tree_list(p: &mut Parser) {
121 assert!(p.at(T!['{']));
122 let m = p.start();
123 p.bump(T!['{']);
124 while !p.at(EOF) && !p.at(T!['}']) {
125 use_tree(p, false);
126 if !p.at(T!['}']) {
127 p.expect(T![,]);
128 }
129 }
130 p.expect(T!['}']);
131 m.complete(p, USE_TREE_LIST);
132}
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs
new file mode 100644
index 000000000..a665ffc13
--- /dev/null
+++ b/crates/parser/src/grammar/params.rs
@@ -0,0 +1,188 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5// test param_list
6// fn a() {}
7// fn b(x: i32) {}
8// fn c(x: i32, ) {}
9// fn d(x: i32, y: ()) {}
10pub(super) fn param_list_fn_def(p: &mut Parser) {
11 list_(p, Flavor::FnDef)
12}
13
14// test param_list_opt_patterns
15// fn foo<F: FnMut(&mut Foo<'a>)>(){}
16pub(super) fn param_list_fn_trait(p: &mut Parser) {
17 list_(p, Flavor::FnTrait)
18}
19
20pub(super) fn param_list_fn_ptr(p: &mut Parser) {
21 list_(p, Flavor::FnPointer)
22}
23
24pub(super) fn param_list_closure(p: &mut Parser) {
25 list_(p, Flavor::Closure)
26}
27
28#[derive(Debug, Clone, Copy)]
29enum Flavor {
30 FnDef, // Includes trait fn params; omitted param idents are not supported
31 FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations
32 FnPointer,
33 Closure,
34}
35
36fn list_(p: &mut Parser, flavor: Flavor) {
37 use Flavor::*;
38
39 let (bra, ket) = match flavor {
40 Closure => (T![|], T![|]),
41 FnDef | FnTrait | FnPointer => (T!['('], T![')']),
42 };
43
44 let m = p.start();
45 p.bump(bra);
46
47 if let FnDef = flavor {
48 // test self_param_outer_attr
49 // fn f(#[must_use] self) {}
50 attributes::outer_attrs(p);
51 opt_self_param(p);
52 }
53
54 while !p.at(EOF) && !p.at(ket) {
55 // test param_outer_arg
56 // fn f(#[attr1] pat: Type) {}
57 attributes::outer_attrs(p);
58
59 if !p.at_ts(PARAM_FIRST) {
60 p.error("expected value parameter");
61 break;
62 }
63 let param = param(p, flavor);
64 if !p.at(ket) {
65 p.expect(T![,]);
66 }
67 if let Variadic(true) = param {
68 break;
69 }
70 }
71
72 p.expect(ket);
73 m.complete(p, PARAM_LIST);
74}
75
76const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
77
78struct Variadic(bool);
79
80fn param(p: &mut Parser, flavor: Flavor) -> Variadic {
81 let mut res = Variadic(false);
82 let m = p.start();
83 match flavor {
84 // test param_list_vararg
85 // extern "C" { fn printf(format: *const i8, ...) -> i32; }
86 Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => res = Variadic(true),
87
88 // test fn_def_param
89 // fn foo((x, y): (i32, i32)) {}
90 Flavor::FnDef => {
91 patterns::pattern(p);
92 if variadic_param(p) {
93 res = Variadic(true)
94 } else {
95 types::ascription(p);
96 }
97 }
98 // test value_parameters_no_patterns
99 // type F = Box<Fn(i32, &i32, &i32, ())>;
100 Flavor::FnTrait => {
101 types::type_(p);
102 }
103 // test fn_pointer_param_ident_path
104 // type Foo = fn(Bar::Baz);
105 // type Qux = fn(baz: Bar::Baz);
106
107 // test fn_pointer_unnamed_arg
108 // type Foo = fn(_: bar);
109 Flavor::FnPointer => {
110 if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) {
111 patterns::pattern_single(p);
112 if variadic_param(p) {
113 res = Variadic(true)
114 } else {
115 types::ascription(p);
116 }
117 } else {
118 types::type_(p);
119 }
120 }
121 // test closure_params
122 // fn main() {
123 // let foo = |bar, baz: Baz, qux: Qux::Quux| ();
124 // }
125 Flavor::Closure => {
126 patterns::pattern_single(p);
127 if p.at(T![:]) && !p.at(T![::]) {
128 types::ascription(p);
129 }
130 }
131 }
132 m.complete(p, PARAM);
133 res
134}
135
136fn variadic_param(p: &mut Parser) -> bool {
137 if p.at(T![:]) && p.nth_at(1, T![...]) {
138 p.bump(T![:]);
139 p.bump(T![...]);
140 true
141 } else {
142 false
143 }
144}
145
146// test self_param
147// impl S {
148// fn a(self) {}
149// fn b(&self,) {}
150// fn c(&'a self,) {}
151// fn d(&'a mut self, x: i32) {}
152// fn e(mut self) {}
153// }
154fn opt_self_param(p: &mut Parser) {
155 let m;
156 if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
157 m = p.start();
158 p.eat(T![mut]);
159 p.eat(T![self]);
160 // test arb_self_types
161 // impl S {
162 // fn a(self: &Self) {}
163 // fn b(mut self: Box<Self>) {}
164 // }
165 if p.at(T![:]) {
166 types::ascription(p);
167 }
168 } else {
169 let la1 = p.nth(1);
170 let la2 = p.nth(2);
171 let la3 = p.nth(3);
172 let n_toks = match (p.current(), la1, la2, la3) {
173 (T![&], T![self], _, _) => 2,
174 (T![&], T![mut], T![self], _) => 3,
175 (T![&], LIFETIME, T![self], _) => 3,
176 (T![&], LIFETIME, T![mut], T![self]) => 4,
177 _ => return,
178 };
179 m = p.start();
180 for _ in 0..n_toks {
181 p.bump_any();
182 }
183 }
184 m.complete(p, SELF_PARAM);
185 if !p.at(T![')']) {
186 p.expect(T![,]);
187 }
188}
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
new file mode 100644
index 000000000..52562afa4
--- /dev/null
+++ b/crates/parser/src/grammar/paths.rs
@@ -0,0 +1,115 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const PATH_FIRST: TokenSet =
6 token_set![IDENT, T![self], T![super], T![crate], T![:], T![<]];
7
8pub(super) fn is_path_start(p: &Parser) -> bool {
9 is_use_path_start(p) || p.at(T![<])
10}
11
12pub(super) fn is_use_path_start(p: &Parser) -> bool {
13 match p.current() {
14 IDENT | T![self] | T![super] | T![crate] => true,
15 T![:] if p.at(T![::]) => true,
16 _ => false,
17 }
18}
19
20pub(super) fn use_path(p: &mut Parser) {
21 path(p, Mode::Use)
22}
23
24pub(crate) fn type_path(p: &mut Parser) {
25 path(p, Mode::Type)
26}
27
28pub(super) fn expr_path(p: &mut Parser) {
29 path(p, Mode::Expr)
30}
31
32#[derive(Clone, Copy, Eq, PartialEq)]
33enum Mode {
34 Use,
35 Type,
36 Expr,
37}
38
39fn path(p: &mut Parser, mode: Mode) {
40 let path = p.start();
41 path_segment(p, mode, true);
42 let mut qual = path.complete(p, PATH);
43 loop {
44 let use_tree = matches!(p.nth(2), T![*] | T!['{']);
45 if p.at(T![::]) && !use_tree {
46 let path = qual.precede(p);
47 p.bump(T![::]);
48 path_segment(p, mode, false);
49 let path = path.complete(p, PATH);
50 qual = path;
51 } else {
52 break;
53 }
54 }
55}
56
57fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
58 let m = p.start();
59 // test qual_paths
60 // type X = <A as B>::Output;
61 // fn foo() { <usize as Default>::default(); }
62 if first && p.eat(T![<]) {
63 types::type_(p);
64 if p.eat(T![as]) {
65 if is_use_path_start(p) {
66 types::path_type(p);
67 } else {
68 p.error("expected a trait");
69 }
70 }
71 p.expect(T![>]);
72 } else {
73 let mut empty = true;
74 if first {
75 p.eat(T![::]);
76 empty = false;
77 }
78 match p.current() {
79 IDENT => {
80 name_ref(p);
81 opt_path_type_args(p, mode);
82 }
83 // test crate_path
84 // use crate::foo;
85 T![self] | T![super] | T![crate] => p.bump_any(),
86 _ => {
87 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
88 if empty {
89 // test_err empty_segment
90 // use crate::;
91 m.abandon(p);
92 return;
93 }
94 }
95 };
96 }
97 m.complete(p, PATH_SEGMENT);
98}
99
100fn opt_path_type_args(p: &mut Parser, mode: Mode) {
101 match mode {
102 Mode::Use => {}
103 Mode::Type => {
104 // test path_fn_trait_args
105 // type F = Box<Fn(i32) -> ()>;
106 if p.at(T!['(']) {
107 params::param_list_fn_trait(p);
108 opt_ret_type(p);
109 } else {
110 type_args::opt_generic_arg_list(p, false)
111 }
112 }
113 Mode::Expr => type_args::opt_generic_arg_list(p, true),
114 }
115}
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs
new file mode 100644
index 000000000..07b1d6dd5
--- /dev/null
+++ b/crates/parser/src/grammar/patterns.rs
@@ -0,0 +1,379 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
6 .union(paths::PATH_FIRST)
7 .union(token_set![T![box], T![ref], T![mut], T!['('], T!['['], T![&], T![_], T![-], T![.]]);
8
9pub(crate) fn pattern(p: &mut Parser) {
10 pattern_r(p, PAT_RECOVERY_SET);
11}
12
13/// Parses a pattern list separated by pipes `|`
14pub(super) fn pattern_top(p: &mut Parser) {
15 pattern_top_r(p, PAT_RECOVERY_SET)
16}
17
18pub(crate) fn pattern_single(p: &mut Parser) {
19 pattern_single_r(p, PAT_RECOVERY_SET);
20}
21
22/// Parses a pattern list separated by pipes `|`
23/// using the given `recovery_set`
24pub(super) fn pattern_top_r(p: &mut Parser, recovery_set: TokenSet) {
25 p.eat(T![|]);
26 pattern_r(p, recovery_set);
27}
28
29/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
30/// given `recovery_set`
31// test or_pattern
32// fn main() {
33// match () {
34// (_ | _) => (),
35// &(_ | _) => (),
36// (_ | _,) => (),
37// [_ | _,] => (),
38// }
39// }
40fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
41 let m = p.start();
42 pattern_single_r(p, recovery_set);
43
44 if !p.at(T![|]) {
45 m.abandon(p);
46 return;
47 }
48 while p.eat(T![|]) {
49 pattern_single_r(p, recovery_set);
50 }
51 m.complete(p, OR_PAT);
52}
53
54fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) {
55 if let Some(lhs) = atom_pat(p, recovery_set) {
56 // test range_pat
57 // fn main() {
58 // match 92 {
59 // 0 ... 100 => (),
60 // 101 ..= 200 => (),
61 // 200 .. 301=> (),
62 // }
63 // }
64 for &range_op in [T![...], T![..=], T![..]].iter() {
65 if p.at(range_op) {
66 let m = lhs.precede(p);
67 p.bump(range_op);
68 atom_pat(p, recovery_set);
69 m.complete(p, RANGE_PAT);
70 return;
71 }
72 }
73 }
74}
75
76const PAT_RECOVERY_SET: TokenSet =
77 token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
78
79fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
80 let m = match p.nth(0) {
81 T![box] => box_pat(p),
82 T![ref] | T![mut] => ident_pat(p, true),
83 IDENT => match p.nth(1) {
84 // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
85 // (T![x]).
86 T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
87 T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
88 _ => ident_pat(p, true),
89 },
90
91 // test type_path_in_pattern
92 // fn main() { let <_>::Foo = (); }
93 _ if paths::is_path_start(p) => path_or_macro_pat(p),
94 _ if is_literal_pat_start(p) => literal_pat(p),
95
96 T![.] if p.at(T![..]) => rest_pat(p),
97 T![_] => wildcard_pat(p),
98 T![&] => ref_pat(p),
99 T!['('] => tuple_pat(p),
100 T!['['] => slice_pat(p),
101
102 _ => {
103 p.err_recover("expected pattern", recovery_set);
104 return None;
105 }
106 };
107
108 Some(m)
109}
110
111fn is_literal_pat_start(p: &Parser) -> bool {
112 p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
113 || p.at_ts(expressions::LITERAL_FIRST)
114}
115
116// test literal_pattern
117// fn main() {
118// match () {
119// -1 => (),
120// 92 => (),
121// 'c' => (),
122// "hello" => (),
123// }
124// }
125fn literal_pat(p: &mut Parser) -> CompletedMarker {
126 assert!(is_literal_pat_start(p));
127 let m = p.start();
128 if p.at(T![-]) {
129 p.bump(T![-]);
130 }
131 expressions::literal(p);
132 m.complete(p, LITERAL_PAT)
133}
134
135// test path_part
136// fn foo() {
137// let foo::Bar = ();
138// let ::Bar = ();
139// let Bar { .. } = ();
140// let Bar(..) = ();
141// }
142fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
143 assert!(paths::is_path_start(p));
144 let m = p.start();
145 paths::expr_path(p);
146 let kind = match p.current() {
147 T!['('] => {
148 tuple_pat_fields(p);
149 TUPLE_STRUCT_PAT
150 }
151 T!['{'] => {
152 record_pat_field_list(p);
153 RECORD_PAT
154 }
155 // test marco_pat
156 // fn main() {
157 // let m!(x) = 0;
158 // }
159 T![!] => {
160 items::macro_call_after_excl(p);
161 return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
162 }
163 _ => PATH_PAT,
164 };
165 m.complete(p, kind)
166}
167
168// test tuple_pat_fields
169// fn foo() {
170// let S() = ();
171// let S(_) = ();
172// let S(_,) = ();
173// let S(_, .. , x) = ();
174// }
175fn tuple_pat_fields(p: &mut Parser) {
176 assert!(p.at(T!['(']));
177 p.bump(T!['(']);
178 pat_list(p, T![')']);
179 p.expect(T![')']);
180}
181
182// test record_field_pat_list
183// fn foo() {
184// let S {} = ();
185// let S { f, ref mut g } = ();
186// let S { h: _, ..} = ();
187// let S { h: _, } = ();
188// }
189fn record_pat_field_list(p: &mut Parser) {
190 assert!(p.at(T!['{']));
191 let m = p.start();
192 p.bump(T!['{']);
193 while !p.at(EOF) && !p.at(T!['}']) {
194 match p.current() {
195 // A trailing `..` is *not* treated as a REST_PAT.
196 T![.] if p.at(T![..]) => p.bump(T![..]),
197 T!['{'] => error_block(p, "expected ident"),
198
199 c => {
200 let m = p.start();
201 match c {
202 // test record_field_pat
203 // fn foo() {
204 // let S { 0: 1 } = ();
205 // let S { x: 1 } = ();
206 // }
207 IDENT | INT_NUMBER if p.nth(1) == T![:] => {
208 name_ref_or_index(p);
209 p.bump(T![:]);
210 pattern(p);
211 }
212 T![box] => {
213 // FIXME: not all box patterns should be allowed
214 box_pat(p);
215 }
216 _ => {
217 ident_pat(p, false);
218 }
219 }
220 m.complete(p, RECORD_PAT_FIELD);
221 }
222 }
223 if !p.at(T!['}']) {
224 p.expect(T![,]);
225 }
226 }
227 p.expect(T!['}']);
228 m.complete(p, RECORD_PAT_FIELD_LIST);
229}
230
231// test placeholder_pat
232// fn main() { let _ = (); }
233fn wildcard_pat(p: &mut Parser) -> CompletedMarker {
234 assert!(p.at(T![_]));
235 let m = p.start();
236 p.bump(T![_]);
237 m.complete(p, WILDCARD_PAT)
238}
239
240// test dot_dot_pat
241// fn main() {
242// let .. = ();
243// //
244// // Tuples
245// //
246// let (a, ..) = ();
247// let (a, ..,) = ();
248// let Tuple(a, ..) = ();
249// let Tuple(a, ..,) = ();
250// let (.., ..) = ();
251// let Tuple(.., ..) = ();
252// let (.., a, ..) = ();
253// let Tuple(.., a, ..) = ();
254// //
255// // Slices
256// //
257// let [..] = ();
258// let [head, ..] = ();
259// let [head, tail @ ..] = ();
260// let [head, .., cons] = ();
261// let [head, mid @ .., cons] = ();
262// let [head, .., .., cons] = ();
263// let [head, .., mid, tail @ ..] = ();
264// let [head, .., mid, .., cons] = ();
265// }
266fn rest_pat(p: &mut Parser) -> CompletedMarker {
267 assert!(p.at(T![..]));
268 let m = p.start();
269 p.bump(T![..]);
270 m.complete(p, REST_PAT)
271}
272
273// test ref_pat
274// fn main() {
275// let &a = ();
276// let &mut b = ();
277// }
278fn ref_pat(p: &mut Parser) -> CompletedMarker {
279 assert!(p.at(T![&]));
280 let m = p.start();
281 p.bump(T![&]);
282 p.eat(T![mut]);
283 pattern_single(p);
284 m.complete(p, REF_PAT)
285}
286
287// test tuple_pat
288// fn main() {
289// let (a, b, ..) = ();
290// let (a,) = ();
291// let (..) = ();
292// let () = ();
293// }
294fn tuple_pat(p: &mut Parser) -> CompletedMarker {
295 assert!(p.at(T!['(']));
296 let m = p.start();
297 p.bump(T!['(']);
298 let mut has_comma = false;
299 let mut has_pat = false;
300 let mut has_rest = false;
301 while !p.at(EOF) && !p.at(T![')']) {
302 has_pat = true;
303 if !p.at_ts(PATTERN_FIRST) {
304 p.error("expected a pattern");
305 break;
306 }
307 has_rest |= p.at(T![..]);
308
309 pattern(p);
310 if !p.at(T![')']) {
311 has_comma = true;
312 p.expect(T![,]);
313 }
314 }
315 p.expect(T![')']);
316
317 m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
318}
319
320// test slice_pat
321// fn main() {
322// let [a, b, ..] = [];
323// }
324fn slice_pat(p: &mut Parser) -> CompletedMarker {
325 assert!(p.at(T!['[']));
326 let m = p.start();
327 p.bump(T!['[']);
328 pat_list(p, T![']']);
329 p.expect(T![']']);
330 m.complete(p, SLICE_PAT)
331}
332
333fn pat_list(p: &mut Parser, ket: SyntaxKind) {
334 while !p.at(EOF) && !p.at(ket) {
335 if !p.at_ts(PATTERN_FIRST) {
336 p.error("expected a pattern");
337 break;
338 }
339
340 pattern(p);
341 if !p.at(ket) {
342 p.expect(T![,]);
343 }
344 }
345}
346
347// test bind_pat
348// fn main() {
349// let a = ();
350// let mut b = ();
351// let ref c = ();
352// let ref mut d = ();
353// let e @ _ = ();
354// let ref mut f @ g @ _ = ();
355// }
356fn ident_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
357 let m = p.start();
358 p.eat(T![ref]);
359 p.eat(T![mut]);
360 name(p);
361 if with_at && p.eat(T![@]) {
362 pattern_single(p);
363 }
364 m.complete(p, IDENT_PAT)
365}
366
367// test box_pat
368// fn main() {
369// let box i = ();
370// let box Outer { box i, j: box Inner(box &x) } = ();
371// let box ref mut i = ();
372// }
373fn box_pat(p: &mut Parser) -> CompletedMarker {
374 assert!(p.at(T![box]));
375 let m = p.start();
376 p.bump(T![box]);
377 pattern_single(p);
378 m.complete(p, BOX_PAT)
379}
diff --git a/crates/parser/src/grammar/type_args.rs b/crates/parser/src/grammar/type_args.rs
new file mode 100644
index 000000000..f2d34a749
--- /dev/null
+++ b/crates/parser/src/grammar/type_args.rs
@@ -0,0 +1,63 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn opt_generic_arg_list(p: &mut Parser, colon_colon_required: bool) {
6 let m;
7 if p.at(T![::]) && p.nth(2) == T![<] {
8 m = p.start();
9 p.bump(T![::]);
10 p.bump(T![<]);
11 } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
12 m = p.start();
13 p.bump(T![<]);
14 } else {
15 return;
16 }
17
18 while !p.at(EOF) && !p.at(T![>]) {
19 generic_arg(p);
20 if !p.at(T![>]) && !p.expect(T![,]) {
21 break;
22 }
23 }
24 p.expect(T![>]);
25 m.complete(p, GENERIC_ARG_LIST);
26}
27
28// test type_arg
29// type A = B<'static, i32, 1, { 2 }, Item=u64>;
30fn generic_arg(p: &mut Parser) {
31 let m = p.start();
32 match p.current() {
33 LIFETIME => {
34 p.bump(LIFETIME);
35 m.complete(p, LIFETIME_ARG);
36 }
37 // test associated_type_bounds
38 // fn print_all<T: Iterator<Item: Display>>(printables: T) {}
39 IDENT if p.nth(1) == T![:] && p.nth(2) != T![:] => {
40 name_ref(p);
41 type_params::bounds(p);
42 m.complete(p, ASSOC_TYPE_ARG);
43 }
44 IDENT if p.nth(1) == T![=] => {
45 name_ref(p);
46 p.bump_any();
47 types::type_(p);
48 m.complete(p, ASSOC_TYPE_ARG);
49 }
50 T!['{'] => {
51 expressions::block_expr(p);
52 m.complete(p, CONST_ARG);
53 }
54 k if k.is_literal() => {
55 expressions::literal(p);
56 m.complete(p, CONST_ARG);
57 }
58 _ => {
59 types::type_(p);
60 m.complete(p, TYPE_ARG);
61 }
62 }
63}
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs
new file mode 100644
index 000000000..bc7d8d724
--- /dev/null
+++ b/crates/parser/src/grammar/type_params.rs
@@ -0,0 +1,209 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn opt_generic_param_list(p: &mut Parser) {
6 if !p.at(T![<]) {
7 return;
8 }
9 generic_param_list(p);
10}
11
12fn generic_param_list(p: &mut Parser) {
13 assert!(p.at(T![<]));
14 let m = p.start();
15 p.bump(T![<]);
16
17 while !p.at(EOF) && !p.at(T![>]) {
18 let m = p.start();
19
20 // test generic_lifetime_type_attribute
21 // fn foo<#[derive(Lifetime)] 'a, #[derive(Type)] T>(_: &'a T) {
22 // }
23 attributes::outer_attrs(p);
24
25 match p.current() {
26 LIFETIME => lifetime_param(p, m),
27 IDENT => type_param(p, m),
28 CONST_KW => const_param(p, m),
29 _ => {
30 m.abandon(p);
31 p.err_and_bump("expected type parameter")
32 }
33 }
34 if !p.at(T![>]) && !p.expect(T![,]) {
35 break;
36 }
37 }
38 p.expect(T![>]);
39 m.complete(p, GENERIC_PARAM_LIST);
40}
41
42fn lifetime_param(p: &mut Parser, m: Marker) {
43 assert!(p.at(LIFETIME));
44 p.bump(LIFETIME);
45 if p.at(T![:]) {
46 lifetime_bounds(p);
47 }
48 m.complete(p, LIFETIME_PARAM);
49}
50
51fn type_param(p: &mut Parser, m: Marker) {
52 assert!(p.at(IDENT));
53 name(p);
54 if p.at(T![:]) {
55 bounds(p);
56 }
57 // test type_param_default
58 // struct S<T = i32>;
59 if p.at(T![=]) {
60 p.bump(T![=]);
61 types::type_(p)
62 }
63 m.complete(p, TYPE_PARAM);
64}
65
66// test const_param
67// struct S<const N: u32>;
68fn const_param(p: &mut Parser, m: Marker) {
69 assert!(p.at(CONST_KW));
70 p.bump(T![const]);
71 name(p);
72 types::ascription(p);
73 m.complete(p, CONST_PARAM);
74}
75
76// test type_param_bounds
77// struct S<T: 'a + ?Sized + (Copy)>;
78pub(super) fn bounds(p: &mut Parser) {
79 assert!(p.at(T![:]));
80 p.bump(T![:]);
81 bounds_without_colon(p);
82}
83
84fn lifetime_bounds(p: &mut Parser) {
85 assert!(p.at(T![:]));
86 p.bump(T![:]);
87 while p.at(LIFETIME) {
88 p.bump(LIFETIME);
89 if !p.eat(T![+]) {
90 break;
91 }
92 }
93}
94
95pub(super) fn bounds_without_colon_m(p: &mut Parser, marker: Marker) -> CompletedMarker {
96 while type_bound(p) {
97 if !p.eat(T![+]) {
98 break;
99 }
100 }
101
102 marker.complete(p, TYPE_BOUND_LIST)
103}
104
105pub(super) fn bounds_without_colon(p: &mut Parser) {
106 let m = p.start();
107 bounds_without_colon_m(p, m);
108}
109
110fn type_bound(p: &mut Parser) -> bool {
111 let m = p.start();
112 let has_paren = p.eat(T!['(']);
113 p.eat(T![?]);
114 match p.current() {
115 LIFETIME => p.bump(LIFETIME),
116 T![for] => types::for_type(p),
117 _ if paths::is_use_path_start(p) => types::path_type_(p, false),
118 _ => {
119 m.abandon(p);
120 return false;
121 }
122 }
123 if has_paren {
124 p.expect(T![')']);
125 }
126 m.complete(p, TYPE_BOUND);
127
128 true
129}
130
131// test where_clause
132// fn foo()
133// where
134// 'a: 'b + 'c,
135// T: Clone + Copy + 'static,
136// Iterator::Item: 'a,
137// <T as Iterator>::Item: 'a
138// {}
139pub(super) fn opt_where_clause(p: &mut Parser) {
140 if !p.at(T![where]) {
141 return;
142 }
143 let m = p.start();
144 p.bump(T![where]);
145
146 while is_where_predicate(p) {
147 where_predicate(p);
148
149 let comma = p.eat(T![,]);
150
151 if is_where_clause_end(p) {
152 break;
153 }
154
155 if !comma {
156 p.error("expected comma");
157 }
158 }
159
160 m.complete(p, WHERE_CLAUSE);
161}
162
163fn is_where_predicate(p: &mut Parser) -> bool {
164 match p.current() {
165 LIFETIME => true,
166 T![impl] => false,
167 token => types::TYPE_FIRST.contains(token),
168 }
169}
170
171fn is_where_clause_end(p: &mut Parser) -> bool {
172 matches!(p.current(), T!['{'] | T![;] | T![=])
173}
174
175fn where_predicate(p: &mut Parser) {
176 let m = p.start();
177 match p.current() {
178 LIFETIME => {
179 p.bump(LIFETIME);
180 if p.at(T![:]) {
181 bounds(p);
182 } else {
183 p.error("expected colon");
184 }
185 }
186 T![impl] => {
187 p.error("expected lifetime or type");
188 }
189 _ => {
190 // test where_pred_for
191 // fn for_trait<F>()
192 // where
193 // for<'a> F: Fn(&'a str)
194 // { }
195 if p.at(T![for]) {
196 types::for_binder(p);
197 }
198
199 types::type_(p);
200
201 if p.at(T![:]) {
202 bounds(p);
203 } else {
204 p.error("expected colon");
205 }
206 }
207 }
208 m.complete(p, WHERE_PRED);
209}
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
new file mode 100644
index 000000000..c876545f4
--- /dev/null
+++ b/crates/parser/src/grammar/types.rs
@@ -0,0 +1,324 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
6 T!['('],
7 T!['['],
8 T![<],
9 T![!],
10 T![*],
11 T![&],
12 T![_],
13 T![fn],
14 T![unsafe],
15 T![extern],
16 T![for],
17 T![impl],
18 T![dyn],
19]);
20
21const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA, L_DOLLAR];
22
23pub(crate) fn type_(p: &mut Parser) {
24 type_with_bounds_cond(p, true);
25}
26
27pub(super) fn type_no_bounds(p: &mut Parser) {
28 type_with_bounds_cond(p, false);
29}
30
31fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
32 match p.current() {
33 T!['('] => paren_or_tuple_type(p),
34 T![!] => never_type(p),
35 T![*] => ptr_type(p),
36 T!['['] => array_or_slice_type(p),
37 T![&] => ref_type(p),
38 T![_] => infer_type(p),
39 T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p),
40 T![for] => for_type(p),
41 T![impl] => impl_trait_type(p),
42 T![dyn] => dyn_trait_type(p),
43 // Some path types are not allowed to have bounds (no plus)
44 T![<] => path_type_(p, allow_bounds),
45 _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds),
46 _ => {
47 p.err_recover("expected type", TYPE_RECOVERY_SET);
48 }
49 }
50}
51
52pub(super) fn ascription(p: &mut Parser) {
53 p.expect(T![:]);
54 type_(p)
55}
56
57fn paren_or_tuple_type(p: &mut Parser) {
58 assert!(p.at(T!['(']));
59 let m = p.start();
60 p.bump(T!['(']);
61 let mut n_types: u32 = 0;
62 let mut trailing_comma: bool = false;
63 while !p.at(EOF) && !p.at(T![')']) {
64 n_types += 1;
65 type_(p);
66 if p.eat(T![,]) {
67 trailing_comma = true;
68 } else {
69 trailing_comma = false;
70 break;
71 }
72 }
73 p.expect(T![')']);
74
75 let kind = if n_types == 1 && !trailing_comma {
76 // test paren_type
77 // type T = (i32);
78 PAREN_TYPE
79 } else {
80 // test unit_type
81 // type T = ();
82
83 // test singleton_tuple_type
84 // type T = (i32,);
85 TUPLE_TYPE
86 };
87 m.complete(p, kind);
88}
89
90// test never_type
91// type Never = !;
92fn never_type(p: &mut Parser) {
93 assert!(p.at(T![!]));
94 let m = p.start();
95 p.bump(T![!]);
96 m.complete(p, NEVER_TYPE);
97}
98
99fn ptr_type(p: &mut Parser) {
100 assert!(p.at(T![*]));
101 let m = p.start();
102 p.bump(T![*]);
103
104 match p.current() {
105 // test pointer_type_mut
106 // type M = *mut ();
107 // type C = *mut ();
108 T![mut] | T![const] => p.bump_any(),
109 _ => {
110 // test_err pointer_type_no_mutability
111 // type T = *();
112 p.error(
113 "expected mut or const in raw pointer type \
114 (use `*mut T` or `*const T` as appropriate)",
115 );
116 }
117 };
118
119 type_no_bounds(p);
120 m.complete(p, PTR_TYPE);
121}
122
123fn array_or_slice_type(p: &mut Parser) {
124 assert!(p.at(T!['[']));
125 let m = p.start();
126 p.bump(T!['[']);
127
128 type_(p);
129 let kind = match p.current() {
130 // test slice_type
131 // type T = [()];
132 T![']'] => {
133 p.bump(T![']']);
134 SLICE_TYPE
135 }
136
137 // test array_type
138 // type T = [(); 92];
139 T![;] => {
140 p.bump(T![;]);
141 expressions::expr(p);
142 p.expect(T![']']);
143 ARRAY_TYPE
144 }
145 // test_err array_type_missing_semi
146 // type T = [() 92];
147 _ => {
148 p.error("expected `;` or `]`");
149 SLICE_TYPE
150 }
151 };
152 m.complete(p, kind);
153}
154
155// test reference_type;
156// type A = &();
157// type B = &'static ();
158// type C = &mut ();
159fn ref_type(p: &mut Parser) {
160 assert!(p.at(T![&]));
161 let m = p.start();
162 p.bump(T![&]);
163 p.eat(LIFETIME);
164 p.eat(T![mut]);
165 type_no_bounds(p);
166 m.complete(p, REF_TYPE);
167}
168
169// test placeholder_type
170// type Placeholder = _;
171fn infer_type(p: &mut Parser) {
172 assert!(p.at(T![_]));
173 let m = p.start();
174 p.bump(T![_]);
175 m.complete(p, INFER_TYPE);
176}
177
178// test fn_pointer_type
179// type A = fn();
180// type B = unsafe fn();
181// type C = unsafe extern "C" fn();
182// type D = extern "C" fn ( u8 , ... ) -> u8;
183fn fn_ptr_type(p: &mut Parser) {
184 let m = p.start();
185 p.eat(T![unsafe]);
186 if p.at(T![extern]) {
187 abi(p);
188 }
189 // test_err fn_pointer_type_missing_fn
190 // type F = unsafe ();
191 if !p.eat(T![fn]) {
192 m.abandon(p);
193 p.error("expected `fn`");
194 return;
195 }
196 if p.at(T!['(']) {
197 params::param_list_fn_ptr(p);
198 } else {
199 p.error("expected parameters")
200 }
201 // test fn_pointer_type_with_ret
202 // type F = fn() -> ();
203 opt_ret_type(p);
204 m.complete(p, FN_PTR_TYPE);
205}
206
207pub(super) fn for_binder(p: &mut Parser) {
208 assert!(p.at(T![for]));
209 p.bump(T![for]);
210 if p.at(T![<]) {
211 type_params::opt_generic_param_list(p);
212 } else {
213 p.error("expected `<`");
214 }
215}
216
217// test for_type
218// type A = for<'a> fn() -> ();
219// type B = for<'a> unsafe extern "C" fn(&'a ()) -> ();
220// type Obj = for<'a> PartialEq<&'a i32>;
221pub(super) fn for_type(p: &mut Parser) {
222 assert!(p.at(T![for]));
223 let m = p.start();
224 for_binder(p);
225 match p.current() {
226 T![fn] | T![unsafe] | T![extern] => {}
227 // OK: legacy trait object format
228 _ if paths::is_use_path_start(p) => {}
229 _ => {
230 p.error("expected a function pointer or path");
231 }
232 }
233 type_no_bounds(p);
234 m.complete(p, FOR_TYPE);
235}
236
237// test impl_trait_type
238// type A = impl Iterator<Item=Foo<'a>> + 'a;
239fn impl_trait_type(p: &mut Parser) {
240 assert!(p.at(T![impl]));
241 let m = p.start();
242 p.bump(T![impl]);
243 type_params::bounds_without_colon(p);
244 m.complete(p, IMPL_TRAIT_TYPE);
245}
246
247// test dyn_trait_type
248// type A = dyn Iterator<Item=Foo<'a>> + 'a;
249fn dyn_trait_type(p: &mut Parser) {
250 assert!(p.at(T![dyn]));
251 let m = p.start();
252 p.bump(T![dyn]);
253 type_params::bounds_without_colon(p);
254 m.complete(p, DYN_TRAIT_TYPE);
255}
256
257// test path_type
258// type A = Foo;
259// type B = ::Foo;
260// type C = self::Foo;
261// type D = super::Foo;
262pub(super) fn path_type(p: &mut Parser) {
263 path_type_(p, true)
264}
265
266// test macro_call_type
267// type A = foo!();
268// type B = crate::foo!();
269fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
270 assert!(paths::is_path_start(p));
271 let m = p.start();
272 paths::type_path(p);
273
274 let kind = if p.at(T![!]) && !p.at(T![!=]) {
275 items::macro_call_after_excl(p);
276 MACRO_CALL
277 } else {
278 PATH_TYPE
279 };
280
281 let path = m.complete(p, kind);
282
283 if allow_bounds {
284 opt_path_type_bounds_as_dyn_trait_type(p, path);
285 }
286}
287
288pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
289 assert!(paths::is_path_start(p));
290 let m = p.start();
291 paths::type_path(p);
292
293 // test path_type_with_bounds
294 // fn foo() -> Box<T + 'f> {}
295 // fn foo() -> Box<dyn T + 'f> {}
296 let path = m.complete(p, PATH_TYPE);
297 if allow_bounds {
298 opt_path_type_bounds_as_dyn_trait_type(p, path);
299 }
300}
301
302/// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE
303/// with a TYPE_BOUND_LIST
304fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) {
305 if !p.at(T![+]) {
306 return;
307 }
308
309 // First create a TYPE_BOUND from the completed PATH_TYPE
310 let m = path_type_marker.precede(p).complete(p, TYPE_BOUND);
311
312 // Next setup a marker for the TYPE_BOUND_LIST
313 let m = m.precede(p);
314
315 // This gets consumed here so it gets properly set
316 // in the TYPE_BOUND_LIST
317 p.eat(T![+]);
318
319 // Parse rest of the bounds into the TYPE_BOUND_LIST
320 let m = type_params::bounds_without_colon_m(p, m);
321
322 // Finally precede everything with DYN_TRAIT_TYPE
323 m.precede(p).complete(p, DYN_TRAIT_TYPE);
324}