aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/grammar
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/grammar')
-rw-r--r--crates/ra_syntax/src/grammar/attributes.rs31
-rw-r--r--crates/ra_syntax/src/grammar/expressions/atom.rs400
-rw-r--r--crates/ra_syntax/src/grammar/expressions/mod.rs450
-rw-r--r--crates/ra_syntax/src/grammar/items/consts.rs21
-rw-r--r--crates/ra_syntax/src/grammar/items/mod.rs393
-rw-r--r--crates/ra_syntax/src/grammar/items/nominal.rs154
-rw-r--r--crates/ra_syntax/src/grammar/items/traits.rs117
-rw-r--r--crates/ra_syntax/src/grammar/items/use_item.rs68
-rw-r--r--crates/ra_syntax/src/grammar/mod.rs188
-rw-r--r--crates/ra_syntax/src/grammar/params.rs142
-rw-r--r--crates/ra_syntax/src/grammar/paths.rs101
-rw-r--r--crates/ra_syntax/src/grammar/patterns.rs224
-rw-r--r--crates/ra_syntax/src/grammar/type_args.rs48
-rw-r--r--crates/ra_syntax/src/grammar/type_params.rs136
-rw-r--r--crates/ra_syntax/src/grammar/types.rs247
15 files changed, 2720 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/grammar/attributes.rs b/crates/ra_syntax/src/grammar/attributes.rs
new file mode 100644
index 000000000..cd30e8a45
--- /dev/null
+++ b/crates/ra_syntax/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_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..f01df56bc
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/expressions/atom.rs
@@ -0,0 +1,400 @@
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 =
17 token_set![TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR,
18 STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING];
19
20pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
21 if !p.at_ts(LITERAL_FIRST) {
22 return None;
23 }
24 let m = p.start();
25 p.bump();
26 Some(m.complete(p, LITERAL))
27}
28
29pub(super) const ATOM_EXPR_FIRST: TokenSet =
30 token_set_union![
31 LITERAL_FIRST,
32 token_set![L_CURLY, L_PAREN, L_BRACK, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW,
33 RETURN_KW, IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
34 ];
35
36const EXPR_RECOVERY_SET: TokenSet =
37 token_set![LET_KW];
38
39pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
40 match literal(p) {
41 Some(m) => return Some(m),
42 None => (),
43 }
44 if paths::is_path_start(p) || p.at(L_ANGLE) {
45 return Some(path_expr(p, r));
46 }
47 let la = p.nth(1);
48 let done = match p.current() {
49 L_PAREN => tuple_expr(p),
50 L_BRACK => array_expr(p),
51 PIPE => lambda_expr(p),
52 MOVE_KW if la == PIPE => lambda_expr(p),
53 IF_KW => if_expr(p),
54
55 LOOP_KW => loop_expr(p, None),
56 FOR_KW => for_expr(p, None),
57 WHILE_KW => while_expr(p, None),
58 LIFETIME if la == COLON => {
59 let m = p.start();
60 label(p);
61 match p.current() {
62 LOOP_KW => loop_expr(p, Some(m)),
63 FOR_KW => for_expr(p, Some(m)),
64 WHILE_KW => while_expr(p, Some(m)),
65 L_CURLY => block_expr(p, Some(m)),
66 _ => {
67 // test misplaced_label_err
68 // fn main() {
69 // 'loop: impl
70 // }
71 p.error("expected a loop");
72 m.complete(p, ERROR);
73 return None;
74 }
75 }
76 }
77
78 MATCH_KW => match_expr(p),
79 UNSAFE_KW if la == L_CURLY => {
80 let m = p.start();
81 p.bump();
82 block_expr(p, Some(m))
83 },
84 L_CURLY => block_expr(p, None),
85 RETURN_KW => return_expr(p),
86 CONTINUE_KW => continue_expr(p),
87 BREAK_KW => break_expr(p),
88 _ => {
89 p.err_recover("expected expression", EXPR_RECOVERY_SET);
90 return None;
91 }
92 };
93 Some(done)
94}
95
96// test tuple_expr
97// fn foo() {
98// ();
99// (1);
100// (1,);
101// }
102fn tuple_expr(p: &mut Parser) -> CompletedMarker {
103 assert!(p.at(L_PAREN));
104 let m = p.start();
105 p.expect(L_PAREN);
106
107 let mut saw_comma = false;
108 let mut saw_expr = false;
109 while !p.at(EOF) && !p.at(R_PAREN) {
110 saw_expr = true;
111 if !p.at_ts(EXPR_FIRST) {
112 p.error("expected expression");
113 break;
114 }
115 expr(p);
116 if !p.at(R_PAREN) {
117 saw_comma = true;
118 p.expect(COMMA);
119 }
120 }
121 p.expect(R_PAREN);
122 m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
123}
124
125// test array_expr
126// fn foo() {
127// [];
128// [1];
129// [1, 2,];
130// [1; 2];
131// }
132fn array_expr(p: &mut Parser) -> CompletedMarker {
133 assert!(p.at(L_BRACK));
134 let m = p.start();
135 p.bump();
136 if p.eat(R_BRACK) {
137 return m.complete(p, ARRAY_EXPR);
138 }
139 expr(p);
140 if p.eat(SEMI) {
141 expr(p);
142 p.expect(R_BRACK);
143 return m.complete(p, ARRAY_EXPR);
144 }
145 while !p.at(EOF) && !p.at(R_BRACK) {
146 p.expect(COMMA);
147 if p.at(R_BRACK) {
148 break;
149 }
150 if !p.at_ts(EXPR_FIRST) {
151 p.error("expected expression");
152 break;
153 }
154 expr(p);
155 }
156 p.expect(R_BRACK);
157 m.complete(p, ARRAY_EXPR)
158}
159
160// test lambda_expr
161// fn foo() {
162// || ();
163// || -> i32 { 92 };
164// |x| x;
165// move |x: i32,| x;
166// }
167fn lambda_expr(p: &mut Parser) -> CompletedMarker {
168 assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
169 let m = p.start();
170 p.eat(MOVE_KW);
171 params::param_list_opt_types(p);
172 if opt_fn_ret_type(p) {
173 if !p.at(L_CURLY) {
174 p.error("expected `{`");
175 }
176 }
177 expr(p);
178 m.complete(p, LAMBDA_EXPR)
179}
180
181// test if_expr
182// fn foo() {
183// if true {};
184// if true {} else {};
185// if true {} else if false {} else {};
186// if S {};
187// }
188fn if_expr(p: &mut Parser) -> CompletedMarker {
189 assert!(p.at(IF_KW));
190 let m = p.start();
191 p.bump();
192 cond(p);
193 block(p);
194 if p.at(ELSE_KW) {
195 p.bump();
196 if p.at(IF_KW) {
197 if_expr(p);
198 } else {
199 block(p);
200 }
201 }
202 m.complete(p, IF_EXPR)
203}
204
205// test label
206// fn foo() {
207// 'a: loop {}
208// 'b: while true {}
209// 'c: for x in () {}
210// }
211fn label(p: &mut Parser) {
212 assert!(p.at(LIFETIME) && p.nth(1) == COLON);
213 let m = p.start();
214 p.bump();
215 p.bump();
216 m.complete(p, LABEL);
217}
218
219// test loop_expr
220// fn foo() {
221// loop {};
222// }
223fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
224 assert!(p.at(LOOP_KW));
225 let m = m.unwrap_or_else(|| p.start());
226 p.bump();
227 block(p);
228 m.complete(p, LOOP_EXPR)
229}
230
231// test while_expr
232// fn foo() {
233// while true {};
234// while let Some(x) = it.next() {};
235// }
236fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
237 assert!(p.at(WHILE_KW));
238 let m = m.unwrap_or_else(|| p.start());
239 p.bump();
240 cond(p);
241 block(p);
242 m.complete(p, WHILE_EXPR)
243}
244
245// test for_expr
246// fn foo() {
247// for x in [] {};
248// }
249fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
250 assert!(p.at(FOR_KW));
251 let m = m.unwrap_or_else(|| p.start());
252 p.bump();
253 patterns::pattern(p);
254 p.expect(IN_KW);
255 expr_no_struct(p);
256 block(p);
257 m.complete(p, FOR_EXPR)
258}
259
260// test cond
261// fn foo() { if let Some(_) = None {} }
262fn cond(p: &mut Parser) {
263 let m = p.start();
264 if p.eat(LET_KW) {
265 patterns::pattern(p);
266 p.expect(EQ);
267 }
268 expr_no_struct(p);
269 m.complete(p, CONDITION);
270}
271
272// test match_expr
273// fn foo() {
274// match () { };
275// match S {};
276// }
277fn match_expr(p: &mut Parser) -> CompletedMarker {
278 assert!(p.at(MATCH_KW));
279 let m = p.start();
280 p.bump();
281 expr_no_struct(p);
282 if p.at(L_CURLY) {
283 match_arm_list(p);
284 } else {
285 p.error("expected `{`")
286 }
287 m.complete(p, MATCH_EXPR)
288}
289
290pub(crate) fn match_arm_list(p: &mut Parser) {
291 assert!(p.at(L_CURLY));
292 let m = p.start();
293 p.eat(L_CURLY);
294 while !p.at(EOF) && !p.at(R_CURLY) {
295 if p.at(L_CURLY) {
296 error_block(p, "expected match arm");
297 continue;
298 }
299 // test match_arms_commas
300 // fn foo() {
301 // match () {
302 // _ => (),
303 // _ => {}
304 // _ => ()
305 // }
306 // }
307 if match_arm(p).is_block() {
308 p.eat(COMMA);
309 } else if !p.at(R_CURLY) {
310 p.expect(COMMA);
311 }
312 }
313 p.expect(R_CURLY);
314 m.complete(p, MATCH_ARM_LIST);
315}
316
317// test match_arm
318// fn foo() {
319// match () {
320// _ => (),
321// X | Y if Z => (),
322// };
323// }
324fn match_arm(p: &mut Parser) -> BlockLike {
325 let m = p.start();
326 patterns::pattern_r(p, TokenSet::EMPTY);
327 while p.eat(PIPE) {
328 patterns::pattern(p);
329 }
330 if p.eat(IF_KW) {
331 expr_no_struct(p);
332 }
333 p.expect(FAT_ARROW);
334 let ret = expr_stmt(p);
335 m.complete(p, MATCH_ARM);
336 ret
337}
338
339// test block_expr
340// fn foo() {
341// {};
342// unsafe {};
343// 'label: {};
344// }
345fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
346 assert!(p.at(L_CURLY));
347 let m = m.unwrap_or_else(|| p.start());
348 block(p);
349 m.complete(p, BLOCK_EXPR)
350}
351
352// test return_expr
353// fn foo() {
354// return;
355// return 92;
356// }
357fn return_expr(p: &mut Parser) -> CompletedMarker {
358 assert!(p.at(RETURN_KW));
359 let m = p.start();
360 p.bump();
361 if p.at_ts(EXPR_FIRST) {
362 expr(p);
363 }
364 m.complete(p, RETURN_EXPR)
365}
366
367// test continue_expr
368// fn foo() {
369// loop {
370// continue;
371// continue 'l;
372// }
373// }
374fn continue_expr(p: &mut Parser) -> CompletedMarker {
375 assert!(p.at(CONTINUE_KW));
376 let m = p.start();
377 p.bump();
378 p.eat(LIFETIME);
379 m.complete(p, CONTINUE_EXPR)
380}
381
382// test break_expr
383// fn foo() {
384// loop {
385// break;
386// break 'l;
387// break 92;
388// break 'l 92;
389// }
390// }
391fn break_expr(p: &mut Parser) -> CompletedMarker {
392 assert!(p.at(BREAK_KW));
393 let m = p.start();
394 p.bump();
395 p.eat(LIFETIME);
396 if p.at_ts(EXPR_FIRST) {
397 expr(p);
398 }
399 m.complete(p, BREAK_EXPR)
400}
diff --git a/crates/ra_syntax/src/grammar/expressions/mod.rs b/crates/ra_syntax/src/grammar/expressions/mod.rs
new file mode 100644
index 000000000..20e0fa328
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/expressions/mod.rs
@@ -0,0 +1,450 @@
1mod atom;
2
3use super::*;
4pub(super) use self::atom::{literal, LITERAL_FIRST};
5pub(crate) use self::atom::match_arm_list;
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 while !p.at(EOF) && !p.at(R_CURLY) {
37 match p.current() {
38 LET_KW => let_stmt(p),
39 _ => {
40 // test block_items
41 // fn a() { fn b() {} }
42 let m = p.start();
43 match items::maybe_item(p, items::ItemFlavor::Mod) {
44 items::MaybeItem::Item(kind) => {
45 m.complete(p, kind);
46 }
47 items::MaybeItem::Modifiers => {
48 m.abandon(p);
49 p.error("expected an item");
50 }
51 // test pub_expr
52 // fn foo() { pub 92; } //FIXME
53 items::MaybeItem::None => {
54 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block;
55 if p.at(R_CURLY) {
56 m.abandon(p);
57 } else {
58 if is_blocklike {
59 p.eat(SEMI);
60 } else {
61 p.expect(SEMI);
62 }
63 m.complete(p, EXPR_STMT);
64 }
65 }
66 }
67 }
68 }
69 }
70 p.expect(R_CURLY);
71 m.complete(p, BLOCK);
72
73 // test let_stmt;
74 // fn foo() {
75 // let a;
76 // let b: i32;
77 // let c = 92;
78 // let d: i32 = 92;
79 // }
80 fn let_stmt(p: &mut Parser) {
81 assert!(p.at(LET_KW));
82 let m = p.start();
83 p.bump();
84 patterns::pattern(p);
85 if p.at(COLON) {
86 types::ascription(p);
87 }
88 if p.eat(EQ) {
89 expressions::expr(p);
90 }
91 p.expect(SEMI);
92 m.complete(p, LET_STMT);
93 }
94}
95
96#[derive(Clone, Copy)]
97struct Restrictions {
98 forbid_structs: bool,
99 prefer_stmt: bool,
100}
101
102enum Op {
103 Simple,
104 Composite(SyntaxKind, u8),
105}
106
107fn current_op(p: &Parser) -> (u8, Op) {
108 if let Some(t) = p.next3() {
109 match t {
110 (L_ANGLE, L_ANGLE, EQ) =>
111 return (1, Op::Composite(SHLEQ, 3)),
112 (R_ANGLE, R_ANGLE, EQ) =>
113 return (1, Op::Composite(SHREQ, 3)),
114 _ => (),
115 }
116 }
117
118 if let Some(t) = p.next2() {
119 match t {
120 (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)),
121 (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)),
122 (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)),
123 (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)),
124 (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)),
125 (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)),
126 (CARET, EQ) => return (1, Op::Composite(CARETEQ, 2)),
127 (PIPE, PIPE) => return (3, Op::Composite(PIPEPIPE, 2)),
128 (AMP, AMP) => return (4, Op::Composite(AMPAMP, 2)),
129 (L_ANGLE, EQ) => return (5, Op::Composite(LTEQ, 2)),
130 (R_ANGLE, EQ) => return (5, Op::Composite(GTEQ, 2)),
131 (L_ANGLE, L_ANGLE) => return (9, Op::Composite(SHL, 2)),
132 (R_ANGLE, R_ANGLE) => return (9, Op::Composite(SHR, 2)),
133 _ => (),
134 }
135 }
136
137 let bp = match p.current() {
138 EQ => 1,
139 DOTDOT => 2,
140 EQEQ | NEQ | L_ANGLE | R_ANGLE => 5,
141 PIPE => 6,
142 CARET => 7,
143 AMP => 8,
144 MINUS | PLUS => 10,
145 STAR | SLASH | PERCENT => 11,
146 _ => 0,
147 };
148 (bp, Op::Simple)
149}
150
151// Parses expression with binding power of at least bp.
152fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
153 let mut lhs = match lhs(p, r) {
154 Some(lhs) => {
155 // test stmt_bin_expr_ambiguity
156 // fn foo() {
157 // let _ = {1} & 2;
158 // {1} &2;
159 // }
160 if r.prefer_stmt && is_block(lhs.kind()) {
161 return BlockLike::Block;
162 }
163 lhs
164 }
165 None => return BlockLike::NotBlock,
166 };
167
168 loop {
169 let is_range = p.current() == DOTDOT;
170 let (op_bp, op) = current_op(p);
171 if op_bp < bp {
172 break;
173 }
174 let m = lhs.precede(p);
175 match op {
176 Op::Simple => p.bump(),
177 Op::Composite(kind, n) => {
178 p.bump_compound(kind, n);
179 }
180 }
181 expr_bp(p, r, op_bp + 1);
182 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
183 }
184 BlockLike::NotBlock
185}
186
187// test no_semi_after_block
188// fn foo() {
189// if true {}
190// loop {}
191// match () {}
192// while true {}
193// for _ in () {}
194// {}
195// {}
196// }
197fn is_block(kind: SyntaxKind) -> bool {
198 match kind {
199 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => true,
200 _ => false,
201 }
202}
203
204const LHS_FIRST: TokenSet =
205 token_set_union![
206 token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
207 atom::ATOM_EXPR_FIRST,
208 ];
209
210fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
211 let m;
212 let kind = match p.current() {
213 // test ref_expr
214 // fn foo() {
215 // let _ = &1;
216 // let _ = &mut &f();
217 // }
218 AMP => {
219 m = p.start();
220 p.bump();
221 p.eat(MUT_KW);
222 REF_EXPR
223 }
224 // test unary_expr
225 // fn foo() {
226 // **&1;
227 // !!true;
228 // --1;
229 // }
230 STAR | EXCL | MINUS => {
231 m = p.start();
232 p.bump();
233 PREFIX_EXPR
234 }
235 // test full_range_expr
236 // fn foo() { xs[..]; }
237 DOTDOT => {
238 m = p.start();
239 p.bump();
240 if p.at_ts(EXPR_FIRST) {
241 expr_bp(p, r, 2);
242 }
243 return Some(m.complete(p, RANGE_EXPR));
244 }
245 _ => {
246 let lhs = atom::atom_expr(p, r)?;
247 return Some(postfix_expr(p, r, lhs));
248 }
249 };
250 expr_bp(p, r, 255);
251 Some(m.complete(p, kind))
252}
253
254fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker {
255 let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind());
256 loop {
257 lhs = match p.current() {
258 // test stmt_postfix_expr_ambiguity
259 // fn foo() {
260 // match () {
261 // _ => {}
262 // () => {}
263 // [] => {}
264 // }
265 // }
266 L_PAREN if allow_calls => call_expr(p, lhs),
267 L_BRACK if allow_calls => index_expr(p, lhs),
268 DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
269 method_call_expr(p, lhs)
270 } else {
271 field_expr(p, lhs)
272 },
273 DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
274 // test postfix_range
275 // fn foo() { let x = 1..; }
276 DOTDOT if !EXPR_FIRST.contains(p.nth(1)) => {
277 let m = lhs.precede(p);
278 p.bump();
279 m.complete(p, RANGE_EXPR)
280 }
281 QUESTION => try_expr(p, lhs),
282 AS_KW => cast_expr(p, lhs),
283 _ => break,
284 };
285 allow_calls = true
286 }
287 lhs
288}
289
290// test call_expr
291// fn foo() {
292// let _ = f();
293// let _ = f()(1)(1, 2,);
294// }
295fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
296 assert!(p.at(L_PAREN));
297 let m = lhs.precede(p);
298 arg_list(p);
299 m.complete(p, CALL_EXPR)
300}
301
302// test index_expr
303// fn foo() {
304// x[1][2];
305// }
306fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
307 assert!(p.at(L_BRACK));
308 let m = lhs.precede(p);
309 p.bump();
310 expr(p);
311 p.expect(R_BRACK);
312 m.complete(p, INDEX_EXPR)
313}
314
315// test method_call_expr
316// fn foo() {
317// x.foo();
318// y.bar::<T>(1, 2,);
319// }
320fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
321 assert!(
322 p.at(DOT) && p.nth(1) == IDENT
323 && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON)
324 );
325 let m = lhs.precede(p);
326 p.bump();
327 name_ref(p);
328 type_args::opt_type_arg_list(p, true);
329 if p.at(L_PAREN) {
330 arg_list(p);
331 }
332 m.complete(p, METHOD_CALL_EXPR)
333}
334
335// test field_expr
336// fn foo() {
337// x.foo;
338// x.0.bar;
339// }
340fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
341 assert!(p.at(DOT) && (p.nth(1) == IDENT || p.nth(1) == INT_NUMBER));
342 let m = lhs.precede(p);
343 p.bump();
344 if p.at(IDENT) {
345 name_ref(p)
346 } else {
347 p.bump()
348 }
349 m.complete(p, FIELD_EXPR)
350}
351
352// test try_expr
353// fn foo() {
354// x?;
355// }
356fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
357 assert!(p.at(QUESTION));
358 let m = lhs.precede(p);
359 p.bump();
360 m.complete(p, TRY_EXPR)
361}
362
363// test cast_expr
364// fn foo() {
365// 82 as i32;
366// }
367fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
368 assert!(p.at(AS_KW));
369 let m = lhs.precede(p);
370 p.bump();
371 types::type_(p);
372 m.complete(p, CAST_EXPR)
373}
374
375fn arg_list(p: &mut Parser) {
376 assert!(p.at(L_PAREN));
377 let m = p.start();
378 p.bump();
379 while !p.at(R_PAREN) && !p.at(EOF) {
380 if !p.at_ts(EXPR_FIRST) {
381 p.error("expected expression");
382 break;
383 }
384 expr(p);
385 if !p.at(R_PAREN) && !p.expect(COMMA) {
386 break;
387 }
388 }
389 p.eat(R_PAREN);
390 m.complete(p, ARG_LIST);
391}
392
393// test path_expr
394// fn foo() {
395// let _ = a;
396// let _ = a::b;
397// let _ = ::a::<b>;
398// let _ = format!();
399// }
400fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
401 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
402 let m = p.start();
403 paths::expr_path(p);
404 match p.current() {
405 L_CURLY if !r.forbid_structs => {
406 named_field_list(p);
407 m.complete(p, STRUCT_LIT)
408 }
409 EXCL => {
410 items::macro_call_after_excl(p);
411 m.complete(p, MACRO_CALL)
412 }
413 _ => m.complete(p, PATH_EXPR)
414 }
415}
416
417// test struct_lit
418// fn foo() {
419// S {};
420// S { x, y: 32, };
421// S { x, y: 32, ..Default::default() };
422// }
423pub(crate) fn named_field_list(p: &mut Parser) {
424 assert!(p.at(L_CURLY));
425 let m = p.start();
426 p.bump();
427 while !p.at(EOF) && !p.at(R_CURLY) {
428 match p.current() {
429 IDENT => {
430 let m = p.start();
431 name_ref(p);
432 if p.eat(COLON) {
433 expr(p);
434 }
435 m.complete(p, NAMED_FIELD);
436 }
437 DOTDOT => {
438 p.bump();
439 expr(p);
440 }
441 L_CURLY => error_block(p, "expected a field"),
442 _ => p.err_and_bump("expected identifier"),
443 }
444 if !p.at(R_CURLY) {
445 p.expect(COMMA);
446 }
447 }
448 p.expect(R_CURLY);
449 m.complete(p, NAMED_FIELD_LIST);
450}
diff --git a/crates/ra_syntax/src/grammar/items/consts.rs b/crates/ra_syntax/src/grammar/items/consts.rs
new file mode 100644
index 000000000..5a5852f83
--- /dev/null
+++ b/crates/ra_syntax/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_syntax/src/grammar/items/mod.rs b/crates/ra_syntax/src/grammar/items/mod.rs
new file mode 100644
index 000000000..2567313ab
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/mod.rs
@@ -0,0 +1,393 @@
1
2mod consts;
3mod nominal;
4mod traits;
5mod use_item;
6
7use super::*;
8pub(crate) use self::{
9 expressions::{named_field_list, match_arm_list},
10 nominal::{enum_variant_list, named_field_def_list},
11 traits::{trait_item_list, impl_item_list},
12 use_item::use_tree_list,
13};
14
15// test mod_contents
16// fn foo() {}
17// macro_rules! foo {}
18// foo::bar!();
19// super::baz! {}
20// struct S;
21pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
22 attributes::inner_attributes(p);
23 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
24 item_or_macro(p, stop_on_r_curly, ItemFlavor::Mod)
25 }
26}
27
28pub(super) enum ItemFlavor {
29 Mod, Trait
30}
31
32const ITEM_RECOVERY_SET: TokenSet =
33 token_set![FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW,
34 MOD_KW, PUB_KW, CRATE_KW];
35
36pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
37 let m = p.start();
38 match maybe_item(p, flavor) {
39 MaybeItem::Item(kind) => {
40 m.complete(p, kind);
41 }
42 MaybeItem::None => {
43 if paths::is_path_start(p) {
44 match macro_call(p) {
45 BlockLike::Block => (),
46 BlockLike::NotBlock => {
47 p.expect(SEMI);
48 }
49 }
50 m.complete(p, MACRO_CALL);
51 } else {
52 m.abandon(p);
53 if p.at(L_CURLY) {
54 error_block(p, "expected an item");
55 } else if p.at(R_CURLY) && !stop_on_r_curly {
56 let e = p.start();
57 p.error("unmatched `}`");
58 p.bump();
59 e.complete(p, ERROR);
60 } else if !p.at(EOF) && !p.at(R_CURLY) {
61 p.err_and_bump("expected an item");
62 } else {
63 p.error("expected an item");
64 }
65 }
66 }
67 MaybeItem::Modifiers => {
68 p.error("expected fn, trait or impl");
69 m.complete(p, ERROR);
70 }
71 }
72}
73
74pub(super) enum MaybeItem {
75 None,
76 Item(SyntaxKind),
77 Modifiers,
78}
79
80pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem {
81 attributes::outer_attributes(p);
82 opt_visibility(p);
83 if let Some(kind) = items_without_modifiers(p) {
84 return MaybeItem::Item(kind);
85 }
86
87 let mut has_mods = false;
88 // modifiers
89 has_mods |= p.eat(CONST_KW);
90
91 // test unsafe_block_in_mod
92 // fn foo(){} unsafe { } fn bar(){}
93 if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY {
94 p.eat(UNSAFE_KW);
95 has_mods = true;
96 }
97 if p.at(EXTERN_KW) {
98 has_mods = true;
99 abi(p);
100 }
101 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
102 p.bump_remap(AUTO_KW);
103 has_mods = true;
104 }
105 if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
106 p.bump_remap(DEFAULT_KW);
107 has_mods = true;
108 }
109
110 // items
111 let kind = match p.current() {
112 // test extern_fn
113 // extern fn foo() {}
114
115 // test const_fn
116 // const fn foo() {}
117
118 // test const_unsafe_fn
119 // const unsafe fn foo() {}
120
121 // test unsafe_extern_fn
122 // unsafe extern "C" fn foo() {}
123
124 // test unsafe_fn
125 // unsafe fn foo() {}
126 FN_KW => {
127 fn_def(p, flavor);
128 FN_DEF
129 }
130
131 // test unsafe_trait
132 // unsafe trait T {}
133
134 // test auto_trait
135 // auto trait T {}
136
137 // test unsafe_auto_trait
138 // unsafe auto trait T {}
139 TRAIT_KW => {
140 traits::trait_def(p);
141 TRAIT_DEF
142 }
143
144 // test unsafe_impl
145 // unsafe impl Foo {}
146
147 // test default_impl
148 // default impl Foo {}
149
150 // test unsafe_default_impl
151 // unsafe default impl Foo {}
152 IMPL_KW => {
153 traits::impl_item(p);
154 IMPL_ITEM
155 }
156 _ => return if has_mods {
157 MaybeItem::Modifiers
158 } else {
159 MaybeItem::None
160 }
161 };
162
163 MaybeItem::Item(kind)
164}
165
166fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
167 let la = p.nth(1);
168 let kind = match p.current() {
169 // test extern_crate
170 // extern crate foo;
171 EXTERN_KW if la == CRATE_KW => {
172 extern_crate_item(p);
173 EXTERN_CRATE_ITEM
174 }
175 TYPE_KW => {
176 type_def(p);
177 TYPE_DEF
178 }
179 MOD_KW => {
180 mod_item(p);
181 MODULE
182 }
183 STRUCT_KW => {
184 // test struct_items
185 // struct Foo;
186 // struct Foo {}
187 // struct Foo();
188 // struct Foo(String, usize);
189 // struct Foo {
190 // a: i32,
191 // b: f32,
192 // }
193 nominal::struct_def(p, STRUCT_KW);
194 if p.at(SEMI) {
195 p.err_and_bump(
196 "expected item, found `;`\n\
197 consider removing this semicolon"
198 );
199 }
200 STRUCT_DEF
201 }
202 IDENT if p.at_contextual_kw("union") => {
203 // test union_items
204 // union Foo {}
205 // union Foo {
206 // a: i32,
207 // b: f32,
208 // }
209 nominal::struct_def(p, UNION_KW);
210 STRUCT_DEF
211 }
212 ENUM_KW => {
213 nominal::enum_def(p);
214 ENUM_DEF
215 }
216 USE_KW => {
217 use_item::use_item(p);
218 USE_ITEM
219 }
220 CONST_KW if (la == IDENT || la == MUT_KW) => {
221 consts::const_def(p);
222 CONST_DEF
223 }
224 STATIC_KW => {
225 consts::static_def(p);
226 STATIC_DEF
227 }
228 // test extern_block
229 // extern {}
230 EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => {
231 abi(p);
232 extern_item_list(p);
233 EXTERN_BLOCK
234 }
235 _ => return None,
236 };
237 Some(kind)
238}
239
240fn extern_crate_item(p: &mut Parser) {
241 assert!(p.at(EXTERN_KW));
242 p.bump();
243 assert!(p.at(CRATE_KW));
244 p.bump();
245 name(p);
246 opt_alias(p);
247 p.expect(SEMI);
248}
249
250pub(crate) fn extern_item_list(p: &mut Parser) {
251 assert!(p.at(L_CURLY));
252 let m = p.start();
253 p.bump();
254 mod_contents(p, true);
255 p.expect(R_CURLY);
256 m.complete(p, EXTERN_ITEM_LIST);
257}
258
259fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
260 assert!(p.at(FN_KW));
261 p.bump();
262
263 name_r(p, ITEM_RECOVERY_SET);
264 // test function_type_params
265 // fn foo<T: Clone + Copy>(){}
266 type_params::opt_type_param_list(p);
267
268 if p.at(L_PAREN) {
269 match flavor {
270 ItemFlavor::Mod =>
271 params::param_list(p),
272 ItemFlavor::Trait =>
273 params::param_list_opt_patterns(p),
274 }
275 } else {
276 p.error("expected function arguments");
277 }
278 // test function_ret_type
279 // fn foo() {}
280 // fn bar() -> () {}
281 opt_fn_ret_type(p);
282
283 // test function_where_clause
284 // fn foo<T>() where T: Copy {}
285 type_params::opt_where_clause(p);
286
287 // test fn_decl
288 // trait T { fn foo(); }
289 if p.at(SEMI) {
290 p.bump();
291 } else {
292 expressions::block(p)
293 }
294}
295
296// test type_item
297// type Foo = Bar;
298fn type_def(p: &mut Parser) {
299 assert!(p.at(TYPE_KW));
300 p.bump();
301
302 name(p);
303
304 // test type_item_type_params
305 // type Result<T> = ();
306 type_params::opt_type_param_list(p);
307
308 if p.at(COLON) {
309 type_params::bounds(p);
310 }
311
312 // test type_item_where_clause
313 // type Foo where Foo: Copy = ();
314 type_params::opt_where_clause(p);
315
316 if p.eat(EQ) {
317 types::type_(p);
318 }
319 p.expect(SEMI);
320}
321
322pub(crate) fn mod_item(p: &mut Parser) {
323 assert!(p.at(MOD_KW));
324 p.bump();
325
326 name(p);
327 if p.at(L_CURLY) {
328 mod_item_list(p);
329 } else if !p.eat(SEMI) {
330 p.error("expected `;` or `{`");
331 }
332}
333
334pub(crate) fn mod_item_list(p: &mut Parser) {
335 assert!(p.at(L_CURLY));
336 let m = p.start();
337 p.bump();
338 mod_contents(p, true);
339 p.expect(R_CURLY);
340 m.complete(p, ITEM_LIST);
341}
342
343fn macro_call(p: &mut Parser) -> BlockLike {
344 assert!(paths::is_path_start(p));
345 paths::use_path(p);
346 macro_call_after_excl(p)
347}
348
349pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
350 p.expect(EXCL);
351 p.eat(IDENT);
352 let flavor = match p.current() {
353 L_CURLY => {
354 token_tree(p);
355 BlockLike::Block
356 }
357 L_PAREN | L_BRACK => {
358 token_tree(p);
359 BlockLike::NotBlock
360 }
361 _ => {
362 p.error("expected `{`, `[`, `(`");
363 BlockLike::NotBlock
364 },
365 };
366
367 flavor
368}
369
370pub(crate) fn token_tree(p: &mut Parser) {
371 let closing_paren_kind = match p.current() {
372 L_CURLY => R_CURLY,
373 L_PAREN => R_PAREN,
374 L_BRACK => R_BRACK,
375 _ => unreachable!(),
376 };
377 let m = p.start();
378 p.bump();
379 while !p.at(EOF) && !p.at(closing_paren_kind) {
380 match p.current() {
381 L_CURLY | L_PAREN | L_BRACK => token_tree(p),
382 R_CURLY => {
383 p.error("unmatched `}`");
384 m.complete(p, TOKEN_TREE);
385 return;
386 }
387 R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"),
388 _ => p.bump()
389 }
390 };
391 p.expect(closing_paren_kind);
392 m.complete(p, TOKEN_TREE);
393}
diff --git a/crates/ra_syntax/src/grammar/items/nominal.rs b/crates/ra_syntax/src/grammar/items/nominal.rs
new file mode 100644
index 000000000..8d02ad555
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/nominal.rs
@@ -0,0 +1,154 @@
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_list(p);
32 p.expect(SEMI);
33 }
34 _ if kind == STRUCT_KW => {
35 p.error("expected `;`, `{`, or `(`");
36 return;
37 }
38 _ => {
39 p.error("expected `{`");
40 return;
41 }
42 }
43}
44
45pub(super) fn enum_def(p: &mut Parser) {
46 assert!(p.at(ENUM_KW));
47 p.bump();
48 name_r(p, ITEM_RECOVERY_SET);
49 type_params::opt_type_param_list(p);
50 type_params::opt_where_clause(p);
51 if p.at(L_CURLY) {
52 enum_variant_list(p);
53 } else {
54 p.error("expected `{`")
55 }
56}
57
58pub(crate) fn enum_variant_list(p: &mut Parser) {
59 assert!(p.at(L_CURLY));
60 let m = p.start();
61 p.bump();
62 while !p.at(EOF) && !p.at(R_CURLY) {
63 if p.at(L_CURLY) {
64 error_block(p, "expected enum variant");
65 continue;
66 }
67 let var = p.start();
68 attributes::outer_attributes(p);
69 if p.at(IDENT) {
70 name(p);
71 match p.current() {
72 L_CURLY => named_field_def_list(p),
73 L_PAREN => pos_field_list(p),
74 EQ => {
75 p.bump();
76 expressions::expr(p);
77 }
78 _ => (),
79 }
80 var.complete(p, ENUM_VARIANT);
81 } else {
82 var.abandon(p);
83 p.err_and_bump("expected enum variant");
84 }
85 if !p.at(R_CURLY) {
86 p.expect(COMMA);
87 }
88 }
89 p.expect(R_CURLY);
90 m.complete(p, ENUM_VARIANT_LIST);
91}
92
93pub(crate) fn named_field_def_list(p: &mut Parser) {
94 assert!(p.at(L_CURLY));
95 let m = p.start();
96 p.bump();
97 while !p.at(R_CURLY) && !p.at(EOF) {
98 if p.at(L_CURLY) {
99 error_block(p, "expected field");
100 continue;
101 }
102 named_field_def(p);
103 if !p.at(R_CURLY) {
104 p.expect(COMMA);
105 }
106 }
107 p.expect(R_CURLY);
108 m.complete(p, NAMED_FIELD_DEF_LIST);
109
110 fn named_field_def(p: &mut Parser) {
111 let m = p.start();
112 // test field_attrs
113 // struct S {
114 // #[serde(with = "url_serde")]
115 // pub uri: Uri,
116 // }
117 attributes::outer_attributes(p);
118 opt_visibility(p);
119 if p.at(IDENT) {
120 name(p);
121 p.expect(COLON);
122 types::type_(p);
123 m.complete(p, NAMED_FIELD_DEF);
124 } else {
125 m.abandon(p);
126 p.err_and_bump("expected field declaration");
127 }
128 }
129}
130
131fn pos_field_list(p: &mut Parser) {
132 assert!(p.at(L_PAREN));
133 let m = p.start();
134 if !p.expect(L_PAREN) {
135 return;
136 }
137 while !p.at(R_PAREN) && !p.at(EOF) {
138 let m = p.start();
139 opt_visibility(p);
140 if !p.at_ts(types::TYPE_FIRST) {
141 p.error("expected a type");
142 m.complete(p, ERROR);
143 break;
144 }
145 types::type_(p);
146 m.complete(p, POS_FIELD);
147
148 if !p.at(R_PAREN) {
149 p.expect(COMMA);
150 }
151 }
152 p.expect(R_PAREN);
153 m.complete(p, POS_FIELD_LIST);
154}
diff --git a/crates/ra_syntax/src/grammar/items/traits.rs b/crates/ra_syntax/src/grammar/items/traits.rs
new file mode 100644
index 000000000..c21cfb1a9
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/traits.rs
@@ -0,0 +1,117 @@
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_item
44// impl Foo {}
45pub(super) fn impl_item(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_item_neg
56 // impl !Send for X {}
57 p.eat(EXCL);
58 types::type_(p);
59 if p.eat(FOR_KW) {
60 types::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
82 while !p.at(EOF) && !p.at(R_CURLY) {
83 if p.at(L_CURLY) {
84 error_block(p, "expected an item");
85 continue;
86 }
87 item_or_macro(p, true, ItemFlavor::Mod);
88 }
89 p.expect(R_CURLY);
90 m.complete(p, ITEM_LIST);
91}
92
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 // `<` (LIFETIME|IDENT) `>` - single generic parameter
101 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
102 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
103 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
104 // The only truly ambiguous case is
105 // `<` IDENT `>` `::` IDENT ...
106 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
107 // because this is what almost always expected in practice, qualified paths in impls
108 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
109 if !p.at(L_ANGLE) {
110 return false;
111 }
112 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
113 return true;
114 }
115 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
116 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
117}
diff --git a/crates/ra_syntax/src/grammar/items/use_item.rs b/crates/ra_syntax/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..1ee4349fd
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/items/use_item.rs
@@ -0,0 +1,68 @@
1use super::*;
2
3pub(super) fn use_item(p: &mut Parser) {
4 assert!(p.at(USE_KW));
5 p.bump();
6 use_tree(p);
7 p.expect(SEMI);
8}
9
10fn use_tree(p: &mut Parser) {
11 let la = p.nth(1);
12 let m = p.start();
13 match (p.current(), la) {
14 (STAR, _) => p.bump(),
15 (COLONCOLON, STAR) => {
16 p.bump();
17 p.bump();
18 }
19 (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
20 if p.at(COLONCOLON) {
21 p.bump();
22 }
23 use_tree_list(p);
24 }
25 _ if paths::is_path_start(p) => {
26 paths::use_path(p);
27 match p.current() {
28 AS_KW => {
29 opt_alias(p);
30 }
31 COLONCOLON => {
32 p.bump();
33 match p.current() {
34 STAR => {
35 p.bump();
36 }
37 L_CURLY => use_tree_list(p),
38 _ => {
39 // is this unreachable?
40 p.error("expected `{` or `*`");
41 }
42 }
43 }
44 _ => (),
45 }
46 }
47 _ => {
48 m.abandon(p);
49 p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
50 return;
51 }
52 }
53 m.complete(p, USE_TREE);
54}
55
56pub(crate) fn use_tree_list(p: &mut Parser) {
57 assert!(p.at(L_CURLY));
58 let m = p.start();
59 p.bump();
60 while !p.at(EOF) && !p.at(R_CURLY) {
61 use_tree(p);
62 if !p.at(R_CURLY) {
63 p.expect(COMMA);
64 }
65 }
66 p.expect(R_CURLY);
67 m.complete(p, USE_TREE_LIST);
68}
diff --git a/crates/ra_syntax/src/grammar/mod.rs b/crates/ra_syntax/src/grammar/mod.rs
new file mode 100644
index 000000000..2cb11dc1e
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/mod.rs
@@ -0,0 +1,188 @@
1//! This is the actual "grammar" of the Rust language.
2//!
3//! Each function in this module and its children corresponds
4//! to a production of the format grammar. Submodules roughly
5//! correspond to different *areas* of the grammar. By convention,
6//! each submodule starts with `use super::*` import and exports
7//! "public" productions via `pub(super)`.
8//!
9//! See docs for `Parser` to learn about API, available to the grammar,
10//! and see docs for `Event` to learn how this actually manages to
11//! produce parse trees.
12//!
13//! Code in this module also contains inline tests, which start with
14//! `// test name-of-the-test` comment and look like this:
15//!
16//! ```
17//! // test function_with_zero_parameters
18//! // fn foo() {}
19//! ```
20//!
21//! After adding a new inline-test, run `cargo collect-tests` to extract
22//! it as a standalone text-fixture into `tests/data/parser/inline`, and
23//! run `cargo test` once to create the "gold" value.
24mod attributes;
25mod expressions;
26mod items;
27mod params;
28mod paths;
29mod patterns;
30mod type_args;
31mod type_params;
32mod types;
33
34use {
35 token_set::TokenSet,
36 parser_api::{Marker, CompletedMarker, Parser},
37 SyntaxKind::{self, *},
38};
39pub(crate) use self::{
40 expressions::{
41 block,
42 },
43 items::{
44 enum_variant_list,
45 extern_item_list,
46 impl_item_list,
47 match_arm_list,
48 mod_item_list,
49 named_field_def_list,
50 named_field_list,
51 token_tree,
52 trait_item_list,
53 use_tree_list,
54 },
55};
56
57pub(crate) fn root(p: &mut Parser) {
58 let m = p.start();
59 p.eat(SHEBANG);
60 items::mod_contents(p, false);
61 m.complete(p, ROOT);
62}
63
64
65#[derive(Clone, Copy, PartialEq, Eq)]
66enum BlockLike {
67 Block,
68 NotBlock,
69}
70
71impl BlockLike {
72 fn is_block(self) -> bool { self == BlockLike::Block }
73}
74
75fn opt_visibility(p: &mut Parser) {
76 match p.current() {
77 PUB_KW => {
78 let m = p.start();
79 p.bump();
80 if p.at(L_PAREN) {
81 match p.nth(1) {
82 // test crate_visibility
83 // pub(crate) struct S;
84 // pub(self) struct S;
85 // pub(self) struct S;
86 // pub(self) struct S;
87 CRATE_KW | SELF_KW | SUPER_KW => {
88 p.bump();
89 p.bump();
90 p.expect(R_PAREN);
91 }
92 IN_KW => {
93 p.bump();
94 p.bump();
95 paths::use_path(p);
96 p.expect(R_PAREN);
97 }
98 _ => (),
99 }
100 }
101 m.complete(p, VISIBILITY);
102 }
103 // test crate_keyword_vis
104 // crate fn main() { }
105 CRATE_KW => {
106 let m = p.start();
107 p.bump();
108 m.complete(p, VISIBILITY);
109 }
110 _ => (),
111 }
112}
113
114fn opt_alias(p: &mut Parser) {
115 if p.at(AS_KW) {
116 let m = p.start();
117 p.bump();
118 name(p);
119 m.complete(p, ALIAS);
120 }
121}
122
123fn abi(p: &mut Parser) {
124 assert!(p.at(EXTERN_KW));
125 let abi = p.start();
126 p.bump();
127 match p.current() {
128 STRING | RAW_STRING => p.bump(),
129 _ => (),
130 }
131 abi.complete(p, ABI);
132}
133
134fn opt_fn_ret_type(p: &mut Parser) -> bool {
135 if p.at(THIN_ARROW) {
136 let m = p.start();
137 p.bump();
138 types::type_(p);
139 m.complete(p, RET_TYPE);
140 true
141 } else {
142 false
143 }
144}
145
146fn name_r(p: &mut Parser, recovery: TokenSet) {
147 if p.at(IDENT) {
148 let m = p.start();
149 p.bump();
150 m.complete(p, NAME);
151 } else {
152 p.err_recover("expected a name", recovery);
153 }
154}
155
156fn name(p: &mut Parser) {
157 name_r(p, TokenSet::EMPTY)
158}
159
160fn name_ref(p: &mut Parser) {
161 if p.at(IDENT) {
162 let m = p.start();
163 p.bump();
164 m.complete(p, NAME_REF);
165 } else {
166 p.err_and_bump("expected identifier");
167 }
168}
169
170fn error_block(p: &mut Parser, message: &str) {
171 go(p, Some(message));
172 fn go(p: &mut Parser, message: Option<&str>) {
173 assert!(p.at(L_CURLY));
174 let m = p.start();
175 if let Some(message) = message {
176 p.error(message);
177 }
178 p.bump();
179 while !p.at(EOF) && !p.at(R_CURLY) {
180 match p.current() {
181 L_CURLY => go(p, None),
182 _ => p.bump(),
183 }
184 }
185 p.eat(R_CURLY);
186 m.complete(p, ERROR);
187 }
188}
diff --git a/crates/ra_syntax/src/grammar/params.rs b/crates/ra_syntax/src/grammar/params.rs
new file mode 100644
index 000000000..903c25939
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/params.rs
@@ -0,0 +1,142 @@
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() {
40 (L_PAREN, R_PAREN)
41 } else {
42 (PIPE, PIPE)
43 };
44 assert!(p.at(bra));
45 let m = p.start();
46 p.bump();
47 if flavor.type_required() {
48 opt_self_param(p);
49 }
50 while !p.at(EOF) && !p.at(ket) {
51 if !p.at_ts(VALUE_PARAMETER_FIRST) {
52 p.error("expected value parameter");
53 break;
54 }
55 value_parameter(p, flavor);
56 if !p.at(ket) {
57 p.expect(COMMA);
58 }
59 }
60 p.expect(ket);
61 m.complete(p, PARAM_LIST);
62}
63
64
65const VALUE_PARAMETER_FIRST: TokenSet =
66 token_set_union![
67 patterns::PATTERN_FIRST,
68 types::TYPE_FIRST,
69 ];
70
71fn value_parameter(p: &mut Parser, flavor: Flavor) {
72 let m = p.start();
73 match flavor {
74 Flavor::OptionalType | Flavor::Normal => {
75 patterns::pattern(p);
76 if p.at(COLON) || flavor.type_required() {
77 types::ascription(p)
78 }
79 },
80 // test value_parameters_no_patterns
81 // type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>;
82 Flavor::OptionalPattern => {
83 let la0 = p.current();
84 let la1 = p.nth(1);
85 let la2 = p.nth(2);
86 let la3 = p.nth(3);
87 if la0 == IDENT && la1 == COLON
88 || la0 == AMP && la1 == IDENT && la2 == COLON
89 || la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON {
90 patterns::pattern(p);
91 types::ascription(p);
92 } else {
93 types::type_(p);
94 }
95 },
96 }
97 m.complete(p, PARAM);
98}
99
100// test self_param
101// impl S {
102// fn a(self) {}
103// fn b(&self,) {}
104// fn c(&'a self,) {}
105// fn d(&'a mut self, x: i32) {}
106// fn e(mut self) {}
107// }
108fn opt_self_param(p: &mut Parser) {
109 let m;
110 if p.at(SELF_KW) || p.at(MUT_KW) && p.nth(1) == SELF_KW {
111 m = p.start();
112 p.eat(MUT_KW);
113 p.eat(SELF_KW);
114 // test arb_self_types
115 // impl S {
116 // fn a(self: &Self) {}
117 // fn b(mut self: Box<Self>) {}
118 // }
119 if p.at(COLON) {
120 types::ascription(p);
121 }
122 } else {
123 let la1 = p.nth(1);
124 let la2 = p.nth(2);
125 let la3 = p.nth(3);
126 let n_toks = match (p.current(), la1, la2, la3) {
127 (AMP, SELF_KW, _, _) => 2,
128 (AMP, MUT_KW, SELF_KW, _) => 3,
129 (AMP, LIFETIME, SELF_KW, _) => 3,
130 (AMP, LIFETIME, MUT_KW, SELF_KW) => 4,
131 _ => return,
132 };
133 m = p.start();
134 for _ in 0..n_toks {
135 p.bump();
136 }
137 }
138 m.complete(p, SELF_PARAM);
139 if !p.at(R_PAREN) {
140 p.expect(COMMA);
141 }
142}
diff --git a/crates/ra_syntax/src/grammar/paths.rs b/crates/ra_syntax/src/grammar/paths.rs
new file mode 100644
index 000000000..7c9fb8be2
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/paths.rs
@@ -0,0 +1,101 @@
1use super::*;
2
3pub(super) const PATH_FIRST: TokenSet =
4 token_set![IDENT, SELF_KW, SUPER_KW, COLONCOLON, L_ANGLE];
5
6pub(super) fn is_path_start(p: &Parser) -> bool {
7 match p.current() {
8 IDENT | SELF_KW | SUPER_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 SELF_KW | SUPER_KW => p.bump(),
78 _ => {
79 p.err_and_bump("expected identifier");
80 }
81 };
82 }
83 m.complete(p, PATH_SEGMENT);
84}
85
86fn opt_path_type_args(p: &mut Parser, mode: Mode) {
87 match mode {
88 Mode::Use => return,
89 Mode::Type => {
90 // test path_fn_trait_args
91 // type F = Box<Fn(x: i32) -> ()>;
92 if p.at(L_PAREN) {
93 params::param_list_opt_patterns(p);
94 opt_fn_ret_type(p);
95 } else {
96 type_args::opt_type_arg_list(p, false)
97 }
98 },
99 Mode::Expr => type_args::opt_type_arg_list(p, true),
100 }
101}
diff --git a/crates/ra_syntax/src/grammar/patterns.rs b/crates/ra_syntax/src/grammar/patterns.rs
new file mode 100644
index 000000000..420bae7a7
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/patterns.rs
@@ -0,0 +1,224 @@
1use super::*;
2
3pub(super) const PATTERN_FIRST: TokenSet =
4 token_set_union![
5 token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE],
6 expressions::LITERAL_FIRST,
7 paths::PATH_FIRST,
8 ];
9
10pub(super) fn pattern(p: &mut Parser) {
11 pattern_r(p, PAT_RECOVERY_SET)
12}
13
14pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
15 if let Some(lhs) = atom_pat(p, recovery_set) {
16 // test range_pat
17 // fn main() {
18 // match 92 { 0 ... 100 => () }
19 // }
20 if p.at(DOTDOTDOT) {
21 let m = lhs.precede(p);
22 p.bump();
23 atom_pat(p, recovery_set);
24 m.complete(p, RANGE_PAT);
25 }
26 }
27}
28
29const PAT_RECOVERY_SET: TokenSet =
30 token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
31
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 || la0 == MUT_KW
37 || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY)) {
38 return Some(bind_pat(p, true));
39 }
40 if paths::is_path_start(p) {
41 return Some(path_pat(p));
42 }
43
44 // test literal_pattern
45 // fn main() {
46 // match () {
47 // 92 => (),
48 // 'c' => (),
49 // "hello" => (),
50 // }
51 // }
52 match expressions::literal(p) {
53 Some(m) => return Some(m),
54 None => (),
55 }
56
57 let m = match la0 {
58 UNDERSCORE => placeholder_pat(p),
59 AMP => ref_pat(p),
60 L_PAREN => tuple_pat(p),
61 L_BRACK => slice_pat(p),
62 _ => {
63 p.err_recover("expected pattern", recovery_set);
64 return None;
65 }
66 };
67 Some(m)
68}
69
70// test path_part
71// fn foo() {
72// let foo::Bar = ();
73// let ::Bar = ();
74// let Bar { .. } = ();
75// let Bar(..) = ();
76// }
77fn path_pat(p: &mut Parser) -> CompletedMarker {
78 assert!(paths::is_path_start(p));
79 let m = p.start();
80 paths::expr_path(p);
81 let kind = match p.current() {
82 L_PAREN => {
83 tuple_pat_fields(p);
84 TUPLE_STRUCT_PAT
85 }
86 L_CURLY => {
87 field_pat_list(p);
88 STRUCT_PAT
89 }
90 _ => PATH_PAT
91 };
92 m.complete(p, kind)
93}
94
95// test tuple_pat_fields
96// fn foo() {
97// let S() = ();
98// let S(_) = ();
99// let S(_,) = ();
100// let S(_, .. , x) = ();
101// }
102fn tuple_pat_fields(p: &mut Parser) {
103 assert!(p.at(L_PAREN));
104 p.bump();
105 pat_list(p, R_PAREN);
106 p.expect(R_PAREN);
107}
108
109// test field_pat_list
110// fn foo() {
111// let S {} = ();
112// let S { f, ref mut g } = ();
113// let S { h: _, ..} = ();
114// let S { h: _, } = ();
115// }
116fn field_pat_list(p: &mut Parser) {
117 assert!(p.at(L_CURLY));
118 let m = p.start();
119 p.bump();
120 while !p.at(EOF) && !p.at(R_CURLY) {
121 match p.current() {
122 DOTDOT => p.bump(),
123 IDENT if p.nth(1) == COLON => {
124 p.bump();
125 p.bump();
126 pattern(p);
127 }
128 L_CURLY => error_block(p, "expected ident"),
129 _ => {
130 bind_pat(p, false);
131 }
132 }
133 if !p.at(R_CURLY) {
134 p.expect(COMMA);
135 }
136 }
137 p.expect(R_CURLY);
138 m.complete(p, FIELD_PAT_LIST);
139}
140
141// test placeholder_pat
142// fn main() { let _ = (); }
143fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
144 assert!(p.at(UNDERSCORE));
145 let m = p.start();
146 p.bump();
147 m.complete(p, PLACEHOLDER_PAT)
148}
149
150// test ref_pat
151// fn main() {
152// let &a = ();
153// let &mut b = ();
154// }
155fn ref_pat(p: &mut Parser) -> CompletedMarker {
156 assert!(p.at(AMP));
157 let m = p.start();
158 p.bump();
159 p.eat(MUT_KW);
160 pattern(p);
161 m.complete(p, REF_PAT)
162}
163
164// test tuple_pat
165// fn main() {
166// let (a, b, ..) = ();
167// }
168fn tuple_pat(p: &mut Parser) -> CompletedMarker {
169 assert!(p.at(L_PAREN));
170 let m = p.start();
171 tuple_pat_fields(p);
172 m.complete(p, TUPLE_PAT)
173}
174
175// test slice_pat
176// fn main() {
177// let [a, b, ..] = [];
178// }
179fn slice_pat(p: &mut Parser) -> CompletedMarker {
180 assert!(p.at(L_BRACK));
181 let m = p.start();
182 p.bump();
183 pat_list(p, R_BRACK);
184 p.expect(R_BRACK);
185 m.complete(p, SLICE_PAT)
186}
187
188fn pat_list(p: &mut Parser, ket: SyntaxKind) {
189 while !p.at(EOF) && !p.at(ket) {
190 match p.current() {
191 DOTDOT => p.bump(),
192 _ => {
193 if !p.at_ts(PATTERN_FIRST) {
194 p.error("expected a pattern");
195 break;
196 }
197 pattern(p)
198 },
199 }
200 if !p.at(ket) {
201 p.expect(COMMA);
202 }
203 }
204}
205
206// test bind_pat
207// fn main() {
208// let a = ();
209// let mut b = ();
210// let ref c = ();
211// let ref mut d = ();
212// let e @ _ = ();
213// let ref mut f @ g @ _ = ();
214// }
215fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
216 let m = p.start();
217 p.eat(REF_KW);
218 p.eat(MUT_KW);
219 name(p);
220 if with_at && p.eat(AT) {
221 pattern(p);
222 }
223 m.complete(p, BIND_PAT)
224}
diff --git a/crates/ra_syntax/src/grammar/type_args.rs b/crates/ra_syntax/src/grammar/type_args.rs
new file mode 100644
index 000000000..29ff6e534
--- /dev/null
+++ b/crates/ra_syntax/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_syntax/src/grammar/type_params.rs b/crates/ra_syntax/src/grammar/type_params.rs
new file mode 100644
index 000000000..79bc95ce4
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/type_params.rs
@@ -0,0 +1,136 @@
1use super::*;
2
3pub(super) fn opt_type_param_list(p: &mut Parser) {
4 if !p.at(L_ANGLE) {
5 return;
6 }
7 let m = p.start();
8 p.bump();
9
10 while !p.at(EOF) && !p.at(R_ANGLE) {
11 match p.current() {
12 LIFETIME => lifetime_param(p),
13 IDENT => type_param(p),
14 _ => p.err_and_bump("expected type parameter"),
15 }
16 if !p.at(R_ANGLE) && !p.expect(COMMA) {
17 break;
18 }
19 }
20 p.expect(R_ANGLE);
21 m.complete(p, TYPE_PARAM_LIST);
22
23 fn lifetime_param(p: &mut Parser) {
24 assert!(p.at(LIFETIME));
25 let m = p.start();
26 p.bump();
27 if p.at(COLON) {
28 lifetime_bounds(p);
29 }
30 m.complete(p, LIFETIME_PARAM);
31 }
32
33 fn type_param(p: &mut Parser) {
34 assert!(p.at(IDENT));
35 let m = p.start();
36 name(p);
37 if p.at(COLON) {
38 bounds(p);
39 }
40 // test type_param_default
41 // struct S<T = i32>;
42 if p.at(EQ) {
43 p.bump();
44 types::type_(p)
45 }
46 m.complete(p, TYPE_PARAM);
47 }
48}
49
50// test type_param_bounds
51// struct S<T: 'a + ?Sized + (Copy)>;
52pub(super) fn bounds(p: &mut Parser) {
53 assert!(p.at(COLON));
54 p.bump();
55 bounds_without_colon(p);
56}
57
58fn lifetime_bounds(p: &mut Parser) {
59 assert!(p.at(COLON));
60 p.bump();
61 while p.at(LIFETIME) {
62 p.bump();
63 if !p.eat(PLUS) {
64 break;
65 }
66 }
67}
68
69pub(super) fn bounds_without_colon(p: &mut Parser) {
70 loop {
71 let has_paren = p.eat(L_PAREN);
72 p.eat(QUESTION);
73 match p.current() {
74 LIFETIME => p.bump(),
75 FOR_KW => {
76 types::for_type(p)
77 }
78 _ if paths::is_path_start(p) => {
79 types::path_type(p)
80 }
81 _ => break,
82 }
83 if has_paren {
84 p.expect(R_PAREN);
85 }
86 if !p.eat(PLUS) {
87 break;
88 }
89 }
90}
91
92// test where_clause
93// fn foo()
94// where
95// 'a: 'b + 'c,
96// T: Clone + Copy + 'static,
97// Iterator::Item: 'a,
98// {}
99pub(super) fn opt_where_clause(p: &mut Parser) {
100 if !p.at(WHERE_KW) {
101 return;
102 }
103 let m = p.start();
104 p.bump();
105 loop {
106 if !(paths::is_path_start(p) || p.current() == LIFETIME) {
107 break
108 }
109 where_predicate(p);
110 if p.current() != L_CURLY && p.current() != SEMI {
111 p.expect(COMMA);
112 }
113 }
114 m.complete(p, WHERE_CLAUSE);
115}
116
117fn where_predicate(p: &mut Parser) {
118 let m = p.start();
119 if p.at(LIFETIME) {
120 p.eat(LIFETIME);
121 if p.at(COLON) {
122 lifetime_bounds(p)
123 } else {
124 p.error("expected colon")
125 }
126 } else {
127 types::path_type(p);
128 if p.at(COLON) {
129 bounds(p);
130 } else {
131 p.error("expected colon")
132 }
133
134 }
135 m.complete(p, WHERE_PRED);
136}
diff --git a/crates/ra_syntax/src/grammar/types.rs b/crates/ra_syntax/src/grammar/types.rs
new file mode 100644
index 000000000..27e5b086e
--- /dev/null
+++ b/crates/ra_syntax/src/grammar/types.rs
@@ -0,0 +1,247 @@
1use super::*;
2
3pub(super) const TYPE_FIRST: TokenSet =
4 token_set_union![
5 token_set![
6 L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, IMPL_KW, DYN_KW, L_ANGLE,
7 ],
8 paths::PATH_FIRST,
9 ];
10
11const TYPE_RECOVERY_SET: TokenSet =
12 token_set![R_PAREN, COMMA];
13
14pub(super) fn type_(p: &mut Parser) {
15 match p.current() {
16 L_PAREN => paren_or_tuple_type(p),
17 EXCL => never_type(p),
18 STAR => pointer_type(p),
19 L_BRACK => array_or_slice_type(p),
20 AMP => reference_type(p),
21 UNDERSCORE => placeholder_type(p),
22 FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
23 FOR_KW => for_type(p),
24 IMPL_KW => impl_trait_type(p),
25 DYN_KW => dyn_trait_type(p),
26 L_ANGLE => path_type(p),
27 _ if paths::is_path_start(p) => path_type(p),
28 _ => {
29 p.err_recover("expected type", TYPE_RECOVERY_SET);
30 }
31 }
32}
33
34pub(super) fn ascription(p: &mut Parser) {
35 p.expect(COLON);
36 type_(p)
37}
38
39fn type_no_plus(p: &mut Parser) {
40 type_(p);
41}
42
43fn paren_or_tuple_type(p: &mut Parser) {
44 assert!(p.at(L_PAREN));
45 let m = p.start();
46 p.bump();
47 let mut n_types: u32 = 0;
48 let mut trailing_comma: bool = false;
49 while !p.at(EOF) && !p.at(R_PAREN) {
50 n_types += 1;
51 type_(p);
52 if p.eat(COMMA) {
53 trailing_comma = true;
54 } else {
55 trailing_comma = false;
56 break;
57 }
58 }
59 p.expect(R_PAREN);
60
61 let kind = if n_types == 1 && !trailing_comma {
62 // test paren_type
63 // type T = (i32);
64 PAREN_TYPE
65 } else {
66 // test unit_type
67 // type T = ();
68
69 // test singleton_tuple_type
70 // type T = (i32,);
71 TUPLE_TYPE
72 };
73 m.complete(p, kind);
74}
75
76// test never_type
77// type Never = !;
78fn never_type(p: &mut Parser) {
79 assert!(p.at(EXCL));
80 let m = p.start();
81 p.bump();
82 m.complete(p, NEVER_TYPE);
83}
84
85fn pointer_type(p: &mut Parser) {
86 assert!(p.at(STAR));
87 let m = p.start();
88 p.bump();
89
90 match p.current() {
91 // test pointer_type_mut
92 // type M = *mut ();
93 // type C = *mut ();
94 MUT_KW | CONST_KW => p.bump(),
95 _ => {
96 // test pointer_type_no_mutability
97 // type T = *();
98 p.error(
99 "expected mut or const in raw pointer type \
100 (use `*mut T` or `*const T` as appropriate)",
101 );
102 }
103 };
104
105 type_no_plus(p);
106 m.complete(p, POINTER_TYPE);
107}
108
109fn array_or_slice_type(p: &mut Parser) {
110 assert!(p.at(L_BRACK));
111 let m = p.start();
112 p.bump();
113
114 type_(p);
115 let kind = match p.current() {
116 // test slice_type
117 // type T = [()];
118 R_BRACK => {
119 p.bump();
120 SLICE_TYPE
121 }
122
123 // test array_type
124 // type T = [(); 92];
125 SEMI => {
126 p.bump();
127 expressions::expr(p);
128 p.expect(R_BRACK);
129 ARRAY_TYPE
130 }
131 // test array_type_missing_semi
132 // type T = [() 92];
133 _ => {
134 p.error("expected `;` or `]`");
135 SLICE_TYPE
136 }
137 };
138 m.complete(p, kind);
139}
140
141// test reference_type;
142// type A = &();
143// type B = &'static ();
144// type C = &mut ();
145fn reference_type(p: &mut Parser) {
146 assert!(p.at(AMP));
147 let m = p.start();
148 p.bump();
149 p.eat(LIFETIME);
150 p.eat(MUT_KW);
151 type_no_plus(p);
152 m.complete(p, REFERENCE_TYPE);
153}
154
155// test placeholder_type
156// type Placeholder = _;
157fn placeholder_type(p: &mut Parser) {
158 assert!(p.at(UNDERSCORE));
159 let m = p.start();
160 p.bump();
161 m.complete(p, PLACEHOLDER_TYPE);
162}
163
164// test fn_pointer_type
165// type A = fn();
166// type B = unsafe fn();
167// type C = unsafe extern "C" fn();
168fn fn_pointer_type(p: &mut Parser) {
169 let m = p.start();
170 p.eat(UNSAFE_KW);
171 if p.at(EXTERN_KW) {
172 abi(p);
173 }
174 // test fn_pointer_type_missing_fn
175 // type F = unsafe ();
176 if !p.eat(FN_KW) {
177 m.abandon(p);
178 p.error("expected `fn`");
179 return;
180 }
181 if p.at(L_PAREN) {
182 params::param_list_opt_patterns(p);
183 } else {
184 p.error("expected parameters")
185 }
186 // test fn_pointer_type_with_ret
187 // type F = fn() -> ();
188 opt_fn_ret_type(p);
189 m.complete(p, FN_POINTER_TYPE);
190}
191
192// test for_type
193// type A = for<'a> fn() -> ();
194pub(super) fn for_type(p: &mut Parser) {
195 assert!(p.at(FOR_KW));
196 let m = p.start();
197 p.bump();
198 type_params::opt_type_param_list(p);
199 match p.current() {
200 FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
201 _ if paths::is_path_start(p) => path_type_(p, false),
202 _ => p.error("expected a path"),
203
204 }
205 m.complete(p, FOR_TYPE);
206}
207
208// test impl_trait_type
209// type A = impl Iterator<Item=Foo<'a>> + 'a;
210fn impl_trait_type(p: &mut Parser) {
211 assert!(p.at(IMPL_KW));
212 let m = p.start();
213 p.bump();
214 type_params::bounds_without_colon(p);
215 m.complete(p, IMPL_TRAIT_TYPE);
216}
217
218// test dyn_trait_type
219// type A = dyn Iterator<Item=Foo<'a>> + 'a;
220fn dyn_trait_type(p: &mut Parser) {
221 assert!(p.at(DYN_KW));
222 let m = p.start();
223 p.bump();
224 type_params::bounds_without_colon(p);
225 m.complete(p, DYN_TRAIT_TYPE);
226}
227
228// test path_type
229// type A = Foo;
230// type B = ::Foo;
231// type C = self::Foo;
232// type D = super::Foo;
233pub(super) fn path_type(p: &mut Parser) {
234 path_type_(p, true)
235}
236
237pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
238 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
239 let m = p.start();
240 paths::type_path(p);
241 // test path_type_with_bounds
242 // fn foo() -> Box<T + 'f> {}
243 if allow_bounds && p.eat(PLUS) {
244 type_params::bounds_without_colon(p);
245 }
246 m.complete(p, PATH_TYPE);
247}