diff --git a/crates/squawk_fmt/Cargo.toml b/crates/squawk_fmt/Cargo.toml index c9f41f0b..216f23ef 100644 --- a/crates/squawk_fmt/Cargo.toml +++ b/crates/squawk_fmt/Cargo.toml @@ -10,6 +10,9 @@ documentation.workspace = true homepage.workspace = true repository.workspace = true +[lib] +doctest = false + [dependencies] tiny_pretty.workspace = true itertools.workspace = true diff --git a/crates/squawk_parser/src/generated/syntax_kind.rs b/crates/squawk_parser/src/generated/syntax_kind.rs index 1b372638..b90468af 100644 --- a/crates/squawk_parser/src/generated/syntax_kind.rs +++ b/crates/squawk_parser/src/generated/syntax_kind.rs @@ -613,6 +613,7 @@ pub enum SyntaxKind { ARRAY_TYPE, AS_FUNC_OPTION, AS_NAME, + AS_POLICY_TYPE, ATTACH_PARTITION, ATTRIBUTE_LIST, ATTRIBUTE_OPTION, @@ -1138,6 +1139,7 @@ pub enum SyntaxKind { UNLISTEN, UPDATE, USING_CLAUSE, + USING_EXPR_CLAUSE, USING_INDEX, USING_METHOD, USING_ON_CLAUSE, @@ -1162,6 +1164,7 @@ pub enum SyntaxKind { WITHIN_CLAUSE, WITHOUT_OIDS, WITHOUT_TIMEZONE, + WITH_CHECK_EXPR_CLAUSE, WITH_CLAUSE, WITH_DATA, WITH_NO_DATA, diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index 586097fa..12f535f4 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -6234,25 +6234,25 @@ fn alter_policy(p: &mut Parser<'_>) -> CompletedMarker { if p.eat(TO_KW) { role_list(p); } - if p.eat(USING_KW) { - p.expect(L_PAREN); - if expr(p).is_none() { - p.error("expected expression"); - } - p.expect(R_PAREN); - } - if p.eat(WITH_KW) { - p.expect(CHECK_KW); - p.expect(L_PAREN); - if expr(p).is_none() { - p.error("expected expression"); - } - p.expect(R_PAREN); - } + opt_using_expr_clause(p); + opt_with_check_expr_clause(p); } m.complete(p, ALTER_POLICY) } +fn opt_using_expr_clause(p: &mut Parser<'_>) { + if p.at(USING_KW) { + let m = p.start(); + p.bump(USING_KW); + p.expect(L_PAREN); + if expr(p).is_none() { + p.error("expected expression"); + } + p.expect(R_PAREN); + m.complete(p, USING_EXPR_CLAUSE); + } +} + fn role_list(p: &mut Parser<'_>) { let m = p.start(); role_ref(p); @@ -9042,9 +9042,7 @@ fn create_policy(p: &mut Parser<'_>) -> CompletedMarker { p.bump(POLICY_KW); name(p); on_table(p); - if p.eat(AS_KW) { - ident(p); - } + opt_as_policy_type(p); if p.eat(FOR_KW) { let _ = p.eat(ALL_KW) || p.eat(SELECT_KW) @@ -9055,22 +9053,33 @@ fn create_policy(p: &mut Parser<'_>) -> CompletedMarker { if p.eat(TO_KW) { role_list(p); } - if p.eat(USING_KW) { - p.expect(L_PAREN); - if expr(p).is_none() { - p.error("expected expression"); - } - p.expect(R_PAREN); + opt_using_expr_clause(p); + opt_with_check_expr_clause(p); + m.complete(p, CREATE_POLICY) +} + +fn opt_as_policy_type(p: &mut Parser<'_>) { + let m = p.start(); + if p.eat(AS_KW) { + ident(p); + m.complete(p, AS_POLICY_TYPE); + } else { + m.abandon(p); } - if p.eat(WITH_KW) { +} + +fn opt_with_check_expr_clause(p: &mut Parser<'_>) { + if p.at(WITH_KW) { + let m = p.start(); + p.bump(WITH_KW); p.expect(CHECK_KW); p.expect(L_PAREN); if expr(p).is_none() { p.error("expected expression"); } p.expect(R_PAREN); + m.complete(p, WITH_CHECK_EXPR_CLAUSE); } - m.complete(p, CREATE_POLICY) } // CREATE [ OR REPLACE ] PROCEDURE diff --git a/crates/squawk_parser/tests/snapshots/tests__alter_policy_ok.snap b/crates/squawk_parser/tests/snapshots/tests__alter_policy_ok.snap index cd4a0c46..82aa33e5 100644 --- a/crates/squawk_parser/tests/snapshots/tests__alter_policy_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__alter_policy_ok.snap @@ -109,18 +109,19 @@ SOURCE_FILE NAME_REF IDENT "t" WHITESPACE "\n " - USING_KW "using" - WHITESPACE " " - L_PAREN "(" - BIN_EXPR - NAME_REF - IDENT "a" - WHITESPACE " " - EQ "=" + USING_EXPR_CLAUSE + USING_KW "using" WHITESPACE " " - NAME_REF - IDENT "b" - R_PAREN ")" + L_PAREN "(" + BIN_EXPR + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + NAME_REF + IDENT "b" + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- with_check" @@ -141,20 +142,21 @@ SOURCE_FILE NAME_REF IDENT "t" WHITESPACE "\n " - WITH_KW "with" - WHITESPACE " " - CHECK_KW "check" - WHITESPACE " " - L_PAREN "(" - BIN_EXPR - NAME_REF - IDENT "c" + WITH_CHECK_EXPR_CLAUSE + WITH_KW "with" WHITESPACE " " - R_ANGLE ">" + CHECK_KW "check" WHITESPACE " " - NAME_REF - IDENT "d" - R_PAREN ")" + L_PAREN "(" + BIN_EXPR + NAME_REF + IDENT "c" + WHITESPACE " " + R_ANGLE ">" + WHITESPACE " " + NAME_REF + IDENT "d" + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- full" @@ -187,32 +189,34 @@ SOURCE_FILE NAME_REF IDENT "s" WHITESPACE "\n " - USING_KW "using" - WHITESPACE " " - L_PAREN "(" - BIN_EXPR - NAME_REF - IDENT "a" - WHITESPACE " " - EQ "=" + USING_EXPR_CLAUSE + USING_KW "using" WHITESPACE " " - NAME_REF - IDENT "b" - R_PAREN ")" + L_PAREN "(" + BIN_EXPR + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + NAME_REF + IDENT "b" + R_PAREN ")" WHITESPACE "\n " - WITH_KW "with" - WHITESPACE " " - CHECK_KW "check" - WHITESPACE " " - L_PAREN "(" - BIN_EXPR - NAME_REF - IDENT "c" + WITH_CHECK_EXPR_CLAUSE + WITH_KW "with" WHITESPACE " " - R_ANGLE ">" + CHECK_KW "check" WHITESPACE " " - NAME_REF - IDENT "d" - R_PAREN ")" + L_PAREN "(" + BIN_EXPR + NAME_REF + IDENT "c" + WHITESPACE " " + R_ANGLE ">" + WHITESPACE " " + NAME_REF + IDENT "d" + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_policy_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_policy_ok.snap index 66db4dd4..70426e47 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_policy_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_policy_ok.snap @@ -40,9 +40,10 @@ SOURCE_FILE NAME_REF IDENT "t" WHITESPACE "\n " - AS_KW "as" - WHITESPACE " " - IDENT "permissive" + AS_POLICY_TYPE + AS_KW "as" + WHITESPACE " " + IDENT "permissive" SEMICOLON ";" WHITESPACE "\n\n" CREATE_POLICY @@ -61,9 +62,10 @@ SOURCE_FILE NAME_REF IDENT "t" WHITESPACE "\n " - AS_KW "as" - WHITESPACE " " - IDENT "restrictive" + AS_POLICY_TYPE + AS_KW "as" + WHITESPACE " " + IDENT "restrictive" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- full" @@ -89,9 +91,10 @@ SOURCE_FILE NAME_REF IDENT "t" WHITESPACE "\n " - AS_KW "as" - WHITESPACE " " - IDENT "permissive" + AS_POLICY_TYPE + AS_KW "as" + WHITESPACE " " + IDENT "permissive" WHITESPACE "\n " FOR_KW "for" WHITESPACE " " @@ -116,46 +119,48 @@ SOURCE_FILE ROLE_REF SESSION_USER_KW "session_user" WHITESPACE "\n " - USING_KW "using" - WHITESPACE " " - L_PAREN "(" - BIN_EXPR + USING_EXPR_CLAUSE + USING_KW "using" + WHITESPACE " " + L_PAREN "(" BIN_EXPR - NAME_REF - IDENT "x" + BIN_EXPR + NAME_REF + IDENT "x" + WHITESPACE " " + R_ANGLE ">" + WHITESPACE " " + NAME_REF + IDENT "b" WHITESPACE " " - R_ANGLE ">" + AND_KW "and" WHITESPACE " " - NAME_REF - IDENT "b" + BIN_EXPR + LITERAL + INT_NUMBER "1" + WHITESPACE " " + L_ANGLE "<" + WHITESPACE " " + LITERAL + INT_NUMBER "2" + R_PAREN ")" + WHITESPACE "\n " + WITH_CHECK_EXPR_CLAUSE + WITH_KW "with" + WHITESPACE " " + CHECK_KW "check" WHITESPACE " " - AND_KW "and" + L_PAREN "(" WHITESPACE " " BIN_EXPR - LITERAL - INT_NUMBER "1" + NAME_REF + IDENT "x" WHITESPACE " " L_ANGLE "<" WHITESPACE " " LITERAL - INT_NUMBER "2" - R_PAREN ")" - WHITESPACE "\n " - WITH_KW "with" - WHITESPACE " " - CHECK_KW "check" - WHITESPACE " " - L_PAREN "(" - WHITESPACE " " - BIN_EXPR - NAME_REF - IDENT "x" - WHITESPACE " " - L_ANGLE "<" - WHITESPACE " " - LITERAL - INT_NUMBER "1" - R_PAREN ")" + INT_NUMBER "1" + R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" COMMENT "-- for_" diff --git a/crates/squawk_syntax/src/ast/generated/nodes.rs b/crates/squawk_syntax/src/ast/generated/nodes.rs index aafbfd54..bd6a0f32 100644 --- a/crates/squawk_syntax/src/ast/generated/nodes.rs +++ b/crates/squawk_syntax/src/ast/generated/nodes.rs @@ -998,10 +998,6 @@ pub struct AlterPolicy { pub(crate) syntax: SyntaxNode, } impl AlterPolicy { - #[inline] - pub fn expr(&self) -> Option { - support::child(&self.syntax) - } #[inline] pub fn name_ref(&self) -> Option { support::child(&self.syntax) @@ -1019,22 +1015,18 @@ impl AlterPolicy { support::child(&self.syntax) } #[inline] - pub fn l_paren_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::L_PAREN) + pub fn using_expr_clause(&self) -> Option { + support::child(&self.syntax) } #[inline] - pub fn r_paren_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::R_PAREN) + pub fn with_check_expr_clause(&self) -> Option { + support::child(&self.syntax) } #[inline] pub fn alter_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::ALTER_KW) } #[inline] - pub fn check_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::CHECK_KW) - } - #[inline] pub fn policy_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::POLICY_KW) } @@ -1042,14 +1034,6 @@ impl AlterPolicy { pub fn to_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::TO_KW) } - #[inline] - pub fn using_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::USING_KW) - } - #[inline] - pub fn with_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::WITH_KW) - } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1921,6 +1905,21 @@ impl AsName { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AsPolicyType { + pub(crate) syntax: SyntaxNode, +} +impl AsPolicyType { + #[inline] + pub fn as_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::AS_KW) + } + #[inline] + pub fn ident_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::IDENT) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AtTimeZone { pub(crate) syntax: SyntaxNode, @@ -3922,7 +3921,7 @@ pub struct CreatePolicy { } impl CreatePolicy { #[inline] - pub fn expr(&self) -> Option { + pub fn as_policy_type(&self) -> Option { support::child(&self.syntax) } #[inline] @@ -3938,26 +3937,18 @@ impl CreatePolicy { support::child(&self.syntax) } #[inline] - pub fn l_paren_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::L_PAREN) + pub fn using_expr_clause(&self) -> Option { + support::child(&self.syntax) } #[inline] - pub fn r_paren_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::R_PAREN) + pub fn with_check_expr_clause(&self) -> Option { + support::child(&self.syntax) } #[inline] pub fn all_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::ALL_KW) } #[inline] - pub fn as_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::AS_KW) - } - #[inline] - pub fn check_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::CHECK_KW) - } - #[inline] pub fn create_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::CREATE_KW) } @@ -3970,10 +3961,6 @@ impl CreatePolicy { support::token(&self.syntax, SyntaxKind::FOR_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) } @@ -3993,14 +3980,6 @@ impl CreatePolicy { pub fn update_token(&self) -> Option { support::token(&self.syntax, SyntaxKind::UPDATE_KW) } - #[inline] - pub fn using_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::USING_KW) - } - #[inline] - pub fn with_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::WITH_KW) - } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -15487,6 +15466,29 @@ impl UsingClause { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UsingExprClause { + pub(crate) syntax: SyntaxNode, +} +impl UsingExprClause { + #[inline] + pub fn expr(&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 using_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::USING_KW) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct UsingIndex { pub(crate) syntax: SyntaxNode, @@ -15894,6 +15896,33 @@ impl WindowSpec { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct WithCheckExprClause { + pub(crate) syntax: SyntaxNode, +} +impl WithCheckExprClause { + #[inline] + pub fn expr(&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 check_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::CHECK_KW) + } + #[inline] + pub fn with_token(&self) -> Option { + support::token(&self.syntax, SyntaxKind::WITH_KW) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct WithClause { pub(crate) syntax: SyntaxNode, @@ -18268,6 +18297,24 @@ impl AstNode for AsName { &self.syntax } } +impl AstNode for AsPolicyType { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::AS_POLICY_TYPE + } + #[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 AtTimeZone { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -27718,6 +27765,24 @@ impl AstNode for UsingClause { &self.syntax } } +impl AstNode for UsingExprClause { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::USING_EXPR_CLAUSE + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for UsingIndex { #[inline] fn can_cast(kind: SyntaxKind) -> bool { @@ -28096,6 +28161,24 @@ impl AstNode for WindowSpec { &self.syntax } } +impl AstNode for WithCheckExprClause { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + kind == SyntaxKind::WITH_CHECK_EXPR_CLAUSE + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for WithClause { #[inline] fn can_cast(kind: SyntaxKind) -> bool { diff --git a/crates/squawk_syntax/src/postgresql.ungram b/crates/squawk_syntax/src/postgresql.ungram index 36376e87..a3c75728 100644 --- a/crates/squawk_syntax/src/postgresql.ungram +++ b/crates/squawk_syntax/src/postgresql.ungram @@ -1818,10 +1818,12 @@ AlterProcedure = AlterPolicy = 'alter' 'policy' NameRef OnTable (RenameTo - | 'to' RoleRefList - | 'using' '(' Expr ')' - | 'with' 'check' '(' Expr ')' - )? + | ( + ('to' RoleRefList)? + UsingExprClause? + WithCheckExprClause? + )) + AlterOperatorFamily = 'alter' 'operator' 'family' Path 'using' NameRef @@ -2227,11 +2229,20 @@ CreateOperatorFamily = CreatePolicy = 'create' 'policy' Name OnTable - ('as' '#ident')? + AsPolicyType? ('for' ('all' | 'select' | 'insert' | 'update' | 'delete'))? ('to' RoleRefList)? - ('using' '(' Expr ')') - ('with' 'check' '(' Expr ')') + UsingExprClause? + WithCheckExprClause? + +AsPolicyType = + 'as' '#ident' + +WithCheckExprClause = + 'with' 'check' '(' Expr ')' + +UsingExprClause = + 'using' '(' Expr ')' CreateProcedure = 'create' OrReplace? 'procedure' Path ParamList option_list:FuncOptionList