Fix ambiguity with if break

Brought up by #290
This commit is contained in:
DJMcNab 2018-12-20 11:35:02 +00:00
parent 8693b13420
commit 5205c016e9
4 changed files with 92 additions and 5 deletions

View file

@ -5,6 +5,7 @@ pub(super) use self::atom::{literal, LITERAL_FIRST};
use super::*;
const EXPR_FIRST: TokenSet = LHS_FIRST;
const EXPR_FIRST_NO_BLOCK: TokenSet = LHS_FIRST_NO_BLOCK;
pub(super) fn expr(p: &mut Parser) -> BlockLike {
let r = Restrictions {
@ -209,6 +210,10 @@ const LHS_FIRST: TokenSet = token_set_union![
token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
atom::ATOM_EXPR_FIRST,
];
const LHS_FIRST_NO_BLOCK: TokenSet = token_set_union![
token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
atom::ATOM_EXPR_FIRST_NO_BLOCK,
];
fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
let m;

View file

@ -35,10 +35,10 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
Some(m.complete(p, LITERAL))
}
pub(super) const ATOM_EXPR_FIRST: TokenSet = token_set_union![
// E.g. for after the break in `if break {}`, this should not match
pub(super) const ATOM_EXPR_FIRST_NO_BLOCK: TokenSet = token_set_union![
LITERAL_FIRST,
token_set![
L_CURLY,
L_PAREN,
L_BRACK,
PIPE,
@ -59,6 +59,9 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = token_set_union![
],
];
pub(super) const ATOM_EXPR_FIRST: TokenSet =
token_set_union![ATOM_EXPR_FIRST_NO_BLOCK, token_set![L_CURLY],];
const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
@ -108,7 +111,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
L_CURLY => block_expr(p, None),
RETURN_KW => return_expr(p),
CONTINUE_KW => continue_expr(p),
BREAK_KW => break_expr(p),
BREAK_KW => break_expr(p, r),
_ => {
p.err_recover("expected expression", EXPR_RECOVERY_SET);
return None;
@ -427,12 +430,20 @@ fn continue_expr(p: &mut Parser) -> CompletedMarker {
// break 'l 92;
// }
// }
fn break_expr(p: &mut Parser) -> CompletedMarker {
fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
assert!(p.at(BREAK_KW));
let m = p.start();
p.bump();
p.eat(LIFETIME);
if p.at_ts(EXPR_FIRST) {
// test break_ambiguity
// fn foo(){
// if break {}
// while break {}
// for i in break {}
// match break {}
// }
if r.forbid_structs && p.at_ts(EXPR_FIRST_NO_BLOCK) || !r.forbid_structs && p.at_ts(EXPR_FIRST)
{
expr(p);
}
m.complete(p, BREAK_EXPR)

View file

@ -0,0 +1,6 @@
fn foo(){
if break {}
while break {}
for i in break {}
match break {}
}

View file

@ -0,0 +1,65 @@
SOURCE_FILE@[0; 88)
FN_DEF@[0; 87)
FN_KW@[0; 2)
WHITESPACE@[2; 3)
NAME@[3; 6)
IDENT@[3; 6) "foo"
PARAM_LIST@[6; 8)
L_PAREN@[6; 7)
R_PAREN@[7; 8)
BLOCK@[8; 87)
L_CURLY@[8; 9)
WHITESPACE@[9; 14)
EXPR_STMT@[14; 25)
IF_EXPR@[14; 25)
IF_KW@[14; 16)
WHITESPACE@[16; 17)
CONDITION@[17; 22)
BREAK_EXPR@[17; 22)
BREAK_KW@[17; 22)
WHITESPACE@[22; 23)
BLOCK@[23; 25)
L_CURLY@[23; 24)
R_CURLY@[24; 25)
WHITESPACE@[25; 30)
EXPR_STMT@[30; 44)
WHILE_EXPR@[30; 44)
WHILE_KW@[30; 35)
WHITESPACE@[35; 36)
CONDITION@[36; 41)
BREAK_EXPR@[36; 41)
BREAK_KW@[36; 41)
WHITESPACE@[41; 42)
BLOCK@[42; 44)
L_CURLY@[42; 43)
R_CURLY@[43; 44)
WHITESPACE@[44; 49)
EXPR_STMT@[49; 66)
FOR_EXPR@[49; 66)
FOR_KW@[49; 52)
WHITESPACE@[52; 53)
BIND_PAT@[53; 54)
NAME@[53; 54)
IDENT@[53; 54) "i"
WHITESPACE@[54; 55)
IN_KW@[55; 57)
WHITESPACE@[57; 58)
BREAK_EXPR@[58; 63)
BREAK_KW@[58; 63)
WHITESPACE@[63; 64)
BLOCK@[64; 66)
L_CURLY@[64; 65)
R_CURLY@[65; 66)
WHITESPACE@[66; 71)
MATCH_EXPR@[71; 85)
MATCH_KW@[71; 76)
WHITESPACE@[76; 77)
BREAK_EXPR@[77; 82)
BREAK_KW@[77; 82)
WHITESPACE@[82; 83)
MATCH_ARM_LIST@[83; 85)
L_CURLY@[83; 84)
R_CURLY@[84; 85)
WHITESPACE@[85; 86)
R_CURLY@[86; 87)
WHITESPACE@[87; 88)