Skip to content

Commit b1c9644

Browse files
authored
parser: improve error recovery for update statements (#701)
Also fix ast::FieldExpr, ast::IndexExpr, ast::BetweenExpr
1 parent 95d1c0c commit b1c9644

File tree

18 files changed

+1606
-981
lines changed

18 files changed

+1606
-981
lines changed

crates/squawk_ide/src/expand_selection.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ const DELIMITED_LIST_KINDS: &[SyntaxKind] = &[
4444
SyntaxKind::PARAM_LIST,
4545
SyntaxKind::PARTITION_ITEM_LIST,
4646
SyntaxKind::ROW_LIST,
47+
SyntaxKind::SET_COLUMN_LIST,
48+
SyntaxKind::SET_EXPR_LIST,
4749
SyntaxKind::SET_OPTIONS_LIST,
4850
SyntaxKind::SORT_BY_LIST,
4951
SyntaxKind::TABLE_ARG_LIST,

crates/squawk_parser/src/generated/syntax_kind.rs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/squawk_parser/src/grammar.rs

Lines changed: 79 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ impl Default for SelectRestrictions {
8181
}
8282
}
8383

84-
fn opt_paren_select(p: &mut Parser<'_>) -> Option<CompletedMarker> {
85-
let m = p.start();
84+
fn opt_paren_select(p: &mut Parser<'_>, m: Option<Marker>) -> Option<CompletedMarker> {
85+
let m = m.unwrap_or_else(|| p.start());
8686
if !p.eat(L_PAREN) {
8787
m.abandon(p);
8888
return None;
@@ -98,7 +98,7 @@ fn opt_paren_select(p: &mut Parser<'_>) -> Option<CompletedMarker> {
9898
{
9999
break;
100100
}
101-
if opt_paren_select(p).is_none() {
101+
if opt_paren_select(p, None).is_none() {
102102
break;
103103
}
104104
if !p.at(R_PAREN) {
@@ -234,16 +234,14 @@ const EXTRACT_ARG_FIRST_: TokenSet =
234234

235235
// IDENT | YEAR_P | MONTH_P | DAY_P | HOUR_P | MINUTE_P | SECOND_P | Sconst
236236
const EXTRACT_ARG_FIRST: TokenSet = IDENTS.union(EXTRACT_ARG_FIRST_);
237-
fn extract_arg(p: &mut Parser<'_>) -> bool {
237+
fn extract_arg(p: &mut Parser<'_>) {
238238
if p.at_ts(EXTRACT_ARG_FIRST) {
239239
p.bump_any();
240-
true
241240
} else {
242241
p.error(format!(
243242
"expected ident, year, month, day, hour, minute, second, or string, got {:?}",
244243
p.current()
245244
));
246-
false
247245
}
248246
}
249247

@@ -2559,7 +2557,7 @@ fn compound_select(p: &mut Parser<'_>, cm: CompletedMarker) -> CompletedMarker {
25592557
p.eat(DISTINCT_KW);
25602558
}
25612559
if p.at(L_PAREN) {
2562-
opt_paren_select(p);
2560+
opt_paren_select(p, None);
25632561
} else {
25642562
if p.at_ts(SELECT_FIRST) {
25652563
select(
@@ -3161,7 +3159,7 @@ fn xml_namespace_element(p: &mut Parser<'_>) {
31613159
fn paren_data_source(p: &mut Parser<'_>) -> Option<CompletedMarker> {
31623160
assert!(p.at(L_PAREN));
31633161
if p.at(L_PAREN) && p.nth_at_ts(1, SELECT_FIRST) {
3164-
return opt_paren_select(p);
3162+
return opt_paren_select(p, None);
31653163
}
31663164
let m = p.start();
31673165
p.bump(L_PAREN);
@@ -3417,7 +3415,7 @@ fn opt_sequence_options(p: &mut Parser<'_>) -> bool {
34173415

34183416
enum ColumnDefKind {
34193417
Name,
3420-
Ref,
3418+
NameRef,
34213419
WithData,
34223420
}
34233421

@@ -3469,7 +3467,7 @@ fn column(p: &mut Parser<'_>, kind: &ColumnDefKind) -> CompletedMarker {
34693467
p.eat(PERIOD_KW);
34703468
match kind {
34713469
ColumnDefKind::Name => name(p),
3472-
ColumnDefKind::Ref => {
3470+
ColumnDefKind::NameRef => {
34733471
// supports parsing things like:
34743472
// INSERT INTO tictactoe (game, board[1:3][1:3])
34753473
name_ref(p).map(|lhs| postfix_expr(p, lhs, true));
@@ -3489,7 +3487,7 @@ fn column(p: &mut Parser<'_>, kind: &ColumnDefKind) -> CompletedMarker {
34893487

34903488
// [ ( column_name [, ... ] ) ]
34913489
fn opt_column_list(p: &mut Parser<'_>) -> bool {
3492-
opt_column_list_with(p, ColumnDefKind::Ref)
3490+
opt_column_list_with(p, ColumnDefKind::NameRef)
34933491
}
34943492

34953493
fn column_list(p: &mut Parser<'_>) {
@@ -5608,7 +5606,7 @@ fn stmt(p: &mut Parser, r: &StmtRestrictions) -> Option<CompletedMarker> {
56085606
(INSERT_KW, _) => Some(insert(p, None)),
56095607
(L_PAREN, _) if p.nth_at_ts(1, SELECT_FIRST) || p.at(L_PAREN) => {
56105608
// can have select nested in parens, i.e., ((select 1));
5611-
opt_paren_select(p)
5609+
opt_paren_select(p, None)
56125610
}
56135611
(LISTEN_KW, _) => Some(listen(p)),
56145612
(LOAD_KW, _) => Some(load(p)),
@@ -12009,7 +12007,7 @@ fn create_schema(p: &mut Parser<'_>) -> CompletedMarker {
1200912007
fn query(p: &mut Parser<'_>) {
1201012008
// TODO: this needs to be more general
1201112009
if (!p.at_ts(SELECT_FIRST) || select(p, None, &SelectRestrictions::default()).is_none())
12012-
&& opt_paren_select(p).is_none()
12010+
&& opt_paren_select(p, None).is_none()
1201312011
{
1201412012
p.error("expected select stmt")
1201512013
}
@@ -12111,55 +12109,82 @@ fn insert(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
1211112109
// ( column_name [, ...] ) = ( sub-SELECT )
1211212110
// } [, ...]
1211312111
fn set_clause(p: &mut Parser<'_>) {
12112+
let m = p.start();
1211412113
p.expect(SET_KW);
12115-
// TODO: generalize
12116-
while !p.at(EOF) {
12117-
// ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
12118-
// ( column_name [, ...] ) = ( sub-SELECT )
12119-
if p.eat(L_PAREN) {
12120-
while !p.at(EOF) {
12121-
name_ref(p).map(|lhs| postfix_expr(p, lhs, true));
12122-
if !p.eat(COMMA) {
12123-
break;
12124-
}
12125-
}
12126-
p.expect(R_PAREN);
12127-
p.expect(EQ);
12128-
// [ ROW ] ( { expression | DEFAULT } [, ...] )
12129-
// ( sub-SELECT )
12130-
let found_row = p.eat(ROW_KW);
12131-
if p.eat(L_PAREN) {
12132-
// ( sub-SELECT )
12133-
if p.at(SELECT_KW) && !found_row {
12134-
if select(p, None, &SelectRestrictions::default()).is_none() {
12135-
p.error("expected sub-SELECT");
12136-
}
12137-
} else {
12138-
// ( { expression | DEFAULT } [, ...] )
12139-
while !p.at(EOF) {
12140-
if !p.eat(DEFAULT_KW) && expr(p).is_none() {
12141-
p.error("expected expression");
12142-
}
12143-
if !p.eat(COMMA) {
12144-
break;
12145-
}
12146-
}
12147-
}
12148-
p.expect(R_PAREN);
12114+
set_column_list(p);
12115+
m.complete(p, SET_CLAUSE);
12116+
}
12117+
12118+
fn set_column_list(p: &mut Parser<'_>) {
12119+
let m = p.start();
12120+
separated(
12121+
p,
12122+
COMMA,
12123+
|| "unexpected comma".to_string(),
12124+
SET_COLUMN_FIRST,
12125+
SET_COLUMN_FOLLOW,
12126+
|p| opt_set_column(p).is_some(),
12127+
);
12128+
m.complete(p, SET_COLUMN_LIST);
12129+
}
12130+
12131+
const SET_COLUMN_FIRST: TokenSet = TokenSet::new(&[L_PAREN]).union(COLUMN_FIRST);
12132+
const SET_COLUMN_FOLLOW: TokenSet = TokenSet::new(&[FROM_KW, WHERE_KW, RETURNING_KW]);
12133+
12134+
fn opt_set_column(p: &mut Parser<'_>) -> Option<CompletedMarker> {
12135+
if !p.at_ts(SET_COLUMN_FIRST) {
12136+
return None;
12137+
}
12138+
let m = p.start();
12139+
// ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
12140+
// ( column_name [, ...] ) = ( sub-SELECT )
12141+
if p.at(L_PAREN) {
12142+
column_list(p);
12143+
p.expect(EQ);
12144+
set_expr_list_or_paren_select(p);
12145+
} else {
12146+
// column_name = { expression | DEFAULT }
12147+
column(p, &ColumnDefKind::NameRef);
12148+
p.expect(EQ);
12149+
set_expr(p);
12150+
}
12151+
Some(m.complete(p, SET_COLUMN))
12152+
}
12153+
12154+
// [ ROW ] ( { expression | DEFAULT } [, ...] )
12155+
// ( sub-SELECT )
12156+
fn set_expr_list_or_paren_select(p: &mut Parser<'_>) {
12157+
let m = p.start();
12158+
p.eat(ROW_KW);
12159+
if p.at(L_PAREN) {
12160+
if p.nth_at(1, SELECT_KW) {
12161+
if opt_paren_select(p, Some(m)).is_none() {
12162+
p.error("expected sub-SELECT");
1214912163
}
12150-
// column_name = { expression | DEFAULT }
1215112164
} else {
12152-
name_ref(p).map(|lhs| postfix_expr(p, lhs, true));
12153-
p.expect(EQ);
12154-
// { expression | DEFAULT }
12155-
if !p.eat(DEFAULT_KW) && expr(p).is_none() {
12156-
p.error("expected expression");
12157-
}
12165+
set_expr_list(p, m);
1215812166
}
12167+
}
12168+
}
12169+
12170+
fn set_expr_list(p: &mut Parser<'_>, m: Marker) {
12171+
assert!(p.at(L_PAREN));
12172+
p.expect(L_PAREN);
12173+
// ( { expression | DEFAULT } [, ...] )
12174+
while !p.at(EOF) {
12175+
set_expr(p);
1215912176
if !p.eat(COMMA) {
1216012177
break;
1216112178
}
1216212179
}
12180+
p.expect(R_PAREN);
12181+
m.complete(p, SET_EXPR_LIST);
12182+
}
12183+
12184+
fn set_expr(p: &mut Parser<'_>) {
12185+
if !p.eat(DEFAULT_KW) && expr(p).is_none() {
12186+
p.error("expected expression");
12187+
}
1216312188
}
1216412189

1216512190
fn opt_as_alias(p: &mut Parser<'_>) -> Option<CompletedMarker> {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
update t set (j k) = (1, 2);
2+
-- ^ missing comma
3+
4+
update t set a = 1 b = 2;
5+
-- ^ missing comma

crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,15 +179,19 @@ SOURCE_FILE
179179
NAME_REF
180180
IDENT "t"
181181
WHITESPACE " "
182-
SET_KW "set"
183-
WHITESPACE " "
184-
NAME_REF
185-
IDENT "foo"
186-
WHITESPACE " "
187-
EQ "="
188-
WHITESPACE " "
189-
LITERAL
190-
INT_NUMBER "1"
182+
SET_CLAUSE
183+
SET_KW "set"
184+
WHITESPACE " "
185+
SET_COLUMN_LIST
186+
SET_COLUMN
187+
COLUMN
188+
NAME_REF
189+
IDENT "foo"
190+
WHITESPACE " "
191+
EQ "="
192+
WHITESPACE " "
193+
LITERAL
194+
INT_NUMBER "1"
191195
SEMICOLON ";"
192196
WHITESPACE "\n "
193197
NOTIFY
@@ -343,15 +347,19 @@ SOURCE_FILE
343347
NAME_REF
344348
IDENT "mytable"
345349
WHITESPACE " "
346-
SET_KW "SET"
347-
WHITESPACE " "
348-
NAME_REF
349-
NAME_KW "name"
350-
WHITESPACE " "
351-
EQ "="
352-
WHITESPACE " "
353-
LITERAL
354-
STRING "'foo'"
350+
SET_CLAUSE
351+
SET_KW "SET"
352+
WHITESPACE " "
353+
SET_COLUMN_LIST
354+
SET_COLUMN
355+
COLUMN
356+
NAME_REF
357+
NAME_KW "name"
358+
WHITESPACE " "
359+
EQ "="
360+
WHITESPACE " "
361+
LITERAL
362+
STRING "'foo'"
355363
WHITESPACE " "
356364
WHERE_CLAUSE
357365
WHERE_KW "WHERE"

0 commit comments

Comments
 (0)