From 03af33796a75f2369802cac72f6fa9f6f51dc66b Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Sun, 13 Mar 2022 00:18:23 +0000 Subject: [PATCH] Fix arithmetic and boolean binary expression order Previously the expression operations happened right-to-left so `1 - 2 - 3 - 4 - 5` was actually calculated as `(1 - (2 - (3 - (4 - (5)))))`. Now the expressions are calculated according to BODMAS, with boolean expressions calculated last. --- lib/src/sql/expression.rs | 42 ++++++++++++++++++++++++++++++-------- lib/src/sql/operator.rs | 15 ++++++++++++++ lib/src/sql/value/value.rs | 6 ++++++ 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/lib/src/sql/expression.rs b/lib/src/sql/expression.rs index de540358..323ef5d6 100644 --- a/lib/src/sql/expression.rs +++ b/lib/src/sql/expression.rs @@ -27,6 +27,35 @@ impl Default for Expression { } } +impl Expression { + // Create a new expression + pub fn new(l: Value, o: Operator, r: Value) -> Expression { + Expression { + l, + o, + r, + } + } + // Augment an existing expression + pub fn augment(mut self, l: Value, o: Operator) -> Expression { + if o.precedence() >= self.o.precedence() { + match self.l { + Value::Expression(x) => { + self.l = x.augment(l, o).into(); + self + } + _ => { + self.l = Expression::new(l, o, self.l).into(); + self + } + } + } else { + let r = Value::from(self); + Expression::new(l, o, r) + } + } +} + impl Expression { pub async fn compute( &self, @@ -96,14 +125,11 @@ pub fn expression(i: &str) -> IResult<&str, Expression> { let (i, l) = single(i)?; let (i, o) = operator(i)?; let (i, r) = value(i)?; - Ok(( - i, - Expression { - l, - o, - r, - }, - )) + let v = match r { + Value::Expression(r) => r.augment(l, o), + _ => Expression::new(l, o, r), + }; + Ok((i, v)) } #[cfg(test)] diff --git a/lib/src/sql/operator.rs b/lib/src/sql/operator.rs index 6f1702c0..a2c0bd87 100644 --- a/lib/src/sql/operator.rs +++ b/lib/src/sql/operator.rs @@ -56,6 +56,21 @@ impl Default for Operator { } } +impl Operator { + #[inline] + pub fn precedence(&self) -> u8 { + match self { + Operator::Or => 1, + Operator::And => 2, + Operator::Sub => 4, + Operator::Add => 5, + Operator::Mul => 6, + Operator::Div => 7, + _ => 3, + } + } +} + impl fmt::Display for Operator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index f3a56571..5c0622a2 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -201,6 +201,12 @@ impl From for Value { } } +impl From> for Value { + fn from(v: Box) -> Self { + Value::Expression(v) + } +} + impl From for Value { fn from(v: i8) -> Self { Value::Number(Number::from(v))