aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser/src/grammar
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_parser/src/grammar')
-rw-r--r--crates/ra_parser/src/grammar/attributes.rs31
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs473
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs475
-rw-r--r--crates/ra_parser/src/grammar/items.rs392
-rw-r--r--crates/ra_parser/src/grammar/items/consts.rs21
-rw-r--r--crates/ra_parser/src/grammar/items/nominal.rs168
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs137
-rw-r--r--crates/ra_parser/src/grammar/items/use_item.rs121
-rw-r--r--crates/ra_parser/src/grammar/params.rs139
-rw-r--r--crates/ra_parser/src/grammar/paths.rs103
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs248
-rw-r--r--crates/ra_parser/src/grammar/type_args.rs48
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs175
-rw-r--r--crates/ra_parser/src/grammar/types.rs278
14 files changed, 2809 insertions, 0 deletions
diff --git a/crates/ra_parser/src/grammar/attributes.rs b/crates/ra_parser/src/grammar/attributes.rs
new file mode 100644
index 000000000..cd30e8a45
--- /dev/null
+++ b/crates/ra_parser/src/grammar/attributes.rs
@@ -0,0 +1,31 @@
1use super::*;
2
3pub(super) fn inner_attributes(p: &mut Parser) {
4 while p.current() == POUND && p.nth(1) == EXCL {
5 attribute(p, true)
6 }
7}
8
9pub(super) fn outer_attributes(p: &mut Parser) {
10 while p.at(POUND) {
11 attribute(p, false)
12 }
13}
14
15fn attribute(p: &mut Parser, inner: bool) {
16 let attr = p.start();
17 assert!(p.at(POUND));
18 p.bump();
19
20 if inner {
21 assert!(p.at(EXCL));
22 p.bump();
23 }
24
25 if p.at(L_BRACK) {
26 items::token_tree(p);
27 } else {
28 p.error("expected `[`");
29 }
30 attr.complete(p, ATTR);
31}
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
new file mode 100644
index 000000000..d5a4f4d7b
--- /dev/null
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -0,0 +1,473 @@
1mod atom;
2
3pub(crate) use self::atom::match_arm_list;
4pub(super) use self::atom::{literal, LITERAL_FIRST};
5use super::*;
6
7const EXPR_FIRST: TokenSet = LHS_FIRST;
8
9pub(super) fn expr(p: &mut Parser) -> BlockLike {
10 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
11 expr_bp(p, r, 1)
12}
13
14pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
15 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
16 expr_bp(p, r, 1)
17}
18
19fn expr_no_struct(p: &mut Parser) {
20 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
21 expr_bp(p, r, 1);
22}
23
24// test block
25// fn a() {}
26// fn b() { let _ = 1; }
27// fn c() { 1; 2; }
28// fn d() { 1; 2 }
29pub(crate) fn block(p: &mut Parser) {
30 if !p.at(L_CURLY) {
31 p.error("expected a block");
32 return;
33 }
34 let m = p.start();
35 p.bump();
36 // This is checked by a validator
37 attributes::inner_attributes(p);
38
39 while !p.at(EOF) && !p.at(R_CURLY) {
40 match p.current() {
41 // test nocontentexpr
42 // fn foo(){
43 // ;;;some_expr();;;;{;;;};;;;Ok(())
44 // }
45 SEMI => p.bump(),
46 _ => {
47 // test block_items
48 // fn a() { fn b() {} }
49 let m = p.start();
50 let has_attrs = p.at(POUND);
51 attributes::outer_attributes(p);
52 if p.at(LET_KW) {
53 let_stmt(p, m);
54 } else {
55 match items::maybe_item(p, items::ItemFlavor::Mod) {
56 items::MaybeItem::Item(kind) => {
57 m.complete(p, kind);
58 }
59 items::MaybeItem::Modifiers => {
60 m.abandon(p);
61 p.error("expected an item");
62 }
63 // test pub_expr
64 // fn foo() { pub 92; } //FIXME
65 items::MaybeItem::None => {
66 if has_attrs {
67 m.abandon(p);
68 p.error(
69 "expected a let statement or an item after attributes in block",
70 );
71 } else {
72 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block;
73 if p.at(R_CURLY) {
74 m.abandon(p);
75 } else {
76 // test no_semi_after_block
77 // fn foo() {
78 // if true {}
79 // loop {}
80 // match () {}
81 // while true {}
82 // for _ in () {}
83 // {}
84 // {}
85 // macro_rules! test {
86 // () => {}
87 // }
88 // test!{}
89 // }
90 if is_blocklike {
91 p.eat(SEMI);
92 } else {
93 p.expect(SEMI);
94 }
95 m.complete(p, EXPR_STMT);
96 }
97 }
98 }
99 }
100 }
101 }
102 }
103 }
104 p.expect(R_CURLY);
105 m.complete(p, BLOCK);
106
107 // test let_stmt;
108 // fn foo() {
109 // let a;
110 // let b: i32;
111 // let c = 92;
112 // let d: i32 = 92;
113 // }
114 fn let_stmt(p: &mut Parser, m: Marker) {
115 assert!(p.at(LET_KW));
116 p.bump();
117 patterns::pattern(p);
118 if p.at(COLON) {
119 types::ascription(p);
120 }
121 if p.eat(EQ) {
122 expressions::expr(p);
123 }
124 p.expect(SEMI);
125 m.complete(p, LET_STMT);
126 }
127}
128
129#[derive(Clone, Copy)]
130struct Restrictions {
131 forbid_structs: bool,
132 prefer_stmt: bool,
133}
134
135enum Op {
136 Simple,
137 Composite(SyntaxKind, u8),
138}
139
140fn current_op(p: &Parser) -> (u8, Op) {
141 if let Some(t) = p.current3() {
142 match t {
143 (L_ANGLE, L_ANGLE, EQ) => return (1, Op::Composite(SHLEQ, 3)),
144 (R_ANGLE, R_ANGLE, EQ) => return (1, Op::Composite(SHREQ, 3)),
145 _ => (),
146 }
147 }
148
149 if let Some(t) = p.current2() {
150 match t {
151 (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)),
152 (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)),
153 (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)),
154 (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)),
155 (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)),
156 (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)),
157 (CARET, EQ) => return (1, Op::Composite(CARETEQ, 2)),
158 (PIPE, PIPE) => return (3, Op::Composite(PIPEPIPE, 2)),
159 (AMP, AMP) => return (4, Op::Composite(AMPAMP, 2)),
160 (L_ANGLE, EQ) => return (5, Op::Composite(LTEQ, 2)),
161 (R_ANGLE, EQ) => return (5, Op::Composite(GTEQ, 2)),
162 (L_ANGLE, L_ANGLE) => return (9, Op::Composite(SHL, 2)),
163 (R_ANGLE, R_ANGLE) => return (9, Op::Composite(SHR, 2)),
164 _ => (),
165 }
166 }
167
168 let bp = match p.current() {
169 EQ => 1,
170 DOTDOT | DOTDOTEQ => 2,
171 EQEQ | NEQ | L_ANGLE | R_ANGLE => 5,
172 PIPE => 6,
173 CARET => 7,
174 AMP => 8,
175 MINUS | PLUS => 10,
176 STAR | SLASH | PERCENT => 11,
177 _ => 0,
178 };
179 (bp, Op::Simple)
180}
181
182// Parses expression with binding power of at least bp.
183fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
184 let mut lhs = match lhs(p, r) {
185 Some((lhs, blocklike)) => {
186 // test stmt_bin_expr_ambiguity
187 // fn foo() {
188 // let _ = {1} & 2;
189 // {1} &2;
190 // }
191 if r.prefer_stmt && blocklike.is_block() {
192 return BlockLike::Block;
193 }
194 lhs
195 }
196 None => return BlockLike::NotBlock,
197 };
198
199 loop {
200 let is_range = p.current() == DOTDOT || p.current() == DOTDOTEQ;
201 let (op_bp, op) = current_op(p);
202 if op_bp < bp {
203 break;
204 }
205 let m = lhs.precede(p);
206 match op {
207 Op::Simple => p.bump(),
208 Op::Composite(kind, n) => {
209 p.bump_compound(kind, n);
210 }
211 }
212 expr_bp(p, r, op_bp + 1);
213 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
214 }
215 BlockLike::NotBlock
216}
217
218const LHS_FIRST: TokenSet =
219 atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOTDOT, DOTDOTEQ, MINUS]);
220
221fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
222 let m;
223 let kind = match p.current() {
224 // test ref_expr
225 // fn foo() {
226 // let _ = &1;
227 // let _ = &mut &f();
228 // }
229 AMP => {
230 m = p.start();
231 p.bump();
232 p.eat(MUT_KW);
233 REF_EXPR
234 }
235 // test unary_expr
236 // fn foo() {
237 // **&1;
238 // !!true;
239 // --1;
240 // }
241 STAR | EXCL | MINUS => {
242 m = p.start();
243 p.bump();
244 PREFIX_EXPR
245 }
246 // test full_range_expr
247 // fn foo() { xs[..]; }
248 DOTDOT | DOTDOTEQ => {
249 m = p.start();
250 p.bump();
251 if p.at_ts(EXPR_FIRST) {
252 expr_bp(p, r, 2);
253 }
254 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
255 }
256 _ => {
257 let (lhs, blocklike) = atom::atom_expr(p, r)?;
258 return Some((
259 postfix_expr(p, lhs, !(r.prefer_stmt && blocklike.is_block())),
260 blocklike,
261 ));
262 }
263 };
264 expr_bp(p, r, 255);
265 Some((m.complete(p, kind), BlockLike::NotBlock))
266}
267
268fn postfix_expr(
269 p: &mut Parser,
270 mut lhs: CompletedMarker,
271 // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
272 // E.g. `while true {break}();` is parsed as
273 // `while true {break}; ();`
274 mut allow_calls: bool,
275) -> CompletedMarker {
276 loop {
277 lhs = match p.current() {
278 // test stmt_postfix_expr_ambiguity
279 // fn foo() {
280 // match () {
281 // _ => {}
282 // () => {}
283 // [] => {}
284 // }
285 // }
286 L_PAREN if allow_calls => call_expr(p, lhs),
287 L_BRACK if allow_calls => index_expr(p, lhs),
288 DOT if p.nth(1) == IDENT && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON) => {
289 method_call_expr(p, lhs)
290 }
291 DOT => field_expr(p, lhs),
292 // test postfix_range
293 // fn foo() { let x = 1..; }
294 DOTDOT | DOTDOTEQ if !EXPR_FIRST.contains(p.nth(1)) => {
295 let m = lhs.precede(p);
296 p.bump();
297 m.complete(p, RANGE_EXPR)
298 }
299 QUESTION => try_expr(p, lhs),
300 AS_KW => cast_expr(p, lhs),
301 _ => break,
302 };
303 allow_calls = true
304 }
305 lhs
306}
307
308// test call_expr
309// fn foo() {
310// let _ = f();
311// let _ = f()(1)(1, 2,);
312// let _ = f(<Foo>::func());
313// f(<Foo as Trait>::func());
314// }
315fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
316 assert!(p.at(L_PAREN));
317 let m = lhs.precede(p);
318 arg_list(p);
319 m.complete(p, CALL_EXPR)
320}
321
322// test index_expr
323// fn foo() {
324// x[1][2];
325// }
326fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
327 assert!(p.at(L_BRACK));
328 let m = lhs.precede(p);
329 p.bump();
330 expr(p);
331 p.expect(R_BRACK);
332 m.complete(p, INDEX_EXPR)
333}
334
335// test method_call_expr
336// fn foo() {
337// x.foo();
338// y.bar::<T>(1, 2,);
339// }
340fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
341 assert!(p.at(DOT) && p.nth(1) == IDENT && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON));
342 let m = lhs.precede(p);
343 p.bump();
344 name_ref(p);
345 type_args::opt_type_arg_list(p, true);
346 if p.at(L_PAREN) {
347 arg_list(p);
348 }
349 m.complete(p, METHOD_CALL_EXPR)
350}
351
352// test field_expr
353// fn foo() {
354// x.foo;
355// x.0.bar;
356// }
357fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
358 assert!(p.at(DOT));
359 let m = lhs.precede(p);
360 p.bump();
361 if p.at(IDENT) {
362 name_ref(p)
363 } else if p.at(INT_NUMBER) {
364 p.bump()
365 } else {
366 p.error("expected field name or number")
367 }
368 m.complete(p, FIELD_EXPR)
369}
370
371// test try_expr
372// fn foo() {
373// x?;
374// }
375fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
376 assert!(p.at(QUESTION));
377 let m = lhs.precede(p);
378 p.bump();
379 m.complete(p, TRY_EXPR)
380}
381
382// test cast_expr
383// fn foo() {
384// 82 as i32;
385// 81 as i8 + 1;
386// 79 as i16 - 1;
387// }
388fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
389 assert!(p.at(AS_KW));
390 let m = lhs.precede(p);
391 p.bump();
392 // Use type_no_bounds(), because cast expressions are not
393 // allowed to have bounds.
394 types::type_no_bounds(p);
395 m.complete(p, CAST_EXPR)
396}
397
398fn arg_list(p: &mut Parser) {
399 assert!(p.at(L_PAREN));
400 let m = p.start();
401 p.bump();
402 while !p.at(R_PAREN) && !p.at(EOF) {
403 if !p.at_ts(EXPR_FIRST) {
404 p.error("expected expression");
405 break;
406 }
407 expr(p);
408 if !p.at(R_PAREN) && !p.expect(COMMA) {
409 break;
410 }
411 }
412 p.eat(R_PAREN);
413 m.complete(p, ARG_LIST);
414}
415
416// test path_expr
417// fn foo() {
418// let _ = a;
419// let _ = a::b;
420// let _ = ::a::<b>;
421// let _ = format!();
422// }
423fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
424 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
425 let m = p.start();
426 paths::expr_path(p);
427 match p.current() {
428 L_CURLY if !r.forbid_structs => {
429 named_field_list(p);
430 (m.complete(p, STRUCT_LIT), BlockLike::NotBlock)
431 }
432 EXCL => {
433 let block_like = items::macro_call_after_excl(p);
434 return (m.complete(p, MACRO_CALL), block_like);
435 }
436 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
437 }
438}
439
440// test struct_lit
441// fn foo() {
442// S {};
443// S { x, y: 32, };
444// S { x, y: 32, ..Default::default() };
445// }
446pub(crate) fn named_field_list(p: &mut Parser) {
447 assert!(p.at(L_CURLY));
448 let m = p.start();
449 p.bump();
450 while !p.at(EOF) && !p.at(R_CURLY) {
451 match p.current() {
452 IDENT => {
453 let m = p.start();
454 name_ref(p);
455 if p.eat(COLON) {
456 expr(p);
457 }
458 m.complete(p, NAMED_FIELD);
459 }
460 DOTDOT => {
461 p.bump();
462 expr(p);
463 }
464 L_CURLY => error_block(p, "expected a field"),
465 _ => p.err_and_bump("expected identifier"),
466 }
467 if !p.at(R_CURLY) {
468 p.expect(COMMA);
469 }
470 }
471 p.expect(R_CURLY);
472 m.complete(p, NAMED_FIELD_LIST);
473}
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..e74305b6a
--- /dev/null
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -0,0 +1,475 @@
1use super::*;
2
3// test expr_literals
4// fn foo() {
5// let _ = true;
6// let _ = false;
7// let _ = 1;
8// let _ = 2.0;
9// let _ = b'a';
10// let _ = 'b';
11// let _ = "c";
12// let _ = r"d";
13// let _ = b"e";
14// let _ = br"f";
15// }
16pub(crate) const LITERAL_FIRST: TokenSet = token_set![
17 TRUE_KW,
18 FALSE_KW,
19 INT_NUMBER,
20 FLOAT_NUMBER,
21 BYTE,
22 CHAR,
23 STRING,
24 RAW_STRING,
25 BYTE_STRING,
26 RAW_BYTE_STRING
27];
28
29pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
30 if !p.at_ts(LITERAL_FIRST) {
31 return None;
32 }
33 let m = p.start();
34 p.bump();
35 Some(m.complete(p, LITERAL))
36}
37
38// E.g. for after the break in `if break {}`, this should not match
39pub(super) const ATOM_EXPR_FIRST: TokenSet =
40 LITERAL_FIRST.union(paths::PATH_FIRST).union(token_set![
41 L_PAREN,
42 L_CURLY,
43 L_BRACK,
44 PIPE,
45 MOVE_KW,
46 IF_KW,
47 WHILE_KW,
48 MATCH_KW,
49 UNSAFE_KW,
50 RETURN_KW,
51 BREAK_KW,
52 CONTINUE_KW,
53 LIFETIME,
54 ]);
55
56const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
57
58pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
59 if let Some(m) = literal(p) {
60 return Some((m, BlockLike::NotBlock));
61 }
62 if paths::is_path_start(p) || p.at(L_ANGLE) {
63 return Some(path_expr(p, r));
64 }
65 let la = p.nth(1);
66 let done = match p.current() {
67 L_PAREN => tuple_expr(p),
68 L_BRACK => array_expr(p),
69 PIPE => lambda_expr(p),
70 MOVE_KW if la == PIPE => lambda_expr(p),
71 IF_KW => if_expr(p),
72
73 LOOP_KW => loop_expr(p, None),
74 FOR_KW => for_expr(p, None),
75 WHILE_KW => while_expr(p, None),
76 LIFETIME if la == COLON => {
77 let m = p.start();
78 label(p);
79 match p.current() {
80 LOOP_KW => loop_expr(p, Some(m)),
81 FOR_KW => for_expr(p, Some(m)),
82 WHILE_KW => while_expr(p, Some(m)),
83 L_CURLY => block_expr(p, Some(m)),
84 _ => {
85 // test_err misplaced_label_err
86 // fn main() {
87 // 'loop: impl
88 // }
89 p.error("expected a loop");
90 m.complete(p, ERROR);
91 return None;
92 }
93 }
94 }
95
96 MATCH_KW => match_expr(p),
97 UNSAFE_KW if la == L_CURLY => {
98 let m = p.start();
99 p.bump();
100 block_expr(p, Some(m))
101 }
102 L_CURLY => block_expr(p, None),
103 RETURN_KW => return_expr(p),
104 CONTINUE_KW => continue_expr(p),
105 BREAK_KW => break_expr(p, r),
106 _ => {
107 p.err_recover("expected expression", EXPR_RECOVERY_SET);
108 return None;
109 }
110 };
111 let blocklike = match done.kind() {
112 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
113 _ => BlockLike::NotBlock,
114 };
115 Some((done, blocklike))
116}
117
118// test tuple_expr
119// fn foo() {
120// ();
121// (1);
122// (1,);
123// }
124fn tuple_expr(p: &mut Parser) -> CompletedMarker {
125 assert!(p.at(L_PAREN));
126 let m = p.start();
127 p.expect(L_PAREN);
128
129 let mut saw_comma = false;
130 let mut saw_expr = false;
131 while !p.at(EOF) && !p.at(R_PAREN) {
132 saw_expr = true;
133 if !p.at_ts(EXPR_FIRST) {
134 p.error("expected expression");
135 break;
136 }
137 expr(p);
138 if !p.at(R_PAREN) {
139 saw_comma = true;
140 p.expect(COMMA);
141 }
142 }
143 p.expect(R_PAREN);
144 m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
145}
146
147// test array_expr
148// fn foo() {
149// [];
150// [1];
151// [1, 2,];
152// [1; 2];
153// }
154fn array_expr(p: &mut Parser) -> CompletedMarker {
155 assert!(p.at(L_BRACK));
156 let m = p.start();
157 p.bump();
158 if p.eat(R_BRACK) {
159 return m.complete(p, ARRAY_EXPR);
160 }
161 expr(p);
162 if p.eat(SEMI) {
163 expr(p);
164 p.expect(R_BRACK);
165 return m.complete(p, ARRAY_EXPR);
166 }
167 while !p.at(EOF) && !p.at(R_BRACK) {
168 p.expect(COMMA);
169 if p.at(R_BRACK) {
170 break;
171 }
172 if !p.at_ts(EXPR_FIRST) {
173 p.error("expected expression");
174 break;
175 }
176 expr(p);
177 }
178 p.expect(R_BRACK);
179 m.complete(p, ARRAY_EXPR)
180}
181
182// test lambda_expr
183// fn foo() {
184// || ();
185// || -> i32 { 92 };
186// |x| x;
187// move |x: i32,| x;
188// }
189fn lambda_expr(p: &mut Parser) -> CompletedMarker {
190 assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
191 let m = p.start();
192 p.eat(MOVE_KW);
193 params::param_list_opt_types(p);
194 if opt_fn_ret_type(p) {
195 if !p.at(L_CURLY) {
196 p.error("expected `{`");
197 }
198 }
199 expr(p);
200 m.complete(p, LAMBDA_EXPR)
201}
202
203// test if_expr
204// fn foo() {
205// if true {};
206// if true {} else {};
207// if true {} else if false {} else {};
208// if S {};
209// }
210fn if_expr(p: &mut Parser) -> CompletedMarker {
211 assert!(p.at(IF_KW));
212 let m = p.start();
213 p.bump();
214 cond(p);
215 block(p);
216 if p.at(ELSE_KW) {
217 p.bump();
218 if p.at(IF_KW) {
219 if_expr(p);
220 } else {
221 block(p);
222 }
223 }
224 m.complete(p, IF_EXPR)
225}
226
227// test label
228// fn foo() {
229// 'a: loop {}
230// 'b: while true {}
231// 'c: for x in () {}
232// }
233fn label(p: &mut Parser) {
234 assert!(p.at(LIFETIME) && p.nth(1) == COLON);
235 let m = p.start();
236 p.bump();
237 p.bump();
238 m.complete(p, LABEL);
239}
240
241// test loop_expr
242// fn foo() {
243// loop {};
244// }
245fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
246 assert!(p.at(LOOP_KW));
247 let m = m.unwrap_or_else(|| p.start());
248 p.bump();
249 block(p);
250 m.complete(p, LOOP_EXPR)
251}
252
253// test while_expr
254// fn foo() {
255// while true {};
256// while let Some(x) = it.next() {};
257// }
258fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
259 assert!(p.at(WHILE_KW));
260 let m = m.unwrap_or_else(|| p.start());
261 p.bump();
262 cond(p);
263 block(p);
264 m.complete(p, WHILE_EXPR)
265}
266
267// test for_expr
268// fn foo() {
269// for x in [] {};
270// }
271fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
272 assert!(p.at(FOR_KW));
273 let m = m.unwrap_or_else(|| p.start());
274 p.bump();
275 patterns::pattern(p);
276 p.expect(IN_KW);
277 expr_no_struct(p);
278 block(p);
279 m.complete(p, FOR_EXPR)
280}
281
282// test cond
283// fn foo() { if let Some(_) = None {} }
284fn cond(p: &mut Parser) {
285 let m = p.start();
286 if p.eat(LET_KW) {
287 patterns::pattern(p);
288 p.expect(EQ);
289 }
290 expr_no_struct(p);
291 m.complete(p, CONDITION);
292}
293
294// test match_expr
295// fn foo() {
296// match () { };
297// match S {};
298// }
299fn match_expr(p: &mut Parser) -> CompletedMarker {
300 assert!(p.at(MATCH_KW));
301 let m = p.start();
302 p.bump();
303 expr_no_struct(p);
304 if p.at(L_CURLY) {
305 match_arm_list(p);
306 } else {
307 p.error("expected `{`")
308 }
309 m.complete(p, MATCH_EXPR)
310}
311
312pub(crate) fn match_arm_list(p: &mut Parser) {
313 assert!(p.at(L_CURLY));
314 let m = p.start();
315 p.eat(L_CURLY);
316
317 // test match_arms_inner_attribute
318 // fn foo() {
319 // match () {
320 // #![doc("Inner attribute")]
321 // #![doc("Can be")]
322 // #![doc("Stacked")]
323 // _ => (),
324 // }
325 // }
326 attributes::inner_attributes(p);
327
328 while !p.at(EOF) && !p.at(R_CURLY) {
329 if p.at(L_CURLY) {
330 error_block(p, "expected match arm");
331 continue;
332 }
333
334 // test match_arms_outer_attributes
335 // fn foo() {
336 // match () {
337 // #[cfg(feature = "some")]
338 // _ => (),
339 // #[cfg(feature = "other")]
340 // _ => (),
341 // #[cfg(feature = "many")]
342 // #[cfg(feature = "attributes")]
343 // #[cfg(feature = "before")]
344 // _ => (),
345 // }
346 // }
347 attributes::outer_attributes(p);
348
349 // test match_arms_commas
350 // fn foo() {
351 // match () {
352 // _ => (),
353 // _ => {}
354 // _ => ()
355 // }
356 // }
357 if match_arm(p).is_block() {
358 p.eat(COMMA);
359 } else if !p.at(R_CURLY) {
360 p.expect(COMMA);
361 }
362 }
363 p.expect(R_CURLY);
364 m.complete(p, MATCH_ARM_LIST);
365}
366
367// test match_arm
368// fn foo() {
369// match () {
370// _ => (),
371// _ if Test > Test{field: 0} => (),
372// X | Y if Z => (),
373// | X | Y if Z => (),
374// | X => (),
375// };
376// }
377fn match_arm(p: &mut Parser) -> BlockLike {
378 let m = p.start();
379 p.eat(PIPE);
380 patterns::pattern_r(p, TokenSet::empty());
381 while p.eat(PIPE) {
382 patterns::pattern(p);
383 }
384 if p.at(IF_KW) {
385 match_guard(p);
386 }
387 p.expect(FAT_ARROW);
388 let ret = expr_stmt(p);
389 m.complete(p, MATCH_ARM);
390 ret
391}
392
393// test match_guard
394// fn foo() {
395// match () {
396// _ if foo => (),
397// }
398// }
399fn match_guard(p: &mut Parser) -> CompletedMarker {
400 assert!(p.at(IF_KW));
401 let m = p.start();
402 p.bump();
403 expr(p);
404 m.complete(p, MATCH_GUARD)
405}
406
407// test block_expr
408// fn foo() {
409// {};
410// unsafe {};
411// 'label: {};
412// }
413fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
414 assert!(p.at(L_CURLY));
415 let m = m.unwrap_or_else(|| p.start());
416 block(p);
417 m.complete(p, BLOCK_EXPR)
418}
419
420// test return_expr
421// fn foo() {
422// return;
423// return 92;
424// }
425fn return_expr(p: &mut Parser) -> CompletedMarker {
426 assert!(p.at(RETURN_KW));
427 let m = p.start();
428 p.bump();
429 if p.at_ts(EXPR_FIRST) {
430 expr(p);
431 }
432 m.complete(p, RETURN_EXPR)
433}
434
435// test continue_expr
436// fn foo() {
437// loop {
438// continue;
439// continue 'l;
440// }
441// }
442fn continue_expr(p: &mut Parser) -> CompletedMarker {
443 assert!(p.at(CONTINUE_KW));
444 let m = p.start();
445 p.bump();
446 p.eat(LIFETIME);
447 m.complete(p, CONTINUE_EXPR)
448}
449
450// test break_expr
451// fn foo() {
452// loop {
453// break;
454// break 'l;
455// break 92;
456// break 'l 92;
457// }
458// }
459fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
460 assert!(p.at(BREAK_KW));
461 let m = p.start();
462 p.bump();
463 p.eat(LIFETIME);
464 // test break_ambiguity
465 // fn foo(){
466 // if break {}
467 // while break {}
468 // for i in break {}
469 // match break {}
470 // }
471 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(L_CURLY)) {
472 expr(p);
473 }
474 m.complete(p, BREAK_EXPR)
475}
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
new file mode 100644
index 000000000..4b962c1f3
--- /dev/null
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -0,0 +1,392 @@
1mod consts;
2mod nominal;
3mod traits;
4mod use_item;
5
6pub(crate) use self::{
7 expressions::{match_arm_list, named_field_list},
8 nominal::{enum_variant_list, named_field_def_list},
9 traits::{impl_item_list, trait_item_list},
10 use_item::use_tree_list,
11};
12use super::*;
13
14// test mod_contents
15// fn foo() {}
16// macro_rules! foo {}
17// foo::bar!();
18// super::baz! {}
19// struct S;
20pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
21 attributes::inner_attributes(p);
22 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
23 item_or_macro(p, stop_on_r_curly, ItemFlavor::Mod)
24 }
25}
26
27pub(super) enum ItemFlavor {
28 Mod,
29 Trait,
30}
31
32pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
33 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
34 CRATE_KW
35];
36
37pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
38 let m = p.start();
39 attributes::outer_attributes(p);
40 match maybe_item(p, flavor) {
41 MaybeItem::Item(kind) => {
42 m.complete(p, kind);
43 }
44 MaybeItem::None => {
45 if paths::is_path_start(p) {
46 match macro_call(p) {
47 BlockLike::Block => (),
48 BlockLike::NotBlock => {
49 p.expect(SEMI);
50 }
51 }
52 m.complete(p, MACRO_CALL);
53 } else {
54 m.abandon(p);
55 if p.at(L_CURLY) {
56 error_block(p, "expected an item");
57 } else if p.at(R_CURLY) && !stop_on_r_curly {
58 let e = p.start();
59 p.error("unmatched `}`");
60 p.bump();
61 e.complete(p, ERROR);
62 } else if !p.at(EOF) && !p.at(R_CURLY) {
63 p.err_and_bump("expected an item");
64 } else {
65 p.error("expected an item");
66 }
67 }
68 }
69 MaybeItem::Modifiers => {
70 p.error("expected fn, trait or impl");
71 m.complete(p, ERROR);
72 }
73 }
74}
75
76pub(super) enum MaybeItem {
77 None,
78 Item(SyntaxKind),
79 Modifiers,
80}
81
82pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem {
83 opt_visibility(p);
84 if let Some(kind) = items_without_modifiers(p) {
85 return MaybeItem::Item(kind);
86 }
87
88 let mut has_mods = false;
89 // modifiers
90 has_mods |= p.eat(CONST_KW);
91
92 // test_err unsafe_block_in_mod
93 // fn foo(){} unsafe { } fn bar(){}
94 if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY {
95 p.eat(UNSAFE_KW);
96 has_mods = true;
97 }
98 if p.at(EXTERN_KW) {
99 has_mods = true;
100 abi(p);
101 }
102 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
103 p.bump_remap(AUTO_KW);
104 has_mods = true;
105 }
106 if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
107 p.bump_remap(DEFAULT_KW);
108 has_mods = true;
109 }
110
111 // items
112 let kind = match p.current() {
113 // test extern_fn
114 // extern fn foo() {}
115
116 // test const_fn
117 // const fn foo() {}
118
119 // test const_unsafe_fn
120 // const unsafe fn foo() {}
121
122 // test unsafe_extern_fn
123 // unsafe extern "C" fn foo() {}
124
125 // test unsafe_fn
126 // unsafe fn foo() {}
127 FN_KW => {
128 fn_def(p, flavor);
129 FN_DEF
130 }
131
132 // test unsafe_trait
133 // unsafe trait T {}
134
135 // test auto_trait
136 // auto trait T {}
137
138 // test unsafe_auto_trait
139 // unsafe auto trait T {}
140 TRAIT_KW => {
141 traits::trait_def(p);
142 TRAIT_DEF
143 }
144
145 // test unsafe_impl
146 // unsafe impl Foo {}
147
148 // test default_impl
149 // default impl Foo {}
150
151 // test unsafe_default_impl
152 // unsafe default impl Foo {}
153 IMPL_KW => {
154 traits::impl_block(p);
155 IMPL_BLOCK
156 }
157 _ => {
158 return if has_mods { MaybeItem::Modifiers } else { MaybeItem::None };
159 }
160 };
161
162 MaybeItem::Item(kind)
163}
164
165fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
166 let la = p.nth(1);
167 let kind = match p.current() {
168 // test extern_crate
169 // extern crate foo;
170 EXTERN_KW if la == CRATE_KW => {
171 extern_crate_item(p);
172 EXTERN_CRATE_ITEM
173 }
174 TYPE_KW => {
175 type_def(p);
176 TYPE_DEF
177 }
178 MOD_KW => {
179 mod_item(p);
180 MODULE
181 }
182 STRUCT_KW => {
183 // test struct_items
184 // struct Foo;
185 // struct Foo {}
186 // struct Foo();
187 // struct Foo(String, usize);
188 // struct Foo {
189 // a: i32,
190 // b: f32,
191 // }
192 nominal::struct_def(p, STRUCT_KW);
193 if p.at(SEMI) {
194 p.err_and_bump(
195 "expected item, found `;`\n\
196 consider removing this semicolon",
197 );
198 }
199 STRUCT_DEF
200 }
201 IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
202 // test union_items
203 // union Foo {}
204 // union Foo {
205 // a: i32,
206 // b: f32,
207 // }
208 nominal::struct_def(p, UNION_KW);
209 STRUCT_DEF
210 }
211 ENUM_KW => {
212 nominal::enum_def(p);
213 ENUM_DEF
214 }
215 USE_KW => {
216 use_item::use_item(p);
217 USE_ITEM
218 }
219 CONST_KW if (la == IDENT || la == MUT_KW) => {
220 consts::const_def(p);
221 CONST_DEF
222 }
223 STATIC_KW => {
224 consts::static_def(p);
225 STATIC_DEF
226 }
227 // test extern_block
228 // extern {}
229 EXTERN_KW
230 if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) =>
231 {
232 abi(p);
233 extern_item_list(p);
234 EXTERN_BLOCK
235 }
236 _ => return None,
237 };
238 Some(kind)
239}
240
241fn extern_crate_item(p: &mut Parser) {
242 assert!(p.at(EXTERN_KW));
243 p.bump();
244 assert!(p.at(CRATE_KW));
245 p.bump();
246 name_ref(p);
247 opt_alias(p);
248 p.expect(SEMI);
249}
250
251pub(crate) fn extern_item_list(p: &mut Parser) {
252 assert!(p.at(L_CURLY));
253 let m = p.start();
254 p.bump();
255 mod_contents(p, true);
256 p.expect(R_CURLY);
257 m.complete(p, EXTERN_ITEM_LIST);
258}
259
260fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
261 assert!(p.at(FN_KW));
262 p.bump();
263
264 name_r(p, ITEM_RECOVERY_SET);
265 // test function_type_params
266 // fn foo<T: Clone + Copy>(){}
267 type_params::opt_type_param_list(p);
268
269 if p.at(L_PAREN) {
270 match flavor {
271 ItemFlavor::Mod => params::param_list(p),
272 ItemFlavor::Trait => params::param_list_opt_patterns(p),
273 }
274 } else {
275 p.error("expected function arguments");
276 }
277 // test function_ret_type
278 // fn foo() {}
279 // fn bar() -> () {}
280 opt_fn_ret_type(p);
281
282 // test function_where_clause
283 // fn foo<T>() where T: Copy {}
284 type_params::opt_where_clause(p);
285
286 // test fn_decl
287 // trait T { fn foo(); }
288 if p.at(SEMI) {
289 p.bump();
290 } else {
291 expressions::block(p)
292 }
293}
294
295// test type_item
296// type Foo = Bar;
297fn type_def(p: &mut Parser) {
298 assert!(p.at(TYPE_KW));
299 p.bump();
300
301 name(p);
302
303 // test type_item_type_params
304 // type Result<T> = ();
305 type_params::opt_type_param_list(p);
306
307 if p.at(COLON) {
308 type_params::bounds(p);
309 }
310
311 // test type_item_where_clause
312 // type Foo where Foo: Copy = ();
313 type_params::opt_where_clause(p);
314
315 if p.eat(EQ) {
316 types::type_(p);
317 }
318 p.expect(SEMI);
319}
320
321pub(crate) fn mod_item(p: &mut Parser) {
322 assert!(p.at(MOD_KW));
323 p.bump();
324
325 name(p);
326 if p.at(L_CURLY) {
327 mod_item_list(p);
328 } else if !p.eat(SEMI) {
329 p.error("expected `;` or `{`");
330 }
331}
332
333pub(crate) fn mod_item_list(p: &mut Parser) {
334 assert!(p.at(L_CURLY));
335 let m = p.start();
336 p.bump();
337 mod_contents(p, true);
338 p.expect(R_CURLY);
339 m.complete(p, ITEM_LIST);
340}
341
342fn macro_call(p: &mut Parser) -> BlockLike {
343 assert!(paths::is_path_start(p));
344 paths::use_path(p);
345 macro_call_after_excl(p)
346}
347
348pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
349 p.expect(EXCL);
350 if p.at(IDENT) {
351 name(p);
352 }
353 match p.current() {
354 L_CURLY => {
355 token_tree(p);
356 BlockLike::Block
357 }
358 L_PAREN | L_BRACK => {
359 token_tree(p);
360 BlockLike::NotBlock
361 }
362 _ => {
363 p.error("expected `{`, `[`, `(`");
364 BlockLike::NotBlock
365 }
366 }
367}
368
369pub(crate) fn token_tree(p: &mut Parser) {
370 let closing_paren_kind = match p.current() {
371 L_CURLY => R_CURLY,
372 L_PAREN => R_PAREN,
373 L_BRACK => R_BRACK,
374 _ => unreachable!(),
375 };
376 let m = p.start();
377 p.bump();
378 while !p.at(EOF) && !p.at(closing_paren_kind) {
379 match p.current() {
380 L_CURLY | L_PAREN | L_BRACK => token_tree(p),
381 R_CURLY => {
382 p.error("unmatched `}`");
383 m.complete(p, TOKEN_TREE);
384 return;
385 }
386 R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"),
387 _ => p.bump(),
388 }
389 }
390 p.expect(closing_paren_kind);
391 m.complete(p, TOKEN_TREE);
392}
diff --git a/crates/ra_parser/src/grammar/items/consts.rs b/crates/ra_parser/src/grammar/items/consts.rs
new file mode 100644
index 000000000..5a5852f83
--- /dev/null
+++ b/crates/ra_parser/src/grammar/items/consts.rs
@@ -0,0 +1,21 @@
1use super::*;
2
3pub(super) fn static_def(p: &mut Parser) {
4 const_or_static(p, STATIC_KW)
5}
6
7pub(super) fn const_def(p: &mut Parser) {
8 const_or_static(p, CONST_KW)
9}
10
11fn const_or_static(p: &mut Parser, kw: SyntaxKind) {
12 assert!(p.at(kw));
13 p.bump();
14 p.eat(MUT_KW); // TODO: validator to forbid const mut
15 name(p);
16 types::ascription(p);
17 if p.eat(EQ) {
18 expressions::expr(p);
19 }
20 p.expect(SEMI);
21}
diff --git a/crates/ra_parser/src/grammar/items/nominal.rs b/crates/ra_parser/src/grammar/items/nominal.rs
new file mode 100644
index 000000000..ff9b38f9c
--- /dev/null
+++ b/crates/ra_parser/src/grammar/items/nominal.rs
@@ -0,0 +1,168 @@
1use super::*;
2
3pub(super) fn struct_def(p: &mut Parser, kind: SyntaxKind) {
4 assert!(p.at(STRUCT_KW) || p.at_contextual_kw("union"));
5 p.bump_remap(kind);
6
7 name_r(p, ITEM_RECOVERY_SET);
8 type_params::opt_type_param_list(p);
9 match p.current() {
10 WHERE_KW => {
11 type_params::opt_where_clause(p);
12 match p.current() {
13 SEMI => {
14 p.bump();
15 return;
16 }
17 L_CURLY => named_field_def_list(p),
18 _ => {
19 //TODO: special case `(` error message
20 p.error("expected `;` or `{`");
21 return;
22 }
23 }
24 }
25 SEMI if kind == STRUCT_KW => {
26 p.bump();
27 return;
28 }
29 L_CURLY => named_field_def_list(p),
30 L_PAREN if kind == STRUCT_KW => {
31 pos_field_def_list(p);
32 // test tuple_struct_where
33 // struct Test<T>(T) where T: Clone;
34 // struct Test<T>(T);
35 type_params::opt_where_clause(p);
36 p.expect(SEMI);
37 }
38 _ if kind == STRUCT_KW => {
39 p.error("expected `;`, `{`, or `(`");
40 return;
41 }
42 _ => {
43 p.error("expected `{`");
44 return;
45 }
46 }
47}
48
49pub(super) fn enum_def(p: &mut Parser) {
50 assert!(p.at(ENUM_KW));
51 p.bump();
52 name_r(p, ITEM_RECOVERY_SET);
53 type_params::opt_type_param_list(p);
54 type_params::opt_where_clause(p);
55 if p.at(L_CURLY) {
56 enum_variant_list(p);
57 } else {
58 p.error("expected `{`")
59 }
60}
61
62pub(crate) fn enum_variant_list(p: &mut Parser) {
63 assert!(p.at(L_CURLY));
64 let m = p.start();
65 p.bump();
66 while !p.at(EOF) && !p.at(R_CURLY) {
67 if p.at(L_CURLY) {
68 error_block(p, "expected enum variant");
69 continue;
70 }
71 let var = p.start();
72 attributes::outer_attributes(p);
73 if p.at(IDENT) {
74 name(p);
75 match p.current() {
76 L_CURLY => named_field_def_list(p),
77 L_PAREN => pos_field_def_list(p),
78 EQ => {
79 p.bump();
80 expressions::expr(p);
81 }
82 _ => (),
83 }
84 var.complete(p, ENUM_VARIANT);
85 } else {
86 var.abandon(p);
87 p.err_and_bump("expected enum variant");
88 }
89 if !p.at(R_CURLY) {
90 p.expect(COMMA);
91 }
92 }
93 p.expect(R_CURLY);
94 m.complete(p, ENUM_VARIANT_LIST);
95}
96
97pub(crate) fn named_field_def_list(p: &mut Parser) {
98 assert!(p.at(L_CURLY));
99 let m = p.start();
100 p.bump();
101 while !p.at(R_CURLY) && !p.at(EOF) {
102 if p.at(L_CURLY) {
103 error_block(p, "expected field");
104 continue;
105 }
106 named_field_def(p);
107 if !p.at(R_CURLY) {
108 p.expect(COMMA);
109 }
110 }
111 p.expect(R_CURLY);
112 m.complete(p, NAMED_FIELD_DEF_LIST);
113
114 fn named_field_def(p: &mut Parser) {
115 let m = p.start();
116 // test field_attrs
117 // struct S {
118 // #[serde(with = "url_serde")]
119 // pub uri: Uri,
120 // }
121 attributes::outer_attributes(p);
122 opt_visibility(p);
123 if p.at(IDENT) {
124 name(p);
125 p.expect(COLON);
126 types::type_(p);
127 m.complete(p, NAMED_FIELD_DEF);
128 } else {
129 m.abandon(p);
130 p.err_and_bump("expected field declaration");
131 }
132 }
133}
134
135fn pos_field_def_list(p: &mut Parser) {
136 assert!(p.at(L_PAREN));
137 let m = p.start();
138 if !p.expect(L_PAREN) {
139 return;
140 }
141 while !p.at(R_PAREN) && !p.at(EOF) {
142 let m = p.start();
143 // test pos_field_attrs
144 // struct S (
145 // #[serde(with = "url_serde")]
146 // pub Uri,
147 // );
148 //
149 // enum S {
150 // Uri(#[serde(with = "url_serde")] Uri),
151 // }
152 attributes::outer_attributes(p);
153 opt_visibility(p);
154 if !p.at_ts(types::TYPE_FIRST) {
155 p.error("expected a type");
156 m.complete(p, ERROR);
157 break;
158 }
159 types::type_(p);
160 m.complete(p, POS_FIELD_DEF);
161
162 if !p.at(R_PAREN) {
163 p.expect(COMMA);
164 }
165 }
166 p.expect(R_PAREN);
167 m.complete(p, POS_FIELD_DEF_LIST);
168}
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs
new file mode 100644
index 000000000..d5a8ccd98
--- /dev/null
+++ b/crates/ra_parser/src/grammar/items/traits.rs
@@ -0,0 +1,137 @@
1use super::*;
2
3// test trait_item
4// trait T<U>: Hash + Clone where U: Copy {}
5pub(super) fn trait_def(p: &mut Parser) {
6 assert!(p.at(TRAIT_KW));
7 p.bump();
8 name_r(p, ITEM_RECOVERY_SET);
9 type_params::opt_type_param_list(p);
10 if p.at(COLON) {
11 type_params::bounds(p);
12 }
13 type_params::opt_where_clause(p);
14 if p.at(L_CURLY) {
15 trait_item_list(p);
16 } else {
17 p.error("expected `{`");
18 }
19}
20
21// test trait_item_list
22// impl F {
23// type A: Clone;
24// const B: i32;
25// fn foo() {}
26// fn bar(&self);
27// }
28pub(crate) fn trait_item_list(p: &mut Parser) {
29 assert!(p.at(L_CURLY));
30 let m = p.start();
31 p.bump();
32 while !p.at(EOF) && !p.at(R_CURLY) {
33 if p.at(L_CURLY) {
34 error_block(p, "expected an item");
35 continue;
36 }
37 item_or_macro(p, true, ItemFlavor::Trait);
38 }
39 p.expect(R_CURLY);
40 m.complete(p, ITEM_LIST);
41}
42
43// test impl_block
44// impl Foo {}
45pub(super) fn impl_block(p: &mut Parser) {
46 assert!(p.at(IMPL_KW));
47 p.bump();
48 if choose_type_params_over_qpath(p) {
49 type_params::opt_type_param_list(p);
50 }
51
52 // TODO: never type
53 // impl ! {}
54
55 // test impl_block_neg
56 // impl !Send for X {}
57 p.eat(EXCL);
58 impl_type(p);
59 if p.eat(FOR_KW) {
60 impl_type(p);
61 }
62 type_params::opt_where_clause(p);
63 if p.at(L_CURLY) {
64 impl_item_list(p);
65 } else {
66 p.error("expected `{`");
67 }
68}
69
70// test impl_item_list
71// impl F {
72// type A = i32;
73// const B: i32 = 92;
74// fn foo() {}
75// fn bar(&self) {}
76// }
77pub(crate) fn impl_item_list(p: &mut Parser) {
78 assert!(p.at(L_CURLY));
79 let m = p.start();
80 p.bump();
81 // test impl_inner_attributes
82 // enum F{}
83 // impl F {
84 // //! This is a doc comment
85 // #![doc("This is also a doc comment")]
86 // }
87 attributes::inner_attributes(p);
88
89 while !p.at(EOF) && !p.at(R_CURLY) {
90 if p.at(L_CURLY) {
91 error_block(p, "expected an item");
92 continue;
93 }
94 item_or_macro(p, true, ItemFlavor::Mod);
95 }
96 p.expect(R_CURLY);
97 m.complete(p, ITEM_LIST);
98}
99
100fn choose_type_params_over_qpath(p: &Parser) -> bool {
101 // There's an ambiguity between generic parameters and qualified paths in impls.
102 // If we see `<` it may start both, so we have to inspect some following tokens.
103 // The following combinations can only start generics,
104 // but not qualified paths (with one exception):
105 // `<` `>` - empty generic parameters
106 // `<` `#` - generic parameters with attributes
107 // `<` (LIFETIME|IDENT) `>` - single generic parameter
108 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
109 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
110 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
111 // The only truly ambiguous case is
112 // `<` IDENT `>` `::` IDENT ...
113 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
114 // because this is what almost always expected in practice, qualified paths in impls
115 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
116 if !p.at(L_ANGLE) {
117 return false;
118 }
119 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
120 return true;
121 }
122 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
123 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
124}
125
126// test_err impl_type
127// impl Type {}
128// impl Trait1 for T {}
129// impl impl NotType {}
130// impl Trait2 for impl NotType {}
131pub(crate) fn impl_type(p: &mut Parser) {
132 if p.at(IMPL_KW) {
133 p.error("expected trait or type");
134 return;
135 }
136 types::type_(p);
137}
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..5111d37eb
--- /dev/null
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -0,0 +1,121 @@
1use super::*;
2
3pub(super) fn use_item(p: &mut Parser) {
4 assert!(p.at(USE_KW));
5 p.bump();
6 use_tree(p);
7 p.expect(SEMI);
8}
9
10/// Parse a use 'tree', such as `some::path` in `use some::path;`
11/// Note that this is called both by `use_item` and `use_tree_list`,
12/// so handles both `some::path::{inner::path}` and `inner::path` in
13/// `use some::path::{inner::path};`
14fn use_tree(p: &mut Parser) {
15 let la = p.nth(1);
16 let m = p.start();
17 match (p.current(), la) {
18 // Finish the use_tree for cases of e.g.
19 // `use some::path::{self, *};` or `use *;`
20 // This does not handle cases such as `use some::path::*`
21 // N.B. in Rust 2015 `use *;` imports all from crate root
22 // however in Rust 2018 `use *;` errors: ('cannot glob-import all possible crates')
23 // TODO: Add this error (if not out of scope)
24
25 // test use_star
26 // use *;
27 // use ::*;
28 // use some::path::{*};
29 // use some::path::{::*};
30 (STAR, _) => p.bump(),
31 (COLONCOLON, STAR) => {
32 // Parse `use ::*;`, which imports all from the crate root in Rust 2015
33 // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`)
34 // but still parses and errors later: ('crate root in paths can only be used in start position')
35 // TODO: Add this error (if not out of scope)
36 // In Rust 2018, it is always invalid (see above)
37 p.bump();
38 p.bump();
39 }
40 // Open a use tree list
41 // Handles cases such as `use {some::path};` or `{inner::path}` in
42 // `use some::path::{{inner::path}, other::path}`
43
44 // test use_tree_list
45 // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`)
46 // use {path::from::root}; // Rust 2015
47 // use ::{some::arbritrary::path}; // Rust 2015
48 // use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig
49 (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
50 if p.at(COLONCOLON) {
51 p.bump();
52 }
53 use_tree_list(p);
54 }
55 // Parse a 'standard' path.
56 // Also handles aliases (e.g. `use something as something_else`)
57
58 // test use_path
59 // use ::crate_name; // Rust 2018 - All flavours
60 // use crate_name; // Rust 2018 - Anchored paths
61 // use item_in_scope_or_crate_name; // Rust 2018 - Uniform Paths
62 //
63 // use self::module::Item;
64 // use crate::Item;
65 // use self::some::Struct;
66 // use crate_name::some_item;
67 _ if paths::is_path_start(p) => {
68 paths::use_path(p);
69 match p.current() {
70 AS_KW => {
71 // test use_alias
72 // use some::path as some_name;
73 // use some::{
74 // other::path as some_other_name,
75 // different::path as different_name,
76 // yet::another::path,
77 // running::out::of::synonyms::for_::different::*
78 // };
79 opt_alias(p);
80 }
81 COLONCOLON => {
82 p.bump();
83 match p.current() {
84 STAR => {
85 p.bump();
86 }
87 // test use_tree_list_after_path
88 // use crate::{Item};
89 // use self::{Item};
90 L_CURLY => use_tree_list(p),
91 _ => {
92 // is this unreachable?
93 p.error("expected `{` or `*`");
94 }
95 }
96 }
97 _ => (),
98 }
99 }
100 _ => {
101 m.abandon(p);
102 p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super` or an indentifier");
103 return;
104 }
105 }
106 m.complete(p, USE_TREE);
107}
108
109pub(crate) fn use_tree_list(p: &mut Parser) {
110 assert!(p.at(L_CURLY));
111 let m = p.start();
112 p.bump();
113 while !p.at(EOF) && !p.at(R_CURLY) {
114 use_tree(p);
115 if !p.at(R_CURLY) {
116 p.expect(COMMA);
117 }
118 }
119 p.expect(R_CURLY);
120 m.complete(p, USE_TREE_LIST);
121}
diff --git a/crates/ra_parser/src/grammar/params.rs b/crates/ra_parser/src/grammar/params.rs
new file mode 100644
index 000000000..185386569
--- /dev/null
+++ b/crates/ra_parser/src/grammar/params.rs
@@ -0,0 +1,139 @@
1use super::*;
2
3// test param_list
4// fn a() {}
5// fn b(x: i32) {}
6// fn c(x: i32, ) {}
7// fn d(x: i32, y: ()) {}
8pub(super) fn param_list(p: &mut Parser) {
9 list_(p, Flavor::Normal)
10}
11
12// test param_list_opt_patterns
13// fn foo<F: FnMut(&mut Foo<'a>)>(){}
14pub(super) fn param_list_opt_patterns(p: &mut Parser) {
15 list_(p, Flavor::OptionalPattern)
16}
17
18pub(super) fn param_list_opt_types(p: &mut Parser) {
19 list_(p, Flavor::OptionalType)
20}
21
22#[derive(Clone, Copy, Eq, PartialEq)]
23enum Flavor {
24 OptionalType,
25 OptionalPattern,
26 Normal,
27}
28
29impl Flavor {
30 fn type_required(self) -> bool {
31 match self {
32 Flavor::OptionalType => false,
33 _ => true,
34 }
35 }
36}
37
38fn list_(p: &mut Parser, flavor: Flavor) {
39 let (bra, ket) = if flavor.type_required() { (L_PAREN, R_PAREN) } else { (PIPE, PIPE) };
40 assert!(p.at(bra));
41 let m = p.start();
42 p.bump();
43 if flavor.type_required() {
44 opt_self_param(p);
45 }
46 while !p.at(EOF) && !p.at(ket) {
47 if !p.at_ts(VALUE_PARAMETER_FIRST) {
48 p.error("expected value parameter");
49 break;
50 }
51 value_parameter(p, flavor);
52 if !p.at(ket) {
53 p.expect(COMMA);
54 }
55 }
56 p.expect(ket);
57 m.complete(p, PARAM_LIST);
58}
59
60const VALUE_PARAMETER_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
61
62fn value_parameter(p: &mut Parser, flavor: Flavor) {
63 let m = p.start();
64 match flavor {
65 Flavor::OptionalType | Flavor::Normal => {
66 patterns::pattern(p);
67 if p.at(COLON) || flavor.type_required() {
68 types::ascription(p)
69 }
70 }
71 // test value_parameters_no_patterns
72 // type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>;
73 Flavor::OptionalPattern => {
74 let la0 = p.current();
75 let la1 = p.nth(1);
76 let la2 = p.nth(2);
77 let la3 = p.nth(3);
78
79 // test trait_fn_placeholder_parameter
80 // trait Foo {
81 // fn bar(_: u64);
82 // }
83 if (la0 == IDENT || la0 == UNDERSCORE) && la1 == COLON
84 || la0 == AMP && la1 == IDENT && la2 == COLON
85 || la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON
86 {
87 patterns::pattern(p);
88 types::ascription(p);
89 } else {
90 types::type_(p);
91 }
92 }
93 }
94 m.complete(p, PARAM);
95}
96
97// test self_param
98// impl S {
99// fn a(self) {}
100// fn b(&self,) {}
101// fn c(&'a self,) {}
102// fn d(&'a mut self, x: i32) {}
103// fn e(mut self) {}
104// }
105fn opt_self_param(p: &mut Parser) {
106 let m;
107 if p.at(SELF_KW) || p.at(MUT_KW) && p.nth(1) == SELF_KW {
108 m = p.start();
109 p.eat(MUT_KW);
110 p.eat(SELF_KW);
111 // test arb_self_types
112 // impl S {
113 // fn a(self: &Self) {}
114 // fn b(mut self: Box<Self>) {}
115 // }
116 if p.at(COLON) {
117 types::ascription(p);
118 }
119 } else {
120 let la1 = p.nth(1);
121 let la2 = p.nth(2);
122 let la3 = p.nth(3);
123 let n_toks = match (p.current(), la1, la2, la3) {
124 (AMP, SELF_KW, _, _) => 2,
125 (AMP, MUT_KW, SELF_KW, _) => 3,
126 (AMP, LIFETIME, SELF_KW, _) => 3,
127 (AMP, LIFETIME, MUT_KW, SELF_KW) => 4,
128 _ => return,
129 };
130 m = p.start();
131 for _ in 0..n_toks {
132 p.bump();
133 }
134 }
135 m.complete(p, SELF_PARAM);
136 if !p.at(R_PAREN) {
137 p.expect(COMMA);
138 }
139}
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs
new file mode 100644
index 000000000..33a11886c
--- /dev/null
+++ b/crates/ra_parser/src/grammar/paths.rs
@@ -0,0 +1,103 @@
1use super::*;
2
3pub(super) const PATH_FIRST: TokenSet =
4 token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, L_ANGLE];
5
6pub(super) fn is_path_start(p: &Parser) -> bool {
7 match p.current() {
8 IDENT | SELF_KW | SUPER_KW | CRATE_KW | COLONCOLON => true,
9 _ => false,
10 }
11}
12
13pub(super) fn use_path(p: &mut Parser) {
14 path(p, Mode::Use)
15}
16
17pub(super) fn type_path(p: &mut Parser) {
18 path(p, Mode::Type)
19}
20
21pub(super) fn expr_path(p: &mut Parser) {
22 path(p, Mode::Expr)
23}
24
25#[derive(Clone, Copy, Eq, PartialEq)]
26enum Mode {
27 Use,
28 Type,
29 Expr,
30}
31
32fn path(p: &mut Parser, mode: Mode) {
33 let path = p.start();
34 path_segment(p, mode, true);
35 let mut qual = path.complete(p, PATH);
36 loop {
37 let use_tree = match p.nth(1) {
38 STAR | L_CURLY => true,
39 _ => false,
40 };
41 if p.at(COLONCOLON) && !use_tree {
42 let path = qual.precede(p);
43 p.bump();
44 path_segment(p, mode, false);
45 let path = path.complete(p, PATH);
46 qual = path;
47 } else {
48 break;
49 }
50 }
51}
52
53fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
54 let m = p.start();
55 // test qual_paths
56 // type X = <A as B>::Output;
57 // fn foo() { <usize as Default>::default(); }
58 if first && p.eat(L_ANGLE) {
59 types::type_(p);
60 if p.eat(AS_KW) {
61 if is_path_start(p) {
62 types::path_type(p);
63 } else {
64 p.error("expected a trait");
65 }
66 }
67 p.expect(R_ANGLE);
68 } else {
69 if first {
70 p.eat(COLONCOLON);
71 }
72 match p.current() {
73 IDENT => {
74 name_ref(p);
75 opt_path_type_args(p, mode);
76 }
77 // test crate_path
78 // use crate::foo;
79 SELF_KW | SUPER_KW | CRATE_KW => p.bump(),
80 _ => {
81 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
82 }
83 };
84 }
85 m.complete(p, PATH_SEGMENT);
86}
87
88fn opt_path_type_args(p: &mut Parser, mode: Mode) {
89 match mode {
90 Mode::Use => return,
91 Mode::Type => {
92 // test path_fn_trait_args
93 // type F = Box<Fn(x: i32) -> ()>;
94 if p.at(L_PAREN) {
95 params::param_list_opt_patterns(p);
96 opt_fn_ret_type(p);
97 } else {
98 type_args::opt_type_arg_list(p, false)
99 }
100 }
101 Mode::Expr => type_args::opt_type_arg_list(p, true),
102 }
103}
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
new file mode 100644
index 000000000..9d7da639d
--- /dev/null
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -0,0 +1,248 @@
1use super::*;
2
3pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
4 .union(paths::PATH_FIRST)
5 .union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE]);
6
7pub(super) fn pattern(p: &mut Parser) {
8 pattern_r(p, PAT_RECOVERY_SET)
9}
10
11pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
12 if let Some(lhs) = atom_pat(p, recovery_set) {
13 // test range_pat
14 // fn main() {
15 // match 92 {
16 // 0 ... 100 => (),
17 // 101 ..= 200 => (),
18 // 200 .. 301=> (),
19 // }
20 // }
21 if p.at(DOTDOTDOT) || p.at(DOTDOTEQ) || p.at(DOTDOT) {
22 let m = lhs.precede(p);
23 p.bump();
24 atom_pat(p, recovery_set);
25 m.complete(p, RANGE_PAT);
26 }
27 }
28}
29
30const PAT_RECOVERY_SET: TokenSet =
31 token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
32
33fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
34 let la0 = p.nth(0);
35 let la1 = p.nth(1);
36 if la0 == REF_KW
37 || la0 == MUT_KW
38 || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY))
39 {
40 return Some(bind_pat(p, true));
41 }
42 if paths::is_path_start(p) {
43 return Some(path_pat(p));
44 }
45
46 if is_literal_pat_start(p) {
47 return Some(literal_pat(p));
48 }
49
50 let m = match la0 {
51 UNDERSCORE => placeholder_pat(p),
52 AMP => ref_pat(p),
53 L_PAREN => tuple_pat(p),
54 L_BRACK => slice_pat(p),
55 _ => {
56 p.err_recover("expected pattern", recovery_set);
57 return None;
58 }
59 };
60 Some(m)
61}
62
63fn is_literal_pat_start(p: &mut Parser) -> bool {
64 p.at(MINUS) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
65 || p.at_ts(expressions::LITERAL_FIRST)
66}
67
68// test literal_pattern
69// fn main() {
70// match () {
71// -1 => (),
72// 92 => (),
73// 'c' => (),
74// "hello" => (),
75// }
76// }
77fn literal_pat(p: &mut Parser) -> CompletedMarker {
78 assert!(is_literal_pat_start(p));
79 let m = p.start();
80 if p.at(MINUS) {
81 p.bump();
82 }
83 expressions::literal(p);
84 m.complete(p, LITERAL_PAT)
85}
86
87// test path_part
88// fn foo() {
89// let foo::Bar = ();
90// let ::Bar = ();
91// let Bar { .. } = ();
92// let Bar(..) = ();
93// }
94fn path_pat(p: &mut Parser) -> CompletedMarker {
95 assert!(paths::is_path_start(p));
96 let m = p.start();
97 paths::expr_path(p);
98 let kind = match p.current() {
99 L_PAREN => {
100 tuple_pat_fields(p);
101 TUPLE_STRUCT_PAT
102 }
103 L_CURLY => {
104 field_pat_list(p);
105 STRUCT_PAT
106 }
107 _ => PATH_PAT,
108 };
109 m.complete(p, kind)
110}
111
112// test tuple_pat_fields
113// fn foo() {
114// let S() = ();
115// let S(_) = ();
116// let S(_,) = ();
117// let S(_, .. , x) = ();
118// }
119fn tuple_pat_fields(p: &mut Parser) {
120 assert!(p.at(L_PAREN));
121 p.bump();
122 pat_list(p, R_PAREN);
123 p.expect(R_PAREN);
124}
125
126// test field_pat_list
127// fn foo() {
128// let S {} = ();
129// let S { f, ref mut g } = ();
130// let S { h: _, ..} = ();
131// let S { h: _, } = ();
132// }
133fn field_pat_list(p: &mut Parser) {
134 assert!(p.at(L_CURLY));
135 let m = p.start();
136 p.bump();
137 while !p.at(EOF) && !p.at(R_CURLY) {
138 match p.current() {
139 DOTDOT => p.bump(),
140 IDENT if p.nth(1) == COLON => field_pat(p),
141 L_CURLY => error_block(p, "expected ident"),
142 _ => {
143 bind_pat(p, false);
144 }
145 }
146 if !p.at(R_CURLY) {
147 p.expect(COMMA);
148 }
149 }
150 p.expect(R_CURLY);
151 m.complete(p, FIELD_PAT_LIST);
152}
153
154fn field_pat(p: &mut Parser) {
155 assert!(p.at(IDENT));
156 assert!(p.nth(1) == COLON);
157
158 let m = p.start();
159 name(p);
160 p.bump();
161 pattern(p);
162 m.complete(p, FIELD_PAT);
163}
164
165// test placeholder_pat
166// fn main() { let _ = (); }
167fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
168 assert!(p.at(UNDERSCORE));
169 let m = p.start();
170 p.bump();
171 m.complete(p, PLACEHOLDER_PAT)
172}
173
174// test ref_pat
175// fn main() {
176// let &a = ();
177// let &mut b = ();
178// }
179fn ref_pat(p: &mut Parser) -> CompletedMarker {
180 assert!(p.at(AMP));
181 let m = p.start();
182 p.bump();
183 p.eat(MUT_KW);
184 pattern(p);
185 m.complete(p, REF_PAT)
186}
187
188// test tuple_pat
189// fn main() {
190// let (a, b, ..) = ();
191// }
192fn tuple_pat(p: &mut Parser) -> CompletedMarker {
193 assert!(p.at(L_PAREN));
194 let m = p.start();
195 tuple_pat_fields(p);
196 m.complete(p, TUPLE_PAT)
197}
198
199// test slice_pat
200// fn main() {
201// let [a, b, ..] = [];
202// }
203fn slice_pat(p: &mut Parser) -> CompletedMarker {
204 assert!(p.at(L_BRACK));
205 let m = p.start();
206 p.bump();
207 pat_list(p, R_BRACK);
208 p.expect(R_BRACK);
209 m.complete(p, SLICE_PAT)
210}
211
212fn pat_list(p: &mut Parser, ket: SyntaxKind) {
213 while !p.at(EOF) && !p.at(ket) {
214 match p.current() {
215 DOTDOT => p.bump(),
216 _ => {
217 if !p.at_ts(PATTERN_FIRST) {
218 p.error("expected a pattern");
219 break;
220 }
221 pattern(p)
222 }
223 }
224 if !p.at(ket) {
225 p.expect(COMMA);
226 }
227 }
228}
229
230// test bind_pat
231// fn main() {
232// let a = ();
233// let mut b = ();
234// let ref c = ();
235// let ref mut d = ();
236// let e @ _ = ();
237// let ref mut f @ g @ _ = ();
238// }
239fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
240 let m = p.start();
241 p.eat(REF_KW);
242 p.eat(MUT_KW);
243 name(p);
244 if with_at && p.eat(AT) {
245 pattern(p);
246 }
247 m.complete(p, BIND_PAT)
248}
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs
new file mode 100644
index 000000000..f889419c5
--- /dev/null
+++ b/crates/ra_parser/src/grammar/type_args.rs
@@ -0,0 +1,48 @@
1use super::*;
2
3pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) {
4 let m;
5 match (colon_colon_required, p.nth(0), p.nth(1)) {
6 (_, COLONCOLON, L_ANGLE) => {
7 m = p.start();
8 p.bump();
9 p.bump();
10 }
11 (false, L_ANGLE, _) => {
12 m = p.start();
13 p.bump();
14 }
15 _ => return,
16 };
17
18 while !p.at(EOF) && !p.at(R_ANGLE) {
19 type_arg(p);
20 if !p.at(R_ANGLE) && !p.expect(COMMA) {
21 break;
22 }
23 }
24 p.expect(R_ANGLE);
25 m.complete(p, TYPE_ARG_LIST);
26}
27
28// test type_arg
29// type A = B<'static, i32, Item=u64>;
30fn type_arg(p: &mut Parser) {
31 let m = p.start();
32 match p.current() {
33 LIFETIME => {
34 p.bump();
35 m.complete(p, LIFETIME_ARG);
36 }
37 IDENT if p.nth(1) == EQ => {
38 name_ref(p);
39 p.bump();
40 types::type_(p);
41 m.complete(p, ASSOC_TYPE_ARG);
42 }
43 _ => {
44 types::type_(p);
45 m.complete(p, TYPE_ARG);
46 }
47 }
48}
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
new file mode 100644
index 000000000..40f998682
--- /dev/null
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -0,0 +1,175 @@
1use super::*;
2
3pub(super) fn opt_type_param_list(p: &mut Parser) {
4 if !p.at(L_ANGLE) {
5 return;
6 }
7 type_param_list(p);
8}
9
10fn type_param_list(p: &mut Parser) {
11 assert!(p.at(L_ANGLE));
12 let m = p.start();
13 p.bump();
14
15 while !p.at(EOF) && !p.at(R_ANGLE) {
16 let m = p.start();
17
18 // test generic_lifetime_type_attribute
19 // fn foo<#[derive(Lifetime)] 'a, #[derive(Type)] T>(_: &'a T) {
20 // }
21 attributes::outer_attributes(p);
22
23 match p.current() {
24 LIFETIME => lifetime_param(p, m),
25 IDENT => type_param(p, m),
26 _ => {
27 m.abandon(p);
28 p.err_and_bump("expected type parameter")
29 }
30 }
31 if !p.at(R_ANGLE) && !p.expect(COMMA) {
32 break;
33 }
34 }
35 p.expect(R_ANGLE);
36 m.complete(p, TYPE_PARAM_LIST);
37}
38
39fn lifetime_param(p: &mut Parser, m: Marker) {
40 assert!(p.at(LIFETIME));
41 p.bump();
42 if p.at(COLON) {
43 lifetime_bounds(p);
44 }
45 m.complete(p, LIFETIME_PARAM);
46}
47
48fn type_param(p: &mut Parser, m: Marker) {
49 assert!(p.at(IDENT));
50 name(p);
51 if p.at(COLON) {
52 bounds(p);
53 }
54 // test type_param_default
55 // struct S<T = i32>;
56 if p.at(EQ) {
57 p.bump();
58 types::type_(p)
59 }
60 m.complete(p, TYPE_PARAM);
61}
62
63// test type_param_bounds
64// struct S<T: 'a + ?Sized + (Copy)>;
65pub(super) fn bounds(p: &mut Parser) {
66 assert!(p.at(COLON));
67 p.bump();
68 bounds_without_colon(p);
69}
70
71fn lifetime_bounds(p: &mut Parser) {
72 assert!(p.at(COLON));
73 p.bump();
74 while p.at(LIFETIME) {
75 p.bump();
76 if !p.eat(PLUS) {
77 break;
78 }
79 }
80}
81
82pub(super) fn bounds_without_colon(p: &mut Parser) {
83 loop {
84 let has_paren = p.eat(L_PAREN);
85 p.eat(QUESTION);
86 match p.current() {
87 LIFETIME => p.bump(),
88 FOR_KW => types::for_type(p),
89 _ if paths::is_path_start(p) => types::path_type(p),
90 _ => break,
91 }
92 if has_paren {
93 p.expect(R_PAREN);
94 }
95 if !p.eat(PLUS) {
96 break;
97 }
98 }
99}
100
101// test where_clause
102// fn foo()
103// where
104// 'a: 'b + 'c,
105// T: Clone + Copy + 'static,
106// Iterator::Item: 'a,
107// <T as Iterator>::Item: 'a
108// {}
109pub(super) fn opt_where_clause(p: &mut Parser) {
110 if !p.at(WHERE_KW) {
111 return;
112 }
113 let m = p.start();
114 p.bump();
115
116 while is_where_predicate(p) {
117 where_predicate(p);
118
119 let comma = p.eat(COMMA);
120
121 if is_where_clause_end(p) {
122 break;
123 }
124
125 if !comma {
126 p.error("expected comma");
127 }
128 }
129
130 m.complete(p, WHERE_CLAUSE);
131}
132
133fn is_where_predicate(p: &mut Parser) -> bool {
134 match p.current() {
135 LIFETIME => true,
136 IMPL_KW => false,
137 token => types::TYPE_FIRST.contains(token),
138 }
139}
140
141fn is_where_clause_end(p: &mut Parser) -> bool {
142 p.current() == L_CURLY || p.current() == SEMI || p.current() == EQ
143}
144
145fn where_predicate(p: &mut Parser) {
146 let m = p.start();
147 match p.current() {
148 LIFETIME => {
149 p.bump();
150 if p.at(COLON) {
151 lifetime_bounds(p);
152 } else {
153 p.error("expected colon");
154 }
155 }
156 IMPL_KW => {
157 p.error("expected lifetime or type");
158 }
159 _ => {
160 // test where_pred_for
161 // fn test<F>()
162 // where
163 // for<'a> F: Fn(&'a str)
164 // { }
165 types::type_(p);
166
167 if p.at(COLON) {
168 bounds(p);
169 } else {
170 p.error("expected colon");
171 }
172 }
173 }
174 m.complete(p, WHERE_PRED);
175}
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs
new file mode 100644
index 000000000..adc189a29
--- /dev/null
+++ b/crates/ra_parser/src/grammar/types.rs
@@ -0,0 +1,278 @@
1use super::*;
2
3pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
4 L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, IMPL_KW,
5 DYN_KW, L_ANGLE,
6]);
7
8const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA];
9
10pub(super) fn type_(p: &mut Parser) {
11 type_with_bounds_cond(p, true);
12}
13
14pub(super) fn type_no_bounds(p: &mut Parser) {
15 type_with_bounds_cond(p, false);
16}
17
18fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
19 match p.current() {
20 L_PAREN => paren_or_tuple_type(p),
21 EXCL => never_type(p),
22 STAR => pointer_type(p),
23 L_BRACK => array_or_slice_type(p),
24 AMP => reference_type(p),
25 UNDERSCORE => placeholder_type(p),
26 FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
27 FOR_KW => for_type(p),
28 IMPL_KW => impl_trait_type(p),
29 DYN_KW => dyn_trait_type(p),
30 // Some path types are not allowed to have bounds (no plus)
31 L_ANGLE => path_type_(p, allow_bounds),
32 _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds),
33 _ => {
34 p.err_recover("expected type", TYPE_RECOVERY_SET);
35 }
36 }
37}
38
39pub(super) fn ascription(p: &mut Parser) {
40 p.expect(COLON);
41 type_(p)
42}
43
44fn paren_or_tuple_type(p: &mut Parser) {
45 assert!(p.at(L_PAREN));
46 let m = p.start();
47 p.bump();
48 let mut n_types: u32 = 0;
49 let mut trailing_comma: bool = false;
50 while !p.at(EOF) && !p.at(R_PAREN) {
51 n_types += 1;
52 type_(p);
53 if p.eat(COMMA) {
54 trailing_comma = true;
55 } else {
56 trailing_comma = false;
57 break;
58 }
59 }
60 p.expect(R_PAREN);
61
62 let kind = if n_types == 1 && !trailing_comma {
63 // test paren_type
64 // type T = (i32);
65 PAREN_TYPE
66 } else {
67 // test unit_type
68 // type T = ();
69
70 // test singleton_tuple_type
71 // type T = (i32,);
72 TUPLE_TYPE
73 };
74 m.complete(p, kind);
75}
76
77// test never_type
78// type Never = !;
79fn never_type(p: &mut Parser) {
80 assert!(p.at(EXCL));
81 let m = p.start();
82 p.bump();
83 m.complete(p, NEVER_TYPE);
84}
85
86fn pointer_type(p: &mut Parser) {
87 assert!(p.at(STAR));
88 let m = p.start();
89 p.bump();
90
91 match p.current() {
92 // test pointer_type_mut
93 // type M = *mut ();
94 // type C = *mut ();
95 MUT_KW | CONST_KW => p.bump(),
96 _ => {
97 // test_err pointer_type_no_mutability
98 // type T = *();
99 p.error(
100 "expected mut or const in raw pointer type \
101 (use `*mut T` or `*const T` as appropriate)",
102 );
103 }
104 };
105
106 type_no_bounds(p);
107 m.complete(p, POINTER_TYPE);
108}
109
110fn array_or_slice_type(p: &mut Parser) {
111 assert!(p.at(L_BRACK));
112 let m = p.start();
113 p.bump();
114
115 type_(p);
116 let kind = match p.current() {
117 // test slice_type
118 // type T = [()];
119 R_BRACK => {
120 p.bump();
121 SLICE_TYPE
122 }
123
124 // test array_type
125 // type T = [(); 92];
126 SEMI => {
127 p.bump();
128 expressions::expr(p);
129 p.expect(R_BRACK);
130 ARRAY_TYPE
131 }
132 // test_err array_type_missing_semi
133 // type T = [() 92];
134 _ => {
135 p.error("expected `;` or `]`");
136 SLICE_TYPE
137 }
138 };
139 m.complete(p, kind);
140}
141
142// test reference_type;
143// type A = &();
144// type B = &'static ();
145// type C = &mut ();
146fn reference_type(p: &mut Parser) {
147 assert!(p.at(AMP));
148 let m = p.start();
149 p.bump();
150 p.eat(LIFETIME);
151 p.eat(MUT_KW);
152 type_no_bounds(p);
153 m.complete(p, REFERENCE_TYPE);
154}
155
156// test placeholder_type
157// type Placeholder = _;
158fn placeholder_type(p: &mut Parser) {
159 assert!(p.at(UNDERSCORE));
160 let m = p.start();
161 p.bump();
162 m.complete(p, PLACEHOLDER_TYPE);
163}
164
165// test fn_pointer_type
166// type A = fn();
167// type B = unsafe fn();
168// type C = unsafe extern "C" fn();
169fn fn_pointer_type(p: &mut Parser) {
170 let m = p.start();
171 p.eat(UNSAFE_KW);
172 if p.at(EXTERN_KW) {
173 abi(p);
174 }
175 // test_err fn_pointer_type_missing_fn
176 // type F = unsafe ();
177 if !p.eat(FN_KW) {
178 m.abandon(p);
179 p.error("expected `fn`");
180 return;
181 }
182 if p.at(L_PAREN) {
183 params::param_list_opt_patterns(p);
184 } else {
185 p.error("expected parameters")
186 }
187 // test fn_pointer_type_with_ret
188 // type F = fn() -> ();
189 opt_fn_ret_type(p);
190 m.complete(p, FN_POINTER_TYPE);
191}
192
193pub(super) fn for_binder(p: &mut Parser) {
194 assert!(p.at(FOR_KW));
195 p.bump();
196 if p.at(L_ANGLE) {
197 type_params::opt_type_param_list(p);
198 } else {
199 p.error("expected `<`");
200 }
201}
202
203// test for_type
204// type A = for<'a> fn() -> ();
205pub(super) fn for_type(p: &mut Parser) {
206 assert!(p.at(FOR_KW));
207 let m = p.start();
208 for_binder(p);
209 match p.current() {
210 FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
211 _ if paths::is_path_start(p) => path_type_(p, false),
212 _ => p.error("expected a path"),
213 }
214 m.complete(p, FOR_TYPE);
215}
216
217// test impl_trait_type
218// type A = impl Iterator<Item=Foo<'a>> + 'a;
219fn impl_trait_type(p: &mut Parser) {
220 assert!(p.at(IMPL_KW));
221 let m = p.start();
222 p.bump();
223 type_params::bounds_without_colon(p);
224 m.complete(p, IMPL_TRAIT_TYPE);
225}
226
227// test dyn_trait_type
228// type A = dyn Iterator<Item=Foo<'a>> + 'a;
229fn dyn_trait_type(p: &mut Parser) {
230 assert!(p.at(DYN_KW));
231 let m = p.start();
232 p.bump();
233 type_params::bounds_without_colon(p);
234 m.complete(p, DYN_TRAIT_TYPE);
235}
236
237// test path_type
238// type A = Foo;
239// type B = ::Foo;
240// type C = self::Foo;
241// type D = super::Foo;
242pub(super) fn path_type(p: &mut Parser) {
243 path_type_(p, true)
244}
245
246// test macro_call_type
247// type A = foo!();
248// type B = crate::foo!();
249fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
250 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
251 let m = p.start();
252 paths::type_path(p);
253
254 let kind = if p.at(EXCL) {
255 items::macro_call_after_excl(p);
256 MACRO_CALL
257 } else {
258 PATH_TYPE
259 };
260
261 if allow_bounds && p.eat(PLUS) {
262 type_params::bounds_without_colon(p);
263 }
264
265 m.complete(p, kind);
266}
267
268pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
269 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
270 let m = p.start();
271 paths::type_path(p);
272 // test path_type_with_bounds
273 // fn foo() -> Box<T + 'f> {}
274 if allow_bounds && p.eat(PLUS) {
275 type_params::bounds_without_colon(p);
276 }
277 m.complete(p, PATH_TYPE);
278}