diff --git a/crates/squawk_ide/src/expand_selection.rs b/crates/squawk_ide/src/expand_selection.rs index 6ba0ac98..49415b91 100644 --- a/crates/squawk_ide/src/expand_selection.rs +++ b/crates/squawk_ide/src/expand_selection.rs @@ -44,6 +44,8 @@ const DELIMITED_LIST_KINDS: &[SyntaxKind] = &[ SyntaxKind::PARAM_LIST, SyntaxKind::PARTITION_ITEM_LIST, SyntaxKind::ROW_LIST, + SyntaxKind::SET_COLUMN_LIST, + SyntaxKind::SET_EXPR_LIST, SyntaxKind::SET_OPTIONS_LIST, SyntaxKind::SORT_BY_LIST, SyntaxKind::TABLE_ARG_LIST, diff --git a/crates/squawk_parser/src/generated/syntax_kind.rs b/crates/squawk_parser/src/generated/syntax_kind.rs index 9f7ad1fa..61e77653 100644 --- a/crates/squawk_parser/src/generated/syntax_kind.rs +++ b/crates/squawk_parser/src/generated/syntax_kind.rs @@ -964,11 +964,16 @@ pub enum SyntaxKind { SERIALIZABLE, SET, SET_ACCESS_METHOD, + SET_CLAUSE, + SET_COLUMN, + SET_COLUMN_LIST, SET_COMPRESSION, SET_CONSTRAINTS, SET_DEFAULT, SET_DEFAULT_COLUMNS, + SET_EXPR, SET_EXPRESSION, + SET_EXPR_LIST, SET_FUNC_OPTION, SET_GENERATED, SET_GENERATED_OPTIONS, diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index 68fa7d03..bfd4bb87 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -81,8 +81,8 @@ impl Default for SelectRestrictions { } } -fn opt_paren_select(p: &mut Parser<'_>) -> Option { - let m = p.start(); +fn opt_paren_select(p: &mut Parser<'_>, m: Option) -> Option { + let m = m.unwrap_or_else(|| p.start()); if !p.eat(L_PAREN) { m.abandon(p); return None; @@ -98,7 +98,7 @@ fn opt_paren_select(p: &mut Parser<'_>) -> Option { { break; } - if opt_paren_select(p).is_none() { + if opt_paren_select(p, None).is_none() { break; } if !p.at(R_PAREN) { @@ -234,16 +234,14 @@ const EXTRACT_ARG_FIRST_: TokenSet = // IDENT | YEAR_P | MONTH_P | DAY_P | HOUR_P | MINUTE_P | SECOND_P | Sconst const EXTRACT_ARG_FIRST: TokenSet = IDENTS.union(EXTRACT_ARG_FIRST_); -fn extract_arg(p: &mut Parser<'_>) -> bool { +fn extract_arg(p: &mut Parser<'_>) { if p.at_ts(EXTRACT_ARG_FIRST) { p.bump_any(); - true } else { p.error(format!( "expected ident, year, month, day, hour, minute, second, or string, got {:?}", p.current() )); - false } } @@ -2559,7 +2557,7 @@ fn compound_select(p: &mut Parser<'_>, cm: CompletedMarker) -> CompletedMarker { p.eat(DISTINCT_KW); } if p.at(L_PAREN) { - opt_paren_select(p); + opt_paren_select(p, None); } else { if p.at_ts(SELECT_FIRST) { select( @@ -3161,7 +3159,7 @@ fn xml_namespace_element(p: &mut Parser<'_>) { fn paren_data_source(p: &mut Parser<'_>) -> Option { assert!(p.at(L_PAREN)); if p.at(L_PAREN) && p.nth_at_ts(1, SELECT_FIRST) { - return opt_paren_select(p); + return opt_paren_select(p, None); } let m = p.start(); p.bump(L_PAREN); @@ -3417,7 +3415,7 @@ fn opt_sequence_options(p: &mut Parser<'_>) -> bool { enum ColumnDefKind { Name, - Ref, + NameRef, WithData, } @@ -3469,7 +3467,7 @@ fn column(p: &mut Parser<'_>, kind: &ColumnDefKind) -> CompletedMarker { p.eat(PERIOD_KW); match kind { ColumnDefKind::Name => name(p), - ColumnDefKind::Ref => { + ColumnDefKind::NameRef => { // supports parsing things like: // INSERT INTO tictactoe (game, board[1:3][1:3]) name_ref(p).map(|lhs| postfix_expr(p, lhs, true)); @@ -3489,7 +3487,7 @@ fn column(p: &mut Parser<'_>, kind: &ColumnDefKind) -> CompletedMarker { // [ ( column_name [, ... ] ) ] fn opt_column_list(p: &mut Parser<'_>) -> bool { - opt_column_list_with(p, ColumnDefKind::Ref) + opt_column_list_with(p, ColumnDefKind::NameRef) } fn column_list(p: &mut Parser<'_>) { @@ -5608,7 +5606,7 @@ fn stmt(p: &mut Parser, r: &StmtRestrictions) -> Option { (INSERT_KW, _) => Some(insert(p, None)), (L_PAREN, _) if p.nth_at_ts(1, SELECT_FIRST) || p.at(L_PAREN) => { // can have select nested in parens, i.e., ((select 1)); - opt_paren_select(p) + opt_paren_select(p, None) } (LISTEN_KW, _) => Some(listen(p)), (LOAD_KW, _) => Some(load(p)), @@ -12009,7 +12007,7 @@ fn create_schema(p: &mut Parser<'_>) -> CompletedMarker { fn query(p: &mut Parser<'_>) { // TODO: this needs to be more general if (!p.at_ts(SELECT_FIRST) || select(p, None, &SelectRestrictions::default()).is_none()) - && opt_paren_select(p).is_none() + && opt_paren_select(p, None).is_none() { p.error("expected select stmt") } @@ -12111,55 +12109,82 @@ fn insert(p: &mut Parser<'_>, m: Option) -> CompletedMarker { // ( column_name [, ...] ) = ( sub-SELECT ) // } [, ...] fn set_clause(p: &mut Parser<'_>) { + let m = p.start(); p.expect(SET_KW); - // TODO: generalize - while !p.at(EOF) { - // ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | - // ( column_name [, ...] ) = ( sub-SELECT ) - if p.eat(L_PAREN) { - while !p.at(EOF) { - name_ref(p).map(|lhs| postfix_expr(p, lhs, true)); - if !p.eat(COMMA) { - break; - } - } - p.expect(R_PAREN); - p.expect(EQ); - // [ ROW ] ( { expression | DEFAULT } [, ...] ) - // ( sub-SELECT ) - let found_row = p.eat(ROW_KW); - if p.eat(L_PAREN) { - // ( sub-SELECT ) - if p.at(SELECT_KW) && !found_row { - if select(p, None, &SelectRestrictions::default()).is_none() { - p.error("expected sub-SELECT"); - } - } else { - // ( { expression | DEFAULT } [, ...] ) - while !p.at(EOF) { - if !p.eat(DEFAULT_KW) && expr(p).is_none() { - p.error("expected expression"); - } - if !p.eat(COMMA) { - break; - } - } - } - p.expect(R_PAREN); + set_column_list(p); + m.complete(p, SET_CLAUSE); +} + +fn set_column_list(p: &mut Parser<'_>) { + let m = p.start(); + separated( + p, + COMMA, + || "unexpected comma".to_string(), + SET_COLUMN_FIRST, + SET_COLUMN_FOLLOW, + |p| opt_set_column(p).is_some(), + ); + m.complete(p, SET_COLUMN_LIST); +} + +const SET_COLUMN_FIRST: TokenSet = TokenSet::new(&[L_PAREN]).union(COLUMN_FIRST); +const SET_COLUMN_FOLLOW: TokenSet = TokenSet::new(&[FROM_KW, WHERE_KW, RETURNING_KW]); + +fn opt_set_column(p: &mut Parser<'_>) -> Option { + if !p.at_ts(SET_COLUMN_FIRST) { + return None; + } + let m = p.start(); + // ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | + // ( column_name [, ...] ) = ( sub-SELECT ) + if p.at(L_PAREN) { + column_list(p); + p.expect(EQ); + set_expr_list_or_paren_select(p); + } else { + // column_name = { expression | DEFAULT } + column(p, &ColumnDefKind::NameRef); + p.expect(EQ); + set_expr(p); + } + Some(m.complete(p, SET_COLUMN)) +} + +// [ ROW ] ( { expression | DEFAULT } [, ...] ) +// ( sub-SELECT ) +fn set_expr_list_or_paren_select(p: &mut Parser<'_>) { + let m = p.start(); + p.eat(ROW_KW); + if p.at(L_PAREN) { + if p.nth_at(1, SELECT_KW) { + if opt_paren_select(p, Some(m)).is_none() { + p.error("expected sub-SELECT"); } - // column_name = { expression | DEFAULT } } else { - name_ref(p).map(|lhs| postfix_expr(p, lhs, true)); - p.expect(EQ); - // { expression | DEFAULT } - if !p.eat(DEFAULT_KW) && expr(p).is_none() { - p.error("expected expression"); - } + set_expr_list(p, m); } + } +} + +fn set_expr_list(p: &mut Parser<'_>, m: Marker) { + assert!(p.at(L_PAREN)); + p.expect(L_PAREN); + // ( { expression | DEFAULT } [, ...] ) + while !p.at(EOF) { + set_expr(p); if !p.eat(COMMA) { break; } } + p.expect(R_PAREN); + m.complete(p, SET_EXPR_LIST); +} + +fn set_expr(p: &mut Parser<'_>) { + if !p.eat(DEFAULT_KW) && expr(p).is_none() { + p.error("expected expression"); + } } fn opt_as_alias(p: &mut Parser<'_>) -> Option { diff --git a/crates/squawk_parser/tests/data/err/update.sql b/crates/squawk_parser/tests/data/err/update.sql new file mode 100644 index 00000000..188df7f2 --- /dev/null +++ b/crates/squawk_parser/tests/data/err/update.sql @@ -0,0 +1,5 @@ +update t set (j k) = (1, 2); +-- ^ missing comma + +update t set a = 1 b = 2; +-- ^ missing comma diff --git a/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap index 4ac9f235..7bfa361e 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap @@ -179,15 +179,19 @@ SOURCE_FILE NAME_REF IDENT "t" WHITESPACE " " - SET_KW "set" - WHITESPACE " " - NAME_REF - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "1" SEMICOLON ";" WHITESPACE "\n " NOTIFY @@ -343,15 +347,19 @@ SOURCE_FILE NAME_REF IDENT "mytable" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - NAME_KW "name" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "'foo'" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + NAME_KW "name" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "'foo'" WHITESPACE " " WHERE_CLAUSE WHERE_KW "WHERE" diff --git a/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap b/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap index 946393e7..1e81e124 100644 --- a/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap @@ -868,21 +868,25 @@ SOURCE_FILE NAME_REF IDENT "employees" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "sales_count" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "sales_count" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "1" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "sales_count" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "sales_count" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + LITERAL + INT_NUMBER "1" WHITESPACE " " WHERE_CLAUSE WHERE_KW "WHERE" @@ -1023,19 +1027,23 @@ SOURCE_FILE WHITESPACE " " UPDATE_KW "UPDATE" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "dname" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FIELD_EXPR - NAME_REF - IDENT "EXCLUDED" - DOT "." - NAME_REF - IDENT "dname" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "dname" + WHITESPACE " " + EQ "=" + WHITESPACE " " + FIELD_EXPR + NAME_REF + IDENT "EXCLUDED" + DOT "." + NAME_REF + IDENT "dname" SEMICOLON ";" WHITESPACE "\n\n" INSERT @@ -1145,47 +1153,51 @@ SOURCE_FILE WHITESPACE " " UPDATE_KW "UPDATE" WHITESPACE "\n " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "dname" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - FIELD_EXPR - NAME_REF - IDENT "EXCLUDED" - DOT "." - NAME_REF - IDENT "dname" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - CUSTOM_OP - PIPE "|" - PIPE "|" - WHITESPACE " " - BIN_EXPR - LITERAL - STRING "' (formerly '" - WHITESPACE " " - CUSTOM_OP - PIPE "|" - PIPE "|" - WHITESPACE " " - BIN_EXPR - FIELD_EXPR - NAME_REF - IDENT "d" - DOT "." + SET_COLUMN_LIST + SET_COLUMN + COLUMN NAME_REF IDENT "dname" WHITESPACE " " - CUSTOM_OP - PIPE "|" - PIPE "|" + EQ "=" WHITESPACE " " - LITERAL - STRING "')'" + BIN_EXPR + FIELD_EXPR + NAME_REF + IDENT "EXCLUDED" + DOT "." + NAME_REF + IDENT "dname" + WHITESPACE " " + CUSTOM_OP + PIPE "|" + PIPE "|" + WHITESPACE " " + BIN_EXPR + LITERAL + STRING "' (formerly '" + WHITESPACE " " + CUSTOM_OP + PIPE "|" + PIPE "|" + WHITESPACE " " + BIN_EXPR + FIELD_EXPR + NAME_REF + IDENT "d" + DOT "." + NAME_REF + IDENT "dname" + WHITESPACE " " + CUSTOM_OP + PIPE "|" + PIPE "|" + WHITESPACE " " + LITERAL + STRING "')'" WHITESPACE "\n " WHERE_CLAUSE WHERE_KW "WHERE" diff --git a/crates/squawk_parser/tests/snapshots/tests__merge_pg17_ok.snap b/crates/squawk_parser/tests/snapshots/tests__merge_pg17_ok.snap index a48d4027..e06e1a58 100644 --- a/crates/squawk_parser/tests/snapshots/tests__merge_pg17_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__merge_pg17_ok.snap @@ -690,105 +690,121 @@ SOURCE_FILE MERGE_UPDATE UPDATE_KW "update" WHITESPACE " " - SET_KW "set" - WHITESPACE "\n " - NAME_REF - IDENT "a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - DEFAULT_KW "default" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "b" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "c" - WHITESPACE " " - EQ "=" - WHITESPACE " " - NAME_REF - IDENT "d" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "e" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - SELECT - SELECT_CLAUSE - SELECT_KW "select" + SET_CLAUSE + SET_KW "set" + WHITESPACE "\n " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "a" WHITESPACE " " - TARGET_LIST - TARGET + EQ "=" + WHITESPACE " " + DEFAULT_KW "default" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "b" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "c" + WHITESPACE " " + EQ "=" + WHITESPACE " " + NAME_REF + IDENT "d" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "e" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PAREN_EXPR + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + LITERAL + INT_NUMBER "1" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "f" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CALL_EXPR + NAME_REF + ROW_KW "row" + ARG_LIST + L_PAREN "(" LITERAL INT_NUMBER "1" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "f" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - NAME_REF - ROW_KW "row" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "1" + COMMA "," + WHITESPACE " " + LITERAL + INT_NUMBER "2" + COMMA "," + WHITESPACE " " + LITERAL + DEFAULT_KW "default" + R_PAREN ")" COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "g" + WHITESPACE " " + EQ "=" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE " " + LITERAL + INT_NUMBER "2" + COMMA "," + WHITESPACE " " + LITERAL + DEFAULT_KW "default" + R_PAREN ")" COMMA "," - WHITESPACE " " - LITERAL - DEFAULT_KW "default" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "g" - WHITESPACE " " - EQ "=" - WHITESPACE " " - TUPLE_EXPR - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - WHITESPACE " " - LITERAL - DEFAULT_KW "default" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "h" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PAREN_EXPR - L_PAREN "(" - LITERAL - DEFAULT_KW "default" - R_PAREN ")" + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "h" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PAREN_EXPR + L_PAREN "(" + LITERAL + DEFAULT_KW "default" + R_PAREN ")" WHITESPACE "\n " MERGE_WHEN_NOT_MATCHED_SOURCE WHEN_KW "when" @@ -806,15 +822,19 @@ SOURCE_FILE MERGE_UPDATE UPDATE_KW "update" WHITESPACE " " - SET_KW "set" - WHITESPACE " " - NAME_REF - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - NAME_REF - IDENT "bar" + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + NAME_REF + IDENT "bar" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- merge_delete" @@ -1022,21 +1042,25 @@ SOURCE_FILE MERGE_UPDATE UPDATE_KW "UPDATE" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "balance" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "balance" - WHITESPACE " " - PLUS "+" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - NAME_REF - IDENT "transaction_value" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "balance" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "balance" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + NAME_REF + IDENT "transaction_value" WHITESPACE "\n" MERGE_WHEN_NOT_MATCHED_TARGET WHEN_KW "WHEN" @@ -1165,21 +1189,25 @@ SOURCE_FILE MERGE_UPDATE UPDATE_KW "UPDATE" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "balance" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "balance" - WHITESPACE " " - PLUS "+" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - NAME_REF - IDENT "transaction_value" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "balance" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "balance" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + NAME_REF + IDENT "transaction_value" WHITESPACE "\n" MERGE_WHEN_NOT_MATCHED_TARGET WHEN_KW "WHEN" @@ -1358,29 +1386,33 @@ SOURCE_FILE MERGE_UPDATE UPDATE_KW "UPDATE" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "stock" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - FIELD_EXPR - NAME_REF - IDENT "w" - DOT "." - NAME_REF - IDENT "stock" - WHITESPACE " " - PLUS "+" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - FIELD_EXPR - NAME_REF - IDENT "s" - DOT "." - NAME_REF - IDENT "stock_delta" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "stock" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + FIELD_EXPR + NAME_REF + IDENT "w" + DOT "." + NAME_REF + IDENT "stock" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + FIELD_EXPR + NAME_REF + IDENT "s" + DOT "." + NAME_REF + IDENT "stock_delta" WHITESPACE "\n" MERGE_WHEN_MATCHED WHEN_KW "WHEN" @@ -1526,19 +1558,23 @@ SOURCE_FILE MERGE_UPDATE UPDATE_KW "UPDATE" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "stock" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FIELD_EXPR - NAME_REF - IDENT "s" - DOT "." - NAME_REF - IDENT "stock" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "stock" + WHITESPACE " " + EQ "=" + WHITESPACE " " + FIELD_EXPR + NAME_REF + IDENT "s" + DOT "." + NAME_REF + IDENT "stock" WHITESPACE "\n" MERGE_WHEN_NOT_MATCHED_SOURCE WHEN_KW "WHEN" diff --git a/crates/squawk_parser/tests/snapshots/tests__misc_ok.snap b/crates/squawk_parser/tests/snapshots/tests__misc_ok.snap index abd6270d..2a5d6fe2 100644 --- a/crates/squawk_parser/tests/snapshots/tests__misc_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__misc_ok.snap @@ -228,77 +228,81 @@ SOURCE_FILE NAME_REF IDENT "movies" WHITESPACE "\n" - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "embedding" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CALL_EXPR - FIELD_EXPR - NAME_REF - IDENT "ai" - DOT "." - NAME_REF - IDENT "cohere_embed" - ARG_LIST - L_PAREN "(" - WHITESPACE "\n " - LITERAL - STRING "'embed-english-v3.0'" - WHITESPACE "\n " - COMMA "," - WHITESPACE " " - CALL_EXPR - NAME_REF - IDENT "CONCAT_WS" - ARG_LIST - L_PAREN "(" - LITERAL - STRING "'. '" - COMMA "," - WHITESPACE "\n " + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN NAME_REF - IDENT "title" - COMMA "," - WHITESPACE "\n " - CALL_EXPR + IDENT "embedding" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CALL_EXPR + FIELD_EXPR NAME_REF - COALESCE_KW "COALESCE" - ARG_LIST - L_PAREN "(" + IDENT "ai" + DOT "." + NAME_REF + IDENT "cohere_embed" + ARG_LIST + L_PAREN "(" + WHITESPACE "\n " + LITERAL + STRING "'embed-english-v3.0'" + WHITESPACE "\n " + COMMA "," + WHITESPACE " " + CALL_EXPR NAME_REF - IDENT "overview" - COMMA "," - WHITESPACE " " + IDENT "CONCAT_WS" + ARG_LIST + L_PAREN "(" + LITERAL + STRING "'. '" + COMMA "," + WHITESPACE "\n " + NAME_REF + IDENT "title" + COMMA "," + WHITESPACE "\n " + CALL_EXPR + NAME_REF + COALESCE_KW "COALESCE" + ARG_LIST + L_PAREN "(" + NAME_REF + IDENT "overview" + COMMA "," + WHITESPACE " " + LITERAL + STRING "''" + R_PAREN ")" + WHITESPACE "\n " + R_PAREN ")" + WHITESPACE "\n " + COMMA "," + WHITESPACE " " + NAMED_ARG + NAME_REF + IDENT "input_type" + FAT_ARROW "=>" LITERAL - STRING "''" - R_PAREN ")" - WHITESPACE "\n " - R_PAREN ")" - WHITESPACE "\n " - COMMA "," - WHITESPACE " " - NAMED_ARG - NAME_REF - IDENT "input_type" - FAT_ARROW "=>" - LITERAL - STRING "'search_document'" - WHITESPACE "\n " - COMMENT "-- , api_key=>%s" - WHITESPACE "\n " - COMMA "," - WHITESPACE " " - NAMED_ARG - NAME_REF - IDENT "api_key" - FAT_ARROW "=>" - LITERAL - POSITIONAL_PARAM "$1" - WHITESPACE "\n" - R_PAREN ")" + STRING "'search_document'" + WHITESPACE "\n " + COMMENT "-- , api_key=>%s" + WHITESPACE "\n " + COMMA "," + WHITESPACE " " + NAMED_ARG + NAME_REF + IDENT "api_key" + FAT_ARROW "=>" + LITERAL + POSITIONAL_PARAM "$1" + WHITESPACE "\n" + R_PAREN ")" WHITESPACE " " WHERE_CLAUSE WHERE_KW "where" @@ -2055,47 +2059,51 @@ SOURCE_FILE NAME_REF IDENT "tng" WHITESPACE "\n " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "vec" - WHITESPACE " " - EQ "=" - WHITESPACE " " - CAST_EXPR - CALL_EXPR - FIELD_EXPR - NAME_REF - IDENT "openai" - DOT "." - NAME_REF - IDENT "vector" - ARG_LIST - L_PAREN "(" - BIN_EXPR + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN NAME_REF - IDENT "title" - WHITESPACE " " - CUSTOM_OP - PIPE "|" - PIPE "|" - WHITESPACE " " - BIN_EXPR - LITERAL - STRING "' -- '" - WHITESPACE " " - CUSTOM_OP - PIPE "|" - PIPE "|" - WHITESPACE " " - NAME_REF - IDENT "plot" - R_PAREN ")" - COLON_COLON - COLON ":" - COLON ":" - NAME_REF - IDENT "vector" + IDENT "vec" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CAST_EXPR + CALL_EXPR + FIELD_EXPR + NAME_REF + IDENT "openai" + DOT "." + NAME_REF + IDENT "vector" + ARG_LIST + L_PAREN "(" + BIN_EXPR + NAME_REF + IDENT "title" + WHITESPACE " " + CUSTOM_OP + PIPE "|" + PIPE "|" + WHITESPACE " " + BIN_EXPR + LITERAL + STRING "' -- '" + WHITESPACE " " + CUSTOM_OP + PIPE "|" + PIPE "|" + WHITESPACE " " + NAME_REF + IDENT "plot" + R_PAREN ")" + COLON_COLON + COLON ":" + COLON ":" + NAME_REF + IDENT "vector" SEMICOLON ";" WHITESPACE "\n\n" SELECT diff --git a/crates/squawk_parser/tests/snapshots/tests__prepare_ok.snap b/crates/squawk_parser/tests/snapshots/tests__prepare_ok.snap index 45651131..370f9ac0 100644 --- a/crates/squawk_parser/tests/snapshots/tests__prepare_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__prepare_ok.snap @@ -232,15 +232,19 @@ SOURCE_FILE NAME_REF IDENT "foo" WHITESPACE " " - SET_KW "set" - WHITESPACE " " - NAME_REF - IDENT "x" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "x" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "1" WHITESPACE " " WHERE_CLAUSE WHERE_KW "where" diff --git a/crates/squawk_parser/tests/snapshots/tests__select_cte_ok.snap b/crates/squawk_parser/tests/snapshots/tests__select_cte_ok.snap index bbc00f5e..6f617b16 100644 --- a/crates/squawk_parser/tests/snapshots/tests__select_cte_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__select_cte_ok.snap @@ -1417,15 +1417,19 @@ SOURCE_FILE NAME_REF IDENT "notification" WHITESPACE "\n" - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "dismissed_at" - WHITESPACE " " - EQ "=" - WHITESPACE " " - NAME_REF - CURRENT_TIMESTAMP_KW "current_timestamp" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "dismissed_at" + WHITESPACE " " + EQ "=" + WHITESPACE " " + NAME_REF + CURRENT_TIMESTAMP_KW "current_timestamp" WHITESPACE "\n" WHERE_CLAUSE WHERE_KW "WHERE" diff --git a/crates/squawk_parser/tests/snapshots/tests__update_err.snap b/crates/squawk_parser/tests/snapshots/tests__update_err.snap new file mode 100644 index 00000000..751e76e1 --- /dev/null +++ b/crates/squawk_parser/tests/snapshots/tests__update_err.snap @@ -0,0 +1,84 @@ +--- +source: crates/squawk_parser/tests/tests.rs +input_file: crates/squawk_parser/tests/data/err/update.sql +--- +SOURCE_FILE + UPDATE + UPDATE_KW "update" + WHITESPACE " " + RELATION_NAME + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE " " + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "j" + WHITESPACE " " + COLUMN + NAME_REF + IDENT "k" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + SET_EXPR_LIST + L_PAREN "(" + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE " " + LITERAL + INT_NUMBER "2" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + COMMENT "-- ^ missing comma" + WHITESPACE "\n\n" + UPDATE + UPDATE_KW "update" + WHITESPACE " " + RELATION_NAME + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE " " + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + WHITESPACE " " + SET_COLUMN + COLUMN + NAME_REF + IDENT "b" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "2" + SEMICOLON ";" + WHITESPACE "\n" + COMMENT "-- ^ missing comma" + WHITESPACE "\n" +--- +ERROR@15: expected COMMA +ERROR@79: expected COMMA diff --git a/crates/squawk_parser/tests/snapshots/tests__update_ok.snap b/crates/squawk_parser/tests/snapshots/tests__update_ok.snap index 603ed2a1..90da1ebd 100644 --- a/crates/squawk_parser/tests/snapshots/tests__update_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__update_ok.snap @@ -16,15 +16,19 @@ SOURCE_FILE NAME_REF IDENT "products" WHITESPACE " " - SET_KW "set" - WHITESPACE " " - NAME_REF - IDENT "price" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "10" + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "price" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "10" WHITESPACE " " WHERE_CLAUSE WHERE_KW "where" @@ -50,21 +54,25 @@ SOURCE_FILE NAME_REF IDENT "products" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "price" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "price" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - STAR "*" - WHITESPACE " " - LITERAL - FLOAT_NUMBER "1.10" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "price" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "price" + WHITESPACE " " + STAR "*" + WHITESPACE " " + LITERAL + FLOAT_NUMBER "1.10" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- set muliple" @@ -78,33 +86,41 @@ SOURCE_FILE NAME_REF IDENT "mytable" WHITESPACE " " - SET_KW "set" - WHITESPACE " " - NAME_REF - IDENT "a" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "5" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "b" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "3" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "c" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - INT_NUMBER "1" + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "5" + COMMA "," + WHITESPACE " " + SET_COLUMN + COLUMN + NAME_REF + IDENT "b" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "3" + COMMA "," + WHITESPACE " " + SET_COLUMN + COLUMN + NAME_REF + IDENT "c" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "1" WHITESPACE " " WHERE_CLAUSE WHERE_KW "where" @@ -130,25 +146,31 @@ SOURCE_FILE NAME_REF IDENT "t" WHITESPACE " " - SET_KW "set" - WHITESPACE " " - L_PAREN "(" - NAME_REF - IDENT "z" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - L_PAREN "(" - SELECT - SELECT_CLAUSE - SELECT_KW "select" - WHITESPACE " " - TARGET_LIST - TARGET - LITERAL - INT_NUMBER "1" - R_PAREN ")" + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "z" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PAREN_SELECT + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + LITERAL + INT_NUMBER "1" + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n\n" COMMENT "-- with_stmt" @@ -184,14 +206,18 @@ SOURCE_FILE NAME_REF IDENT "t2" WHITESPACE " " - SET_KW "set" - WHITESPACE " \n " - NAME_REF - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - DEFAULT_KW "default" + SET_CLAUSE + SET_KW "set" + WHITESPACE " \n " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + DEFAULT_KW "default" WHITESPACE "\n" FROM_CLAUSE FROM_KW "from" @@ -242,82 +268,101 @@ SOURCE_FILE NAME IDENT "t2" WHITESPACE " \n" - SET_KW "set" - WHITESPACE " \n " - NAME_REF - IDENT "bar" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "a" - WHITESPACE " " - STAR "*" - WHITESPACE " " - LITERAL - INT_NUMBER "2" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - DEFAULT_KW "default" - COMMA "," - WHITESPACE "\n " - L_PAREN "(" - NAME_REF - IDENT "a" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - ROW_KW "row" - L_PAREN "(" - DEFAULT_KW "default" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - L_PAREN "(" - NAME_REF - IDENT "b" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "c" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - L_PAREN "(" - LITERAL - INT_NUMBER "2" - COMMA "," - WHITESPACE " " - LITERAL - INT_NUMBER "3" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - L_PAREN "(" - NAME_REF - IDENT "z" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - L_PAREN "(" - SELECT - SELECT_CLAUSE - SELECT_KW "select" - WHITESPACE " " - TARGET_LIST - TARGET + SET_CLAUSE + SET_KW "set" + WHITESPACE " \n " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "bar" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "a" + WHITESPACE " " + STAR "*" + WHITESPACE " " LITERAL - INT_NUMBER "1" - R_PAREN ")" + INT_NUMBER "2" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + DEFAULT_KW "default" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "a" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + SET_EXPR_LIST + ROW_KW "row" + L_PAREN "(" + DEFAULT_KW "default" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "b" + COMMA "," + WHITESPACE " " + COLUMN + NAME_REF + IDENT "c" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + SET_EXPR_LIST + L_PAREN "(" + LITERAL + INT_NUMBER "2" + COMMA "," + WHITESPACE " " + LITERAL + INT_NUMBER "3" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "z" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PAREN_SELECT + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + LITERAL + INT_NUMBER "1" + R_PAREN ")" WHITESPACE "\n" FROM_CLAUSE FROM_KW "from" @@ -379,15 +424,19 @@ SOURCE_FILE NAME_REF IDENT "films" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "kind" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "'Dramatic'" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "kind" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "'Dramatic'" WHITESPACE " " WHERE_CLAUSE WHERE_KW "WHERE" @@ -411,40 +460,48 @@ SOURCE_FILE NAME_REF IDENT "weather" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "temp_lo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "temp_lo" - PLUS "+" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "temp_hi" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "temp_lo" - PLUS "+" - LITERAL - INT_NUMBER "15" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "prcp" - WHITESPACE " " - EQ "=" - WHITESPACE " " - DEFAULT_KW "DEFAULT" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "temp_lo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "temp_lo" + PLUS "+" + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE " " + SET_COLUMN + COLUMN + NAME_REF + IDENT "temp_hi" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "temp_lo" + PLUS "+" + LITERAL + INT_NUMBER "15" + COMMA "," + WHITESPACE " " + SET_COLUMN + COLUMN + NAME_REF + IDENT "prcp" + WHITESPACE " " + EQ "=" + WHITESPACE " " + DEFAULT_KW "DEFAULT" WHITESPACE "\n " WHERE_CLAUSE WHERE_KW "WHERE" @@ -480,40 +537,48 @@ SOURCE_FILE NAME_REF IDENT "weather" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "temp_lo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "temp_lo" - PLUS "+" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "temp_hi" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "temp_lo" - PLUS "+" - LITERAL - INT_NUMBER "15" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "prcp" - WHITESPACE " " - EQ "=" - WHITESPACE " " - DEFAULT_KW "DEFAULT" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "temp_lo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "temp_lo" + PLUS "+" + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE " " + SET_COLUMN + COLUMN + NAME_REF + IDENT "temp_hi" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "temp_lo" + PLUS "+" + LITERAL + INT_NUMBER "15" + COMMA "," + WHITESPACE " " + SET_COLUMN + COLUMN + NAME_REF + IDENT "prcp" + WHITESPACE " " + EQ "=" + WHITESPACE " " + DEFAULT_KW "DEFAULT" WHITESPACE "\n " WHERE_CLAUSE WHERE_KW "WHERE" @@ -567,42 +632,50 @@ SOURCE_FILE NAME_REF IDENT "weather" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - L_PAREN "(" - NAME_REF - IDENT "temp_lo" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "temp_hi" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "prcp" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - L_PAREN "(" - BIN_EXPR - NAME_REF - IDENT "temp_lo" - PLUS "+" - LITERAL - INT_NUMBER "1" - COMMA "," - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "temp_lo" - PLUS "+" - LITERAL - INT_NUMBER "15" - COMMA "," - WHITESPACE " " - DEFAULT_KW "DEFAULT" - R_PAREN ")" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "temp_lo" + COMMA "," + WHITESPACE " " + COLUMN + NAME_REF + IDENT "temp_hi" + COMMA "," + WHITESPACE " " + COLUMN + NAME_REF + IDENT "prcp" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + SET_EXPR_LIST + L_PAREN "(" + BIN_EXPR + NAME_REF + IDENT "temp_lo" + PLUS "+" + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "temp_lo" + PLUS "+" + LITERAL + INT_NUMBER "15" + COMMA "," + WHITESPACE " " + DEFAULT_KW "DEFAULT" + R_PAREN ")" WHITESPACE "\n " WHERE_CLAUSE WHERE_KW "WHERE" @@ -638,21 +711,25 @@ SOURCE_FILE NAME_REF IDENT "employees" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "sales_count" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "sales_count" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "1" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "sales_count" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "sales_count" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + LITERAL + INT_NUMBER "1" WHITESPACE " " FROM_CLAUSE FROM_KW "FROM" @@ -707,21 +784,25 @@ SOURCE_FILE NAME_REF IDENT "employees" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "sales_count" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "sales_count" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - PLUS "+" - WHITESPACE " " - LITERAL - INT_NUMBER "1" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "sales_count" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "sales_count" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + LITERAL + INT_NUMBER "1" WHITESPACE " " WHERE_CLAUSE WHERE_KW "WHERE" @@ -773,61 +854,68 @@ SOURCE_FILE NAME_REF IDENT "accounts" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - L_PAREN "(" - NAME_REF - IDENT "contact_first_name" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "contact_last_name" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE "\n " - L_PAREN "(" - SELECT - SELECT_CLAUSE - SELECT_KW "SELECT" - WHITESPACE " " - TARGET_LIST - TARGET - NAME_REF - IDENT "first_name" - COMMA "," - WHITESPACE " " - TARGET - NAME_REF - IDENT "last_name" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - FROM_CLAUSE - FROM_KW "FROM" - WHITESPACE " " - FROM_ITEM - NAME_REF - IDENT "employees" - WHITESPACE "\n " - WHERE_CLAUSE - WHERE_KW "WHERE" - WHITESPACE " " - BIN_EXPR - FIELD_EXPR - NAME_REF - IDENT "employees" - DOT "." - NAME_REF - IDENT "id" + SET_COLUMN_LIST + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "contact_first_name" + COMMA "," + WHITESPACE " " + COLUMN + NAME_REF + IDENT "contact_last_name" + R_PAREN ")" WHITESPACE " " EQ "=" - WHITESPACE " " - FIELD_EXPR - NAME_REF - IDENT "accounts" - DOT "." - NAME_REF - IDENT "sales_person" - R_PAREN ")" + WHITESPACE "\n " + PAREN_SELECT + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + NAME_REF + IDENT "first_name" + COMMA "," + WHITESPACE " " + TARGET + NAME_REF + IDENT "last_name" + WHITESPACE " " + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + FROM_ITEM + NAME_REF + IDENT "employees" + WHITESPACE "\n " + WHERE_CLAUSE + WHERE_KW "WHERE" + WHITESPACE " " + BIN_EXPR + FIELD_EXPR + NAME_REF + IDENT "employees" + DOT "." + NAME_REF + IDENT "id" + WHITESPACE " " + EQ "=" + WHITESPACE " " + FIELD_EXPR + NAME_REF + IDENT "accounts" + DOT "." + NAME_REF + IDENT "sales_person" + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" UPDATE @@ -839,24 +927,30 @@ SOURCE_FILE NAME_REF IDENT "accounts" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "contact_first_name" - WHITESPACE " " - EQ "=" - WHITESPACE " " - NAME_REF - IDENT "first_name" - COMMA "," - WHITESPACE "\n " - NAME_REF - IDENT "contact_last_name" - WHITESPACE " " - EQ "=" - WHITESPACE " " - NAME_REF - IDENT "last_name" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "contact_first_name" + WHITESPACE " " + EQ "=" + WHITESPACE " " + NAME_REF + IDENT "first_name" + COMMA "," + WHITESPACE "\n " + SET_COLUMN + COLUMN + NAME_REF + IDENT "contact_last_name" + WHITESPACE " " + EQ "=" + WHITESPACE " " + NAME_REF + IDENT "last_name" WHITESPACE "\n " FROM_CLAUSE FROM_KW "FROM" @@ -899,107 +993,116 @@ SOURCE_FILE NAME IDENT "s" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - L_PAREN "(" - NAME_REF - IDENT "sum_x" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "sum_y" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "avg_x" - COMMA "," - WHITESPACE " " - NAME_REF - IDENT "avg_y" - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE "\n " - L_PAREN "(" - SELECT - SELECT_CLAUSE - SELECT_KW "SELECT" - WHITESPACE " " - TARGET_LIST - TARGET - CALL_EXPR + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN_LIST + L_PAREN "(" + COLUMN NAME_REF - IDENT "sum" - ARG_LIST - L_PAREN "(" - NAME_REF - IDENT "x" - R_PAREN ")" - COMMA "," - WHITESPACE " " - TARGET - CALL_EXPR + IDENT "sum_x" + COMMA "," + WHITESPACE " " + COLUMN NAME_REF - IDENT "sum" - ARG_LIST - L_PAREN "(" - NAME_REF - IDENT "y" - R_PAREN ")" - COMMA "," - WHITESPACE " " - TARGET - CALL_EXPR + IDENT "sum_y" + COMMA "," + WHITESPACE " " + COLUMN NAME_REF - IDENT "avg" - ARG_LIST - L_PAREN "(" - NAME_REF - IDENT "x" - R_PAREN ")" - COMMA "," - WHITESPACE " " - TARGET - CALL_EXPR + IDENT "avg_x" + COMMA "," + WHITESPACE " " + COLUMN NAME_REF - IDENT "avg" - ARG_LIST - L_PAREN "(" - NAME_REF - IDENT "y" - R_PAREN ")" - WHITESPACE " " - FROM_CLAUSE - FROM_KW "FROM" - WHITESPACE " " - FROM_ITEM - NAME_REF - DATA_KW "data" - WHITESPACE " " - ALIAS - NAME - IDENT "d" - WHITESPACE "\n " - WHERE_CLAUSE - WHERE_KW "WHERE" - WHITESPACE " " - BIN_EXPR - FIELD_EXPR - NAME_REF - IDENT "d" - DOT "." - NAME_REF - IDENT "group_id" + IDENT "avg_y" + R_PAREN ")" WHITESPACE " " EQ "=" - WHITESPACE " " - FIELD_EXPR - NAME_REF - IDENT "s" - DOT "." - NAME_REF - IDENT "group_id" - R_PAREN ")" + WHITESPACE "\n " + PAREN_SELECT + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + CALL_EXPR + NAME_REF + IDENT "sum" + ARG_LIST + L_PAREN "(" + NAME_REF + IDENT "x" + R_PAREN ")" + COMMA "," + WHITESPACE " " + TARGET + CALL_EXPR + NAME_REF + IDENT "sum" + ARG_LIST + L_PAREN "(" + NAME_REF + IDENT "y" + R_PAREN ")" + COMMA "," + WHITESPACE " " + TARGET + CALL_EXPR + NAME_REF + IDENT "avg" + ARG_LIST + L_PAREN "(" + NAME_REF + IDENT "x" + R_PAREN ")" + COMMA "," + WHITESPACE " " + TARGET + CALL_EXPR + NAME_REF + IDENT "avg" + ARG_LIST + L_PAREN "(" + NAME_REF + IDENT "y" + R_PAREN ")" + WHITESPACE " " + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + FROM_ITEM + NAME_REF + DATA_KW "data" + WHITESPACE " " + ALIAS + NAME + IDENT "d" + WHITESPACE "\n " + WHERE_CLAUSE + WHERE_KW "WHERE" + WHITESPACE " " + BIN_EXPR + FIELD_EXPR + NAME_REF + IDENT "d" + DOT "." + NAME_REF + IDENT "group_id" + WHITESPACE " " + EQ "=" + WHITESPACE " " + FIELD_EXPR + NAME_REF + IDENT "s" + DOT "." + NAME_REF + IDENT "group_id" + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" BEGIN @@ -1061,21 +1164,25 @@ SOURCE_FILE NAME_REF IDENT "wines" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "stock" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "stock" - WHITESPACE " " - PLUS "+" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - LITERAL - INT_NUMBER "24" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "stock" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "stock" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + LITERAL + INT_NUMBER "24" WHITESPACE " " WHERE_CLAUSE WHERE_KW "WHERE" @@ -1105,15 +1212,19 @@ SOURCE_FILE NAME_REF IDENT "films" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "kind" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "'Dramatic'" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "kind" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "'Dramatic'" WHITESPACE " " WHERE_KW "WHERE" WHITESPACE " " @@ -1230,15 +1341,19 @@ SOURCE_FILE NAME_REF IDENT "work_item" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "status" - WHITESPACE " " - EQ "=" - WHITESPACE " " - LITERAL - STRING "'failed'" + SET_CLAUSE + SET_KW "SET" + WHITESPACE " " + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "status" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "'failed'" WHITESPACE "\n " FROM_CLAUSE FROM_KW "FROM" diff --git a/crates/squawk_parser/tests/snapshots/tests__values_ok.snap b/crates/squawk_parser/tests/snapshots/tests__values_ok.snap index 09215ebb..c81a3246 100644 --- a/crates/squawk_parser/tests/snapshots/tests__values_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__values_ok.snap @@ -303,25 +303,29 @@ SOURCE_FILE NAME_REF IDENT "employees" WHITESPACE " " - SET_KW "SET" - WHITESPACE " " - NAME_REF - IDENT "salary" - WHITESPACE " " - EQ "=" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "salary" - WHITESPACE " " - STAR "*" + SET_CLAUSE + SET_KW "SET" WHITESPACE " " - FIELD_EXPR - NAME_REF - IDENT "v" - DOT "." - NAME_REF - IDENT "increase" + SET_COLUMN_LIST + SET_COLUMN + COLUMN + NAME_REF + IDENT "salary" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "salary" + WHITESPACE " " + STAR "*" + WHITESPACE " " + FIELD_EXPR + NAME_REF + IDENT "v" + DOT "." + NAME_REF + IDENT "increase" WHITESPACE "\n" FROM_CLAUSE FROM_KW "FROM" diff --git a/crates/squawk_syntax/src/ast/generated/nodes.rs b/crates/squawk_syntax/src/ast/generated/nodes.rs index 6fd3506a..45997d21 100644 --- a/crates/squawk_syntax/src/ast/generated/nodes.rs +++ b/crates/squawk_syntax/src/ast/generated/nodes.rs @@ -1339,18 +1339,6 @@ pub struct BetweenExpr { pub(crate) syntax: SyntaxNode, } impl BetweenExpr { - #[inline] - pub fn end(&self) -> Option { - support::child(&self.syntax) - } - #[inline] - pub fn start(&self) -> Option { - support::child(&self.syntax) - } - #[inline] - pub fn target(&self) -> Option { - support::child(&self.syntax) - } #[inline] pub fn and_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::AND_KW) @@ -4821,14 +4809,6 @@ pub struct FieldExpr { pub(crate) syntax: SyntaxNode, } impl FieldExpr { - #[inline] - pub fn expr(&self) -> Option { - support::child(&self.syntax) - } - #[inline] - pub fn name_ref(&self) -> Option { - support::child(&self.syntax) - } #[inline] pub fn star_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::STAR) @@ -5296,14 +5276,6 @@ pub struct IndexExpr { pub(crate) syntax: SyntaxNode, } impl IndexExpr { - #[inline] - pub fn base(&self) -> Option { - support::child(&self.syntax) - } - #[inline] - pub fn index(&self) -> Option { - support::child(&self.syntax) - } #[inline] pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::L_BRACK) @@ -9060,6 +9032,63 @@ impl SetAccessMethod { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SetClause { + pub(crate) syntax: SyntaxNode, +} +impl SetClause { + #[inline] + pub fn set_column_list(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn set_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::SET_KW) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SetColumn { + pub(crate) syntax: SyntaxNode, +} +impl SetColumn { + #[inline] + pub fn column(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn column_list(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn paren_select(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn set_expr_list(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn eq_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::EQ) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SetColumnList { + pub(crate) syntax: SyntaxNode, +} +impl SetColumnList { + #[inline] + pub fn set_column(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn comma_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::COMMA) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct SetCompression { pub(crate) syntax: SyntaxNode, @@ -9128,6 +9157,44 @@ impl SetDefaultColumns { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SetExpr { + pub(crate) syntax: SyntaxNode, +} +impl SetExpr { + #[inline] + pub fn expr(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn default_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::DEFAULT_KW) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SetExprList { + pub(crate) syntax: SyntaxNode, +} +impl SetExprList { + #[inline] + pub fn set_exprs(&self) -> AstChildren { + support::children(&self.syntax) + } + #[inline] + pub fn l_paren_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::L_PAREN) + } + #[inline] + pub fn r_paren_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::R_PAREN) + } + #[inline] + pub fn row_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::ROW_KW) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct SetExpression { pub(crate) syntax: SyntaxNode, @@ -9862,6 +9929,10 @@ pub struct TupleExpr { pub(crate) syntax: SyntaxNode, } impl TupleExpr { + #[inline] + pub fn exprs(&self) -> AstChildren { + support::children(&self.syntax) + } #[inline] pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::L_PAREN) @@ -9959,6 +10030,10 @@ impl Update { support::child(&self.syntax) } #[inline] + pub fn set_clause(&self) -> Option { + support::child(&self.syntax) + } + #[inline] pub fn update_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::UPDATE_KW) } @@ -18638,6 +18713,60 @@ impl AstNode for SetAccessMethod { &self.syntax } } +impl AstNode for SetClause { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::SET_CLAUSE + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for SetColumn { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::SET_COLUMN + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for SetColumnList { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::SET_COLUMN_LIST + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for SetCompression { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -18710,6 +18839,42 @@ impl AstNode for SetDefaultColumns { &self.syntax } } +impl AstNode for SetExpr { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::SET_EXPR + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for SetExprList { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::SET_EXPR_LIST + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for SetExpression { #[inline] fn can_cast(kind: SyntaxKind) -> bool { diff --git a/crates/squawk_syntax/src/ast/node_ext.rs b/crates/squawk_syntax/src/ast/node_ext.rs index f42f4ae9..c508338b 100644 --- a/crates/squawk_syntax/src/ast/node_ext.rs +++ b/crates/squawk_syntax/src/ast/node_ext.rs @@ -42,15 +42,57 @@ impl ast::Constraint { } impl ast::BinExpr { + #[inline] pub fn lhs(&self) -> Option { support::children(self.syntax()).next() } + #[inline] pub fn rhs(&self) -> Option { support::children(self.syntax()).nth(1) } } +impl ast::FieldExpr { + // We have NameRef as a variant of Expr which complicates things (and it + // might not be worth it). + // Rust analyzer doesn't do this so it doesn't have to special case this. + #[inline] + pub fn base(&self) -> Option { + support::children(self.syntax()).next() + } + #[inline] + pub fn field(&self) -> Option { + support::children(self.syntax()).last() + } +} + +impl ast::IndexExpr { + #[inline] + pub fn base(&self) -> Option { + support::children(&self.syntax).next() + } + #[inline] + pub fn index(&self) -> Option { + support::children(&self.syntax).nth(1) + } +} + +impl ast::BetweenExpr { + #[inline] + pub fn target(&self) -> Option { + support::children(&self.syntax).nth(0) + } + #[inline] + pub fn start(&self) -> Option { + support::children(&self.syntax).nth(1) + } + #[inline] + pub fn end(&self) -> Option { + support::children(&self.syntax).nth(2) + } +} + impl ast::NameRef { #[inline] pub fn text(&self) -> TokenText<'_> { diff --git a/crates/squawk_syntax/src/lib.rs b/crates/squawk_syntax/src/lib.rs index f0a332dc..a5b9c224 100644 --- a/crates/squawk_syntax/src/lib.rs +++ b/crates/squawk_syntax/src/lib.rs @@ -480,3 +480,89 @@ fn create_table() { ] "#) } + +#[test] +fn index_expr() { + let source_code = " + select foo[bar]; + "; + let parse = SourceFile::parse(source_code); + assert!(parse.errors().is_empty()); + let file: SourceFile = parse.tree(); + let stmt = file.stmts().next().unwrap(); + let ast::Stmt::Select(select) = stmt else { + unreachable!() + }; + let select_clause = select.select_clause().unwrap(); + let target = select_clause + .target_list() + .unwrap() + .targets() + .next() + .unwrap(); + let ast::Expr::IndexExpr(index_expr) = target.expr().unwrap() else { + unreachable!() + }; + let base = index_expr.base().unwrap(); + let index = index_expr.index().unwrap(); + assert_eq!(base.syntax().text(), "foo"); + assert_eq!(index.syntax().text(), "bar"); +} + +#[test] +fn field_expr() { + let source_code = " + select foo.bar; + "; + let parse = SourceFile::parse(source_code); + assert!(parse.errors().is_empty()); + let file: SourceFile = parse.tree(); + let stmt = file.stmts().next().unwrap(); + let ast::Stmt::Select(select) = stmt else { + unreachable!() + }; + let select_clause = select.select_clause().unwrap(); + let target = select_clause + .target_list() + .unwrap() + .targets() + .next() + .unwrap(); + let ast::Expr::FieldExpr(field_expr) = target.expr().unwrap() else { + unreachable!() + }; + let base = field_expr.base().unwrap(); + let field = field_expr.field().unwrap(); + assert_eq!(base.syntax().text(), "foo"); + assert_eq!(field.syntax().text(), "bar"); +} + +#[test] +fn between_expr() { + let source_code = " + select 2 between 1 and 3; + "; + let parse = SourceFile::parse(source_code); + assert!(parse.errors().is_empty()); + let file: SourceFile = parse.tree(); + let stmt = file.stmts().next().unwrap(); + let ast::Stmt::Select(select) = stmt else { + unreachable!() + }; + let select_clause = select.select_clause().unwrap(); + let target = select_clause + .target_list() + .unwrap() + .targets() + .next() + .unwrap(); + let ast::Expr::BetweenExpr(between_expr) = target.expr().unwrap() else { + unreachable!() + }; + let target = between_expr.target().unwrap(); + let start = between_expr.start().unwrap(); + let end = between_expr.end().unwrap(); + assert_eq!(target.syntax().text(), "2"); + assert_eq!(start.syntax().text(), "1"); + assert_eq!(end.syntax().text(), "3"); +} diff --git a/crates/squawk_syntax/src/postgresql.ungram b/crates/squawk_syntax/src/postgresql.ungram index e625ace4..25b764b1 100644 --- a/crates/squawk_syntax/src/postgresql.ungram +++ b/crates/squawk_syntax/src/postgresql.ungram @@ -210,7 +210,9 @@ CaseExpr = 'case' Expr? WhenClauseList ElseClause? FieldExpr = - Expr '.' (NameRef | '*') + // We manually implement these as we have NameRef as a variant of Expr. + // Rust analyzer avoids this by having a PathExpr instead that wraps NameRef. + base:Expr '.' (field:NameRef | '*') Expr = CallExpr @@ -939,8 +941,27 @@ Insert = ('default' 'values' | Values | Stmt) ('on' 'conflict')? +SetClause = + 'set' SetColumnList + +SetColumnList = + SetColumn (',' SetColumn) + +SetColumn = + (Column | ColumnList) + '=' + (SetExprList | ParenSelect) + +SetExprList = + 'row'? '(' (SetExpr (',' SetExpr)*) ')' + +SetExpr = + Expr +| 'default' + Update = 'update' + SetClause ReturningClause? ReturningClause = @@ -1027,7 +1048,7 @@ ParenExpr = '(' Expr | Select ')' TupleExpr = - '(' ')' + '(' (Expr (',' Expr)*) ')' PrefixExpr = Expr @@ -1042,7 +1063,7 @@ IndexExpr = base:Expr '[' index:Expr ']' BetweenExpr = - target:Expr 'between' (start:Expr) 'and' (end:Expr) + target:Expr 'between' start:Expr 'and' end:Expr JsonTableColumn = Name 'for' 'ordinality' @@ -1253,7 +1274,7 @@ ExcludeConstraint = 'exclude' ConstraintIndexMethod? ConstraintExclusionList FrameClause = - ('range' | 'rows' | 'groups') + 'range' | 'rows' | 'groups' WindowSpec = '#ident'? ('partition' 'by' (Expr (',' Expr)*))? OrderByClause? FrameClause? diff --git a/crates/xtask/src/codegen.rs b/crates/xtask/src/codegen.rs index cc790c8b..8e3e7588 100644 --- a/crates/xtask/src/codegen.rs +++ b/crates/xtask/src/codegen.rs @@ -511,23 +511,13 @@ fn lower(grammar: &Grammar) -> AstSrc { let rule = &grammar[node].rule; match lower_enum(grammar, rule) { Some(variants) => { - let enum_src = AstEnumSrc { - // doc: Vec::new(), - name, - // traits: Vec::new(), - variants, - }; + let enum_src = AstEnumSrc { name, variants }; res.enums.push(enum_src); } None => { let mut fields = Vec::new(); lower_rule(&mut fields, grammar, None, rule); - res.nodes.push(AstNodeSrc { - // doc: Vec::new(), - name, - // traits: Vec::new(), - fields, - }); + res.nodes.push(AstNodeSrc { name, fields }); } } } @@ -537,14 +527,12 @@ fn lower(grammar: &Grammar) -> AstSrc { res.enums.sort_by_key(|it| it.name.clone()); res.tokens.sort(); res.nodes.iter_mut().for_each(|it| { - // it.traits.sort(); it.fields.sort_by_key(|it| match it { Field::Token(name) => (true, name.clone()), Field::Node { name, .. } => (false, name.clone()), }); }); res.enums.iter_mut().for_each(|it| { - // it.traits.sort(); it.variants.sort(); }); @@ -629,7 +617,18 @@ fn lower_rule(acc: &mut Vec, grammar: &Grammar, label: Option<&String>, r } Rule::Labeled { label: l, rule } => { assert!(label.is_none()); - let manually_implemented = matches!(l.as_str(), "value" | "lhs" | "rhs"); + let manually_implemented = matches!( + l.as_str(), + "value" + // bin expr fields + | "lhs" | "rhs" + // between expr fields + | "target" | "start" | "end" + // index expr fields + | "base" | "index" + // field expr fields + | /* "base" | */ "field" + ); if manually_implemented { return; }