Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/squawk_parser/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3542,7 +3542,7 @@ fn select(p: &mut Parser, m: Option<Marker>, r: &SelectRestrictions) -> Option<C
}

pub(crate) fn perform_select(p: &mut Parser<'_>) -> CompletedMarker {
assert!(p.nth_at_contextual_kw(0, PERFORM_KW));
assert!(p.at_contextual_kw(PERFORM_KW));
let m = p.start();
let clause = p.start();
// Postgres rewrites this to `select` before passing to the sql parser, but
Expand Down
5 changes: 5 additions & 0 deletions crates/squawk_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,11 @@ impl<'t> Parser<'t> {
self.do_bump(kind, 1);
}

/// Checks if the current token is contextual keyword `kw`.
pub(crate) fn at_contextual_kw(&self, kw: SyntaxKind) -> bool {
self.contextual_kind_at(self.pos) == kw
}

/// Checks if the nth token is contextual keyword `kw`.
pub(crate) fn nth_at_contextual_kw(&self, n: usize, kw: SyntaxKind) -> bool {
self.contextual_kind_at(self.pos + n) == kw
Expand Down
97 changes: 50 additions & 47 deletions crates/squawk_parser/src/plpgsql_grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ fn comp_option(p: &mut Parser) {
p.bump(OPTION_KW);
expect_contextual_kw(p, DUMP_KW);
PLPGSQL_COMP_OPTION_DUMP
} else if p.nth_at_contextual_kw(0, VARIABLE_CONFLICT_KW) {
} else if p.at_contextual_kw(VARIABLE_CONFLICT_KW) {
p.bump_remap(VARIABLE_CONFLICT_KW);
variable_conflict_value(p);
PLPGSQL_COMP_OPTION_VARIABLE_CONFLICT
} else if p.nth_at_contextual_kw(0, PRINT_STRICT_PARAMS_KW) {
} else if p.at_contextual_kw(PRINT_STRICT_PARAMS_KW) {
p.bump_remap(PRINT_STRICT_PARAMS_KW);
option_value(p);
PLPGSQL_COMP_OPTION_PRINT_STRICT_PARAMS
Expand All @@ -59,7 +59,7 @@ fn variable_conflict_value(p: &mut Parser) {
}

fn option_value(p: &mut Parser) {
if !at_name(p, 0) {
if !at_name(p) {
p.error(format!("expected an option value, got {:?}", p.current()));
return;
}
Expand Down Expand Up @@ -97,7 +97,7 @@ fn opt_label(p: &mut Parser) {
}

fn opt_label_name_ref(p: &mut Parser) {
if !at_name(p, 0) {
if !at_name(p) {
return;
}
name(p, PLPGSQL_LABEL_NAME_REF);
Expand Down Expand Up @@ -132,7 +132,7 @@ fn opt_declare_section(p: &mut Parser) {
fn var_decl(p: &mut Parser) {
let m = p.start();
name(p, PLPGSQL_VAR_NAME);
if p.nth_at_contextual_kw(0, CONSTANT_KW) {
if p.at_contextual_kw(CONSTANT_KW) {
p.bump_remap(CONSTANT_KW);
}
decl_datatype(p);
Expand Down Expand Up @@ -201,7 +201,7 @@ fn cursor_arg_list(p: &mut Parser) {

fn cursor_arg(p: &mut Parser) {
let m = p.start();
if at_name(p, 0) {
if at_name(p) {
name(p, PLPGSQL_VAR_NAME);
decl_datatype(p);
} else {
Expand Down Expand Up @@ -264,7 +264,7 @@ fn at_percent_datatype(p: &Parser) -> bool {

fn at_path(p: &Parser) -> Option<usize> {
let mut n = 0;
while !p.nth_at(n, EOF) && at_name(p, n) {
while !p.nth_at(n, EOF) && nth_at_name(p, n) {
let unicode_ident = p.nth_at(n, IDENT);
n += 1;
if unicode_ident && p.nth_at(n, UESCAPE_KW) && p.nth_at(n + 1, STRING) {
Expand Down Expand Up @@ -393,13 +393,13 @@ fn stmt(p: &mut Parser) {
call_stmt(p);
} else if p.at(DO_KW) {
do_stmt(p);
} else if p.nth_at_contextual_kw(0, PERFORM_KW) {
} else if p.at_contextual_kw(PERFORM_KW) {
perform_stmt(p);
} else if p.at(RETURN_KW) {
return_stmt(p);
} else if p.nth_at_contextual_kw(0, ASSERT_KW) {
} else if p.at_contextual_kw(ASSERT_KW) {
assert_stmt(p);
} else if p.nth_at_contextual_kw(0, RAISE_KW) {
} else if p.at_contextual_kw(RAISE_KW) {
raise_stmt(p);
} else if at_stmt_kw(p, GET_KW) {
get_diag_stmt(p);
Expand Down Expand Up @@ -482,7 +482,7 @@ fn do_stmt(p: &mut Parser) {
}

fn perform_stmt(p: &mut Parser) {
assert!(p.nth_at_contextual_kw(0, PERFORM_KW));
assert!(p.at_contextual_kw(PERFORM_KW));
let m = p.start();
match grammar::perform_select(p).kind() {
SELECT | SELECT_INTO | COMPOUND_SELECT => (),
Expand All @@ -505,13 +505,13 @@ fn return_stmt(p: &mut Parser) {
expr_until_semi(p);
}
PLPGSQL_RETURN_NEXT_STMT
} else if p.nth_at_contextual_kw(0, QUERY_KW) && !composite && p.nth_at(1, EXECUTE_KW) {
} else if p.at_contextual_kw(QUERY_KW) && !composite && p.nth_at(1, EXECUTE_KW) {
p.bump_remap(QUERY_KW);
p.bump(EXECUTE_KW);
expr_until_using(p);
opt_using_clause(p, comma_expr);
PLPGSQL_RETURN_QUERY_EXECUTE_STMT
} else if p.nth_at_contextual_kw(0, QUERY_KW) && !composite {
} else if p.at_contextual_kw(QUERY_KW) && !composite {
p.bump_remap(QUERY_KW);
if grammar::stmt(p, &grammar::StmtRestrictions::default()).is_none() {
p.error("expected a query");
Expand All @@ -528,7 +528,7 @@ fn return_stmt(p: &mut Parser) {
}

fn assert_stmt(p: &mut Parser) {
assert!(p.nth_at_contextual_kw(0, ASSERT_KW));
assert!(p.at_contextual_kw(ASSERT_KW));
let m = p.start();
p.bump_remap(ASSERT_KW);
comma_expr(p);
Expand Down Expand Up @@ -574,7 +574,7 @@ const RAISE_OPTIONS: [(SyntaxKind, SyntaxKind); 9] = [
];

fn raise_stmt(p: &mut Parser) {
assert!(p.nth_at_contextual_kw(0, RAISE_KW));
assert!(p.at_contextual_kw(RAISE_KW));
let m = p.start();
p.bump_remap(RAISE_KW);
if !p.at(SEMICOLON) {
Expand Down Expand Up @@ -689,7 +689,7 @@ fn get_diag_stmt(p: &mut Parser) {
}

fn opt_diag_area(p: &mut Parser) {
if !p.at(CURRENT_KW) && !p.nth_at_contextual_kw(0, STACKED_KW) {
if !p.at(CURRENT_KW) && !p.at_contextual_kw(STACKED_KW) {
return;
}
let m = p.start();
Expand All @@ -710,7 +710,7 @@ fn diag_item_list(p: &mut Parser) {

fn diag_item(p: &mut Parser) {
let m = p.start();
if at_name(p, 0) {
if at_name(p) {
scalar_target(p, PLPGSQL_DIAG_TARGET);
if !p.eat(COLON_EQ) {
p.expect(EQ);
Expand All @@ -726,7 +726,7 @@ fn diag_item(p: &mut Parser) {
}

fn scalar_target(p: &mut Parser, kind: SyntaxKind) {
assert!(at_name(p, 0));
assert!(at_name(p));
let m = p.start();
name(p, PLPGSQL_VAR_NAME_REF);
while !p.at(EOF) && p.at(DOT) {
Expand All @@ -745,12 +745,12 @@ fn diag_kind(p: &mut Parser) {
let m = p.start();
match DIAG_ITEM_KINDS
.into_iter()
.find(|&kw| p.nth_at_contextual_kw(0, kw))
.find(|&kw| p.at_contextual_kw(kw))
{
Some(kw) => p.bump_remap(kw),
None => {
p.error("unrecognized GET DIAGNOSTICS item");
if at_name(p, 0) {
if at_name(p) {
p.bump_any();
}
}
Expand Down Expand Up @@ -859,7 +859,7 @@ fn into_target_list(p: &mut Parser) {
}

fn into_target(p: &mut Parser) {
if !at_name(p, 0) {
if !at_name(p) {
p.error(format!("expected an INTO target, got {:?}", p.current()));
return;
}
Expand All @@ -876,7 +876,7 @@ fn close_stmt(p: &mut Parser) {
}

fn cursor_variable_ref(p: &mut Parser) {
if !at_name(p, 0) {
if !at_name(p) {
p.error(format!("expected a cursor variable, got {:?}", p.current()));
return;
}
Expand Down Expand Up @@ -957,13 +957,13 @@ fn loop_stmt(p: &mut Parser) {
assert!(at_loop_start(p));
let m = p.start();
opt_label(p);
let kind = if p.nth_at_contextual_kw(0, WHILE_KW) {
let kind = if p.at_contextual_kw(WHILE_KW) {
p.bump_remap(WHILE_KW);
expr_until_loop(p, TokenSet::EMPTY);
PLPGSQL_WHILE_STMT
} else if p.at(FOR_KW) {
for_head(p)
} else if p.nth_at_contextual_kw(0, FOREACH_KW) {
} else if p.at_contextual_kw(FOREACH_KW) {
foreach_head(p)
} else {
PLPGSQL_LOOP_STMT
Expand Down Expand Up @@ -1010,7 +1010,7 @@ fn for_head(p: &mut Parser) -> SyntaxKind {
}

fn foreach_head(p: &mut Parser) -> SyntaxKind {
assert!(p.nth_at_contextual_kw(0, FOREACH_KW));
assert!(p.at_contextual_kw(FOREACH_KW));
p.bump_remap(FOREACH_KW);
for_variable_list(p);
opt_foreach_slice(p);
Expand All @@ -1021,7 +1021,7 @@ fn foreach_head(p: &mut Parser) -> SyntaxKind {
}

fn opt_foreach_slice(p: &mut Parser) {
if !p.nth_at_contextual_kw(0, SLICE_KW) {
if !p.at_contextual_kw(SLICE_KW) {
return;
}
let m = p.start();
Expand Down Expand Up @@ -1059,7 +1059,7 @@ fn for_variable_list(p: &mut Parser) {
}

fn for_variable(p: &mut Parser) {
if !at_name(p, 0) {
if !at_name(p) {
p.error(format!("expected a loop variable, got {:?}", p.current()));
return;
}
Expand Down Expand Up @@ -1115,7 +1115,7 @@ fn opt_exit_when(p: &mut Parser) {
}

fn expect_contextual_kw(p: &mut Parser, kw: SyntaxKind) {
if p.nth_at_contextual_kw(0, kw) {
if p.at_contextual_kw(kw) {
p.bump_remap(kw);
} else {
p.error(format!("expected {kw:?}"));
Expand All @@ -1127,7 +1127,7 @@ fn opt_elsif_clause(p: &mut Parser) -> bool {
return false;
}
let m = p.start();
if p.nth_at_contextual_kw(0, ELSEIF_KW) {
if p.at_contextual_kw(ELSEIF_KW) {
p.bump_remap(ELSEIF_KW);
} else {
p.bump_remap(ELSIF_KW);
Expand Down Expand Up @@ -1174,7 +1174,7 @@ fn skip_to_stmt_end(p: &mut Parser) {
}

fn opt_exception_section(p: &mut Parser) {
if !p.nth_at_contextual_kw(0, EXCEPTION_KW) {
if !p.at_contextual_kw(EXCEPTION_KW) {
return;
}
let m = p.start();
Expand All @@ -1201,28 +1201,27 @@ fn exception_handler(p: &mut Parser) {

fn condition(p: &mut Parser) {
let m = p.start();
if at_name(p, 0) {
let sqlstate = p.nth_at_contextual_kw(0, SQLSTATE_KW);
if p.at_contextual_kw(SQLSTATE_KW) {
p.bump_remap(SQLSTATE_KW);
p.expect(STRING);
} else if at_name(p) {
p.bump_any();
if sqlstate {
p.expect(STRING);
}
} else {
p.error(format!("expected a condition name, got {:?}", p.current()));
}
m.complete(p, PLPGSQL_CONDITION);
}

fn at_alias_decl(p: &Parser) -> bool {
at_name(p, 0) && p.nth_at_contextual_kw(1, ALIAS_KW)
at_name(p) && p.nth_at_contextual_kw(1, ALIAS_KW)
}

fn at_cursor_decl(p: &Parser) -> bool {
at_name(p, 0) && (p.nth_at(1, CURSOR_KW) || p.nth_at(1, SCROLL_KW) || p.nth_at(1, NO_KW))
at_name(p) && (p.nth_at(1, CURSOR_KW) || p.nth_at(1, SCROLL_KW) || p.nth_at(1, NO_KW))
}

fn at_var_decl(p: &Parser) -> bool {
at_name(p, 0)
at_name(p)
}

fn at_block_start(p: &Parser) -> bool {
Expand All @@ -1234,7 +1233,7 @@ fn at_block_label(p: &Parser) -> bool {
}

fn at_label(p: &Parser) -> bool {
p.at(LESS_LESS) && at_name(p, 2) && p.nth_at(3, GREATER_GREATER)
p.at(LESS_LESS) && nth_at_name(p, 2) && p.nth_at(3, GREATER_GREATER)
}

fn at_loop_start(p: &Parser) -> bool {
Expand All @@ -1251,7 +1250,7 @@ fn at_loop_kw(p: &Parser, n: usize) -> bool {
const NOT_A_CURSOR_NAME: TokenSet = TokenSet::new(&[SELECT_KW, VALUES_KW]);

fn at_for_cursor(p: &Parser, n: usize) -> bool {
if !at_name(p, n) || p.nth_at_ts(n, NOT_A_CURSOR_NAME) {
if !nth_at_name(p, n) || p.nth_at_ts(n, NOT_A_CURSOR_NAME) {
return false;
}
let Some(n) = cursor_args_end(p, n + 1) else {
Expand Down Expand Up @@ -1314,7 +1313,7 @@ fn top_level_terminator(
}

fn at_exec_sql_stmt(p: &Parser) -> bool {
if !at_name(p, 0) || at_assign_op(p) {
if !at_name(p) || at_assign_op(p) {
return false;
}
if p.at(IMPORT_KW) {
Expand Down Expand Up @@ -1365,7 +1364,7 @@ fn at_assign_op(p: &Parser) -> bool {
}

fn at_assign_target(p: &Parser) -> bool {
at_name(p, 0) && (p.at_ts(grammar::NAME_FIRST) || p.at(POSITIONAL_PARAM))
at_name(p) && (p.at_ts(grammar::NAME_FIRST) || p.at(POSITIONAL_PARAM))
}

fn at_stmt_kw(p: &Parser, kw: SyntaxKind) -> bool {
Expand All @@ -1377,10 +1376,14 @@ fn at_transaction_stmt(p: &Parser) -> bool {
}

fn at_exit_stmt(p: &Parser) -> bool {
p.at(CONTINUE_KW) || p.nth_at_contextual_kw(0, EXIT_KW)
p.at(CONTINUE_KW) || p.at_contextual_kw(EXIT_KW)
}

fn at_name(p: &Parser) -> bool {
nth_at_name(p, 0)
}

fn at_name(p: &Parser, n: usize) -> bool {
fn nth_at_name(p: &Parser, n: usize) -> bool {
if p.nth_at(n, IDENT) {
return !p.nth_at_contextual_ts(n, PLPGSQL_RESERVED_CONTEXTUAL_KEYWORDS);
}
Expand All @@ -1403,16 +1406,16 @@ fn bump_maybe_contextual_kw(p: &mut Parser, kw: SyntaxKind) {
}

fn at_elsif(p: &Parser) -> bool {
p.nth_at_contextual_kw(0, ELSIF_KW) || p.nth_at_contextual_kw(0, ELSEIF_KW)
p.at_contextual_kw(ELSIF_KW) || p.at_contextual_kw(ELSEIF_KW)
}

fn at_body_end(p: &Parser, kind: BodyKind) -> bool {
if at_block_end(p) {
return true;
}
match kind {
BodyKind::Block => p.nth_at_contextual_kw(0, EXCEPTION_KW),
BodyKind::ExceptionHandler => p.nth_at_contextual_kw(0, EXCEPTION_KW) || p.at(WHEN_KW),
BodyKind::Block => p.at_contextual_kw(EXCEPTION_KW),
BodyKind::ExceptionHandler => p.at_contextual_kw(EXCEPTION_KW) || p.at(WHEN_KW),
BodyKind::IfThen => at_end_if(p) || p.at(ELSE_KW) || at_elsif(p),
BodyKind::IfElse => at_end_if(p),
BodyKind::CaseWhen => at_end_case(p) || p.at(WHEN_KW) || p.at(ELSE_KW),
Expand Down
4 changes: 4 additions & 0 deletions crates/squawk_syntax/src/ast/generated/nodes.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/squawk_syntax/src/postgresql.ungram
Original file line number Diff line number Diff line change
Expand Up @@ -2093,6 +2093,7 @@ PlpgsqlExceptionHandler =

PlpgsqlCondition =
'#name'?
'sqlstate'?
'@positional_param'?
'@string'?

Expand Down
Loading
Loading