diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index fa186ae835..f85a077cd8 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -3991,9 +3991,10 @@ enum OperatorOrDef { } fn bin_op<'a>(check_for_defs: bool) -> impl Parser<'a, BinOp, EExpr<'a>> { - (move |_, state: State<'a>, min_indent| { + (move |arena: &'a Bump, state: State<'a>, min_indent| { let start = state.pos(); - let (_, op, state) = operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent)?; + let (_, op, state) = + operator_help(arena, EExpr::Start, EExpr::BadOperator, state, min_indent)?; let err_progress = if check_for_defs { MadeProgress } else { @@ -4014,12 +4015,15 @@ fn bin_op<'a>(check_for_defs: bool) -> impl Parser<'a, BinOp, EExpr<'a>> { } fn operator<'a>() -> impl Parser<'a, OperatorOrDef, EExpr<'a>> { - (move |_, state, min_indent| operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent)) - .trace("operator") + (move |arena: &'a Bump, state, min_indent| { + operator_help(arena, EExpr::Start, EExpr::BadOperator, state, min_indent) + }) + .trace("operator") } #[inline(always)] fn operator_help<'a, F, G, E>( + arena: &'a Bump, to_expectation: F, to_error: G, mut state: State<'a>, @@ -4030,20 +4034,17 @@ where G: Fn(&'a str, Position) -> E, E: 'a, { - match *state.bytes() { - [b'o', b'r', ..] => { - return Ok(( - MadeProgress, - OperatorOrDef::BinOp(BinOp::Or), - state.advance(2), - )) + let and_or = either( + parser::keyword(keyword::AND, EExpr::End), + parser::keyword(keyword::OR, EExpr::End), + ); + + match and_or.parse(arena, state.clone(), min_indent) { + Ok((MadeProgress, Either::First(_), state)) => { + return Ok((MadeProgress, OperatorOrDef::BinOp(BinOp::And), state)) } - [b'a', b'n', b'd', ..] => { - return Ok(( - MadeProgress, - OperatorOrDef::BinOp(BinOp::And), - state.advance(3), - )) + Ok((MadeProgress, Either::Second(_), state)) => { + return Ok((MadeProgress, OperatorOrDef::BinOp(BinOp::Or), state)) } _ => {} } diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.formatted.roc new file mode 100644 index 0000000000..20d5bd2e8b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.formatted.roc @@ -0,0 +1,3 @@ +a +ands +d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.result-ast new file mode 100644 index 0000000000..c38110d34e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.result-ast @@ -0,0 +1,55 @@ +@0-11 SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + EitherIndex(2147483649), + ], + regions: [ + @0-1, + @2-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + Slice { start: 0, length: 1 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + Slice { start: 1, length: 0 }, + ], + spaces: [ + Newline, + ], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Var { + module_name: "", + ident: "a", + }, + ), + Body( + @2-4 RecordDestructure( + [], + ), + @5-9 Var { + module_name: "", + ident: "ands", + }, + ), + ], + }, + @10-11 SpaceBefore( + Var { + module_name: "", + ident: "d", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.roc new file mode 100644 index 0000000000..ce9da1f0dc --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/sneaky_and_expr.expr.roc @@ -0,0 +1,3 @@ +a +{}=ands +d diff --git a/crates/compiler/test_syntax/tests/test_snapshots.rs b/crates/compiler/test_syntax/tests/test_snapshots.rs index b71bc6acfb..6fd95b8c86 100644 --- a/crates/compiler/test_syntax/tests/test_snapshots.rs +++ b/crates/compiler/test_syntax/tests/test_snapshots.rs @@ -704,6 +704,7 @@ mod test_snapshots { pass/single_question_binop_closure.expr, pass/single_question_binop_tag.expr, pass/single_underscore_closure.expr, + pass/sneaky_and_expr.expr, pass/sneaky_implements_in_opaque_fn_type.expr, pass/space_after_opt_field_pat.expr, pass/space_before_colon.full,