use crate::expr_fn::binary_expr;
use crate::Expr;
use crate::Like;
use std::fmt;
use std::ops;
use std::ops::Not;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
pub enum Operator {
Eq,
NotEq,
Lt,
LtEq,
Gt,
GtEq,
Plus,
Minus,
Multiply,
Divide,
Modulo,
And,
Or,
IsDistinctFrom,
IsNotDistinctFrom,
RegexMatch,
RegexIMatch,
RegexNotMatch,
RegexNotIMatch,
BitwiseAnd,
BitwiseOr,
BitwiseXor,
BitwiseShiftRight,
BitwiseShiftLeft,
StringConcat,
AtArrow,
ArrowAt,
}
impl Operator {
pub fn negate(&self) -> Option<Operator> {
match self {
Operator::Eq => Some(Operator::NotEq),
Operator::NotEq => Some(Operator::Eq),
Operator::Lt => Some(Operator::GtEq),
Operator::LtEq => Some(Operator::Gt),
Operator::Gt => Some(Operator::LtEq),
Operator::GtEq => Some(Operator::Lt),
Operator::IsDistinctFrom => Some(Operator::IsNotDistinctFrom),
Operator::IsNotDistinctFrom => Some(Operator::IsDistinctFrom),
Operator::Plus
| Operator::Minus
| Operator::Multiply
| Operator::Divide
| Operator::Modulo
| Operator::And
| Operator::Or
| Operator::RegexMatch
| Operator::RegexIMatch
| Operator::RegexNotMatch
| Operator::RegexNotIMatch
| Operator::BitwiseAnd
| Operator::BitwiseOr
| Operator::BitwiseXor
| Operator::BitwiseShiftRight
| Operator::BitwiseShiftLeft
| Operator::StringConcat
| Operator::AtArrow
| Operator::ArrowAt => None,
}
}
pub fn is_numerical_operators(&self) -> bool {
matches!(
self,
Operator::Plus
| Operator::Minus
| Operator::Multiply
| Operator::Divide
| Operator::Modulo
)
}
pub fn is_comparison_operator(&self) -> bool {
matches!(
self,
Operator::Eq
| Operator::NotEq
| Operator::Lt
| Operator::LtEq
| Operator::Gt
| Operator::GtEq
| Operator::IsDistinctFrom
| Operator::IsNotDistinctFrom
| Operator::RegexMatch
| Operator::RegexIMatch
| Operator::RegexNotMatch
| Operator::RegexNotIMatch
)
}
pub fn is_logic_operator(&self) -> bool {
matches!(self, Operator::And | Operator::Or)
}
pub fn swap(&self) -> Option<Operator> {
match self {
Operator::Eq => Some(Operator::Eq),
Operator::NotEq => Some(Operator::NotEq),
Operator::Lt => Some(Operator::Gt),
Operator::LtEq => Some(Operator::GtEq),
Operator::Gt => Some(Operator::Lt),
Operator::GtEq => Some(Operator::LtEq),
Operator::AtArrow => Some(Operator::ArrowAt),
Operator::ArrowAt => Some(Operator::AtArrow),
Operator::IsDistinctFrom
| Operator::IsNotDistinctFrom
| Operator::Plus
| Operator::Minus
| Operator::Multiply
| Operator::Divide
| Operator::Modulo
| Operator::And
| Operator::Or
| Operator::RegexMatch
| Operator::RegexIMatch
| Operator::RegexNotMatch
| Operator::RegexNotIMatch
| Operator::BitwiseAnd
| Operator::BitwiseOr
| Operator::BitwiseXor
| Operator::BitwiseShiftRight
| Operator::BitwiseShiftLeft
| Operator::StringConcat => None,
}
}
pub fn precedence(&self) -> u8 {
match self {
Operator::Or => 5,
Operator::And => 10,
Operator::NotEq
| Operator::Eq
| Operator::Lt
| Operator::LtEq
| Operator::Gt
| Operator::GtEq => 20,
Operator::Plus | Operator::Minus => 30,
Operator::Multiply | Operator::Divide | Operator::Modulo => 40,
Operator::IsDistinctFrom
| Operator::IsNotDistinctFrom
| Operator::RegexMatch
| Operator::RegexNotMatch
| Operator::RegexIMatch
| Operator::RegexNotIMatch
| Operator::BitwiseAnd
| Operator::BitwiseOr
| Operator::BitwiseShiftLeft
| Operator::BitwiseShiftRight
| Operator::BitwiseXor
| Operator::StringConcat
| Operator::AtArrow
| Operator::ArrowAt => 0,
}
}
}
impl fmt::Display for Operator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let display = match &self {
Operator::Eq => "=",
Operator::NotEq => "!=",
Operator::Lt => "<",
Operator::LtEq => "<=",
Operator::Gt => ">",
Operator::GtEq => ">=",
Operator::Plus => "+",
Operator::Minus => "-",
Operator::Multiply => "*",
Operator::Divide => "/",
Operator::Modulo => "%",
Operator::And => "AND",
Operator::Or => "OR",
Operator::RegexMatch => "~",
Operator::RegexIMatch => "~*",
Operator::RegexNotMatch => "!~",
Operator::RegexNotIMatch => "!~*",
Operator::IsDistinctFrom => "IS DISTINCT FROM",
Operator::IsNotDistinctFrom => "IS NOT DISTINCT FROM",
Operator::BitwiseAnd => "&",
Operator::BitwiseOr => "|",
Operator::BitwiseXor => "BIT_XOR",
Operator::BitwiseShiftRight => ">>",
Operator::BitwiseShiftLeft => "<<",
Operator::StringConcat => "||",
Operator::AtArrow => "@>",
Operator::ArrowAt => "<@",
};
write!(f, "{display}")
}
}
impl ops::Add for Expr {
type Output = Self;
fn add(self, rhs: Self) -> Self {
binary_expr(self, Operator::Plus, rhs)
}
}
impl ops::Sub for Expr {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
binary_expr(self, Operator::Minus, rhs)
}
}
impl ops::Mul for Expr {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
binary_expr(self, Operator::Multiply, rhs)
}
}
impl ops::Div for Expr {
type Output = Self;
fn div(self, rhs: Self) -> Self {
binary_expr(self, Operator::Divide, rhs)
}
}
impl ops::Rem for Expr {
type Output = Self;
fn rem(self, rhs: Self) -> Self {
binary_expr(self, Operator::Modulo, rhs)
}
}
impl ops::BitAnd for Expr {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
binary_expr(self, Operator::BitwiseAnd, rhs)
}
}
impl ops::BitOr for Expr {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
binary_expr(self, Operator::BitwiseOr, rhs)
}
}
impl ops::BitXor for Expr {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self {
binary_expr(self, Operator::BitwiseXor, rhs)
}
}
impl ops::Shl for Expr {
type Output = Self;
fn shl(self, rhs: Self) -> Self::Output {
binary_expr(self, Operator::BitwiseShiftLeft, rhs)
}
}
impl ops::Shr for Expr {
type Output = Self;
fn shr(self, rhs: Self) -> Self::Output {
binary_expr(self, Operator::BitwiseShiftRight, rhs)
}
}
impl ops::Neg for Expr {
type Output = Self;
fn neg(self) -> Self::Output {
Expr::Negative(Box::new(self))
}
}
impl Not for Expr {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Expr::Like(Like {
negated,
expr,
pattern,
escape_char,
case_insensitive,
}) => Expr::Like(Like::new(
!negated,
expr,
pattern,
escape_char,
case_insensitive,
)),
Expr::SimilarTo(Like {
negated,
expr,
pattern,
escape_char,
case_insensitive,
}) => Expr::SimilarTo(Like::new(
!negated,
expr,
pattern,
escape_char,
case_insensitive,
)),
_ => Expr::Not(Box::new(self)),
}
}
}
#[cfg(test)]
mod tests {
use crate::lit;
#[test]
fn test_operators() {
assert_eq!(
format!("{}", lit(1u32) + lit(2u32)),
"UInt32(1) + UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) - lit(2u32)),
"UInt32(1) - UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) * lit(2u32)),
"UInt32(1) * UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) / lit(2u32)),
"UInt32(1) / UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) % lit(2u32)),
"UInt32(1) % UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) & lit(2u32)),
"UInt32(1) & UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) | lit(2u32)),
"UInt32(1) | UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) ^ lit(2u32)),
"UInt32(1) BIT_XOR UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) << lit(2u32)),
"UInt32(1) << UInt32(2)"
);
assert_eq!(
format!("{}", lit(1u32) >> lit(2u32)),
"UInt32(1) >> UInt32(2)"
);
assert_eq!(format!("{}", -lit(1u32)), "(- UInt32(1))");
assert_eq!(format!("{}", !lit(1u32)), "NOT UInt32(1)");
}
}