From 016981f757b18b3f0df741e36c5c1e2909c92ce8 Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 28 Jun 2025 20:57:29 -0400 Subject: [PATCH 1/2] parser: improve json_table column options --- .github/workflows/rust.yml | 15 +- .gitignore | 2 +- PLAN.md | 16 + .../src/generated/syntax_kind.rs | 30 +- crates/squawk_parser/src/grammar.rs | 124 +-- .../tests__select_funcs_pg17_ok.snap | 758 +++++++++--------- .../squawk_syntax/src/ast/generated/nodes.rs | 462 ++++++++++- .../squawk_syntax/src/ast/generated/tokens.rs | 2 +- crates/squawk_syntax/src/postgresql.ungram | 48 +- crates/xtask/src/codegen.rs | 11 +- 10 files changed, 1001 insertions(+), 467 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 80b3123f..d4dc62ec 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -238,7 +238,14 @@ jobs: publish-npm: if: startsWith(github.ref, 'refs/tags/') - needs: [build-linux-x64, build-linux-musl-x64, build-mac, build-windows] + needs: + [ + build-linux-x64, + build-linux-musl-x64, + build-linux-arm64, + build-mac, + build-windows, + ] runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -300,7 +307,8 @@ jobs: cache-to: type=gha,mode=max deploy-playground: - if: startsWith(github.ref, 'refs/tags/') + needs: pre_job + if: needs.pre_job.outputs.should_skip != 'true' || startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-22.04 steps: - name: Checkout @@ -388,9 +396,6 @@ jobs: - name: Cache uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # pin@v2 - - name: Install ripgrep - run: cargo install ripgrep - - name: Test run: ./s/test diff --git a/.gitignore b/.gitignore index f1d95ef3..2313b86e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ # IntelliJ IDE users .idea -dist +dist/ .DS_Store temp.sql diff --git a/PLAN.md b/PLAN.md index ed49980c..c2f6d222 100644 --- a/PLAN.md +++ b/PLAN.md @@ -624,6 +624,22 @@ create function pg_catalog.jsonb_extract_path( as $$jsonb_extract_path$$ ``` +#### Json path expressions + +```sql +select * from json_table( + jsonb '[1,2,3]', + '$[*] ? (@ < $x)' + -- ^^ go to def jumps to the def in the passing clause + passing 10 as x, 3 as y + -- ^ find references + -- ^ find references + columns (a text format json path '$ ? (@ < $y)') + -- references json_table arg ^ + -- also references passing clause ^^ +); +``` + ### Autocomplete - [datagrip postfix completion](https://blog.jetbrains.com/datagrip/2019/03/11/top-9-sql-features-of-datagrip-you-have-to-know/#postfix_completion) diff --git a/crates/squawk_parser/src/generated/syntax_kind.rs b/crates/squawk_parser/src/generated/syntax_kind.rs index c0180845..f7b75dd8 100644 --- a/crates/squawk_parser/src/generated/syntax_kind.rs +++ b/crates/squawk_parser/src/generated/syntax_kind.rs @@ -549,13 +549,11 @@ pub enum SyntaxKind { ALTER_AGGREGATE, ALTER_COLLATION, ALTER_COLUMN, - ALTER_COLUMN_OPTION, ALTER_CONSTRAINT, ALTER_CONVERSION, ALTER_DATABASE, ALTER_DEFAULT_PRIVILEGES, ALTER_DOMAIN, - ALTER_DOMAIN_ACTION, ALTER_EVENT_TRIGGER, ALTER_EXTENSION, ALTER_FOREIGN_DATA_WRAPPER, @@ -583,7 +581,6 @@ pub enum SyntaxKind { ALTER_SYSTEM, ALTER_TABLE, ALTER_TABLESPACE, - ALTER_TABLE_ACTION, ALTER_TEXT_SEARCH_CONFIGURATION, ALTER_TEXT_SEARCH_DICTIONARY, ALTER_TEXT_SEARCH_PARSER, @@ -628,7 +625,6 @@ pub enum SyntaxKind { COMMIT, COMPOUND_SELECT, COMPRESSION_METHOD, - CONSTRAINT, CONSTRAINT_EXCLUSIONS, CONSTRAINT_INCLUDE_CLAUSE, CONSTRAINT_INDEX_METHOD, @@ -755,7 +751,6 @@ pub enum SyntaxKind { EXCLUDE_CONSTRAINT, EXECUTE, EXPLAIN, - EXPR, FAT_ARROW, FETCH, FETCH_CLAUSE, @@ -766,7 +761,6 @@ pub enum SyntaxKind { FRAME_CLAUSE, FROM_CLAUSE, FROM_ITEM, - FUNC_OPTION, FUNC_OPTION_LIST, GENERATED_CONSTRAINT, GRANT, @@ -811,18 +805,27 @@ pub enum SyntaxKind { JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, - JOIN_TYPE, JOIN_USING_CLAUSE, - JSON_BEHAVIOR_CLAUSE, + JSON_BEHAVIOR_DEFAULT, + JSON_BEHAVIOR_EMPTY_ARRAY, + JSON_BEHAVIOR_EMPTY_OBJECT, + JSON_BEHAVIOR_ERROR, + JSON_BEHAVIOR_FALSE, + JSON_BEHAVIOR_NULL, + JSON_BEHAVIOR_TRUE, + JSON_BEHAVIOR_UNKNOWN, JSON_FORMAT_CLAUSE, JSON_KEYS_UNIQUE_CLAUSE, JSON_KEY_VALUE, JSON_NULL_CLAUSE, + JSON_ON_EMPTY_CLAUSE, JSON_ON_ERROR_CLAUSE, + JSON_PASSING_ARG, JSON_PASSING_CLAUSE, JSON_QUOTES_CLAUSE, JSON_RETURNING_CLAUSE, JSON_TABLE_COLUMN, + JSON_TABLE_COLUMN_LIST, JSON_VALUE_EXPR, JSON_WRAPPER_BEHAVIOR_CLAUSE, LANGUAGE_FUNC_OPTION, @@ -838,7 +841,6 @@ pub enum SyntaxKind { MATCH_FULL, MATCH_PARTIAL, MATCH_SIMPLE, - MATCH_TYPE, MATERIALIZED, MERGE, MOVE, @@ -872,7 +874,6 @@ pub enum SyntaxKind { OF_TYPE, ON_CLAUSE, ON_COMMIT, - ON_COMMIT_ACTION, ON_DELETE_ACTION, ON_UPDATE_ACTION, OP, @@ -888,7 +889,6 @@ pub enum SyntaxKind { PARAM_IN, PARAM_IN_OUT, PARAM_LIST, - PARAM_MODE, PARAM_OUT, PARAM_VARIADIC, PAREN_EXPR, @@ -900,7 +900,6 @@ pub enum SyntaxKind { PARTITION_FOR_VALUES_WITH, PARTITION_ITEM, PARTITION_OF, - PARTITION_TYPE, PATH, PATH_SEGMENT, PATH_TYPE, @@ -919,7 +918,6 @@ pub enum SyntaxKind { REASSIGN, REFERENCES_CONSTRAINT, REFRESH, - REF_ACTION, REINDEX, RELATION_NAME, RELEASE_SAVEPOINT, @@ -985,26 +983,20 @@ pub enum SyntaxKind { SORT_DESC, SORT_USING, SOURCE_FILE, - STMT, STORAGE, STRICT_FUNC_OPTION, SUPPORT_FUNC_OPTION, TABLE, TABLESPACE, - TABLE_ARG, TABLE_ARG_LIST, - TABLE_CONSTRAINT, TABLE_LIST, TARGET, TARGET_LIST, - TIMEZONE, TIME_TYPE, - TRANSACTION_MODE, TRANSACTION_MODE_LIST, TRANSFORM_FUNC_OPTION, TRUNCATE, TUPLE_EXPR, - TYPE, UNICODE_NORMAL_FORM, UNIQUE_CONSTRAINT, UNLISTEN, diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index 4b3a6e57..263a9864 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -589,10 +589,16 @@ fn json_table_arg_list(p: &mut Parser<'_>) { if p.eat(AS_KW) { name(p); } - // [ PASSING { value AS varname } [, ...] ] opt_json_passing_clause(p); - // COLUMNS ( json_table_column [, ...] ) - if p.eat(COLUMNS_KW) { + json_table_column_list(p); + opt_json_on_error_clause(p); +} + +// COLUMNS ( json_table_column [, ...] ) +fn json_table_column_list(p: &mut Parser<'_>) { + if p.at(COLUMNS_KW) { + let m = p.start(); + p.bump(COLUMNS_KW); p.expect(L_PAREN); while !p.at(EOF) { json_table_column(p); @@ -601,10 +607,9 @@ fn json_table_arg_list(p: &mut Parser<'_>) { } } p.expect(R_PAREN); - } - if opt_json_behavior(p) { - p.expect(ON_KW); - p.expect(ERROR_KW); + m.complete(p, JSON_TABLE_COLUMN_LIST); + } else { + p.error("expected json table columns"); } } @@ -633,15 +638,7 @@ fn json_table_column(p: &mut Parser<'_>) { if p.eat(AS_KW) { name(p); } - p.expect(COLUMNS_KW); - p.expect(L_PAREN); - while !p.at(EOF) { - json_table_column(p); - if !p.eat(COMMA) { - break; - } - } - p.expect(R_PAREN); + json_table_column_list(p); } else { name(p); // FOR ORDINALITY @@ -1116,21 +1113,20 @@ fn opt_json_quotes_clause(p: &mut Parser<'_>) -> Option { } } -fn opt_json_behavior_clause(p: &mut Parser<'_>) -> Option { +fn opt_json_behavior_clause(p: &mut Parser<'_>) { let m = p.start(); - if opt_json_behavior(p) { + if opt_json_behavior(p).is_some() { p.expect(ON_KW); - if !p.eat(ERROR_KW) { + let kind = if p.eat(ERROR_KW) { + JSON_ON_ERROR_CLAUSE + } else { p.expect(EMPTY_KW); - if opt_json_behavior(p) { - p.expect(ON_KW); - p.expect(ERROR_KW); - } - } - Some(m.complete(p, JSON_BEHAVIOR_CLAUSE)) + JSON_ON_EMPTY_CLAUSE + }; + m.complete(p, kind); + opt_json_on_error_clause(p); } else { m.abandon(p); - None } } @@ -1192,7 +1188,7 @@ fn json_exists_fn(p: &mut Parser<'_>) -> CompletedMarker { fn opt_json_on_error_clause(p: &mut Parser<'_>) { let m = p.start(); - if opt_json_behavior(p) { + if opt_json_behavior(p).is_some() { p.expect(ON_KW); p.expect(ERROR_KW); m.complete(p, JSON_ON_ERROR_CLAUSE); @@ -1201,44 +1197,78 @@ fn opt_json_on_error_clause(p: &mut Parser<'_>) { } } -fn opt_json_behavior(p: &mut Parser<'_>) -> bool { - match p.current() { +fn opt_json_behavior(p: &mut Parser<'_>) -> Option { + let m = p.start(); + let kind = match p.current() { DEFAULT_KW => { p.bump(DEFAULT_KW); if expr(p).is_none() { p.error("expected expression"); } + JSON_BEHAVIOR_DEFAULT } - ERROR_KW | NULL_KW | TRUE_KW | FALSE_KW | UNKNOWN_KW => { - p.bump_any(); + ERROR_KW => { + p.bump(ERROR_KW); + JSON_BEHAVIOR_ERROR + } + NULL_KW => { + p.bump(NULL_KW); + JSON_BEHAVIOR_NULL + } + TRUE_KW => { + p.bump(TRUE_KW); + JSON_BEHAVIOR_TRUE + } + FALSE_KW => { + p.bump(FALSE_KW); + JSON_BEHAVIOR_FALSE + } + UNKNOWN_KW => { + p.bump(UNKNOWN_KW); + JSON_BEHAVIOR_UNKNOWN } EMPTY_KW => { p.bump(EMPTY_KW); - let _ = p.eat(ARRAY_KW) || p.eat(OBJECT_KW); + if p.eat(OBJECT_KW) { + JSON_BEHAVIOR_EMPTY_OBJECT + } else { + p.eat(ARRAY_KW); + JSON_BEHAVIOR_EMPTY_ARRAY + } } - _ => return false, - } - true + _ => { + m.abandon(p); + return None; + } + }; + Some(m.complete(p, kind)) } -fn json_args(p: &mut Parser<'_>) { - while !p.at(EOF) { - if expr(p).is_none() { - p.error("expected expr"); - } - opt_json_format_clause(p); - p.expect(AS_KW); - col_label(p); - if !p.eat(COMMA) { - break; - } +fn opt_json_passing_arg(p: &mut Parser<'_>) -> Option { + if !p.at_ts(EXPR_FIRST) { + return None; } + let m = p.start(); + if expr(p).is_none() { + p.error("expected expr"); + } + opt_json_format_clause(p); + p.expect(AS_KW); + col_label(p); + Some(m.complete(p, JSON_PASSING_ARG)) } fn opt_json_passing_clause(p: &mut Parser<'_>) { let m = p.start(); if p.eat(PASSING_KW) { - json_args(p); + while !p.at(EOF) { + if opt_json_passing_arg(p).is_none() { + break; + } + if !p.eat(COMMA) { + break; + } + } m.complete(p, JSON_PASSING_CLAUSE); } else { m.abandon(p); diff --git a/crates/squawk_parser/tests/snapshots/tests__select_funcs_pg17_ok.snap b/crates/squawk_parser/tests/snapshots/tests__select_funcs_pg17_ok.snap index 77dbe624..5507254b 100644 --- a/crates/squawk_parser/tests/snapshots/tests__select_funcs_pg17_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__select_funcs_pg17_ok.snap @@ -40,76 +40,77 @@ SOURCE_FILE LITERAL STRING "'$.favorites[*]'" WHITESPACE " " - COLUMNS_KW "COLUMNS" - WHITESPACE " " - L_PAREN "(" - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "id" - WHITESPACE " " - FOR_KW "FOR" - WHITESPACE " " - ORDINALITY_KW "ORDINALITY" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "kind" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.kind'" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "title" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.films[*].title'" + JSON_TABLE_COLUMN_LIST + COLUMNS_KW "COLUMNS" WHITESPACE " " - JSON_WRAPPER_BEHAVIOR_CLAUSE - WITH_KW "WITH" + L_PAREN "(" + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "id" WHITESPACE " " - WRAPPER_KW "WRAPPER" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "director" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.films[*].director'" - WHITESPACE " " - JSON_WRAPPER_BEHAVIOR_CLAUSE - WITH_KW "WITH" + FOR_KW "FOR" WHITESPACE " " - WRAPPER_KW "WRAPPER" - R_PAREN ")" + ORDINALITY_KW "ORDINALITY" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "kind" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.kind'" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "title" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.films[*].title'" + WHITESPACE " " + JSON_WRAPPER_BEHAVIOR_CLAUSE + WITH_KW "WITH" + WHITESPACE " " + WRAPPER_KW "WRAPPER" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "director" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.films[*].director'" + WHITESPACE " " + JSON_WRAPPER_BEHAVIOR_CLAUSE + WITH_KW "WITH" + WHITESPACE " " + WRAPPER_KW "WRAPPER" + R_PAREN ")" R_PAREN ")" WHITESPACE " " ALIAS @@ -159,58 +160,32 @@ SOURCE_FILE JSON_PASSING_CLAUSE PASSING_KW "PASSING" WHITESPACE " " - LITERAL - STRING "'Alfred Hitchcock'" - WHITESPACE " " - AS_KW "AS" - WHITESPACE " " - NAME - FILTER_KW "filter" + JSON_PASSING_ARG + LITERAL + STRING "'Alfred Hitchcock'" + WHITESPACE " " + AS_KW "AS" + WHITESPACE " " + NAME + FILTER_KW "filter" WHITESPACE "\n " - COLUMNS_KW "COLUMNS" - WHITESPACE " " - L_PAREN "(" - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "id" - WHITESPACE " " - FOR_KW "FOR" - WHITESPACE " " - ORDINALITY_KW "ORDINALITY" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "kind" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.kind'" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NESTED_KW "NESTED" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.films[*]'" - WHITESPACE " " + JSON_TABLE_COLUMN_LIST COLUMNS_KW "COLUMNS" WHITESPACE " " L_PAREN "(" - WHITESPACE "\n " + WHITESPACE "\n " JSON_TABLE_COLUMN NAME - IDENT "title" + IDENT "id" + WHITESPACE " " + FOR_KW "FOR" + WHITESPACE " " + ORDINALITY_KW "ORDINALITY" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "kind" WHITESPACE " " PATH_TYPE PATH @@ -218,44 +193,73 @@ SOURCE_FILE NAME_REF TEXT_KW "text" WHITESPACE " " - JSON_FORMAT_CLAUSE - FORMAT_KW "FORMAT" - WHITESPACE " " - JSON_KW "JSON" - WHITESPACE " " PATH_KW "PATH" WHITESPACE " " LITERAL - STRING "'$.title'" - WHITESPACE " " - JSON_QUOTES_CLAUSE - OMIT_KW "OMIT" - WHITESPACE " " - QUOTES_KW "QUOTES" + STRING "'$.kind'" COMMA "," - WHITESPACE "\n " + WHITESPACE "\n " JSON_TABLE_COLUMN - NAME - IDENT "director" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" + NESTED_KW "NESTED" WHITESPACE " " PATH_KW "PATH" WHITESPACE " " LITERAL - STRING "'$.director'" + STRING "'$.films[*]'" WHITESPACE " " - JSON_QUOTES_CLAUSE - KEEP_KW "KEEP" + JSON_TABLE_COLUMN_LIST + COLUMNS_KW "COLUMNS" WHITESPACE " " - QUOTES_KW "QUOTES" + L_PAREN "(" + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "title" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + JSON_FORMAT_CLAUSE + FORMAT_KW "FORMAT" + WHITESPACE " " + JSON_KW "JSON" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.title'" + WHITESPACE " " + JSON_QUOTES_CLAUSE + OMIT_KW "OMIT" + WHITESPACE " " + QUOTES_KW "QUOTES" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "director" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.director'" + WHITESPACE " " + JSON_QUOTES_CLAUSE + KEEP_KW "KEEP" + WHITESPACE " " + QUOTES_KW "QUOTES" + R_PAREN ")" R_PAREN ")" R_PAREN ")" - R_PAREN ")" WHITESPACE " " ALIAS AS_KW "AS" @@ -301,50 +305,23 @@ SOURCE_FILE LITERAL STRING "'$.favorites[*]'" WHITESPACE "\n " - COLUMNS_KW "COLUMNS" - WHITESPACE " " - L_PAREN "(" - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "id" - WHITESPACE " " - FOR_KW "FOR" - WHITESPACE " " - ORDINALITY_KW "ORDINALITY" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "kind" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.kind'" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NESTED_KW "NESTED" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.films[*]'" - WHITESPACE " " + JSON_TABLE_COLUMN_LIST COLUMNS_KW "COLUMNS" WHITESPACE " " L_PAREN "(" - WHITESPACE "\n " + WHITESPACE "\n " JSON_TABLE_COLUMN NAME - IDENT "title" + IDENT "id" + WHITESPACE " " + FOR_KW "FOR" + WHITESPACE " " + ORDINALITY_KW "ORDINALITY" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "kind" WHITESPACE " " PATH_TYPE PATH @@ -352,44 +329,73 @@ SOURCE_FILE NAME_REF TEXT_KW "text" WHITESPACE " " - JSON_FORMAT_CLAUSE - FORMAT_KW "FORMAT" - WHITESPACE " " - JSON_KW "JSON" - WHITESPACE " " PATH_KW "PATH" WHITESPACE " " LITERAL - STRING "'$.title'" - WHITESPACE " " - JSON_QUOTES_CLAUSE - OMIT_KW "OMIT" - WHITESPACE " " - QUOTES_KW "QUOTES" + STRING "'$.kind'" COMMA "," - WHITESPACE "\n " + WHITESPACE "\n " JSON_TABLE_COLUMN - NAME - IDENT "director" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" + NESTED_KW "NESTED" WHITESPACE " " PATH_KW "PATH" WHITESPACE " " LITERAL - STRING "'$.director'" + STRING "'$.films[*]'" WHITESPACE " " - JSON_QUOTES_CLAUSE - KEEP_KW "KEEP" + JSON_TABLE_COLUMN_LIST + COLUMNS_KW "COLUMNS" WHITESPACE " " - QUOTES_KW "QUOTES" + L_PAREN "(" + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "title" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + JSON_FORMAT_CLAUSE + FORMAT_KW "FORMAT" + WHITESPACE " " + JSON_KW "JSON" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.title'" + WHITESPACE " " + JSON_QUOTES_CLAUSE + OMIT_KW "OMIT" + WHITESPACE " " + QUOTES_KW "QUOTES" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "director" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.director'" + WHITESPACE " " + JSON_QUOTES_CLAUSE + KEEP_KW "KEEP" + WHITESPACE " " + QUOTES_KW "QUOTES" + R_PAREN ")" R_PAREN ")" R_PAREN ")" - R_PAREN ")" WHITESPACE " " ALIAS AS_KW "AS" @@ -432,138 +438,142 @@ SOURCE_FILE LITERAL STRING "'$.favorites[*]'" WHITESPACE "\n" - COLUMNS_KW "COLUMNS" - WHITESPACE " " - L_PAREN "(" - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "user_id" - WHITESPACE " " - FOR_KW "FOR" - WHITESPACE " " - ORDINALITY_KW "ORDINALITY" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NESTED_KW "NESTED" - WHITESPACE " " - LITERAL - STRING "'$.movies[*]'" - WHITESPACE "\n " + JSON_TABLE_COLUMN_LIST COLUMNS_KW "COLUMNS" WHITESPACE " " L_PAREN "(" - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "movie_id" - WHITESPACE " " - FOR_KW "FOR" - WHITESPACE " " - ORDINALITY_KW "ORDINALITY" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "mname" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.name'" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "director" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - R_PAREN ")" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NESTED_KW "NESTED" - WHITESPACE " " - LITERAL - STRING "'$.books[*]'" - WHITESPACE "\n " - COLUMNS_KW "COLUMNS" - WHITESPACE " " - L_PAREN "(" - WHITESPACE "\n " + WHITESPACE "\n " JSON_TABLE_COLUMN NAME - IDENT "book_id" + IDENT "user_id" WHITESPACE " " FOR_KW "FOR" WHITESPACE " " ORDINALITY_KW "ORDINALITY" COMMA "," - WHITESPACE "\n " + WHITESPACE "\n " JSON_TABLE_COLUMN - NAME - IDENT "bname" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" + NESTED_KW "NESTED" WHITESPACE " " LITERAL - STRING "'$.name'" + STRING "'$.movies[*]'" + WHITESPACE "\n " + JSON_TABLE_COLUMN_LIST + COLUMNS_KW "COLUMNS" + WHITESPACE " " + L_PAREN "(" + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "movie_id" + WHITESPACE " " + FOR_KW "FOR" + WHITESPACE " " + ORDINALITY_KW "ORDINALITY" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "mname" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.name'" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "director" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + R_PAREN ")" COMMA "," - WHITESPACE "\n " + WHITESPACE "\n " JSON_TABLE_COLUMN NESTED_KW "NESTED" WHITESPACE " " LITERAL - STRING "'$.authors[*]'" - WHITESPACE "\n " - COLUMNS_KW "COLUMNS" - WHITESPACE " " - L_PAREN "(" - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "author_id" - WHITESPACE " " - FOR_KW "FOR" + STRING "'$.books[*]'" + WHITESPACE "\n " + JSON_TABLE_COLUMN_LIST + COLUMNS_KW "COLUMNS" WHITESPACE " " - ORDINALITY_KW "ORDINALITY" - COMMA "," - WHITESPACE "\n " - JSON_TABLE_COLUMN - NAME - IDENT "author_name" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - TEXT_KW "text" - WHITESPACE " " - PATH_KW "PATH" - WHITESPACE " " - LITERAL - STRING "'$.name'" - R_PAREN ")" + L_PAREN "(" + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "book_id" + WHITESPACE " " + FOR_KW "FOR" + WHITESPACE " " + ORDINALITY_KW "ORDINALITY" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "bname" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.name'" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NESTED_KW "NESTED" + WHITESPACE " " + LITERAL + STRING "'$.authors[*]'" + WHITESPACE "\n " + JSON_TABLE_COLUMN_LIST + COLUMNS_KW "COLUMNS" + WHITESPACE " " + L_PAREN "(" + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "author_id" + WHITESPACE " " + FOR_KW "FOR" + WHITESPACE " " + ORDINALITY_KW "ORDINALITY" + COMMA "," + WHITESPACE "\n " + JSON_TABLE_COLUMN + NAME + IDENT "author_name" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + TEXT_KW "text" + WHITESPACE " " + PATH_KW "PATH" + WHITESPACE " " + LITERAL + STRING "'$.name'" + R_PAREN ")" + R_PAREN ")" R_PAREN ")" R_PAREN ")" - R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- json" @@ -850,22 +860,24 @@ SOURCE_FILE JSON_PASSING_CLAUSE PASSING_KW "passing" WHITESPACE " " - NAME_REF - IDENT "c" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - NAME - IDENT "foo" + JSON_PASSING_ARG + NAME_REF + IDENT "c" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + NAME + IDENT "foo" COMMA "," WHITESPACE " \n " - NAME_REF - IDENT "d" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - NAME - IDENT "bar" + JSON_PASSING_ARG + NAME_REF + IDENT "d" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + NAME + IDENT "bar" WHITESPACE " \n " JSON_RETURNING_CLAUSE RETURNING_KW "returning" @@ -901,16 +913,19 @@ SOURCE_FILE WHITESPACE " " STRING_KW "string" WHITESPACE "\n " - JSON_BEHAVIOR_CLAUSE - UNKNOWN_KW "unknown" + JSON_ON_EMPTY_CLAUSE + JSON_BEHAVIOR_UNKNOWN + UNKNOWN_KW "unknown" WHITESPACE " " ON_KW "on" WHITESPACE " " EMPTY_KW "empty" - WHITESPACE "\n " - EMPTY_KW "empty" - WHITESPACE " " - ARRAY_KW "array" + WHITESPACE "\n " + JSON_ON_ERROR_CLAUSE + JSON_BEHAVIOR_EMPTY_ARRAY + EMPTY_KW "empty" + WHITESPACE " " + ARRAY_KW "array" WHITESPACE " " ON_KW "on" WHITESPACE " " @@ -968,19 +983,21 @@ SOURCE_FILE JSON_PASSING_CLAUSE PASSING_KW "passing" WHITESPACE " " - NAME_REF - IDENT "c" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - NAME - IDENT "d" + JSON_PASSING_ARG + NAME_REF + IDENT "c" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + NAME + IDENT "d" WHITESPACE "\n " JSON_ON_ERROR_CLAUSE - DEFAULT_KW "default" - WHITESPACE " " - NAME_REF - IDENT "z" + JSON_BEHAVIOR_DEFAULT + DEFAULT_KW "default" + WHITESPACE " " + NAME_REF + IDENT "z" WHITESPACE " " ON_KW "on" WHITESPACE " " @@ -1016,13 +1033,14 @@ SOURCE_FILE JSON_PASSING_CLAUSE PASSING_KW "PASSING" WHITESPACE " " - LITERAL - INT_NUMBER "2" - WHITESPACE " " - AS_KW "AS" - WHITESPACE " " - NAME - IDENT "x" + JSON_PASSING_ARG + LITERAL + INT_NUMBER "2" + WHITESPACE " " + AS_KW "AS" + WHITESPACE " " + NAME + IDENT "x" R_PAREN ")" SEMICOLON ";" WHITESPACE "\n" @@ -1049,7 +1067,8 @@ SOURCE_FILE STRING "'lax $.a[5]'" WHITESPACE " " JSON_ON_ERROR_CLAUSE - ERROR_KW "ERROR" + JSON_BEHAVIOR_ERROR + ERROR_KW "ERROR" WHITESPACE " " ON_KW "ON" WHITESPACE " " @@ -1080,7 +1099,8 @@ SOURCE_FILE STRING "'strict $.a[5]'" WHITESPACE " " JSON_ON_ERROR_CLAUSE - ERROR_KW "ERROR" + JSON_BEHAVIOR_ERROR + ERROR_KW "ERROR" WHITESPACE " " ON_KW "ON" WHITESPACE " " @@ -1137,13 +1157,14 @@ SOURCE_FILE JSON_PASSING_CLAUSE PASSING_KW "passing" WHITESPACE " " - NAME_REF - IDENT "c" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - NAME - IDENT "d" + JSON_PASSING_ARG + NAME_REF + IDENT "c" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + NAME + IDENT "d" WHITESPACE "\n " JSON_RETURNING_CLAUSE RETURNING_KW "returning" @@ -1159,17 +1180,20 @@ SOURCE_FILE WHITESPACE " " JSON_KW "json" WHITESPACE "\n " - JSON_BEHAVIOR_CLAUSE - UNKNOWN_KW "unknown" + JSON_ON_EMPTY_CLAUSE + JSON_BEHAVIOR_UNKNOWN + UNKNOWN_KW "unknown" WHITESPACE " " ON_KW "on" WHITESPACE " " EMPTY_KW "empty" - WHITESPACE "\n " - DEFAULT_KW "default" - WHITESPACE " " - NAME_REF - IDENT "z" + WHITESPACE "\n " + JSON_ON_ERROR_CLAUSE + JSON_BEHAVIOR_DEFAULT + DEFAULT_KW "default" + WHITESPACE " " + NAME_REF + IDENT "z" WHITESPACE " " ON_KW "on" WHITESPACE " " diff --git a/crates/squawk_syntax/src/ast/generated/nodes.rs b/crates/squawk_syntax/src/ast/generated/nodes.rs index 4b61df08..71371b46 100644 --- a/crates/squawk_syntax/src/ast/generated/nodes.rs +++ b/crates/squawk_syntax/src/ast/generated/nodes.rs @@ -1,8 +1,8 @@ -use crate::SyntaxKind; use crate::ast::AstNode; -use crate::ast::{AstChildren, support}; +use crate::ast::{support, AstChildren}; use crate::syntax_node::SyntaxNode; use crate::syntax_node::SyntaxToken; +use crate::SyntaxKind; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AddColumn { @@ -5720,10 +5720,10 @@ impl JoinUsingClause { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct JsonBehaviorClause { +pub struct JsonBehaviorDefault { pub(crate) syntax: SyntaxNode, } -impl JsonBehaviorClause { +impl JsonBehaviorDefault { #[inline] pub fn expr(&self) -> Option { support::child(&self.syntax) @@ -5732,21 +5732,90 @@ impl JsonBehaviorClause { pub fn default_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::DEFAULT_KW) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonBehaviorEmptyArray { + pub(crate) syntax: SyntaxNode, +} +impl JsonBehaviorEmptyArray { + #[inline] + pub fn array_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::ARRAY_KW) + } #[inline] pub fn empty_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::EMPTY_KW) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonBehaviorEmptyObject { + pub(crate) syntax: SyntaxNode, +} +impl JsonBehaviorEmptyObject { + #[inline] + pub fn empty_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::EMPTY_KW) + } + #[inline] + pub fn object_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::OBJECT_KW) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonBehaviorError { + pub(crate) syntax: SyntaxNode, +} +impl JsonBehaviorError { #[inline] pub fn error_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::ERROR_KW) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonBehaviorFalse { + pub(crate) syntax: SyntaxNode, +} +impl JsonBehaviorFalse { + #[inline] + pub fn false_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::FALSE_KW) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonBehaviorNull { + pub(crate) syntax: SyntaxNode, +} +impl JsonBehaviorNull { #[inline] pub fn null_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::NULL_KW) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonBehaviorTrue { + pub(crate) syntax: SyntaxNode, +} +impl JsonBehaviorTrue { + #[inline] + pub fn true_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::TRUE_KW) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonBehaviorUnknown { + pub(crate) syntax: SyntaxNode, +} +impl JsonBehaviorUnknown { #[inline] - pub fn on_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::ON_KW) + pub fn unknown_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::UNKNOWN_KW) } } @@ -5835,21 +5904,36 @@ impl JsonNullClause { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct JsonOnErrorClause { +pub struct JsonOnEmptyClause { pub(crate) syntax: SyntaxNode, } -impl JsonOnErrorClause { +impl JsonOnEmptyClause { + #[inline] + pub fn json_behavior(&self) -> Option { + support::child(&self.syntax) + } #[inline] pub fn empty_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::EMPTY_KW) } #[inline] - pub fn error_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::ERROR_KW) + pub fn on_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::ON_KW) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonOnErrorClause { + pub(crate) syntax: SyntaxNode, +} +impl JsonOnErrorClause { #[inline] - pub fn null_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::NULL_KW) + pub fn json_behavior(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn error_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::ERROR_KW) } #[inline] pub fn on_token(&self) -> Option { @@ -5857,13 +5941,36 @@ impl JsonOnErrorClause { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonPassingArg { + pub(crate) syntax: SyntaxNode, +} +impl JsonPassingArg { + #[inline] + pub fn expr(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn json_format_clause(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn name(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn as_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::AS_KW) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct JsonPassingClause { pub(crate) syntax: SyntaxNode, } impl JsonPassingClause { #[inline] - pub fn named_args(&self) -> AstChildren { + pub fn json_passing_args(&self) -> AstChildren { support::children(&self.syntax) } #[inline] @@ -5941,6 +6048,29 @@ impl JsonTableColumn { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct JsonTableColumnList { + pub(crate) syntax: SyntaxNode, +} +impl JsonTableColumnList { + #[inline] + pub fn json_table_columns(&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 columns_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::COLUMNS_KW) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct JsonValueExpr { pub(crate) syntax: SyntaxNode, @@ -9812,6 +9942,18 @@ pub enum JoinType { JoinRight(JoinRight), } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum JsonBehavior { + JsonBehaviorDefault(JsonBehaviorDefault), + JsonBehaviorEmptyArray(JsonBehaviorEmptyArray), + JsonBehaviorEmptyObject(JsonBehaviorEmptyObject), + JsonBehaviorError(JsonBehaviorError), + JsonBehaviorFalse(JsonBehaviorFalse), + JsonBehaviorNull(JsonBehaviorNull), + JsonBehaviorTrue(JsonBehaviorTrue), + JsonBehaviorUnknown(JsonBehaviorUnknown), +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum MatchType { MatchFull(MatchFull), @@ -14848,10 +14990,136 @@ impl AstNode for JoinUsingClause { &self.syntax } } -impl AstNode for JsonBehaviorClause { +impl AstNode for JsonBehaviorDefault { #[inline] fn can_cast(kind: SyntaxKind) -> bool { - kind == SyntaxKind::JSON_BEHAVIOR_CLAUSE + kind == SyntaxKind::JSON_BEHAVIOR_DEFAULT + } + #[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 JsonBehaviorEmptyArray { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_BEHAVIOR_EMPTY_ARRAY + } + #[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 JsonBehaviorEmptyObject { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_BEHAVIOR_EMPTY_OBJECT + } + #[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 JsonBehaviorError { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_BEHAVIOR_ERROR + } + #[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 JsonBehaviorFalse { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_BEHAVIOR_FALSE + } + #[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 JsonBehaviorNull { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_BEHAVIOR_NULL + } + #[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 JsonBehaviorTrue { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_BEHAVIOR_TRUE + } + #[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 JsonBehaviorUnknown { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_BEHAVIOR_UNKNOWN } #[inline] fn cast(syntax: SyntaxNode) -> Option { @@ -14938,6 +15206,24 @@ impl AstNode for JsonNullClause { &self.syntax } } +impl AstNode for JsonOnEmptyClause { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_ON_EMPTY_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 JsonOnErrorClause { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -14956,6 +15242,24 @@ impl AstNode for JsonOnErrorClause { &self.syntax } } +impl AstNode for JsonPassingArg { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_PASSING_ARG + } + #[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 JsonPassingClause { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -15028,6 +15332,24 @@ impl AstNode for JsonTableColumn { &self.syntax } } +impl AstNode for JsonTableColumnList { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::JSON_TABLE_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 JsonValueExpr { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -19900,6 +20222,116 @@ impl From for JoinType { JoinType::JoinRight(node) } } +impl AstNode for JsonBehavior { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + matches!( + kind, + SyntaxKind::JSON_BEHAVIOR_DEFAULT + | SyntaxKind::JSON_BEHAVIOR_EMPTY_ARRAY + | SyntaxKind::JSON_BEHAVIOR_EMPTY_OBJECT + | SyntaxKind::JSON_BEHAVIOR_ERROR + | SyntaxKind::JSON_BEHAVIOR_FALSE + | SyntaxKind::JSON_BEHAVIOR_NULL + | SyntaxKind::JSON_BEHAVIOR_TRUE + | SyntaxKind::JSON_BEHAVIOR_UNKNOWN + ) + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + SyntaxKind::JSON_BEHAVIOR_DEFAULT => { + JsonBehavior::JsonBehaviorDefault(JsonBehaviorDefault { syntax }) + } + SyntaxKind::JSON_BEHAVIOR_EMPTY_ARRAY => { + JsonBehavior::JsonBehaviorEmptyArray(JsonBehaviorEmptyArray { syntax }) + } + SyntaxKind::JSON_BEHAVIOR_EMPTY_OBJECT => { + JsonBehavior::JsonBehaviorEmptyObject(JsonBehaviorEmptyObject { syntax }) + } + SyntaxKind::JSON_BEHAVIOR_ERROR => { + JsonBehavior::JsonBehaviorError(JsonBehaviorError { syntax }) + } + SyntaxKind::JSON_BEHAVIOR_FALSE => { + JsonBehavior::JsonBehaviorFalse(JsonBehaviorFalse { syntax }) + } + SyntaxKind::JSON_BEHAVIOR_NULL => { + JsonBehavior::JsonBehaviorNull(JsonBehaviorNull { syntax }) + } + SyntaxKind::JSON_BEHAVIOR_TRUE => { + JsonBehavior::JsonBehaviorTrue(JsonBehaviorTrue { syntax }) + } + SyntaxKind::JSON_BEHAVIOR_UNKNOWN => { + JsonBehavior::JsonBehaviorUnknown(JsonBehaviorUnknown { syntax }) + } + _ => { + return None; + } + }; + Some(res) + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + match self { + JsonBehavior::JsonBehaviorDefault(it) => &it.syntax, + JsonBehavior::JsonBehaviorEmptyArray(it) => &it.syntax, + JsonBehavior::JsonBehaviorEmptyObject(it) => &it.syntax, + JsonBehavior::JsonBehaviorError(it) => &it.syntax, + JsonBehavior::JsonBehaviorFalse(it) => &it.syntax, + JsonBehavior::JsonBehaviorNull(it) => &it.syntax, + JsonBehavior::JsonBehaviorTrue(it) => &it.syntax, + JsonBehavior::JsonBehaviorUnknown(it) => &it.syntax, + } + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorDefault) -> JsonBehavior { + JsonBehavior::JsonBehaviorDefault(node) + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorEmptyArray) -> JsonBehavior { + JsonBehavior::JsonBehaviorEmptyArray(node) + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorEmptyObject) -> JsonBehavior { + JsonBehavior::JsonBehaviorEmptyObject(node) + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorError) -> JsonBehavior { + JsonBehavior::JsonBehaviorError(node) + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorFalse) -> JsonBehavior { + JsonBehavior::JsonBehaviorFalse(node) + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorNull) -> JsonBehavior { + JsonBehavior::JsonBehaviorNull(node) + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorTrue) -> JsonBehavior { + JsonBehavior::JsonBehaviorTrue(node) + } +} +impl From for JsonBehavior { + #[inline] + fn from(node: JsonBehaviorUnknown) -> JsonBehavior { + JsonBehavior::JsonBehaviorUnknown(node) + } +} impl AstNode for MatchType { #[inline] fn can_cast(kind: SyntaxKind) -> bool { diff --git a/crates/squawk_syntax/src/ast/generated/tokens.rs b/crates/squawk_syntax/src/ast/generated/tokens.rs index fd14e662..a99d7002 100644 --- a/crates/squawk_syntax/src/ast/generated/tokens.rs +++ b/crates/squawk_syntax/src/ast/generated/tokens.rs @@ -1,4 +1,4 @@ -use crate::{SyntaxKind, SyntaxToken, ast::AstToken}; +use crate::{ast::AstToken, SyntaxKind, SyntaxToken}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Null { diff --git a/crates/squawk_syntax/src/postgresql.ungram b/crates/squawk_syntax/src/postgresql.ungram index 384cbf37..ee8b8735 100644 --- a/crates/squawk_syntax/src/postgresql.ungram +++ b/crates/squawk_syntax/src/postgresql.ungram @@ -942,6 +942,9 @@ JsonTableColumn = | Name Type | 'nested' 'path'? Expr +JsonTableColumnList = + 'columns' '(' (JsonTableColumn (',' JsonTableColumn)*) ')' + JsonReturningClause = 'returning' Type @@ -954,17 +957,54 @@ JsonKeysUniqueClause = JsonQuotesClause = 'keep' 'quotes' | 'omit' 'quotes' -JsonBehaviorClause = - 'error' 'on' 'error' | 'null' 'on' 'error' | 'empty' 'on' 'error' | 'default' Expr 'on' 'error' +JsonBehaviorDefault = + 'default' Expr + +JsonBehaviorError = + 'error' + +JsonBehaviorNull = + 'null' + +JsonBehaviorTrue = + 'true' + +JsonBehaviorFalse = + 'false' + +JsonBehaviorUnknown = + 'unknown' + +JsonBehaviorEmptyArray = + 'empty' 'array'? + +JsonBehaviorEmptyObject = + 'empty' 'object' + +JsonBehavior = + JsonBehaviorDefault +| JsonBehaviorError +| JsonBehaviorNull +| JsonBehaviorTrue +| JsonBehaviorFalse +| JsonBehaviorUnknown +| JsonBehaviorEmptyArray +| JsonBehaviorEmptyObject JsonWrapperBehaviorClause = 'with' 'wrapper' | 'without' 'wrapper' | 'with' 'conditional' 'wrapper' JsonOnErrorClause = - 'error' 'on' 'error' | 'null' 'on' 'error' | 'empty' 'on' 'error' + JsonBehavior 'on' 'error' + +JsonOnEmptyClause = + JsonBehavior 'on' 'empty' + +JsonPassingArg = + Expr JsonFormatClause? 'as' Name JsonPassingClause = - 'passing' (NamedArg (',' NamedArg)*) + 'passing' (JsonPassingArg (',' JsonPassingArg)*) PercentTypeClause = Path PercentTypeClause diff --git a/crates/xtask/src/codegen.rs b/crates/xtask/src/codegen.rs index c1d17f4b..dcaaf7b1 100644 --- a/crates/xtask/src/codegen.rs +++ b/crates/xtask/src/codegen.rs @@ -81,12 +81,7 @@ pub(crate) fn codegen() -> Result<()> { let token_sets_file = project_root().join("crates/squawk_parser/src/generated/token_sets.rs"); std::fs::write(token_sets_file, token_sets).context("problem writing generated token sets")?; - let kinds = generate_kind_src( - &ast_src.nodes, - &ast_src.enums, - &grammar, - keyword_kinds.all_keywords, - ); + let kinds = generate_kind_src(&ast_src.nodes, &grammar, keyword_kinds.all_keywords); let syntax_kinds = generate_syntax_kinds(kinds)?; let syntax_kinds_file = @@ -143,7 +138,6 @@ const PUNCT: &[(&str, &str)] = &[ fn generate_kind_src( nodes: &[AstNodeSrc], - enums: &[AstEnumSrc], grammar: &ungrammar::Grammar, pg_keywords: Vec, ) -> KindsSrc { @@ -195,7 +189,8 @@ fn generate_kind_src( let nodes = nodes .iter() .map(|it| &it.name) - .chain(enums.iter().map(|it| &it.name)) + // We don't include enums since they don't compare against a specific syntax kind + // .chain(enums.iter().map(|it| &it.name)) .map(|it| it.to_case(Case::UpperSnake)) .map(String::leak) .map(|it| &*it) From cb5097e6cbf97f06efb4ee7265080ca59a18108b Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 28 Jun 2025 21:01:17 -0400 Subject: [PATCH 2/2] fix --- crates/squawk_syntax/src/ast/generated/nodes.rs | 4 ++-- crates/squawk_syntax/src/ast/generated/tokens.rs | 2 +- s/lint | 11 ++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/squawk_syntax/src/ast/generated/nodes.rs b/crates/squawk_syntax/src/ast/generated/nodes.rs index 71371b46..c9f8cb48 100644 --- a/crates/squawk_syntax/src/ast/generated/nodes.rs +++ b/crates/squawk_syntax/src/ast/generated/nodes.rs @@ -1,8 +1,8 @@ +use crate::SyntaxKind; use crate::ast::AstNode; -use crate::ast::{support, AstChildren}; +use crate::ast::{AstChildren, support}; use crate::syntax_node::SyntaxNode; use crate::syntax_node::SyntaxToken; -use crate::SyntaxKind; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AddColumn { diff --git a/crates/squawk_syntax/src/ast/generated/tokens.rs b/crates/squawk_syntax/src/ast/generated/tokens.rs index a99d7002..fd14e662 100644 --- a/crates/squawk_syntax/src/ast/generated/tokens.rs +++ b/crates/squawk_syntax/src/ast/generated/tokens.rs @@ -1,4 +1,4 @@ -use crate::{ast::AstToken, SyntaxKind, SyntaxToken}; +use crate::{SyntaxKind, SyntaxToken, ast::AstToken}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Null { diff --git a/s/lint b/s/lint index fd9d5f67..906865e6 100755 --- a/s/lint +++ b/s/lint @@ -1,5 +1,10 @@ #!/bin/sh -set -eu +set -e -cargo fmt -- --check -cargo clippy --all-targets --all-features -- -D warnings +if [[ "$CI" ]]; then + cargo fmt -- --check + cargo clippy --all-targets --all-features -- -D warnings +else + cargo fmt + cargo clippy --fix --allow-staged --allow-dirty --all-targets --all-features -- -D warnings +fi