diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index b1e22089..26ab24a3 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -20,6 +20,14 @@ const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[ // which should be written as: // select 1; select 2; SELECT_KW, + // select case when x then y else end; + // ^ missing expr + END_KW, + // select case when x then else z end; + // ^ missing expr + ELSE_KW, // select case when then y end; + // ^ missing expr + THEN_KW, ]); fn literal(p: &mut Parser<'_>) -> Option { @@ -208,8 +216,8 @@ fn opt_else_clause(p: &mut Parser<'_>) { return; } let m = p.start(); - if p.eat(ELSE_KW) && expr(p).is_none() { - p.error("expected an expression"); + if p.eat(ELSE_KW) { + expr(p); } m.complete(p, ELSE_CLAUSE); } @@ -219,13 +227,9 @@ fn opt_else_clause(p: &mut Parser<'_>) { fn when_clause(p: &mut Parser<'_>) -> CompletedMarker { let m = p.start(); p.expect(WHEN_KW); - if expr(p).is_none() { - p.error("expected an expression"); - } + expr(p); p.expect(THEN_KW); - if expr(p).is_none() { - p.error("expected an expression"); - } + expr(p); m.complete(p, WHEN_CLAUSE) } @@ -2334,7 +2338,6 @@ fn postfix_dot_expr( }) } -#[must_use] fn expr(p: &mut Parser) -> Option { expr_bp(p, 1, &Restrictions::default()) } diff --git a/crates/squawk_parser/tests/data/err/select.sql b/crates/squawk_parser/tests/data/err/select.sql index 2f5e1f86..3680659e 100644 --- a/crates/squawk_parser/tests/data/err/select.sql +++ b/crates/squawk_parser/tests/data/err/select.sql @@ -55,5 +55,14 @@ select select; -- extra comma select a, from t; +-- case missing then expr +select case when 1 then end; + +-- case missing when expr +select case when then x end; + +-- case missing else expr +select case when 1 then 2 else end; + -- trailing comma at EOF select 1, diff --git a/crates/squawk_parser/tests/snapshots/tests__select_err.snap b/crates/squawk_parser/tests/snapshots/tests__select_err.snap index 5fcde5ea..28b2beb0 100644 --- a/crates/squawk_parser/tests/snapshots/tests__select_err.snap +++ b/crates/squawk_parser/tests/snapshots/tests__select_err.snap @@ -610,6 +610,81 @@ SOURCE_FILE IDENT "t" SEMICOLON ";" WHITESPACE "\n\n" + COMMENT "-- case missing then expr" + WHITESPACE "\n" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + CASE_EXPR + CASE_KW "case" + WHITESPACE " " + WHEN_CLAUSE_LIST + WHEN_CLAUSE + WHEN_KW "when" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + WHITESPACE " " + THEN_KW "then" + WHITESPACE " " + END_KW "end" + SEMICOLON ";" + WHITESPACE "\n\n" + COMMENT "-- case missing when expr" + WHITESPACE "\n" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + CASE_EXPR + CASE_KW "case" + WHITESPACE " " + WHEN_CLAUSE_LIST + WHEN_CLAUSE + WHEN_KW "when" + WHITESPACE " " + THEN_KW "then" + WHITESPACE " " + NAME_REF + IDENT "x" + WHITESPACE " " + END_KW "end" + SEMICOLON ";" + WHITESPACE "\n\n" + COMMENT "-- case missing else expr" + WHITESPACE "\n" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + CASE_EXPR + CASE_KW "case" + WHITESPACE " " + WHEN_CLAUSE_LIST + WHEN_CLAUSE + WHEN_KW "when" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + WHITESPACE " " + THEN_KW "then" + WHITESPACE " " + LITERAL + INT_NUMBER "2" + WHITESPACE " " + ELSE_CLAUSE + ELSE_KW "else" + WHITESPACE " " + END_KW "end" + SEMICOLON ";" + WHITESPACE "\n\n" COMMENT "-- trailing comma at EOF" WHITESPACE "\n" SELECT @@ -649,4 +724,7 @@ ERROR@1047: unexpected comma ERROR@1079: unexpected trailing comma ERROR@1203: expected SEMICOLON ERROR@1236: unexpected trailing comma -ERROR@1280: unexpected trailing comma +ERROR@1296: expected an expression, found END_KW +ERROR@1345: expected an expression, found THEN_KW +ERROR@1415: expected an expression, found END_KW +ERROR@1455: unexpected trailing comma