diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-21 10:46:17 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-21 10:46:17 +0000 |
commit | d77b5857c2420666e84dcd433f254e000e2843aa (patch) | |
tree | 416e333019e349bf4ee369f2548d9e6f6a9c67e9 /crates/ra_parser/src/grammar/expressions.rs | |
parent | 18b0c509f77a8e06141fee6668532cced1ebf5d8 (diff) | |
parent | 46179230a05331b1debd4dfa3bb197fa38d92347 (diff) |
Merge #867
867: This moves the parser to separate crate r=matklad a=matklad
That makes parser independent form both the token and the tree representation.
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_parser/src/grammar/expressions.rs')
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 473 |
1 files changed, 473 insertions, 0 deletions
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 @@ | |||
1 | mod atom; | ||
2 | |||
3 | pub(crate) use self::atom::match_arm_list; | ||
4 | pub(super) use self::atom::{literal, LITERAL_FIRST}; | ||
5 | use super::*; | ||
6 | |||
7 | const EXPR_FIRST: TokenSet = LHS_FIRST; | ||
8 | |||
9 | pub(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 | |||
14 | pub(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 | |||
19 | fn 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 } | ||
29 | pub(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)] | ||
130 | struct Restrictions { | ||
131 | forbid_structs: bool, | ||
132 | prefer_stmt: bool, | ||
133 | } | ||
134 | |||
135 | enum Op { | ||
136 | Simple, | ||
137 | Composite(SyntaxKind, u8), | ||
138 | } | ||
139 | |||
140 | fn 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. | ||
183 | fn 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 | |||
218 | const LHS_FIRST: TokenSet = | ||
219 | atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOTDOT, DOTDOTEQ, MINUS]); | ||
220 | |||
221 | fn 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 | |||
268 | fn 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 | // } | ||
315 | fn 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 | // } | ||
326 | fn 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 | // } | ||
340 | fn 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 | // } | ||
357 | fn 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 | // } | ||
375 | fn 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 | // } | ||
388 | fn 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 | |||
398 | fn 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 | // } | ||
423 | fn 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 | // } | ||
446 | pub(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 | } | ||