From 5205c016e9f704796aa7893f89ef108248bda2e2 Mon Sep 17 00:00:00 2001 From: DJMcNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 20 Dec 2018 11:35:02 +0000 Subject: Fix ambiguity with if break Brought up by #290 --- crates/ra_syntax/src/grammar/expressions.rs | 5 ++ crates/ra_syntax/src/grammar/expressions/atom.rs | 21 +++++-- .../data/parser/inline/0119_break_ambiguity.rs | 6 ++ .../data/parser/inline/0119_break_ambiguity.txt | 65 ++++++++++++++++++++++ 4 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.rs create mode 100644 crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.txt (limited to 'crates/ra_syntax') diff --git a/crates/ra_syntax/src/grammar/expressions.rs b/crates/ra_syntax/src/grammar/expressions.rs index 4f8c46ab3..79de0add0 100644 --- a/crates/ra_syntax/src/grammar/expressions.rs +++ b/crates/ra_syntax/src/grammar/expressions.rs @@ -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; diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs index cd7d62aff..fcc0a4490 100644 --- a/crates/ra_syntax/src/grammar/expressions/atom.rs +++ b/crates/ra_syntax/src/grammar/expressions/atom.rs @@ -35,10 +35,10 @@ pub(crate) fn literal(p: &mut Parser) -> Option { 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) diff --git a/crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.rs b/crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.rs new file mode 100644 index 000000000..560eb05b9 --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.rs @@ -0,0 +1,6 @@ +fn foo(){ + if break {} + while break {} + for i in break {} + match break {} +} diff --git a/crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.txt b/crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.txt new file mode 100644 index 000000000..6032a6c17 --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/0119_break_ambiguity.txt @@ -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) -- cgit v1.2.3