This is an automated email from the ASF dual-hosted git repository. LucaCappelletti94 pushed a commit to branch prefix-bang-display-space in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 545dda21b8356b4680700591232b6e762f3ce12f Author: LucaCappelletti94 <[email protected]> AuthorDate: Tue Sep 22 10:05:13 2026 +0200 Generic: Render prefix ! operator with space before operator characters --- src/ast/mod.rs | 32 ++++++++++++++------------------ tests/sqlparser_common.rs | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index dcfd1a96..9d001ead 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1965,7 +1965,7 @@ impl fmt::Display for Expr { | UnaryOperator::PGAbs | UnaryOperator::QuestionDash | UnaryOperator::QuestionPipe => write!(f, "{op} {expr}"), - UnaryOperator::Minus => { + UnaryOperator::Minus | UnaryOperator::BangNot => { if starts_with_operator_char(expr) { write!(f, "{op} {expr}") } else { @@ -1973,7 +1973,6 @@ impl fmt::Display for Expr { } } UnaryOperator::Plus - | UnaryOperator::BangNot | UnaryOperator::PGPrefixFactorial | UnaryOperator::PGSquareRoot | UnaryOperator::PGCubeRoot => write!(f, "{op}{expr}"), @@ -8089,24 +8088,21 @@ impl fmt::Display for FunctionArg { } } -/// Whether `expr` renders with an operator character first. A prefix `-` -/// must not abut one, since `--` starts a line comment and operator-run -/// dialects fuse `-@`, `-~`, `-#`, `-!!` and `-||/` into single tokens. -fn starts_with_operator_char(expr: &Expr) -> bool { - use fmt::Write; - struct FirstChar(Option<char>); - impl fmt::Write for FirstChar { - fn write_str(&mut self, s: &str) -> fmt::Result { - if self.0.is_none() { - self.0 = s.chars().next(); - } - Ok(()) +/// Whether `expr` renders with an operator character first. A prefix `-` or `!` +/// must not abut one, since `--` starts a line comment and compound tokens +/// like `!!` or `!~` alter the parsed AST or fail to parse. +fn starts_with_operator_char(mut expr: &Expr) -> bool { + loop { + match expr { + Expr::UnaryOp { op, expr: inner } => match op { + UnaryOperator::PGPostfixFactorial => expr = inner, + UnaryOperator::Not => return false, + _ => return true, + }, + Expr::BinaryOp { left, .. } => expr = left, + _ => return false, } } - let mut first = FirstChar(None); - let _ = write!(first, "{expr}"); - const OPERATOR_CHARS: &str = "+-*/<>=~!@%#^&|"; - first.0.is_some_and(|c| OPERATOR_CHARS.contains(c)) } /// `FunctionArgOperator::Space` has no token of its own, so the name and the diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index c4aa607d..63aa2a7d 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -20080,3 +20080,17 @@ fn parse_unary_minus_never_renders_line_comment() { all_dialects().verified_stmt("SELECT -1"); all_dialects().verified_stmt("SELECT -x"); } + +#[test] +fn parse_bang_not_renders_apart_from_operand() { + let dialects = all_dialects_where(|d| d.supports_bang_not_operator()); + dialects.verified_stmt("SELECT ! !a"); + dialects.verified_stmt("SELECT ! ! !a"); + dialects.verified_stmt("SELECT ! ~ a"); + dialects.verified_stmt("SELECT ! -a"); + dialects.verified_stmt("SELECT ! +a"); + dialects.verified_stmt("SELECT !a"); + dialects.verified_stmt("SELECT !(b > 3)"); + dialects.verified_stmt("SET eaac_cion = ! !o"); + dialects.one_statement_parses_to("SET eaac_cion = ! ! o", "SET eaac_cion = ! !o"); +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
