use sql_dialect_fmt_syntax::SyntaxKind;
use sql_dialect_fmt_syntax::SyntaxKind::*;
use crate::parser::{CompletedMarker, ContextualKeyword, Parser};
mod delta;
mod dml;
mod stmt;
const BP_OR: (u8, u8) = (1, 2);
const BP_AND: (u8, u8) = (3, 4);
const BP_CMP: (u8, u8) = (7, 8);
const BP_CONCAT: (u8, u8) = (9, 10);
const BP_ADD: (u8, u8) = (11, 12);
const BP_MUL: (u8, u8) = (13, 14);
const BP_PREFIX_NOT: u8 = 6; const BP_PREFIX_NEG: u8 = 15;
pub(crate) fn source_file(p: &mut Parser) {
let m = p.start();
while !p.at_eof() {
if p.at(SEMICOLON) {
p.bump(SEMICOLON); } else if stmt::at_stmt_start(p) {
stmt::statement_or_flow(p);
} else {
p.err_and_bump("expected a statement");
}
}
m.complete(p, SOURCE_FILE);
}
fn at_stmt_terminator(p: &Parser) -> bool {
p.at(SEMICOLON) || (p.dialect().supports_flow_operator() && p.at(FLOW_PIPE)) || p.at_eof()
}
fn if_exists_clause(p: &mut Parser) {
if p.at(IF_KW) {
p.bump(IF_KW);
p.eat(NOT_KW);
p.eat(EXISTS_KW);
}
}
fn create_stmt(p: &mut Parser) {
let m = p.start();
p.bump(CREATE_KW);
if p.at(OR_KW) {
p.bump(OR_KW);
if p.at(REPLACE_KW) {
p.bump(REPLACE_KW);
} else {
p.expect(ALTER_KW);
}
}
while !at_object_kind(p) && !at_stmt_terminator(p) && !at_create_body(p) {
if p.nth_contextual(0, ContextualKeyword::Materialized)
|| p.nth_contextual(0, ContextualKeyword::Local)
|| p.nth_contextual(0, ContextualKeyword::Global)
{
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}
if p.at(VIEW_KW) {
create_view(p);
} else if p.at(TABLE_KW) {
create_table(p);
} else if p.at(PROCEDURE_KW) || p.at(FUNCTION_KW) {
create_routine(p);
} else if at_policy_object_kind(p) {
create_policy(p);
} else if at_named_object_kind(p) {
create_object(p);
} else {
create_other(p);
}
m.complete(p, CREATE_STMT);
}
fn at_object_kind(p: &Parser) -> bool {
p.at(TABLE_KW)
|| p.at(VIEW_KW)
|| p.at(PROCEDURE_KW)
|| p.at(FUNCTION_KW)
|| at_policy_object_kind(p)
|| at_named_object_kind(p)
}
fn at_named_object_kind(p: &Parser) -> bool {
p.at(TASK_KW)
|| p.at(WAREHOUSE_KW)
|| p.nth_contextual(0, ContextualKeyword::Schema)
|| p.nth_contextual(0, ContextualKeyword::Database)
|| p.nth_contextual(0, ContextualKeyword::Stage)
|| p.nth_contextual(0, ContextualKeyword::Sequence)
|| p.nth_contextual(0, ContextualKeyword::Stream)
|| p.nth_contextual(0, ContextualKeyword::Dynamic)
|| p.nth_contextual(0, ContextualKeyword::Semantic)
|| p.nth_contextual(0, ContextualKeyword::File)
|| p.nth_contextual(0, ContextualKeyword::Tag)
}
fn at_policy_object_kind(p: &Parser) -> bool {
(p.nth_contextual(0, ContextualKeyword::Masking)
&& p.nth_contextual(1, ContextualKeyword::Policy))
|| (p.at(ROW_KW)
&& p.nth_contextual(1, ContextualKeyword::Access)
&& p.nth_contextual(2, ContextualKeyword::Policy))
}
fn create_object(p: &mut Parser) {
object_kind_words(p);
if_exists_clause(p);
if p.at_name() {
name_ref(p);
}
if p.at(L_PAREN) {
column_def_list(p);
}
p.eat(WITH_KW); object_property_region(p);
if at_create_body(p) {
p.bump(AS_KW);
create_body(p);
}
}
fn object_kind_words(p: &mut Parser) {
if p.nth_contextual(0, ContextualKeyword::File) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.nth_contextual(0, ContextualKeyword::Format) {
p.bump_as(CONTEXTUAL_KEYWORD); }
} else if p.nth_contextual(0, ContextualKeyword::Dynamic) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(TABLE_KW) {
p.bump(TABLE_KW);
}
} else if p.nth_contextual(0, ContextualKeyword::Semantic) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(VIEW_KW) {
p.bump(VIEW_KW);
}
} else if p.nth_contextual(0, ContextualKeyword::Tag) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else if p.at_keyword() {
p.bump_any();
} else {
p.bump_as(CONTEXTUAL_KEYWORD);
}
}
fn create_policy(p: &mut Parser) {
policy_kind_words(p);
if_exists_clause(p);
if p.at_name() {
name_ref(p);
}
while !at_stmt_terminator(p) {
bump_ddl_word(p);
}
}
fn policy_kind_words(p: &mut Parser) {
if p.nth_contextual(0, ContextualKeyword::Masking) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.nth_contextual(0, ContextualKeyword::Policy) {
p.bump_as(CONTEXTUAL_KEYWORD); }
} else {
p.bump(ROW_KW);
if p.nth_contextual(0, ContextualKeyword::Access) {
p.bump_as(CONTEXTUAL_KEYWORD); }
if p.nth_contextual(0, ContextualKeyword::Policy) {
p.bump_as(CONTEXTUAL_KEYWORD); }
}
}
fn object_property_region(p: &mut Parser) {
while !at_create_body(p) && !at_stmt_terminator(p) {
if p.dialect().supports_semantic_view() && at_semantic_view_clause_start(p) {
semantic_view_clause(p);
} else if p.at(ON_KW) {
stream_source(p);
} else if p.at(AFTER_KW) {
task_after(p);
} else if p.at(WHEN_KW) {
let m = p.start();
p.bump(WHEN_KW);
expr(p);
m.complete(p, OBJECT_PROPERTY);
} else {
object_property(p);
}
}
}
fn semantic_view_clause(p: &mut Parser) {
let m = p.start();
if p.at(WITH_KW) {
p.bump(WITH_KW);
if p.nth_contextual(0, ContextualKeyword::Tag) {
p.bump_as(CONTEXTUAL_KEYWORD);
}
if p.at(L_PAREN) {
semantic_view_paren_list(p);
}
} else if p.at(COPY_KW) {
p.bump(COPY_KW);
p.eat(GRANTS_KW);
} else {
semantic_view_word(p);
if p.at(L_PAREN) {
semantic_view_paren_list(p);
} else if !at_semantic_view_clause_start(p)
&& !p.at(SEMICOLON)
&& !p.at_eof()
&& !at_create_body(p)
{
semantic_view_word(p);
}
}
m.complete(p, SEMANTIC_VIEW_CLAUSE);
}
fn at_semantic_view_clause_start(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::Tables)
|| p.nth_contextual(0, ContextualKeyword::Relationships)
|| p.nth_contextual(0, ContextualKeyword::Facts)
|| p.nth_contextual(0, ContextualKeyword::Dimensions)
|| p.nth_contextual(0, ContextualKeyword::Metrics)
|| p.nth_contextual(0, ContextualKeyword::AiSqlGeneration)
|| p.nth_contextual(0, ContextualKeyword::AiQuestionCategorization)
|| p.nth_contextual(0, ContextualKeyword::AiVerifiedQueries)
|| (p.at(WITH_KW) && p.nth_contextual(1, ContextualKeyword::Tag))
|| (p.at(COPY_KW) && p.nth_at(1, GRANTS_KW))
}
fn semantic_view_paren_list(p: &mut Parser) {
p.bump(L_PAREN);
if !p.at(R_PAREN) {
semantic_view_item(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
semantic_view_item(p);
}
}
p.expect(R_PAREN);
}
fn semantic_view_item(p: &mut Parser) {
let m = p.start();
let mut depth = 0u32;
while !p.at_eof() {
if depth == 0 && (p.at(COMMA) || p.at(R_PAREN)) {
break;
}
if p.at(L_PAREN) {
depth += 1;
p.bump(L_PAREN);
} else if p.at(R_PAREN) {
depth -= 1;
p.bump(R_PAREN);
} else {
semantic_view_word(p);
}
}
m.complete(p, SEMANTIC_VIEW_ITEM);
}
fn semantic_view_word(p: &mut Parser) {
if is_semantic_view_contextual_word(p) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}
fn is_semantic_view_contextual_word(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::Tables)
|| p.nth_contextual(0, ContextualKeyword::Relationships)
|| p.nth_contextual(0, ContextualKeyword::Facts)
|| p.nth_contextual(0, ContextualKeyword::Dimensions)
|| p.nth_contextual(0, ContextualKeyword::Metrics)
|| p.nth_contextual(0, ContextualKeyword::Public)
|| p.nth_contextual(0, ContextualKeyword::Private)
|| p.nth_contextual(0, ContextualKeyword::Primary)
|| p.nth_contextual(0, ContextualKeyword::Key)
|| p.nth_contextual(0, ContextualKeyword::References)
|| p.nth_contextual(0, ContextualKeyword::Synonyms)
|| p.nth_contextual(0, ContextualKeyword::Labels)
|| p.nth_contextual(0, ContextualKeyword::AiSqlGeneration)
|| p.nth_contextual(0, ContextualKeyword::AiQuestionCategorization)
|| p.nth_contextual(0, ContextualKeyword::AiVerifiedQueries)
|| p.nth_contextual(0, ContextualKeyword::Question)
|| p.nth_contextual(0, ContextualKeyword::VerifiedAt)
|| p.nth_contextual(0, ContextualKeyword::OnboardingQuestion)
|| p.nth_contextual(0, ContextualKeyword::VerifiedBy)
|| p.nth_contextual(0, ContextualKeyword::Tag)
}
fn object_property(p: &mut Parser) {
let m = p.start();
let is_allowed_values = p.nth_contextual(0, ContextualKeyword::AllowedValues);
if is_allowed_values {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any(); }
if p.eat(EQ) {
if p.at(L_PAREN) {
balanced_parens(p); } else if !at_create_body(p) && !at_stmt_terminator(p) {
p.bump_any(); }
while at_property_value_tail(p) {
p.bump_any();
}
} else if is_allowed_values {
while at_allowed_values_tail(p) {
p.bump_any();
}
} else {
while at_property_value_tail(p) {
p.bump_any();
}
}
m.complete(p, OBJECT_PROPERTY);
}
fn at_allowed_values_tail(p: &Parser) -> bool {
if p.at(COMMA) {
return true;
}
let starts_new_property = p.nth_at(1, EQ);
!starts_new_property
&& !p.at(SEMICOLON)
&& !p.at(ON_KW)
&& !p.at(AFTER_KW)
&& !p.at(WHEN_KW)
&& !at_create_body(p)
&& !p.at_eof()
&& (p.at(STRING) || p.at(INT_NUMBER) || p.at(FLOAT_NUMBER))
}
fn at_property_value_tail(p: &Parser) -> bool {
if p.at(WITH_KW) || p.at(BY_KW) {
return true;
}
let starts_new_property = p.nth_at(1, EQ);
!starts_new_property
&& !p.at(SEMICOLON)
&& !p.at(ON_KW)
&& !p.at(AFTER_KW)
&& !p.at(WHEN_KW)
&& !at_create_body(p)
&& !p.at_eof()
&& (p.at(INT_NUMBER) || p.at(FLOAT_NUMBER) || p.at(STRING) || p.at(VARIABLE))
}
fn stream_source(p: &mut Parser) {
let m = p.start();
p.bump(ON_KW);
if p.at(TABLE_KW) || p.at(VIEW_KW) {
p.bump_any();
} else if p.nth_contextual(0, ContextualKeyword::Stage) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else if p.at_keyword() {
p.bump_any();
}
if p.at_name() {
name_ref(p);
}
if p.nth_contextual(0, ContextualKeyword::At) || p.nth_contextual(0, ContextualKeyword::Before)
{
p.bump_as(CONTEXTUAL_KEYWORD);
if p.at(L_PAREN) {
balanced_parens(p);
}
}
m.complete(p, STREAM_SOURCE);
}
fn task_after(p: &mut Parser) {
let m = p.start();
p.bump(AFTER_KW);
if p.at_name() {
name_ref(p);
while p.eat(COMMA) {
if p.at_name() {
name_ref(p);
} else {
break;
}
}
}
m.complete(p, TASK_AFTER);
}
fn create_body(p: &mut Parser) {
if p.at(SELECT_KW)
|| p.at(WITH_KW)
|| p.at(VALUES_KW)
|| (p.at(L_PAREN) && (p.nth_at(1, SELECT_KW) || p.nth_at(1, WITH_KW)))
{
query_expr(p);
} else if p.at(INSERT_KW) {
dml::insert_stmt(p);
} else if p.at(UPDATE_KW) {
dml::update_stmt(p);
} else if p.at(DELETE_KW) {
dml::delete_stmt(p);
} else if p.at(MERGE_KW) {
dml::merge_stmt(p);
} else if p.at(CALL_KW) {
call_stmt(p);
} else if at_block_start(p) {
block_stmt(p);
} else if !at_stmt_terminator(p) {
let m = p.start();
expr(p);
m.complete(p, EXPR_STMT);
}
}
fn create_other(p: &mut Parser) {
while !at_stmt_terminator(p) {
if at_create_body(p) {
p.error("CREATE ... AS <body> is not yet formatted; left verbatim");
while !at_stmt_terminator(p) {
p.bump_any();
}
return;
}
p.bump_any();
}
}
fn grant_stmt(p: &mut Parser) {
let m = p.start();
p.bump(GRANT_KW);
priv_list(p, |p| p.at(ON_KW) || at_to(p));
if p.at(ON_KW) {
grant_target(p);
}
if at_to(p) {
grantee(p, GranteeIntro::To);
}
grant_tail(p);
m.complete(p, GRANT_STMT);
}
fn at_to(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::To)
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum GranteeIntro {
To,
From,
}
fn revoke_stmt(p: &mut Parser) {
let m = p.start();
p.bump(REVOKE_KW);
if p.at(GRANT_KW) && p.nth_contextual(1, ContextualKeyword::Option) {
p.bump(GRANT_KW);
p.bump_as(CONTEXTUAL_KEYWORD); p.eat(FOR_KW);
}
priv_list(p, |p| p.at(ON_KW) || p.at(FROM_KW));
if p.at(ON_KW) {
grant_target(p);
}
if p.at(FROM_KW) {
grantee(p, GranteeIntro::From);
}
grant_tail(p);
m.complete(p, REVOKE_STMT);
}
fn priv_list(p: &mut Parser, stop: impl Fn(&Parser) -> bool) {
let m = p.start();
while !stop(p) && !at_to(p) && !at_stmt_terminator(p) {
if p.at(COMMA) {
p.bump(COMMA);
} else if p.nth_contextual(0, ContextualKeyword::Privileges) {
p.bump_as(CONTEXTUAL_KEYWORD); } else {
p.bump_any();
}
}
m.complete(p, PRIV_LIST);
}
fn grant_target(p: &mut Parser) {
let m = p.start();
p.bump(ON_KW);
while !at_to(p) && !p.at(FROM_KW) && !at_grant_tail(p) && !at_stmt_terminator(p) {
if at_object_type_word(p) {
p.bump_as(CONTEXTUAL_KEYWORD); } else {
p.bump_any();
}
}
m.complete(p, GRANT_TARGET);
}
fn at_object_type_word(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::Schema)
|| p.nth_contextual(0, ContextualKeyword::Database)
|| p.nth_contextual(0, ContextualKeyword::Stage)
|| p.nth_contextual(0, ContextualKeyword::Sequence)
|| p.nth_contextual(0, ContextualKeyword::Stream)
}
fn grantee(p: &mut Parser, intro: GranteeIntro) {
let m = p.start();
match intro {
GranteeIntro::To => {
if at_to(p) {
p.bump_as(CONTEXTUAL_KEYWORD);
}
}
GranteeIntro::From => p.expect(FROM_KW),
}
while at_grantee_kind(p) {
p.bump_as(CONTEXTUAL_KEYWORD);
}
if p.at_name() {
name_ref(p);
}
m.complete(p, GRANTEE);
}
fn at_grantee_kind(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::Role)
|| p.nth_contextual(0, ContextualKeyword::User)
|| p.nth_contextual(0, ContextualKeyword::Share)
|| p.nth_contextual(0, ContextualKeyword::Database)
}
fn grant_tail(p: &mut Parser) {
while !at_stmt_terminator(p) {
if p.nth_contextual(0, ContextualKeyword::Option)
|| p.nth_contextual(0, ContextualKeyword::Cascade)
|| p.nth_contextual(0, ContextualKeyword::Restrict)
{
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}
}
fn at_grant_tail(p: &Parser) -> bool {
p.at(WITH_KW)
|| p.nth_contextual(0, ContextualKeyword::Cascade)
|| p.nth_contextual(0, ContextualKeyword::Restrict)
}
fn at_create_body(p: &Parser) -> bool {
p.at(AS_KW)
&& (p.nth_at(1, SELECT_KW)
|| p.nth_at(1, WITH_KW)
|| p.nth_at(1, VALUES_KW)
|| p.nth_at(1, INSERT_KW)
|| p.nth_at(1, UPDATE_KW)
|| p.nth_at(1, DELETE_KW)
|| p.nth_at(1, MERGE_KW)
|| p.nth_at(1, CALL_KW)
|| p.nth_at(1, BEGIN_KW)
|| p.nth_at(1, L_PAREN))
}
fn create_routine(p: &mut Parser) {
p.bump_any(); name_ref(p);
if p.at(L_PAREN) {
column_def_list(p); }
while !at_routine_body(p) && !at_stmt_terminator(p) {
p.bump_any();
}
if at_routine_body(p) {
p.bump(AS_KW);
if p.at(DOLLAR_STRING) || p.at(STRING) {
p.bump_any(); } else if at_block_start(p) {
block_stmt(p);
}
} else {
p.error("expected a routine body (AS $$ … $$, AS '…', or AS BEGIN … END)");
}
}
fn at_routine_body(p: &Parser) -> bool {
p.at(AS_KW)
&& (p.nth_at(1, DOLLAR_STRING)
|| p.nth_at(1, STRING)
|| p.nth_at(1, DECLARE_KW)
|| (p.nth_at(1, BEGIN_KW)
&& !p.nth_at(2, SEMICOLON)
&& !p.nth_contextual(2, ContextualKeyword::Transaction)
&& !p.nth_contextual(2, ContextualKeyword::Work)))
}
fn copy_stmt(p: &mut Parser) {
let m = p.start();
p.bump(COPY_KW);
p.expect(INTO_KW);
copy_operand(p);
if p.eat(FROM_KW) {
copy_operand(p);
}
while !at_stmt_terminator(p) {
copy_option(p);
}
m.complete(p, COPY_STMT);
}
fn stage_ref(p: &mut Parser) {
let m = p.start();
p.bump(AT); p.eat(TILDE); p.eat(PERCENT); eat_stage_atom(p); while p.at(DOT) || p.at(SLASH) {
p.bump_any(); while eat_stage_atom(p) {}
}
m.complete(p, STAGE_REF);
}
fn eat_stage_atom(p: &mut Parser) -> bool {
if p.at(IDENT)
|| p.at(QUOTED_IDENT)
|| p.at(INT_NUMBER)
|| p.at(FLOAT_NUMBER)
|| p.at(TILDE)
|| p.at(PERCENT)
{
p.bump_any();
true
} else {
false
}
}
fn copy_operand(p: &mut Parser) {
if p.at(L_PAREN) {
subquery(p);
return;
}
let m = p.start();
while !p.at(FROM_KW) && !at_stmt_terminator(p) && !at_copy_option_start(p) {
p.bump_any();
}
m.complete(p, COPY_LOCATION);
}
fn at_copy_option_start(p: &Parser) -> bool {
p.at(PARTITION_KW) || p.nth_at(1, EQ)
}
fn copy_option(p: &mut Parser) {
let m = p.start();
if p.at(PARTITION_KW) {
p.bump(PARTITION_KW);
p.expect(BY_KW);
if p.at(L_PAREN) {
balanced_parens(p);
}
} else {
p.bump_any(); if p.eat(EQ) {
if p.at(L_PAREN) {
balanced_parens(p);
} else if !at_stmt_terminator(p) {
p.bump_any(); }
}
}
m.complete(p, COPY_OPTION);
}
fn set_stmt(p: &mut Parser) {
let m = p.start();
p.bump(SET_KW);
if p.at(L_PAREN) {
column_list(p);
} else {
name_ref(p);
}
p.expect(EQ);
if p.at(L_PAREN) {
p.bump(L_PAREN);
if p.at(SELECT_KW) || p.at(WITH_KW) {
query_expr(p);
} else if !p.at(R_PAREN) {
expr_list(p);
}
p.expect(R_PAREN);
} else {
expr(p);
}
m.complete(p, SET_STMT);
}
fn execute_stmt(p: &mut Parser) {
let m = p.start();
p.bump(EXECUTE_KW);
p.expect(IMMEDIATE_KW);
expr(p);
if p.eat(USING_KW) {
if p.at(L_PAREN) {
p.bump(L_PAREN);
if !p.at(R_PAREN) {
expr_list(p);
}
p.expect(R_PAREN);
} else {
expr(p);
while p.eat(COMMA) {
expr(p);
}
}
}
m.complete(p, EXECUTE_STMT);
}
fn create_view(p: &mut Parser) {
p.bump(VIEW_KW);
if_exists_clause(p);
name_ref(p);
if p.at(L_PAREN) {
column_list(p);
}
while !p.at(AS_KW) && !p.at(SELECT_KW) && !p.at(WITH_KW) && !at_stmt_terminator(p) {
bump_ddl_word(p);
}
p.eat(AS_KW);
if p.at(SELECT_KW) || p.at(WITH_KW) || p.at(VALUES_KW) || p.at(L_PAREN) {
query_expr(p);
}
}
fn create_table(p: &mut Parser) {
p.bump(TABLE_KW);
if_exists_clause(p);
name_ref(p);
if p.at(L_PAREN) {
column_def_list(p);
}
if p.nth_contextual(0, ContextualKeyword::Clone) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at_name() {
name_ref(p);
}
}
while !p.at(AS_KW) && !at_stmt_terminator(p) {
if p.dialect().supports_delta_table_options() && at_databricks_table_option(p) {
databricks_table_option(p);
} else {
bump_ddl_word(p);
}
}
if p.eat(AS_KW) {
query_expr(p);
}
}
fn at_databricks_table_option(p: &Parser) -> bool {
p.at(USING_KW)
|| p.nth_contextual(0, ContextualKeyword::Location)
|| p.nth_contextual(0, ContextualKeyword::Tblproperties)
|| p.nth_contextual(0, ContextualKeyword::Options)
|| (p.nth_contextual(0, ContextualKeyword::Partitioned) && p.nth_at(1, BY_KW))
|| (p.nth_contextual(0, ContextualKeyword::Cluster) && p.nth_at(1, BY_KW))
}
fn databricks_table_option(p: &mut Parser) {
let m = p.start();
if p.at(USING_KW) {
p.bump(USING_KW);
if p.at_name() {
name_ref(p);
} else if !at_databricks_table_option_stop(p) {
p.bump_any();
}
} else if p.nth_contextual(0, ContextualKeyword::Location) {
p.bump_as(CONTEXTUAL_KEYWORD);
if !at_databricks_table_option_stop(p) {
p.bump_any();
}
} else if p.nth_contextual(0, ContextualKeyword::Tblproperties)
|| p.nth_contextual(0, ContextualKeyword::Options)
{
p.bump_as(CONTEXTUAL_KEYWORD);
if p.at(L_PAREN) {
balanced_parens(p);
} else {
databricks_table_option_tail(p);
}
} else if p.nth_contextual(0, ContextualKeyword::Partitioned)
|| p.nth_contextual(0, ContextualKeyword::Cluster)
{
p.bump_as(CONTEXTUAL_KEYWORD);
p.expect(BY_KW);
if p.at(L_PAREN) {
balanced_parens(p);
} else {
databricks_table_option_tail(p);
}
} else {
bump_ddl_word(p);
}
m.complete(p, OBJECT_PROPERTY);
}
fn databricks_table_option_tail(p: &mut Parser) {
while !at_databricks_table_option_stop(p) && !at_databricks_table_option(p) {
if p.at(L_PAREN) {
balanced_parens(p);
} else {
bump_ddl_word(p);
}
}
}
fn at_databricks_table_option_stop(p: &Parser) -> bool {
p.at(AS_KW) || at_stmt_terminator(p)
}
fn column_def_list(p: &mut Parser) {
let m = p.start();
p.bump(L_PAREN);
if !p.at(R_PAREN) {
column_def(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
column_def(p);
}
}
p.expect(R_PAREN);
m.complete(p, COLUMN_DEF_LIST);
}
fn column_def(p: &mut Parser) {
let m = p.start();
let starts_with_constraint = p.nth_contextual(0, ContextualKeyword::Constraint)
|| p.nth_contextual(0, ContextualKeyword::Primary)
|| p.nth_contextual(0, ContextualKeyword::Unique)
|| p.nth_contextual(0, ContextualKeyword::Foreign)
|| p.nth_contextual(0, ContextualKeyword::Check);
if !starts_with_constraint && !p.at(COMMA) && !p.at(R_PAREN) && !p.at_eof() {
p.bump_any(); }
let mut depth = 0u32;
while !p.at_eof() {
if depth == 0 && (p.at(COMMA) || p.at(R_PAREN)) {
break;
}
if p.at(L_PAREN) {
depth += 1;
p.bump_any();
} else if p.at(R_PAREN) {
depth -= 1;
p.bump_any();
} else {
bump_ddl_word(p);
}
}
m.complete(p, COLUMN_DEF);
}
fn bump_ddl_word(p: &mut Parser) {
if p.at_keyword() {
p.bump_any(); } else if is_ddl_contextual_word(p) {
p.bump_as(CONTEXTUAL_KEYWORD); } else {
p.bump_any();
}
}
fn is_ddl_contextual_word(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::Default)
|| p.nth_contextual(0, ContextualKeyword::Primary)
|| p.nth_contextual(0, ContextualKeyword::Key)
|| p.nth_contextual(0, ContextualKeyword::Unique)
|| p.nth_contextual(0, ContextualKeyword::Foreign)
|| p.nth_contextual(0, ContextualKeyword::References)
|| p.nth_contextual(0, ContextualKeyword::Constraint)
|| p.nth_contextual(0, ContextualKeyword::Check)
|| p.nth_contextual(0, ContextualKeyword::Collate)
|| p.nth_contextual(0, ContextualKeyword::Comment)
|| p.nth_contextual(0, ContextualKeyword::Cluster)
|| p.nth_contextual(0, ContextualKeyword::Clone)
|| p.nth_contextual(0, ContextualKeyword::Cascade)
|| p.nth_contextual(0, ContextualKeyword::Restrict)
|| p.nth_contextual(0, ContextualKeyword::Materialized)
|| p.nth_contextual(0, ContextualKeyword::Masking)
|| p.nth_contextual(0, ContextualKeyword::Policy)
|| p.nth_contextual(0, ContextualKeyword::Access)
|| p.nth_contextual(0, ContextualKeyword::Tag)
|| p.nth_contextual(0, ContextualKeyword::AllowedValues)
|| p.nth_contextual(0, ContextualKeyword::Propagate)
|| p.nth_contextual(0, ContextualKeyword::ExemptOtherPolicies)
}
fn drop_stmt(p: &mut Parser) {
let m = p.start();
p.bump(DROP_KW);
if !at_stmt_terminator(p) {
p.bump_any();
}
if_exists_clause(p);
if p.at_name() {
name_ref(p);
}
while !at_stmt_terminator(p) {
bump_ddl_word(p);
}
m.complete(p, DROP_STMT);
}
fn alter_stmt(p: &mut Parser) {
let m = p.start();
p.bump(ALTER_KW);
while !at_stmt_terminator(p) {
p.bump_any();
}
m.complete(p, ALTER_STMT);
}
fn lenient_stmt(p: &mut Parser, node: SyntaxKind) {
let m = p.start();
p.bump_any(); while !at_stmt_terminator(p) {
p.bump_any();
}
m.complete(p, node);
}
fn at_comment_stmt(p: &Parser) -> bool {
p.nth_contextual(0, ContextualKeyword::Comment) && p.nth_at(1, ON_KW)
}
fn at_begin_transaction(p: &Parser) -> bool {
p.at(BEGIN_KW)
&& (p.nth_at(1, SEMICOLON)
|| p.nth_contextual(1, ContextualKeyword::Transaction)
|| p.nth_contextual(1, ContextualKeyword::Work))
}
fn comment_stmt(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); while !at_stmt_terminator(p) {
p.bump_any();
}
m.complete(p, COMMENT_STMT);
}
fn call_stmt(p: &mut Parser) {
let m = p.start();
p.bump(CALL_KW);
expr(p); while !at_stmt_terminator(p) {
p.bump_any();
}
m.complete(p, CALL_STMT);
}
fn at_block_start(p: &Parser) -> bool {
p.at(DECLARE_KW) || (p.at(BEGIN_KW) && !at_begin_transaction(p))
}
fn block_stmt(p: &mut Parser) {
let m = p.start();
if p.at(DECLARE_KW) {
declare_section(p);
}
p.expect(BEGIN_KW);
stmt_list(p, |p| p.at(END_KW) || p.at(EXCEPTION_KW));
if p.at(EXCEPTION_KW) {
exception_section(p);
}
p.expect(END_KW);
if p.at_name() {
name_ref(p); }
m.complete(p, BLOCK_STMT);
}
fn declare_section(p: &mut Parser) {
let m = p.start();
p.bump(DECLARE_KW);
while !p.at(BEGIN_KW) && !p.at_eof() {
if p.eat(SEMICOLON) {
continue;
}
declare_item(p);
p.eat(SEMICOLON);
}
m.complete(p, DECLARE_SECTION);
}
fn declare_item(p: &mut Parser) {
let m = p.start();
let mut first = true;
while !p.at(SEMICOLON) && !p.at(BEGIN_KW) && !p.at_eof() {
if !first && p.nth_contextual(0, ContextualKeyword::Default) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
first = false;
}
m.complete(p, DECLARE_ITEM);
}
fn stmt_list(p: &mut Parser, is_end: impl Fn(&Parser) -> bool) {
let m = p.start();
while !is_end(p) && !p.at_eof() {
if p.eat(SEMICOLON) {
continue; }
block_statement(p);
p.eat(SEMICOLON);
}
m.complete(p, STMT_LIST);
}
fn block_statement(p: &mut Parser) {
if p.at(IF_KW) {
if_stmt(p);
} else if p.at(FOR_KW) || p.at(WHILE_KW) || p.at(LOOP_KW) || p.at(REPEAT_KW) {
loop_stmt(p);
} else if at_block_start(p) {
block_stmt(p); } else if p.at(CASE_KW) {
case_stmt(p);
} else if p.at(LET_KW) {
simple_script_stmt(p, LET_STMT);
} else if p.at(RETURN_KW) {
simple_script_stmt(p, RETURN_STMT);
} else if at_sql_statement_start(p) {
stmt::statement(p);
} else if p.at_name() && p.nth_at(1, ASSIGN) {
simple_script_stmt(p, ASSIGN_STMT);
} else {
simple_script_stmt(p, SCRIPT_STMT);
}
}
fn at_sql_statement_start(p: &Parser) -> bool {
p.at(WITH_KW)
|| p.at(SELECT_KW)
|| p.at(VALUES_KW)
|| p.at(INSERT_KW)
|| p.at(UPDATE_KW)
|| p.at(DELETE_KW)
|| p.at(MERGE_KW)
|| p.at(CREATE_KW)
|| p.at(DROP_KW)
|| p.at(ALTER_KW)
|| p.at(GRANT_KW)
|| p.at(REVOKE_KW)
|| p.at(USE_KW)
|| p.at(SHOW_KW)
|| p.at(DESCRIBE_KW)
|| p.at(DESC_KW)
|| p.at(TRUNCATE_KW)
|| p.at(COMMIT_KW)
|| p.at(ROLLBACK_KW)
|| p.at(UNDROP_KW)
|| at_comment_stmt(p)
|| p.at(CALL_KW)
|| p.at(SET_KW)
|| p.at(EXECUTE_KW)
|| p.at(COPY_KW)
|| at_begin_transaction(p)
}
fn simple_script_stmt(p: &mut Parser, node: SyntaxKind) {
let m = p.start();
let mut first = true;
while !p.at(SEMICOLON) && !p.at_eof() {
let up = if first {
p.nth_contextual(0, ContextualKeyword::Break)
|| p.nth_contextual(0, ContextualKeyword::Continue)
} else {
p.nth_contextual(0, ContextualKeyword::Default) && !p.nth_at(1, ASSIGN)
};
if up {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
first = false;
}
m.complete(p, node);
}
fn if_stmt(p: &mut Parser) {
let m = p.start();
p.bump(IF_KW);
expr(p); p.expect(THEN_KW);
stmt_list(p, |p| p.at(ELSEIF_KW) || p.at(ELSE_KW) || p.at(END_KW));
while p.at(ELSEIF_KW) {
p.bump(ELSEIF_KW);
expr(p);
p.expect(THEN_KW);
stmt_list(p, |p| p.at(ELSEIF_KW) || p.at(ELSE_KW) || p.at(END_KW));
}
if p.eat(ELSE_KW) {
stmt_list(p, |p| p.at(END_KW));
}
p.expect(END_KW);
p.expect(IF_KW);
m.complete(p, IF_STMT);
}
fn case_stmt(p: &mut Parser) {
let m = p.start();
p.bump(CASE_KW);
if !p.at(WHEN_KW) {
expr(p); }
while p.at(WHEN_KW) {
let arm = p.start();
p.bump(WHEN_KW);
expr(p);
p.expect(THEN_KW);
stmt_list(p, |p| p.at(WHEN_KW) || p.at(ELSE_KW) || p.at(END_KW));
arm.complete(p, CASE_STMT_WHEN);
}
if p.eat(ELSE_KW) {
stmt_list(p, |p| p.at(END_KW));
}
p.expect(END_KW);
p.eat(CASE_KW); m.complete(p, CASE_STMT);
}
fn loop_stmt(p: &mut Parser) {
let m = p.start();
if p.at(FOR_KW) || p.at(WHILE_KW) {
p.bump_any(); while !p.at(DO_KW) && !p.at(SEMICOLON) && !p.at(END_KW) && !p.at_eof() {
if p.nth_contextual(0, ContextualKeyword::Reverse)
|| p.nth_contextual(0, ContextualKeyword::To)
{
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any(); }
}
p.expect(DO_KW);
stmt_list(p, |p| p.at(END_KW));
} else if p.at(LOOP_KW) {
p.bump(LOOP_KW);
stmt_list(p, |p| p.at(END_KW));
} else {
p.bump(REPEAT_KW);
stmt_list(p, |p| p.at(UNTIL_KW) || p.at(END_KW));
if p.eat(UNTIL_KW) {
expr(p); while !p.at(END_KW) && !p.at(SEMICOLON) && !p.at_eof() {
p.bump_any();
}
}
}
p.expect(END_KW);
if p.at(FOR_KW) || p.at(WHILE_KW) || p.at(LOOP_KW) || p.at(REPEAT_KW) {
p.bump_any();
}
m.complete(p, LOOP_STMT);
}
fn exception_section(p: &mut Parser) {
let m = p.start();
p.bump(EXCEPTION_KW);
while p.at(WHEN_KW) {
exception_when(p);
}
m.complete(p, EXCEPTION_SECTION);
}
fn exception_when(p: &mut Parser) {
let m = p.start();
p.bump(WHEN_KW);
while !p.at(THEN_KW) && !p.at(WHEN_KW) && !p.at(END_KW) && !p.at_eof() {
p.bump_any(); }
p.expect(THEN_KW);
stmt_list(p, |p| p.at(WHEN_KW) || p.at(END_KW));
m.complete(p, EXCEPTION_WHEN);
}
fn with_query(p: &mut Parser) -> CompletedMarker {
let m = p.start();
with_clause(p);
query_expr(p);
m.complete(p, WITH_QUERY)
}
fn with_clause(p: &mut Parser) {
let m = p.start();
p.bump(WITH_KW);
p.eat(RECURSIVE_KW);
cte(p);
while p.eat(COMMA) {
cte(p);
}
m.complete(p, WITH_CLAUSE);
}
fn cte(p: &mut Parser) {
let m = p.start();
name(p);
if p.at(L_PAREN) {
column_list(p);
}
p.expect(AS_KW);
subquery(p);
m.complete(p, CTE);
}
fn query_expr(p: &mut Parser) -> Option<CompletedMarker> {
let mut lhs = query_primary(p)?;
while p.at(UNION_KW) || p.at(EXCEPT_KW) || p.at(INTERSECT_KW) || p.at(MINUS_KW) {
let m = lhs.precede(p);
p.bump_any(); if p.at(ALL_KW) {
p.bump(ALL_KW);
} else if p.at(DISTINCT_KW) {
p.bump(DISTINCT_KW);
}
query_primary(p);
lhs = m.complete(p, SET_OP);
}
Some(lhs)
}
fn query_primary(p: &mut Parser) -> Option<CompletedMarker> {
if p.at(L_PAREN) {
Some(subquery(p))
} else if p.at(SELECT_KW) {
Some(select_core(p))
} else if p.at(WITH_KW) {
Some(with_query(p)) } else if p.at(VALUES_KW) {
Some(values_clause(p))
} else {
p.error("expected a query (SELECT, VALUES, WITH, or a parenthesized subquery)");
None
}
}
fn subquery(p: &mut Parser) -> CompletedMarker {
let m = p.start();
p.expect(L_PAREN);
query_expr(p);
p.expect(R_PAREN);
m.complete(p, SUBQUERY)
}
fn select_core(p: &mut Parser) -> CompletedMarker {
let m = p.start();
if p.at(SELECT_KW) {
p.bump(SELECT_KW);
} else {
p.error("expected SELECT");
}
if p.at(DISTINCT_KW) {
p.bump(DISTINCT_KW);
} else if p.at(ALL_KW) {
p.bump(ALL_KW);
}
select_list(p);
if p.at(FROM_KW) {
from_clause(p);
}
if p.at(WHERE_KW) {
where_clause(p);
}
while p.at(START_KW) || p.at(CONNECT_KW) {
if p.at(START_KW) {
start_with_clause(p);
} else {
connect_by_clause(p);
}
}
if p.at(GROUP_KW) {
group_by_clause(p);
}
if p.at(HAVING_KW) {
having_clause(p);
}
if p.at(QUALIFY_KW) {
qualify_clause(p);
}
if p.at(ORDER_KW) {
order_by_clause(p);
}
if p.at(LIMIT_KW) {
limit_clause(p);
}
if p.at(OFFSET_KW) {
offset_clause(p);
}
m.complete(p, SELECT_STMT)
}
fn select_list(p: &mut Parser) {
let m = p.start();
select_item(p);
while p.eat(COMMA) {
if p.at_eof() {
p.error("expected a select item after ','");
break;
}
if at_clause_end(p) {
break; }
select_item(p);
}
m.complete(p, SELECT_LIST);
}
fn at_clause_end(p: &Parser) -> bool {
p.at(FROM_KW)
|| p.at(WHERE_KW)
|| p.at(GROUP_KW)
|| p.at(HAVING_KW)
|| p.at(QUALIFY_KW)
|| p.at(ORDER_KW)
|| p.at(LIMIT_KW)
|| p.at(OFFSET_KW)
}
fn select_item(p: &mut Parser) {
let m = p.start();
if p.at(STAR) {
let s = p.start();
p.bump(STAR);
s.complete(p, STAR_EXPR);
} else if at_expr_start(p) {
expr(p);
let explicit_alias = p.eat(AS_KW);
if explicit_alias || p.at_name() {
name(p); }
} else {
p.error("expected a select item");
}
m.complete(p, SELECT_ITEM);
}
fn from_clause(p: &mut Parser) {
let m = p.start();
p.bump(FROM_KW);
table_ref(p);
loop {
if p.dialect().supports_lateral_view() && at_lateral_view(p) {
lateral_view(p);
} else if at_join_start(p) {
join(p);
} else if p.eat(COMMA) {
table_ref(p);
} else {
break;
}
}
m.complete(p, FROM_CLAUSE);
}
fn table_ref(p: &mut Parser) {
let m = p.start();
p.eat(LATERAL_KW); if p.at(L_PAREN) {
subquery(p); } else if p.at(VALUES_KW) {
values_clause(p); } else if p.at(FLATTEN_KW) || p.at(TABLE_KW) {
p.bump_any();
if p.at(L_PAREN) {
arg_list(p);
} else {
p.error("expected '(' after table function");
}
} else if p.at(VARIABLE) {
let r = p.start();
p.bump(VARIABLE);
r.complete(p, NAME_REF);
} else if p.at(AT) {
stage_ref(p);
if p.at(L_PAREN) {
arg_list(p); }
} else if p.at_name() {
name_ref(p);
if p.at(L_PAREN) {
arg_list(p); }
} else {
p.error("expected a table reference");
}
if p.nth_contextual(0, ContextualKeyword::Changes) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(L_PAREN) {
balanced_parens(p);
}
}
if at_time_travel(p) {
time_travel(p);
}
if p.dialect().supports_as_of_travel() && at_databricks_as_of_travel(p) {
databricks_as_of_travel(p);
}
if p.at(END_KW) && p.nth_at(1, L_PAREN) {
p.bump(END_KW); balanced_parens(p);
}
if p.at(SAMPLE_KW) || p.at(TABLESAMPLE_KW) {
sample_clause(p);
}
if p.nth_contextual(0, ContextualKeyword::MatchRecognize) {
match_recognize(p);
}
while p.at(PIVOT_KW) || p.at(UNPIVOT_KW) {
pivot_clause(p);
}
table_alias(p);
m.complete(p, TABLE_REF);
}
fn at_lateral_view(p: &Parser) -> bool {
p.at(LATERAL_KW) && p.nth_at(1, VIEW_KW)
}
fn lateral_view(p: &mut Parser) {
let m = p.start();
p.bump(LATERAL_KW);
p.expect(VIEW_KW);
p.eat(OUTER_KW);
if at_expr_start(p) {
expr(p);
} else {
p.error("expected a generator expression after LATERAL VIEW");
}
if p.at_name() {
name(p);
}
p.eat(AS_KW);
if p.at_name() {
name(p);
while p.eat(COMMA) {
if p.at_name() {
name(p);
} else {
p.error("expected a column alias after ','");
break;
}
}
}
m.complete(p, LATERAL_VIEW);
}
fn at_time_travel(p: &Parser) -> bool {
(p.nth_contextual(0, ContextualKeyword::At) || p.nth_contextual(0, ContextualKeyword::Before))
&& p.nth_at(1, L_PAREN)
}
fn time_travel(p: &mut Parser) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(L_PAREN) {
balanced_parens(p);
}
}
fn at_databricks_as_of_travel(p: &Parser) -> bool {
(p.nth_contextual(0, ContextualKeyword::Version)
|| p.nth_contextual(0, ContextualKeyword::Timestamp))
&& p.nth_at(1, AS_KW)
&& p.nth_contextual(2, ContextualKeyword::Of)
}
fn databricks_as_of_travel(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); p.expect(AS_KW);
if p.nth_contextual(0, ContextualKeyword::Of) {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.error("expected OF in time travel clause");
}
if at_expr_start(p) {
expr(p);
} else {
p.error("expected a time travel value");
}
m.complete(p, AS_OF_TRAVEL);
}
fn sample_clause(p: &mut Parser) {
p.bump_any(); if p.at(ROW_KW) && p.nth_at(1, L_PAREN) {
p.bump(ROW_KW);
} else if p.at_name() {
name_ref(p);
}
if p.at(L_PAREN) {
balanced_parens(p);
}
if p.at_name() && p.nth_at(1, L_PAREN) {
name_ref(p);
balanced_parens(p);
}
}
fn match_recognize(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); if !p.eat(L_PAREN) {
p.error("expected '(' after MATCH_RECOGNIZE");
m.complete(p, MATCH_RECOGNIZE);
return;
}
while !p.at(R_PAREN) && !p.at_eof() {
if p.at(PARTITION_KW) {
partition_by_clause(p);
} else if p.at(ORDER_KW) {
order_by_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Measures) {
measures_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Pattern) {
pattern_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Define) {
define_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Subset) {
subset_clause(p);
} else if at_row_match_clause(p) {
row_match_clause(p);
} else if p.at(AFTER_KW) {
after_match_clause(p);
} else {
p.bump_any(); }
}
p.expect(R_PAREN);
m.complete(p, MATCH_RECOGNIZE);
}
fn measures_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); select_item(p);
while p.eat(COMMA) {
select_item(p);
}
m.complete(p, MEASURES_CLAUSE);
}
fn pattern_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(L_PAREN) {
let b = p.start();
balanced_parens(p);
b.complete(p, PATTERN_BODY);
} else {
p.error("expected '(' after PATTERN");
}
m.complete(p, PATTERN_CLAUSE);
}
fn define_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); define_item(p);
while p.eat(COMMA) {
define_item(p);
}
m.complete(p, DEFINE_CLAUSE);
}
fn define_item(p: &mut Parser) {
let m = p.start();
name_ref(p); p.expect(AS_KW);
expr(p); m.complete(p, DEFINE_ITEM);
}
fn subset_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); loop {
name_ref(p);
p.expect(EQ);
if p.at(L_PAREN) {
column_list(p);
}
if !p.eat(COMMA) {
break;
}
}
m.complete(p, SUBSET_CLAUSE);
}
fn at_row_match_clause(p: &Parser) -> bool {
(p.nth_contextual(0, ContextualKeyword::One) || p.at(ALL_KW))
&& (p.nth_at(1, ROW_KW) || p.nth_at(1, ROWS_KW))
}
fn row_match_clause(p: &mut Parser) {
let m = p.start();
if p.at(ALL_KW) {
p.bump(ALL_KW);
} else {
p.bump_as(CONTEXTUAL_KEYWORD); }
while !p.at(R_PAREN) && !p.at_eof() && !at_mr_clause_start(p) {
soft_keyword_word(p);
}
m.complete(p, ROW_MATCH_CLAUSE);
}
fn after_match_clause(p: &mut Parser) {
let m = p.start();
p.bump(AFTER_KW);
if p.nth_contextual(0, ContextualKeyword::Match) {
p.bump_as(CONTEXTUAL_KEYWORD); }
if p.nth_contextual(0, ContextualKeyword::Skip) {
p.bump_as(CONTEXTUAL_KEYWORD); }
if p.nth_contextual(0, ContextualKeyword::Past) {
p.bump_as(CONTEXTUAL_KEYWORD); p.eat(LAST_KW);
p.eat(ROW_KW);
} else if p.nth_contextual(0, ContextualKeyword::To) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.nth_contextual(0, ContextualKeyword::Next) {
p.bump_as(CONTEXTUAL_KEYWORD); p.eat(ROW_KW);
} else {
if p.at(FIRST_KW) || p.at(LAST_KW) {
p.bump_any();
}
if p.at_name() {
name_ref(p); }
}
}
m.complete(p, AFTER_MATCH_CLAUSE);
}
fn at_mr_clause_start(p: &Parser) -> bool {
p.at(PARTITION_KW)
|| p.at(ORDER_KW)
|| p.at(AFTER_KW)
|| p.nth_contextual(0, ContextualKeyword::Measures)
|| p.nth_contextual(0, ContextualKeyword::Pattern)
|| p.nth_contextual(0, ContextualKeyword::Define)
|| p.nth_contextual(0, ContextualKeyword::Subset)
|| at_row_match_clause(p)
}
fn soft_keyword_word(p: &mut Parser) {
if p.at_ident_like() {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}
fn balanced_parens(p: &mut Parser) {
p.bump(L_PAREN);
let mut depth = 1u32;
while depth > 0 && !p.at_eof() {
if p.at(L_PAREN) {
depth += 1;
} else if p.at(R_PAREN) {
depth -= 1;
}
p.bump_any();
}
}
fn pivot_clause(p: &mut Parser) {
let m = p.start();
let is_pivot = p.at(PIVOT_KW);
p.bump_any(); p.expect(L_PAREN);
if is_pivot {
expr(p);
} else {
name_ref(p);
}
p.expect(FOR_KW);
name_ref(p);
p.expect(IN_KW);
p.expect(L_PAREN);
if !p.at(R_PAREN) {
pivot_value(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
pivot_value(p);
}
}
p.expect(R_PAREN);
p.expect(R_PAREN);
m.complete(p, PIVOT_CLAUSE);
}
fn pivot_value(p: &mut Parser) {
expr(p);
if p.eat(AS_KW) || p.at_name() {
name(p);
}
}
fn table_alias(p: &mut Parser) {
let explicit_alias = p.eat(AS_KW);
if explicit_alias || (p.at_name() && !at_alias_blocker(p)) {
name(p);
if p.at(L_PAREN) {
column_list(p); }
}
}
fn at_alias_blocker(p: &Parser) -> bool {
(p.nth_contextual(0, ContextualKeyword::Asof) && p.nth_at(1, JOIN_KW))
|| (p.nth_contextual(0, ContextualKeyword::MatchCondition) && p.nth_at(1, L_PAREN))
|| at_time_travel(p)
|| (p.dialect().supports_as_of_travel() && at_databricks_as_of_travel(p))
|| (p.dialect().supports_lateral_view() && at_lateral_view(p))
}
fn at_join_start(p: &Parser) -> bool {
p.at(JOIN_KW)
|| p.at(INNER_KW)
|| p.at(LEFT_KW)
|| p.at(RIGHT_KW)
|| p.at(FULL_KW)
|| p.at(CROSS_KW)
|| p.at(NATURAL_KW)
|| (p.nth_contextual(0, ContextualKeyword::Asof) && p.nth_at(1, JOIN_KW))
}
fn join(p: &mut Parser) {
let m = p.start();
p.eat(NATURAL_KW);
if p.nth_contextual(0, ContextualKeyword::Asof) {
p.bump_as(CONTEXTUAL_KEYWORD); } else if p.at(INNER_KW) {
p.bump(INNER_KW);
} else if p.at(LEFT_KW) || p.at(RIGHT_KW) || p.at(FULL_KW) {
p.bump_any();
p.eat(OUTER_KW);
} else if p.at(CROSS_KW) {
p.bump(CROSS_KW);
}
p.expect(JOIN_KW);
table_ref(p);
if p.nth_contextual(0, ContextualKeyword::MatchCondition) {
p.bump_as(CONTEXTUAL_KEYWORD); p.expect(L_PAREN);
expr(p);
p.expect(R_PAREN);
}
if p.eat(ON_KW) {
expr(p);
} else if p.eat(USING_KW) {
column_list(p);
}
m.complete(p, JOIN);
}
fn where_clause(p: &mut Parser) {
let m = p.start();
p.bump(WHERE_KW);
expr(p);
m.complete(p, WHERE_CLAUSE);
}
fn start_with_clause(p: &mut Parser) {
let m = p.start();
p.bump(START_KW);
p.expect(WITH_KW);
expr(p);
m.complete(p, START_WITH_CLAUSE);
}
fn connect_by_clause(p: &mut Parser) {
let m = p.start();
p.bump(CONNECT_KW);
p.expect(BY_KW);
if p.nth_contextual(0, ContextualKeyword::NoCycle) {
p.bump_as(CONTEXTUAL_KEYWORD); }
expr(p);
m.complete(p, CONNECT_BY_CLAUSE);
}
fn group_by_clause(p: &mut Parser) {
let m = p.start();
p.bump(GROUP_KW);
p.expect(BY_KW);
if p.at(ALL_KW) {
p.bump(ALL_KW);
} else {
grouping_element(p);
while p.eat(COMMA) {
grouping_element(p);
}
}
m.complete(p, GROUP_BY_CLAUSE);
}
fn grouping_element(p: &mut Parser) {
if p.nth_contextual(0, ContextualKeyword::Grouping)
&& p.nth_contextual(1, ContextualKeyword::Sets)
{
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); p.bump_as(CONTEXTUAL_KEYWORD); p.expect(L_PAREN);
if !p.at(R_PAREN) {
grouping_set(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
grouping_set(p);
}
}
p.expect(R_PAREN);
m.complete(p, GROUPING_SETS);
} else {
expr(p);
}
}
fn grouping_set(p: &mut Parser) {
if p.at(L_PAREN) {
p.bump(L_PAREN);
if !p.at(R_PAREN) {
expr(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
expr(p);
}
}
p.expect(R_PAREN);
} else {
expr(p);
}
}
fn having_clause(p: &mut Parser) {
let m = p.start();
p.bump(HAVING_KW);
expr(p);
m.complete(p, HAVING_CLAUSE);
}
fn qualify_clause(p: &mut Parser) {
let m = p.start();
p.bump(QUALIFY_KW);
expr(p);
m.complete(p, QUALIFY_CLAUSE);
}
fn order_by_clause(p: &mut Parser) {
let m = p.start();
p.bump(ORDER_KW);
p.expect(BY_KW);
order_by_item(p);
while p.eat(COMMA) {
order_by_item(p);
}
m.complete(p, ORDER_BY_CLAUSE);
}
fn order_by_item(p: &mut Parser) {
let m = p.start();
expr(p);
if p.at(ASC_KW) || p.at(DESC_KW) {
p.bump_any();
}
if p.at(NULLS_KW) {
p.bump(NULLS_KW);
if p.at(FIRST_KW) || p.at(LAST_KW) {
p.bump_any();
} else {
p.error("expected FIRST or LAST after NULLS");
}
}
m.complete(p, ORDER_BY_ITEM);
}
fn limit_clause(p: &mut Parser) {
let m = p.start();
p.bump(LIMIT_KW);
expr(p);
m.complete(p, LIMIT_CLAUSE);
}
fn offset_clause(p: &mut Parser) {
let m = p.start();
p.bump(OFFSET_KW);
expr(p);
m.complete(p, OFFSET_CLAUSE);
}
fn name(p: &mut Parser) {
let m = p.start();
if p.at_name() {
p.bump_any();
} else {
p.error("expected a name");
}
m.complete(p, NAME);
}
fn name_ref(p: &mut Parser) -> CompletedMarker {
let m = p.start();
if p.at_name() {
p.bump_any();
while p.at(DOT) {
p.bump(DOT);
if p.at_name() {
p.bump_any();
} else if p.at(STAR) {
p.bump(STAR); break;
} else {
p.error("expected a name after '.'");
break;
}
}
} else {
p.error("expected a name");
}
m.complete(p, NAME_REF)
}
fn column_list(p: &mut Parser) {
let m = p.start();
p.bump(L_PAREN);
if p.at_name() {
name(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
name(p);
}
}
p.expect(R_PAREN);
m.complete(p, COLUMN_LIST);
}
fn at_expr_start(p: &Parser) -> bool {
p.at(INT_NUMBER)
|| p.at(FLOAT_NUMBER)
|| p.at(STRING)
|| p.at(DOLLAR_STRING)
|| p.at(TRUE_KW)
|| p.at(FALSE_KW)
|| p.at(NULL_KW)
|| p.at(VARIABLE)
|| p.at(L_PAREN)
|| p.at(MINUS)
|| p.at(PLUS)
|| p.at(NOT_KW)
|| (p.at(EXISTS_KW) && p.nth_at(1, L_PAREN))
|| p.at(CASE_KW)
|| p.at(CAST_KW)
|| p.at(TRY_CAST_KW)
|| p.at(FLATTEN_KW)
|| p.at_name()
|| at_keyword_call_name(p) }
pub(crate) fn expr(p: &mut Parser) {
expr_bp(p, 0);
}
fn expr_bp(p: &mut Parser, min_bp: u8) -> Option<CompletedMarker> {
let mut lhs = lhs(p)?;
loop {
if p.at(L_PAREN) {
let m = lhs.precede(p);
arg_list(p);
lhs = m.complete(p, CALL_EXPR);
continue;
}
if p.at(L_BRACKET) {
let m = lhs.precede(p);
p.bump(L_BRACKET);
expr(p);
p.expect(R_BRACKET);
lhs = m.complete(p, INDEX_EXPR);
continue;
}
if p.at(COLON2) {
let m = lhs.precede(p);
p.bump(COLON2);
type_name(p);
lhs = m.complete(p, CAST_EXPR);
continue;
}
if p.at(COLON) {
let m = lhs.precede(p);
json_path(p);
lhs = m.complete(p, JSON_ACCESS);
continue;
}
if p.at(OVER_KW) {
let m = lhs.precede(p);
p.bump(OVER_KW);
if p.at(L_PAREN) {
window_spec(p);
} else if p.at_name() {
name_ref(p);
} else {
p.error("expected a window specification");
}
lhs = m.complete(p, WINDOW_EXPR);
continue;
}
if p.at(WITHIN_KW) {
let m = lhs.precede(p);
p.bump(WITHIN_KW);
p.expect(GROUP_KW);
p.expect(L_PAREN);
if p.at(ORDER_KW) {
order_by_clause(p);
}
p.expect(R_PAREN);
lhs = m.complete(p, WITHIN_GROUP);
continue;
}
if p.dialect().supports_lambda_expr() && p.at(ARROW) {
if 0 < min_bp {
break;
}
let m = lhs.precede(p);
p.bump(ARROW);
expr_bp(p, 1);
lhs = m.complete(p, LAMBDA_EXPR);
continue;
}
if p.at(IS_KW) {
if BP_CMP.0 < min_bp {
break;
}
let m = lhs.precede(p);
p.bump(IS_KW);
p.eat(NOT_KW);
is_rhs(p);
lhs = m.complete(p, IS_EXPR);
continue;
}
let neg = p.at(NOT_KW);
if p.at(BETWEEN_KW) || (neg && p.nth_at(1, BETWEEN_KW)) {
if BP_CMP.0 < min_bp {
break;
}
let m = lhs.precede(p);
p.eat(NOT_KW);
p.bump(BETWEEN_KW);
expr_bp(p, BP_CMP.1); p.expect(AND_KW);
expr_bp(p, BP_CMP.1); lhs = m.complete(p, BETWEEN_EXPR);
continue;
}
if p.at(IN_KW) || (neg && p.nth_at(1, IN_KW)) {
if BP_CMP.0 < min_bp {
break;
}
let m = lhs.precede(p);
p.eat(NOT_KW);
p.bump(IN_KW);
in_rhs(p);
lhs = m.complete(p, IN_EXPR);
continue;
}
if neg && (p.nth_at(1, LIKE_KW) || p.nth_at(1, ILIKE_KW)) {
if BP_CMP.0 < min_bp {
break;
}
let m = lhs.precede(p);
p.bump(NOT_KW);
p.bump_any(); expr_bp(p, BP_CMP.1);
lhs = m.complete(p, BIN_EXPR);
continue;
}
let (lbp, rbp) = match infix_bp(p) {
Some(bp) => bp,
None => break,
};
if lbp < min_bp {
break;
}
let m = lhs.precede(p);
p.bump_any(); expr_bp(p, rbp);
lhs = m.complete(p, BIN_EXPR);
}
Some(lhs)
}
fn lhs(p: &mut Parser) -> Option<CompletedMarker> {
if p.at(NOT_KW) {
let m = p.start();
p.bump(NOT_KW);
expr_bp(p, BP_PREFIX_NOT);
return Some(m.complete(p, PREFIX_EXPR));
}
if p.at(PRIOR_KW) {
let m = p.start();
p.bump(PRIOR_KW);
expr_bp(p, BP_PREFIX_NEG);
return Some(m.complete(p, PREFIX_EXPR));
}
if p.at(MINUS) || p.at(PLUS) {
let m = p.start();
p.bump_any();
expr_bp(p, BP_PREFIX_NEG);
return Some(m.complete(p, PREFIX_EXPR));
}
primary(p)
}
fn primary(p: &mut Parser) -> Option<CompletedMarker> {
let cm = if p.at(INT_NUMBER)
|| p.at(FLOAT_NUMBER)
|| p.at(STRING)
|| p.at(DOLLAR_STRING)
|| p.at(TRUE_KW)
|| p.at(FALSE_KW)
|| p.at(NULL_KW)
|| p.at(VARIABLE)
{
let m = p.start();
p.bump_any();
m.complete(p, LITERAL)
} else if p.at(EXISTS_KW) && p.nth_at(1, L_PAREN) {
let m = p.start();
p.bump(EXISTS_KW);
subquery(p);
m.complete(p, EXISTS_EXPR)
} else if p.at(L_PAREN) && (p.nth_at(1, SELECT_KW) || p.nth_at(1, WITH_KW)) {
subquery(p) } else if p.dialect().supports_lambda_expr() && at_parenthesized_lambda_params(p) {
lambda_params(p)
} else if p.at(L_PAREN) {
let m = p.start();
p.bump(L_PAREN);
expr(p);
p.expect(R_PAREN);
m.complete(p, PAREN_EXPR)
} else if p.at(CASE_KW) {
case_expr(p)
} else if p.at(CAST_KW) || p.at(TRY_CAST_KW) {
cast_fn_expr(p)
} else if p.at(FLATTEN_KW) {
let m = p.start();
p.bump(FLATTEN_KW);
m.complete(p, NAME_REF)
} else if at_keyword_call_name(p) {
let m = p.start();
p.bump_as(IDENT);
m.complete(p, NAME_REF)
} else if p.at_name() {
name_ref(p)
} else {
p.err_and_bump("expected an expression");
return None;
};
Some(cm)
}
fn at_parenthesized_lambda_params(p: &Parser) -> bool {
if !p.at(L_PAREN) {
return false;
}
let mut depth = 0u32;
for i in 0..48 {
if p.nth_at(i, EOF) {
return false;
}
if p.nth_at(i, L_PAREN) {
depth += 1;
} else if p.nth_at(i, R_PAREN) {
depth = depth.saturating_sub(1);
if depth == 0 {
return p.nth_at(i + 1, ARROW);
}
}
}
false
}
fn lambda_params(p: &mut Parser) -> CompletedMarker {
let m = p.start();
p.bump(L_PAREN);
if !p.at(R_PAREN) {
if p.at_name() {
name(p);
} else {
p.error("expected a lambda parameter");
}
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
name(p);
}
}
p.expect(R_PAREN);
m.complete(p, LAMBDA_PARAMS)
}
fn at_keyword_call_name(p: &Parser) -> bool {
(p.at(FIRST_KW) || p.at(LAST_KW) || p.at(LEFT_KW) || p.at(RIGHT_KW)) && p.nth_at(1, L_PAREN)
}
fn is_rhs(p: &mut Parser) {
if p.at(DISTINCT_KW) {
p.bump(DISTINCT_KW);
p.expect(FROM_KW);
expr_bp(p, BP_CMP.1);
} else if p.at(NULL_KW) || p.at(TRUE_KW) || p.at(FALSE_KW) {
let m = p.start();
p.bump_any();
m.complete(p, LITERAL);
} else {
expr_bp(p, BP_CMP.1);
}
}
fn in_rhs(p: &mut Parser) {
if !p.eat(L_PAREN) {
p.error("expected '(' after IN");
return;
}
if p.at(SELECT_KW) || p.at(WITH_KW) {
query_expr(p);
} else if !p.at(R_PAREN) {
expr_list(p);
}
p.expect(R_PAREN);
}
fn expr_list(p: &mut Parser) {
let m = p.start();
expr(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
expr(p);
}
m.complete(p, EXPR_LIST);
}
fn arg_list(p: &mut Parser) {
let m = p.start();
p.bump(L_PAREN);
if p.at(DISTINCT_KW) || p.at(ALL_KW) {
p.bump_any();
}
if !p.at(R_PAREN) {
arg(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
arg(p);
}
}
if !p.eat(R_PAREN) {
p.err_and_bump(format!("expected {}", R_PAREN.describe()));
}
m.complete(p, ARG_LIST);
}
fn arg(p: &mut Parser) {
if p.at(STAR) {
let m = p.start();
p.bump(STAR);
m.complete(p, STAR_EXPR);
} else if p.at_ident_like() && p.nth_at(1, FAT_ARROW) {
let m = p.start();
p.bump_any(); p.bump(FAT_ARROW);
expr(p);
m.complete(p, NAMED_ARG);
} else if at_expr_start(p) {
expr(p);
} else {
p.error("expected an argument");
}
}
fn type_name(p: &mut Parser) {
let m = p.start();
if p.at_name() {
p.bump_any();
if p.eat(L_PAREN) {
while !p.at(R_PAREN) && !p.at_eof() {
p.bump_any();
}
p.expect(R_PAREN);
}
} else {
p.error("expected a type name");
}
m.complete(p, TYPE_NAME);
}
fn window_spec(p: &mut Parser) {
let m = p.start();
p.bump(L_PAREN);
if p.at(PARTITION_KW) {
partition_by_clause(p);
}
if p.at(ORDER_KW) {
order_by_clause(p);
}
if p.at(ROWS_KW) || p.at(RANGE_KW) {
window_frame(p);
}
p.expect(R_PAREN);
m.complete(p, WINDOW_SPEC);
}
fn partition_by_clause(p: &mut Parser) {
let m = p.start();
p.bump(PARTITION_KW);
p.expect(BY_KW);
expr(p);
while p.eat(COMMA) {
expr(p);
}
m.complete(p, PARTITION_BY_CLAUSE);
}
fn window_frame(p: &mut Parser) {
let m = p.start();
p.bump_any(); if p.eat(BETWEEN_KW) {
frame_bound(p);
p.expect(AND_KW);
frame_bound(p);
} else {
frame_bound(p);
}
m.complete(p, WINDOW_FRAME);
}
fn frame_bound(p: &mut Parser) {
if p.at(UNBOUNDED_KW) {
p.bump(UNBOUNDED_KW);
if p.at(PRECEDING_KW) || p.at(FOLLOWING_KW) {
p.bump_any();
} else {
p.error("expected PRECEDING or FOLLOWING");
}
} else if p.at(CURRENT_KW) {
p.bump(CURRENT_KW);
p.expect(ROW_KW);
} else {
expr(p);
if p.at(PRECEDING_KW) || p.at(FOLLOWING_KW) {
p.bump_any();
} else {
p.error("expected PRECEDING or FOLLOWING");
}
}
}
fn case_expr(p: &mut Parser) -> CompletedMarker {
let m = p.start();
p.bump(CASE_KW);
if !p.at(WHEN_KW) {
expr(p); }
while p.at(WHEN_KW) {
let arm = p.start();
p.bump(WHEN_KW);
expr(p);
p.expect(THEN_KW);
expr(p);
arm.complete(p, CASE_WHEN);
}
if p.eat(ELSE_KW) {
expr(p);
}
p.expect(END_KW);
m.complete(p, CASE_EXPR)
}
fn cast_fn_expr(p: &mut Parser) -> CompletedMarker {
let m = p.start();
p.bump_any(); p.expect(L_PAREN);
expr(p);
p.expect(AS_KW);
type_name(p);
p.expect(R_PAREN);
m.complete(p, CAST_EXPR)
}
fn json_path(p: &mut Parser) {
p.bump(COLON);
json_path_segment(p);
loop {
if p.at(DOT) {
p.bump(DOT);
json_path_segment(p);
} else if p.at(COLON) {
p.bump(COLON);
json_path_segment(p);
} else if p.at(L_BRACKET) {
p.bump(L_BRACKET);
expr(p);
p.expect(R_BRACKET);
} else {
break;
}
}
}
fn json_path_segment(p: &mut Parser) {
if p.at_ident_like() {
p.bump_as(IDENT);
} else if p.at(STRING) {
p.bump_any();
} else {
p.error("expected a path segment after ':'");
}
}
fn values_clause(p: &mut Parser) -> CompletedMarker {
let m = p.start();
p.bump(VALUES_KW);
values_row(p);
while p.eat(COMMA) {
values_row(p);
}
m.complete(p, VALUES_CLAUSE)
}
fn values_row(p: &mut Parser) {
let m = p.start();
p.expect(L_PAREN);
if !p.at(R_PAREN) {
expr(p);
while p.eat(COMMA) {
if p.at(R_PAREN) {
break;
}
expr(p);
}
}
p.expect(R_PAREN);
m.complete(p, VALUES_ROW);
}
fn infix_bp(p: &Parser) -> Option<(u8, u8)> {
let bp = if p.at(OR_KW) {
BP_OR
} else if p.at(AND_KW) {
BP_AND
} else if p.at(EQ)
|| p.at(NEQ)
|| p.at(LT)
|| p.at(LTE)
|| p.at(GT)
|| p.at(GTE)
|| p.at(LIKE_KW)
|| p.at(ILIKE_KW)
{
BP_CMP
} else if p.at(CONCAT) {
BP_CONCAT
} else if p.at(PLUS) || p.at(MINUS) {
BP_ADD
} else if p.at(STAR) || p.at(SLASH) || p.at(PERCENT) {
BP_MUL
} else {
return None;
};
Some(bp)
}