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.
This commit is contained in:
Tobie Morgan Hitchcock 2022-03-13 00:18:23 +00:00
parent 0f6d700f6b
commit 03af33796a
3 changed files with 55 additions and 8 deletions

View file

@ -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 { impl Expression {
pub async fn compute( pub async fn compute(
&self, &self,
@ -96,14 +125,11 @@ pub fn expression(i: &str) -> IResult<&str, Expression> {
let (i, l) = single(i)?; let (i, l) = single(i)?;
let (i, o) = operator(i)?; let (i, o) = operator(i)?;
let (i, r) = value(i)?; let (i, r) = value(i)?;
Ok(( let v = match r {
i, Value::Expression(r) => r.augment(l, o),
Expression { _ => Expression::new(l, o, r),
l, };
o, Ok((i, v))
r,
},
))
} }
#[cfg(test)] #[cfg(test)]

View file

@ -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 { impl fmt::Display for Operator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {

View file

@ -201,6 +201,12 @@ impl From<Expression> for Value {
} }
} }
impl From<Box<Expression>> for Value {
fn from(v: Box<Expression>) -> Self {
Value::Expression(v)
}
}
impl From<i8> for Value { impl From<i8> for Value {
fn from(v: i8) -> Self { fn from(v: i8) -> Self {
Value::Number(Number::from(v)) Value::Number(Number::from(v))