diff options
author | Geoffry Song <[email protected]> | 2019-11-15 08:08:43 +0000 |
---|---|---|
committer | Geoffry Song <[email protected]> | 2019-11-15 08:18:28 +0000 |
commit | 989cebc99c02acd427f01724c4fa77d81691e886 (patch) | |
tree | 89c2ed0185257de734b60eb3db01be2f5270b7c3 /crates/ra_parser | |
parent | 3ad11973ac7596323f085a9fcb9530e47f021c41 (diff) |
Fix parsing of "postfix" range expressions.
Right now they are handled in `postfix_dot_expr`, but that doesn't allow it to
correctly handle precedence. Integrate it more tightly with the Pratt parser
instead.
Also includes a drive-by fix for parsing `match .. {}`.
Fixes #2242.
Diffstat (limited to 'crates/ra_parser')
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 54 |
1 files changed, 24 insertions, 30 deletions
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 45f2e3de4..cf69da25a 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -290,6 +290,25 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, | |||
290 | let m = lhs.precede(p); | 290 | let m = lhs.precede(p); |
291 | p.bump(op); | 291 | p.bump(op); |
292 | 292 | ||
293 | if is_range { | ||
294 | // test postfix_range | ||
295 | // fn foo() { | ||
296 | // let x = 1..; | ||
297 | // match 1.. { _ => () }; | ||
298 | // match a.b()..S { _ => () }; | ||
299 | // } | ||
300 | let has_trailing_expression = | ||
301 | p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])); | ||
302 | if !has_trailing_expression { | ||
303 | if op == T![..=] { | ||
304 | p.error("expected expression to end inclusive range"); | ||
305 | } | ||
306 | // no RHS | ||
307 | lhs = m.complete(p, RANGE_EXPR); | ||
308 | break; | ||
309 | } | ||
310 | } | ||
311 | |||
293 | expr_bp(p, r, op_bp + 1); | 312 | expr_bp(p, r, op_bp + 1); |
294 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); | 313 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); |
295 | } | 314 | } |
@@ -330,7 +349,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> | |||
330 | if p.at(op) { | 349 | if p.at(op) { |
331 | m = p.start(); | 350 | m = p.start(); |
332 | p.bump(op); | 351 | p.bump(op); |
333 | if p.at_ts(EXPR_FIRST) { | 352 | if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) { |
334 | expr_bp(p, r, 2); | 353 | expr_bp(p, r, 2); |
335 | } | 354 | } |
336 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); | 355 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); |
@@ -344,13 +363,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> | |||
344 | // } | 363 | // } |
345 | // | 364 | // |
346 | let (lhs, blocklike) = atom::atom_expr(p, r)?; | 365 | let (lhs, blocklike) = atom::atom_expr(p, r)?; |
347 | return Some(postfix_expr( | 366 | return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); |
348 | p, | ||
349 | lhs, | ||
350 | blocklike, | ||
351 | !(r.prefer_stmt && blocklike.is_block()), | ||
352 | r.forbid_structs, | ||
353 | )); | ||
354 | } | 367 | } |
355 | }; | 368 | }; |
356 | // parse the interior of the unary expression | 369 | // parse the interior of the unary expression |
@@ -366,7 +379,6 @@ fn postfix_expr( | |||
366 | // `while true {break}; ();` | 379 | // `while true {break}; ();` |
367 | mut block_like: BlockLike, | 380 | mut block_like: BlockLike, |
368 | mut allow_calls: bool, | 381 | mut allow_calls: bool, |
369 | forbid_structs: bool, | ||
370 | ) -> (CompletedMarker, BlockLike) { | 382 | ) -> (CompletedMarker, BlockLike) { |
371 | loop { | 383 | loop { |
372 | lhs = match p.current() { | 384 | lhs = match p.current() { |
@@ -380,7 +392,7 @@ fn postfix_expr( | |||
380 | // } | 392 | // } |
381 | T!['('] if allow_calls => call_expr(p, lhs), | 393 | T!['('] if allow_calls => call_expr(p, lhs), |
382 | T!['['] if allow_calls => index_expr(p, lhs), | 394 | T!['['] if allow_calls => index_expr(p, lhs), |
383 | T![.] => match postfix_dot_expr(p, lhs, forbid_structs) { | 395 | T![.] => match postfix_dot_expr(p, lhs) { |
384 | Ok(it) => it, | 396 | Ok(it) => it, |
385 | Err(it) => { | 397 | Err(it) => { |
386 | lhs = it; | 398 | lhs = it; |
@@ -398,7 +410,6 @@ fn postfix_expr( | |||
398 | fn postfix_dot_expr( | 410 | fn postfix_dot_expr( |
399 | p: &mut Parser, | 411 | p: &mut Parser, |
400 | lhs: CompletedMarker, | 412 | lhs: CompletedMarker, |
401 | forbid_structs: bool, | ||
402 | ) -> Result<CompletedMarker, CompletedMarker> { | 413 | ) -> Result<CompletedMarker, CompletedMarker> { |
403 | assert!(p.at(T![.])); | 414 | assert!(p.at(T![.])); |
404 | if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { | 415 | if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { |
@@ -418,25 +429,8 @@ fn postfix_expr( | |||
418 | return Ok(m.complete(p, AWAIT_EXPR)); | 429 | return Ok(m.complete(p, AWAIT_EXPR)); |
419 | } | 430 | } |
420 | 431 | ||
421 | // test postfix_range | 432 | if p.at(T![..=]) || p.at(T![..]) { |
422 | // fn foo() { | 433 | return Err(lhs); |
423 | // let x = 1..; | ||
424 | // match 1.. { _ => () }; | ||
425 | // match a.b()..S { _ => () }; | ||
426 | // } | ||
427 | for &(op, la) in &[(T![..=], 3), (T![..], 2)] { | ||
428 | if p.at(op) { | ||
429 | let next_token = p.nth(la); | ||
430 | let has_trailing_expression = | ||
431 | !(forbid_structs && next_token == T!['{']) && EXPR_FIRST.contains(next_token); | ||
432 | return if has_trailing_expression { | ||
433 | Err(lhs) | ||
434 | } else { | ||
435 | let m = lhs.precede(p); | ||
436 | p.bump(op); | ||
437 | Ok(m.complete(p, RANGE_EXPR)) | ||
438 | }; | ||
439 | } | ||
440 | } | 434 | } |
441 | 435 | ||
442 | Ok(field_expr(p, lhs)) | 436 | Ok(field_expr(p, lhs)) |