From 96aca8e855387d1f68cb3f5fbea0ce6b3ddb56f4 Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Wed, 25 Jun 2025 19:32:55 -0400 Subject: [PATCH] parser: improve error handling for type args --- PLAN.md | 17 ++- crates/squawk_parser/src/grammar.rs | 135 ++++++++---------- .../squawk_parser/tests/data/err/select.sql | 5 + .../snapshots/tests__alter_extension_ok.snap | 18 +-- .../tests__alter_operator_family_ok.snap | 2 +- .../snapshots/tests__alter_sequence_ok.snap | 2 +- .../snapshots/tests__alter_table_ok.snap | 4 +- .../tests/snapshots/tests__alter_type_ok.snap | 4 +- .../tests/snapshots/tests__comment_ok.snap | 4 +- .../snapshots/tests__create_domain_ok.snap | 2 +- .../snapshots/tests__create_function_ok.snap | 6 +- .../tests__create_operator_class_ok.snap | 6 +- .../snapshots/tests__create_operator_ok.snap | 2 +- .../snapshots/tests__create_sequence_ok.snap | 2 +- .../snapshots/tests__create_table_err.snap | 18 ++- .../snapshots/tests__create_transform_ok.snap | 2 +- .../snapshots/tests__drop_transform_ok.snap | 2 +- .../snapshots/tests__select_casts_ok.snap | 4 +- .../tests/snapshots/tests__select_err.snap | 108 +++++++++++++- 19 files changed, 231 insertions(+), 112 deletions(-) diff --git a/PLAN.md b/PLAN.md index e4e7785f..d2d0cfd3 100644 --- a/PLAN.md +++ b/PLAN.md @@ -434,6 +434,21 @@ suggest using an aggregate or grouping by Provide options to select from in quick fix +```sql +create table t (t_id int, name text, created timestampz); +create table u (u_id int, t_id int, created timestampz); + +select name, created from u join t using (t_id); +-- ^^^^^^^ error: ambiguous column name `created`, prefix with either `t` or `u` +-- action: Prefix with... +-- Prefix with `t` +-- Prefix with `u` + +-- gives + +select name, u.created from u join t using (t_id); +``` + ### Rule: column label is the same as an existing column ```sql @@ -792,7 +807,7 @@ becomes after filling in alias name with `b` select b.name, b.email from bar ``` -should prompt for table name for each entry when there is an ambigous column +should prompt for table name for each entry when there is an ambiguous column related: diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index 0a8bed6f..8d005139 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -548,14 +548,15 @@ fn json_table_fn(p: &mut Parser<'_>) -> CompletedMarker { fn custom_fn( p: &mut Parser<'_>, - kind: SyntaxKind, + name: SyntaxKind, mut body: impl FnMut(&mut Parser<'_>), ) -> CompletedMarker { - assert!(p.at(kind)); + assert!(p.at(name)); let m = p.start(); let name_ref = p.start(); - p.expect(kind); + p.expect(name); name_ref.complete(p, NAME_REF); + let args = p.start(); p.expect(L_PAREN); if !p.at(R_PAREN) { @@ -563,6 +564,7 @@ fn custom_fn( } p.expect(R_PAREN); args.complete(p, ARG_LIST); + opt_agg_clauses(p); m.complete(p, CALL_EXPR) } @@ -1613,21 +1615,26 @@ fn type_mods( return Some(m.complete(p, PERCENT_TYPE)); } if p.at(L_PAREN) && type_args_enabled { - p.bump(L_PAREN); - let type_args = p.start(); - while !p.at(EOF) && !p.at(R_PAREN) { - let arg = p.start(); - if expr(p).is_none() { - arg.abandon(p); - break; - } - arg.complete(p, ARG); - if !p.eat(COMMA) { - break; - } - } - p.expect(R_PAREN); - type_args.complete(p, ARG_LIST); + let m = p.start(); + delimited( + p, + L_PAREN, + R_PAREN, + COMMA, + || "unexpected comma".to_string(), + EXPR_FIRST, + |p| { + let m = p.start(); + if expr(p).is_some() { + m.complete(p, ARG); + true + } else { + m.abandon(p); + false + } + }, + ); + m.complete(p, ARG_LIST); } let cm = m.complete(p, kind); if !p.at(L_BRACK) && !p.at(ARRAY_KW) { @@ -1715,6 +1722,13 @@ fn opt_type_name_with(p: &mut Parser<'_>, type_args_enabled: bool) -> Option { + m.abandon(p); + return None; + } _ if p.at_ts(TYPE_KEYWORDS) || p.at(IDENT) => { path_name_ref(p); PATH_TYPE @@ -3785,12 +3799,6 @@ fn index_elem(p: &mut Parser<'_>) { } } -#[derive(PartialEq, Eq, Clone, Copy)] -enum ColDefType { - WithData, - ColumnNameOnly, -} - fn opt_operator(p: &mut Parser<'_>) -> bool { let (power, kind, _) = current_op(p, &Restrictions::default()); if power == 0 { @@ -4122,20 +4130,21 @@ const COLUMN_NAME_KEYWORDS: TokenSet = TokenSet::new(&[ XMLTABLE_KW, ]); +const COL_DEF_FIRST: TokenSet = TokenSet::new(&[LIKE_KW]) + .union(TABLE_CONSTRAINT_FIRST) + .union(NAME_FIRST); + // column_name data_type [ STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT } ] [ COMPRESSION compression_method ] [ COLLATE collation ] [ column_constraint [ ... ] ] // { column_name data_type [ STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT } ] [ COMPRESSION compression_method ] [ COLLATE collation ] [ column_constraint [ ... ] ] // | table_constraint // | LIKE source_table [ like_option ... ] } -fn col_def(p: &mut Parser<'_>, t: ColDefType) -> Option { - if !(p.at(LIKE_KW) - || p.at_ts(TABLE_CONSTRAINT_FIRST) - // ColId - || p.at_ts(NAME_FIRST)) - { +fn opt_col_def(p: &mut Parser<'_>) -> Option { + if !p.at_ts(COL_DEF_FIRST) { return None; } + // TODO: add validation to check we only specify this when data types are allowed for args // LIKE source_table [ like_option ... ] - if t == ColDefType::WithData && p.at(LIKE_KW) { + if p.at(LIKE_KW) { return Some(like_clause(p)); } if p.at_ts(TABLE_CONSTRAINT_FIRST) { @@ -4143,17 +4152,11 @@ fn col_def(p: &mut Parser<'_>, t: ColDefType) -> Option { } let m = p.start(); name(p); - match t { - ColDefType::WithData => { - if opt_type_name(p) { - opt_storage(p); - opt_compression_method(p); - } - } - ColDefType::ColumnNameOnly => { - opt_with_options(p); - } + if opt_type_name(p) { + opt_storage(p); + opt_compression_method(p); } + opt_with_options(p); opt_collate(p); opt_column_constraint_list(p); Some(m.complete(p, COLUMN)) @@ -4558,6 +4561,8 @@ const LHS_FIRST: TokenSet = TokenSet::new(&[ ARRAY_KW, ROW_KW, DEFAULT_KW, + // for non-standard params, like :foo + COLON, ]) .union(OPERATOR_FIRST) .union(LITERAL_FIRST) @@ -4789,31 +4794,18 @@ fn opt_nulls_order(p: &mut Parser<'_>) { } } -fn table_arg_list(p: &mut Parser<'_>, t: ColDefType) -> Option { +fn table_arg_list(p: &mut Parser<'_>) -> Option { assert!(p.at(L_PAREN)); let m = p.start(); - match t { - ColDefType::WithData => { - p.expect(L_PAREN); - } - ColDefType::ColumnNameOnly => { - if !p.eat(L_PAREN) { - m.abandon(p); - return None; - } - } - } - while !p.at(EOF) && !p.at(R_PAREN) { - col_def(p, t); - if p.at(COMMA) && p.nth_at(1, R_PAREN) { - p.err_and_bump("unexpected trailing comma"); - break; - } - if !p.eat(COMMA) { - break; - } - } - p.expect(R_PAREN); + delimited( + p, + L_PAREN, + R_PAREN, + COMMA, + || "unexpected comma".to_string(), + COL_DEF_FIRST, + |p| opt_col_def(p).is_some(), + ); Some(m.complete(p, TABLE_ARG_LIST)) } @@ -4918,28 +4910,25 @@ fn create_table(p: &mut Parser<'_>) -> CompletedMarker { p.expect(TABLE_KW); opt_if_not_exists(p); path_name(p); - let mut col_def_t = ColDefType::WithData; let mut is_partition = false; // OF type_name if p.at(OF_KW) { of_type(p); - col_def_t = ColDefType::ColumnNameOnly; - // PARTITION OF parent_table + // TODO: add validation to check that table args don't have data types + // PARTITION OF parent_table } else if p.at(PARTITION_KW) { partition_of(p); - col_def_t = ColDefType::ColumnNameOnly; + // TODO: add validation to check that table args don't have data types is_partition = true; } if p.at(L_PAREN) { - table_arg_list(p, col_def_t); + table_arg_list(p); } if is_partition { partition_option(p); } - // [ INHERITS ( parent_table [, ... ] ) ] - if col_def_t == ColDefType::WithData { - opt_inherits_tables(p); - } + // TODO: add validation to check we don't specify this when data types aren't allowed + opt_inherits_tables(p); opt_partition_by(p); opt_using_method(p); if opt_with_params(p).is_none() { diff --git a/crates/squawk_parser/tests/data/err/select.sql b/crates/squawk_parser/tests/data/err/select.sql index e1b04a15..048fb8d3 100644 --- a/crates/squawk_parser/tests/data/err/select.sql +++ b/crates/squawk_parser/tests/data/err/select.sql @@ -32,6 +32,11 @@ select array[1, ,3]; -- trailing comma select array[1,2,3,]; +-- cast with malformed type mod args +select cast(x as varchar(100 200)); +select cast(x as varchar(100, , 200)); +select cast(x as t(a, b,)); + -- regression test: this would cause the parser to get stuck & panic, now it -- warns about a missing semicolon select select; diff --git a/crates/squawk_parser/tests/snapshots/tests__alter_extension_ok.snap b/crates/squawk_parser/tests/snapshots/tests__alter_extension_ok.snap index 1951357a..07a2e609 100644 --- a/crates/squawk_parser/tests/snapshots/tests__alter_extension_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__alter_extension_ok.snap @@ -231,8 +231,8 @@ SOURCE_FILE L_PAREN "(" CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -671,8 +671,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -752,8 +752,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -881,8 +881,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -916,8 +916,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -1140,8 +1140,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -1221,8 +1221,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -1279,8 +1279,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -1360,8 +1360,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__alter_operator_family_ok.snap b/crates/squawk_parser/tests/snapshots/tests__alter_operator_family_ok.snap index 2391f04d..bcf6a0f6 100644 --- a/crates/squawk_parser/tests/snapshots/tests__alter_operator_family_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__alter_operator_family_ok.snap @@ -153,8 +153,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__alter_sequence_ok.snap b/crates/squawk_parser/tests/snapshots/tests__alter_sequence_ok.snap index ab17af05..85b5dd34 100644 --- a/crates/squawk_parser/tests/snapshots/tests__alter_sequence_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__alter_sequence_ok.snap @@ -29,8 +29,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__alter_table_ok.snap b/crates/squawk_parser/tests/snapshots/tests__alter_table_ok.snap index 72782947..8938daf5 100644 --- a/crates/squawk_parser/tests/snapshots/tests__alter_table_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__alter_table_ok.snap @@ -59,8 +59,8 @@ SOURCE_FILE PATH_SEGMENT NAME_REF NUMERIC_KW "numeric" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "10" @@ -3687,8 +3687,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "30" diff --git a/crates/squawk_parser/tests/snapshots/tests__alter_type_ok.snap b/crates/squawk_parser/tests/snapshots/tests__alter_type_ok.snap index 0f169be8..71dd723a 100644 --- a/crates/squawk_parser/tests/snapshots/tests__alter_type_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__alter_type_ok.snap @@ -452,8 +452,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -592,8 +592,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__comment_ok.snap b/crates/squawk_parser/tests/snapshots/tests__comment_ok.snap index 6442d668..6e54ff7a 100644 --- a/crates/squawk_parser/tests/snapshots/tests__comment_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__comment_ok.snap @@ -630,8 +630,8 @@ SOURCE_FILE L_PAREN "(" CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -640,8 +640,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "200" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_domain_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_domain_ok.snap index 2bb01f80..804b4948 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_domain_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_domain_ok.snap @@ -38,8 +38,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_function_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_function_ok.snap index a684c62c..decbdfdc 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_function_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_function_ok.snap @@ -606,8 +606,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "255" @@ -623,8 +623,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -2124,8 +2124,8 @@ SOURCE_FILE WHITESPACE " " BIT_TYPE BIT_KW "bit" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "8" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_operator_class_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_operator_class_ok.snap index 210848bf..aeb896cb 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_operator_class_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_operator_class_ok.snap @@ -68,8 +68,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -160,8 +160,8 @@ SOURCE_FILE L_PAREN "(" CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" @@ -170,8 +170,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "10" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_operator_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_operator_ok.snap index 81da6723..abe6c9ae 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_operator_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_operator_ok.snap @@ -117,8 +117,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_sequence_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_sequence_ok.snap index 4517f0d8..752c6f0f 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_sequence_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_sequence_ok.snap @@ -41,8 +41,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_table_err.snap b/crates/squawk_parser/tests/snapshots/tests__create_table_err.snap index 74578180..1ecd591f 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_table_err.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_table_err.snap @@ -88,10 +88,14 @@ SOURCE_FILE WHITESPACE " " TABLE_ARG_LIST L_PAREN "(" - COMMA "," - COMMA "," - COMMA "," - COMMA "," + ERROR + COMMA "," + ERROR + COMMA "," + ERROR + COMMA "," + ERROR + COMMA "," ERROR COMMA "," R_PAREN ")" @@ -486,5 +490,9 @@ SOURCE_FILE --- ERROR@39: expected path name ERROR@143: unexpected trailing comma -ERROR@201: unexpected trailing comma +ERROR@197: unexpected comma +ERROR@198: unexpected comma +ERROR@199: unexpected comma +ERROR@200: unexpected comma +ERROR@201: unexpected comma ERROR@947: expected SEMICOLON diff --git a/crates/squawk_parser/tests/snapshots/tests__create_transform_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_transform_ok.snap index 858ccee0..e6616f54 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_transform_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_transform_ok.snap @@ -79,8 +79,8 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "t" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "10231" diff --git a/crates/squawk_parser/tests/snapshots/tests__drop_transform_ok.snap b/crates/squawk_parser/tests/snapshots/tests__drop_transform_ok.snap index e0774698..78d9d779 100644 --- a/crates/squawk_parser/tests/snapshots/tests__drop_transform_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__drop_transform_ok.snap @@ -63,8 +63,8 @@ SOURCE_FILE WHITESPACE " " CHAR_TYPE VARCHAR_KW "varchar" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "100" diff --git a/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap b/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap index 21b113db..a5dd89be 100644 --- a/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__select_casts_ok.snap @@ -113,8 +113,8 @@ SOURCE_FILE WHITESPACE " " BIT_TYPE BIT_KW "bit" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "12" @@ -2690,8 +2690,8 @@ SOURCE_FILE WHITESPACE " " BIT_TYPE BIT_KW "bit" - L_PAREN "(" ARG_LIST + L_PAREN "(" ARG LITERAL INT_NUMBER "12" diff --git a/crates/squawk_parser/tests/snapshots/tests__select_err.snap b/crates/squawk_parser/tests/snapshots/tests__select_err.snap index b924e6c7..56ed2ebb 100644 --- a/crates/squawk_parser/tests/snapshots/tests__select_err.snap +++ b/crates/squawk_parser/tests/snapshots/tests__select_err.snap @@ -278,6 +278,105 @@ SOURCE_FILE R_BRACK "]" SEMICOLON ";" WHITESPACE "\n\n" + COMMENT "-- cast with malformed type mod args" + WHITESPACE "\n" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + CAST_EXPR + CAST_KW "cast" + L_PAREN "(" + NAME_REF + IDENT "x" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + CHAR_TYPE + VARCHAR_KW "varchar" + ARG_LIST + L_PAREN "(" + ARG + LITERAL + INT_NUMBER "100" + WHITESPACE " " + ARG + LITERAL + INT_NUMBER "200" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + CAST_EXPR + CAST_KW "cast" + L_PAREN "(" + NAME_REF + IDENT "x" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + CHAR_TYPE + VARCHAR_KW "varchar" + ARG_LIST + L_PAREN "(" + ARG + LITERAL + INT_NUMBER "100" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + WHITESPACE " " + ARG + LITERAL + INT_NUMBER "200" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + SELECT + SELECT_CLAUSE + SELECT_KW "select" + WHITESPACE " " + TARGET_LIST + TARGET + CAST_EXPR + CAST_KW "cast" + L_PAREN "(" + NAME_REF + IDENT "x" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + ARG_LIST + L_PAREN "(" + ARG + NAME_REF + IDENT "a" + COMMA "," + WHITESPACE " " + ARG + NAME_REF + IDENT "b" + ERROR + COMMA "," + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n\n" COMMENT "-- regression test: this would cause the parser to get stuck & panic, now it" WHITESPACE "\n" COMMENT "-- warns about a missing semicolon" @@ -339,6 +438,9 @@ ERROR@520: missing comma ERROR@559: expected COMMA ERROR@597: unexpected comma ERROR@638: unexpected trailing comma -ERROR@761: expected SEMICOLON -ERROR@794: unexpected trailing comma -ERROR@838: unexpected trailing comma +ERROR@708: expected COMMA +ERROR@746: unexpected comma +ERROR@778: unexpected trailing comma +ERROR@902: expected SEMICOLON +ERROR@935: unexpected trailing comma +ERROR@979: unexpected trailing comma