diff --git a/crates/squawk_ide/src/expand_selection.rs b/crates/squawk_ide/src/expand_selection.rs index 91ca3374..3c059d89 100644 --- a/crates/squawk_ide/src/expand_selection.rs +++ b/crates/squawk_ide/src/expand_selection.rs @@ -59,6 +59,7 @@ const DELIMITED_LIST_KINDS: &[SyntaxKind] = &[ SyntaxKind::REVOKE_COMMAND_LIST, SyntaxKind::ROLE_REF_LIST, SyntaxKind::ROW_LIST, + SyntaxKind::RULE_STMT_LIST, SyntaxKind::EXPR_AS_NAME_LIST, SyntaxKind::XML_NAMESPACE_LIST, SyntaxKind::SET_COLUMN_LIST, diff --git a/crates/squawk_ide/src/folding_ranges.rs b/crates/squawk_ide/src/folding_ranges.rs index 4feb1897..13dca43a 100644 --- a/crates/squawk_ide/src/folding_ranges.rs +++ b/crates/squawk_ide/src/folding_ranges.rs @@ -144,6 +144,7 @@ fn fold_kind(kind: SyntaxKind) -> Option { | SyntaxKind::ROLE_OPTION_LIST | SyntaxKind::ROLE_REF_LIST | SyntaxKind::ROW_LIST + | SyntaxKind::RULE_STMT_LIST | SyntaxKind::SEQUENCE_OPTION_LIST | SyntaxKind::SET_COLUMN_LIST | SyntaxKind::SET_EXPR_LIST diff --git a/crates/squawk_parser/src/generated/syntax_kind.rs b/crates/squawk_parser/src/generated/syntax_kind.rs index 0b4cd6fb..0a280dd3 100644 --- a/crates/squawk_parser/src/generated/syntax_kind.rs +++ b/crates/squawk_parser/src/generated/syntax_kind.rs @@ -977,6 +977,7 @@ pub enum SyntaxKind { NEQ, NEQB, NON_STANDARD_PARAM, + NOTHING, NOTIFY, NOT_DEFERRABLE, NOT_DEFERRABLE_CONSTRAINT_OPTION, @@ -1112,6 +1113,9 @@ pub enum SyntaxKind { ROW, ROWS_FUNC_OPTION, ROW_LIST, + RULE_DO, + RULE_ON, + RULE_STMT_LIST, SAVEPOINT, SECURITY_FUNC_OPTION, SECURITY_LABEL, diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index 05a2dc3f..09289480 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -10033,6 +10033,31 @@ fn create_rule(p: &mut Parser<'_>) -> CompletedMarker { p.expect(RULE_KW); name(p); p.expect(AS_KW); + rule_on(p); + rule_do(p); + p.eat(SEMICOLON); + m.complete(p, CREATE_RULE) +} + +fn rule_do(p: &mut Parser<'_>) { + let m = p.start(); + p.expect(DO_KW); + let _ = p.eat(ALSO_KW) || p.eat(INSTEAD_KW); + if p.at(L_PAREN) { + rule_stmt_list(p); + } else if p.at(NOTHING_KW) { + let m = p.start(); + p.bump(NOTHING_KW); + m.complete(p, NOTHING); + // pass + } else { + select_insert_delete_update_or_notify(p, false); + } + m.complete(p, RULE_DO); +} + +fn rule_on(p: &mut Parser<'_>) { + let m = p.start(); p.expect(ON_KW); if p.at(SELECT_KW) || p.at(INSERT_KW) || p.at(UPDATE_KW) || p.at(DELETE_KW) { p.bump_any(); @@ -10042,22 +10067,20 @@ fn create_rule(p: &mut Parser<'_>) -> CompletedMarker { p.expect(TO_KW); path_name_ref(p); opt_where_clause(p); - p.expect(DO_KW); - let _ = p.eat(ALSO_KW) || p.eat(INSTEAD_KW); - if p.eat(L_PAREN) { - // TODO: use delimited - // ( command ; command ... ) - while !p.at(EOF) && !p.at(R_PAREN) { - select_insert_delete_update_or_notify(p, true); - } - p.expect(R_PAREN); - } else if p.eat(NOTHING_KW) { - // pass - } else { - select_insert_delete_update_or_notify(p, false); + m.complete(p, RULE_ON); +} + +fn rule_stmt_list(p: &mut Parser<'_>) { + assert!(p.at(L_PAREN)); + let m = p.start(); + p.expect(L_PAREN); + // TODO: use delimited + // ( command ; command ... ) + while !p.at(EOF) && !p.at(R_PAREN) { + select_insert_delete_update_or_notify(p, true); } - p.eat(SEMICOLON); - m.complete(p, CREATE_RULE) + p.expect(R_PAREN); + m.complete(p, RULE_STMT_LIST); } // CREATE [ { TEMPORARY | TEMP } | UNLOGGED ] SEQUENCE [ IF NOT EXISTS ] name diff --git a/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap index eeef3197..0e51b70b 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_rule_ok.snap @@ -15,20 +15,23 @@ SOURCE_FILE WHITESPACE " " AS_KW "as" WHITESPACE " " - ON_KW "on" - WHITESPACE " " - SELECT_KW "select" - WHITESPACE "\n " - TO_KW "to" - WHITESPACE " " - PATH - PATH_SEGMENT - NAME_REF - IDENT "t" + RULE_ON + ON_KW "on" + WHITESPACE " " + SELECT_KW "select" + WHITESPACE "\n " + TO_KW "to" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" WHITESPACE "\n " - DO_KW "do" - WHITESPACE " " - NOTHING_KW "nothing" + RULE_DO + DO_KW "do" + WHITESPACE " " + NOTHING + NOTHING_KW "nothing" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- full" @@ -48,161 +51,164 @@ SOURCE_FILE WHITESPACE " " AS_KW "as" WHITESPACE " " - ON_KW "on" - WHITESPACE " " - SELECT_KW "select" - WHITESPACE "\n " - TO_KW "to" - WHITESPACE " " - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "foo" - DOT "." - PATH_SEGMENT - NAME_REF - IDENT "t" - WHITESPACE "\n " - WHERE_CLAUSE - WHERE_KW "where" + RULE_ON + ON_KW "on" WHITESPACE " " - BIN_EXPR - BIN_EXPR - FIELD_EXPR - NAME_REF - NEW_KW "new" - DOT "." - NAME_REF - IDENT "foo" - WHITESPACE " " - EQ "=" - WHITESPACE " " - FIELD_EXPR - NAME_REF - OLD_KW "old" - DOT "." + SELECT_KW "select" + WHITESPACE "\n " + TO_KW "to" + WHITESPACE " " + PATH + PATH + PATH_SEGMENT NAME_REF IDENT "foo" - WHITESPACE " " - OR_KW "or" + DOT "." + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE "\n " + WHERE_CLAUSE + WHERE_KW "where" WHITESPACE " " BIN_EXPR - FIELD_EXPR - NAME_REF - OLD_KW "old" - DOT "." - NAME_REF - IDENT "id" + BIN_EXPR + FIELD_EXPR + NAME_REF + NEW_KW "new" + DOT "." + NAME_REF + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + FIELD_EXPR + NAME_REF + OLD_KW "old" + DOT "." + NAME_REF + IDENT "foo" WHITESPACE " " - NEQ "!=" + OR_KW "or" WHITESPACE " " - FIELD_EXPR - NAME_REF - NEW_KW "new" - DOT "." - NAME_REF - IDENT "id" + BIN_EXPR + FIELD_EXPR + NAME_REF + OLD_KW "old" + DOT "." + NAME_REF + IDENT "id" + WHITESPACE " " + NEQ "!=" + WHITESPACE " " + FIELD_EXPR + NAME_REF + NEW_KW "new" + DOT "." + NAME_REF + IDENT "id" WHITESPACE "\n " - DO_KW "do" - WHITESPACE " " - L_PAREN "(" - WHITESPACE "\n " - SELECT - SELECT_CLAUSE - SELECT_KW "select" - WHITESPACE " " - TARGET_LIST - TARGET - LITERAL - INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - INSERT - INSERT_KW "insert" - WHITESPACE " " - INTO_KW "into" - WHITESPACE " " - PATH - PATH_SEGMENT - NAME_REF - IDENT "t" + RULE_DO + DO_KW "do" WHITESPACE " " - VALUES - VALUES_KW "values" - WHITESPACE " " - ROW_LIST - ROW - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," + RULE_STMT_LIST + L_PAREN "(" + WHITESPACE "\n " + SELECT + SELECT_CLAUSE + SELECT_KW "select" WHITESPACE " " - LITERAL - INT_NUMBER "2" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - DELETE - DELETE_KW "delete" - WHITESPACE " " - FROM_KW "from" - WHITESPACE " " - RELATION_NAME - PATH - PATH_SEGMENT - NAME_REF - IDENT "t" - SEMICOLON ";" - WHITESPACE "\n " - VALUES - VALUES_KW "values" - WHITESPACE " " - ROW_LIST - ROW - L_PAREN "(" - LITERAL - INT_NUMBER "1" - COMMA "," + TARGET_LIST + TARGET + LITERAL + INT_NUMBER "1" + SEMICOLON ";" + WHITESPACE "\n " + INSERT + INSERT_KW "insert" WHITESPACE " " - LITERAL - INT_NUMBER "2" - R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - UPDATE - UPDATE_KW "update" - WHITESPACE " " - RELATION_NAME - PATH - PATH_SEGMENT - NAME_REF - IDENT "t" - WHITESPACE " " - SET_CLAUSE - SET_KW "set" - WHITESPACE " " - SET_COLUMN_LIST - SET_SINGLE_COLUMN - COLUMN + INTO_KW "into" + WHITESPACE " " + PATH + PATH_SEGMENT NAME_REF - IDENT "foo" - WHITESPACE " " - EQ "=" + IDENT "t" + WHITESPACE " " + VALUES + VALUES_KW "values" WHITESPACE " " - SET_EXPR + ROW_LIST + ROW + L_PAREN "(" + LITERAL + INT_NUMBER "1" + COMMA "," + WHITESPACE " " + LITERAL + INT_NUMBER "2" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n " + DELETE + DELETE_KW "delete" + WHITESPACE " " + FROM_KW "from" + WHITESPACE " " + RELATION_NAME + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + SEMICOLON ";" + WHITESPACE "\n " + VALUES + VALUES_KW "values" + WHITESPACE " " + ROW_LIST + ROW + L_PAREN "(" LITERAL INT_NUMBER "1" - SEMICOLON ";" - WHITESPACE "\n " - NOTIFY - NOTIFY_KW "notify" - WHITESPACE " " - NAME_REF - IDENT "f" - SEMICOLON ";" - WHITESPACE "\n " - R_PAREN ")" + COMMA "," + WHITESPACE " " + LITERAL + INT_NUMBER "2" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n " + UPDATE + UPDATE_KW "update" + WHITESPACE " " + RELATION_NAME + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE " " + SET_CLAUSE + SET_KW "set" + WHITESPACE " " + SET_COLUMN_LIST + SET_SINGLE_COLUMN + COLUMN + NAME_REF + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + SET_EXPR + LITERAL + INT_NUMBER "1" + SEMICOLON ";" + WHITESPACE "\n " + NOTIFY + NOTIFY_KW "notify" + WHITESPACE " " + NAME_REF + IDENT "f" + SEMICOLON ";" + WHITESPACE "\n " + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- doc_1" @@ -217,35 +223,37 @@ SOURCE_FILE WHITESPACE " " AS_KW "AS" WHITESPACE "\n " - ON_KW "ON" - WHITESPACE " " - SELECT_KW "SELECT" - WHITESPACE " " - TO_KW "TO" - WHITESPACE " " - PATH - PATH_SEGMENT - NAME_REF - IDENT "t1" + RULE_ON + ON_KW "ON" + WHITESPACE " " + SELECT_KW "SELECT" + WHITESPACE " " + TO_KW "TO" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + IDENT "t1" WHITESPACE "\n " - DO_KW "DO" - WHITESPACE " " - INSTEAD_KW "INSTEAD" - WHITESPACE "\n " - SELECT - SELECT_CLAUSE - SELECT_KW "SELECT" - WHITESPACE " " - TARGET_LIST - TARGET - STAR "*" + RULE_DO + DO_KW "DO" WHITESPACE " " - FROM_CLAUSE - FROM_KW "FROM" + INSTEAD_KW "INSTEAD" + WHITESPACE "\n " + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + STAR "*" WHITESPACE " " - FROM_ITEM - NAME_REF - IDENT "t2" + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + FROM_ITEM + NAME_REF + IDENT "t2" SEMICOLON ";" WHITESPACE "\n\n" CREATE_RULE @@ -258,35 +266,37 @@ SOURCE_FILE WHITESPACE " " AS_KW "AS" WHITESPACE "\n " - ON_KW "ON" - WHITESPACE " " - SELECT_KW "SELECT" - WHITESPACE " " - TO_KW "TO" - WHITESPACE " " - PATH - PATH_SEGMENT - NAME_REF - IDENT "t2" + RULE_ON + ON_KW "ON" + WHITESPACE " " + SELECT_KW "SELECT" + WHITESPACE " " + TO_KW "TO" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + IDENT "t2" WHITESPACE "\n " - DO_KW "DO" - WHITESPACE " " - INSTEAD_KW "INSTEAD" - WHITESPACE "\n " - SELECT - SELECT_CLAUSE - SELECT_KW "SELECT" - WHITESPACE " " - TARGET_LIST - TARGET - STAR "*" + RULE_DO + DO_KW "DO" WHITESPACE " " - FROM_CLAUSE - FROM_KW "FROM" + INSTEAD_KW "INSTEAD" + WHITESPACE "\n " + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + STAR "*" WHITESPACE " " - FROM_ITEM - NAME_REF - IDENT "t1" + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + FROM_ITEM + NAME_REF + IDENT "t1" SEMICOLON ";" WHITESPACE "\n\n" SELECT @@ -317,27 +327,29 @@ SOURCE_FILE WHITESPACE " " AS_KW "AS" WHITESPACE " " - ON_KW "ON" - WHITESPACE " " - UPDATE_KW "UPDATE" - WHITESPACE " " - TO_KW "TO" + RULE_ON + ON_KW "ON" + WHITESPACE " " + UPDATE_KW "UPDATE" + WHITESPACE " " + TO_KW "TO" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + IDENT "mytable" WHITESPACE " " - PATH - PATH_SEGMENT + RULE_DO + DO_KW "DO" + WHITESPACE " " + ALSO_KW "ALSO" + WHITESPACE " " + NOTIFY + NOTIFY_KW "NOTIFY" + WHITESPACE " " NAME_REF IDENT "mytable" - WHITESPACE " " - DO_KW "DO" - WHITESPACE " " - ALSO_KW "ALSO" - WHITESPACE " " - NOTIFY - NOTIFY_KW "NOTIFY" - WHITESPACE " " - NAME_REF - IDENT "mytable" - SEMICOLON ";" + SEMICOLON ";" WHITESPACE "\n\n" UPDATE UPDATE_KW "UPDATE" diff --git a/crates/squawk_syntax/src/ast/generated/nodes.rs b/crates/squawk_syntax/src/ast/generated/nodes.rs index 532367ad..b414d1d6 100644 --- a/crates/squawk_syntax/src/ast/generated/nodes.rs +++ b/crates/squawk_syntax/src/ast/generated/nodes.rs @@ -5067,38 +5067,18 @@ impl CreateRule { support::child(&self.syntax) } #[inline] - pub fn path(&self) -> Option { + pub fn rule_do(&self) -> Option { support::child(&self.syntax) } #[inline] - pub fn rule_stmt(&self) -> Option { + pub fn rule_on(&self) -> Option { support::child(&self.syntax) } #[inline] - pub fn rule_stmts(&self) -> AstChildren { - support::children(&self.syntax) - } - #[inline] - pub fn where_clause(&self) -> Option { - support::child(&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 semicolon_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::SEMICOLON) } #[inline] - pub fn also_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::ALSO_KW) - } - #[inline] pub fn as_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::AS_KW) } @@ -5107,49 +5087,9 @@ impl CreateRule { support::token(&self.syntax, SyntaxKind::CREATE_KW) } #[inline] - pub fn delete_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::DELETE_KW) - } - #[inline] - pub fn do_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::DO_KW) - } - #[inline] - pub fn ident_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::IDENT) - } - #[inline] - pub fn insert_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::INSERT_KW) - } - #[inline] - pub fn instead_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::INSTEAD_KW) - } - #[inline] - pub fn nothing_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::NOTHING_KW) - } - #[inline] - pub fn on_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::ON_KW) - } - #[inline] pub fn rule_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::RULE_KW) } - #[inline] - pub fn select_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::SELECT_KW) - } - #[inline] - pub fn to_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::TO_KW) - } - #[inline] - pub fn update_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::UPDATE_KW) - } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -12895,6 +12835,17 @@ impl NotValid { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Nothing { + pub(crate) syntax: SyntaxNode, +} +impl Nothing { + #[inline] + pub fn nothing_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::NOTHING_KW) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Notify { pub(crate) syntax: SyntaxNode, @@ -15773,6 +15724,91 @@ impl RowsFuncOption { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct RuleDo { + pub(crate) syntax: SyntaxNode, +} +impl RuleDo { + #[inline] + pub fn rule_action(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn also_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::ALSO_KW) + } + #[inline] + pub fn do_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::DO_KW) + } + #[inline] + pub fn instead_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::INSTEAD_KW) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct RuleOn { + pub(crate) syntax: SyntaxNode, +} +impl RuleOn { + #[inline] + pub fn path(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn where_clause(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn delete_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::DELETE_KW) + } + #[inline] + pub fn ident_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::IDENT) + } + #[inline] + pub fn insert_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::INSERT_KW) + } + #[inline] + pub fn on_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::ON_KW) + } + #[inline] + pub fn select_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::SELECT_KW) + } + #[inline] + pub fn to_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::TO_KW) + } + #[inline] + pub fn update_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::UPDATE_KW) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct RuleStmtList { + pub(crate) syntax: SyntaxNode, +} +impl RuleStmtList { + #[inline] + pub fn rule_stmts(&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) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Savepoint { pub(crate) syntax: SyntaxNode, @@ -19529,6 +19565,13 @@ pub enum RefAction { SetNullColumns(SetNullColumns), } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum RuleAction { + Nothing(Nothing), + RuleStmtList(RuleStmtList), + RuleStmt(RuleStmt), +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum RuleStmt { Delete(Delete), @@ -27558,6 +27601,24 @@ impl AstNode for NotValid { &self.syntax } } +impl AstNode for Nothing { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::NOTHING + } + #[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 Notify { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -29682,6 +29743,60 @@ impl AstNode for RowsFuncOption { &self.syntax } } +impl AstNode for RuleDo { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::RULE_DO + } + #[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 RuleOn { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::RULE_ON + } + #[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 RuleStmtList { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::RULE_STMT_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 Savepoint { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -35176,6 +35291,46 @@ impl From for RefAction { RefAction::SetNullColumns(node) } } +impl AstNode for RuleAction { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, SyntaxKind::NOTHING | SyntaxKind::RULE_STMT_LIST) + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + SyntaxKind::NOTHING => RuleAction::Nothing(Nothing { syntax }), + SyntaxKind::RULE_STMT_LIST => RuleAction::RuleStmtList(RuleStmtList { syntax }), + _ => { + if let Some(result) = RuleStmt::cast(syntax) { + return Some(RuleAction::RuleStmt(result)); + } + return None; + } + }; + Some(res) + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + match self { + RuleAction::Nothing(it) => &it.syntax, + RuleAction::RuleStmtList(it) => &it.syntax, + RuleAction::RuleStmt(it) => it.syntax(), + } + } +} +impl From for RuleAction { + #[inline] + fn from(node: Nothing) -> RuleAction { + RuleAction::Nothing(node) + } +} +impl From for RuleAction { + #[inline] + fn from(node: RuleStmtList) -> RuleAction { + RuleAction::RuleStmtList(node) + } +} impl AstNode for RuleStmt { #[inline] fn can_cast(kind: SyntaxKind) -> bool { diff --git a/crates/squawk_syntax/src/postgresql.ungram b/crates/squawk_syntax/src/postgresql.ungram index 0d57c532..8cf6741b 100644 --- a/crates/squawk_syntax/src/postgresql.ungram +++ b/crates/squawk_syntax/src/postgresql.ungram @@ -2617,12 +2617,29 @@ CreateRole = 'create' 'role' Name RoleOptionList ';'? CreateRule = - 'create' OrReplace? 'rule' Name 'as' 'on' ('#ident' | 'select' | 'insert' | 'update' | 'delete') + 'create' OrReplace? 'rule' Name 'as' + RuleOn + RuleDo + ';'? + +RuleOn = + 'on' ('#ident' | 'select' | 'insert' | 'update' | 'delete') 'to' Path WhereClause? + +RuleDo = 'do' ('also' | 'instead')? - ('nothing' - | '(' (RuleStmt (',' RuleStmt)*) ')' - | RuleStmt) ';'? + RuleAction + +Nothing = + 'nothing' + +RuleAction = + Nothing +| RuleStmtList +| RuleStmt + +RuleStmtList = + '(' (RuleStmt (',' RuleStmt)*) ')' RuleStmt = SelectVariant