From 140890c27951541a717998abf861eaeb4c97b9f6 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Sun, 25 Jul 2021 22:51:25 -0400 Subject: [PATCH] refactor evaluation of order of operations --- src/parse/value/eval.rs | 79 +++++++++++++++++++++++++++++++----- tests/order-of-operations.rs | 5 +++ 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/src/parse/value/eval.rs b/src/parse/value/eval.rs index e0ab381..3adbf03 100644 --- a/src/parse/value/eval.rs +++ b/src/parse/value/eval.rs @@ -60,6 +60,65 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> { } } + fn bin_op_one_level( + &mut self, + val1: HigherIntermediateValue, + op: Op, + val2: HigherIntermediateValue, + in_parens: bool, + ) -> SassResult { + let val1 = self.unary(val1, in_parens)?; + let val2 = self.unary(val2, in_parens)?; + + let val1 = match val1 { + HigherIntermediateValue::Literal(val1) => val1, + HigherIntermediateValue::BinaryOp(val1_1, val1_op, val1_2) => { + if val1_op.precedence() >= op.precedence() { + return Ok(HigherIntermediateValue::BinaryOp( + Box::new(self.bin_op_one_level(*val1_1, val1_op, *val1_2, in_parens)?), + op, + Box::new(val2), + )); + } else { + return Ok(HigherIntermediateValue::BinaryOp( + val1_1, + val1_op, + Box::new(self.bin_op_one_level(*val1_2, op, val2, in_parens)?), + )); + } + } + _ => unreachable!(), + }; + + let val2 = match val2 { + HigherIntermediateValue::Literal(val2) => val2, + HigherIntermediateValue::BinaryOp(val2_1, val2_op, val2_2) => { + todo!() + } + _ => unreachable!(), + }; + + let val1 = HigherIntermediateValue::Literal(val1); + let val2 = HigherIntermediateValue::Literal(val2); + + Ok(HigherIntermediateValue::Literal(match op { + Op::Plus => self.add(val1, val2)?, + Op::Minus => self.sub(val1, val2)?, + Op::Mul => self.mul(val1, val2)?, + Op::Div => self.div(val1, val2, in_parens)?, + Op::Rem => self.rem(val1, val2)?, + Op::And => Self::and(val1, val2), + Op::Or => Self::or(val1, val2), + Op::Equal => Self::equal(val1, val2), + Op::NotEqual => Self::not_equal(val1, val2), + Op::GreaterThan => self.greater_than(val1, val2)?, + Op::GreaterThanEqual => self.greater_than_or_equal(val1, val2)?, + Op::LessThan => self.less_than(val1, val2)?, + Op::LessThanEqual => self.less_than_or_equal(val1, val2)?, + Op::Not => unreachable!(), + })) + } + fn bin_op( &mut self, val1: HigherIntermediateValue, @@ -68,18 +127,17 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> { in_parens: bool, ) -> SassResult { let mut val1 = self.unary(val1, in_parens)?; - let val2 = self.unary(val2, in_parens)?; + let mut val2 = self.unary(val2, in_parens)?; - if let HigherIntermediateValue::BinaryOp(val1_1, op2, val1_2) = val1 { - let in_parens = op != Op::Div || op2 != Op::Div; - if op2.precedence() >= op.precedence() { - val1 = HigherIntermediateValue::Literal( - self.bin_op(*val1_1, op2, *val1_2, in_parens)?, - ); + if let HigherIntermediateValue::BinaryOp(val1_1, val1_op, val1_2) = val1 { + let in_parens = op != Op::Div || val1_op != Op::Div; + + if val1_op.precedence() >= op.precedence() { + val1 = self.bin_op_one_level(*val1_1, val1_op, *val1_2, in_parens)?; + return self.bin_op(val1, op, val2, in_parens); } else { - let val2 = - HigherIntermediateValue::Literal(self.bin_op(*val1_2, op, val2, in_parens)?); - return self.bin_op(*val1_1, op2, val2, in_parens); + val2 = self.bin_op_one_level(*val1_2, op, val2, in_parens)?; + return self.bin_op(*val1_1, val1_op, val2, in_parens); } } @@ -243,6 +301,7 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> { .into()); } if unit == unit2 { + // dbg!(&num, &num2, num.clone() + num2.clone(), unit.clone(), unit2.clone()); Value::Dimension(Some(num + num2), unit, true) } else if unit == Unit::None { Value::Dimension(Some(num + num2), unit2, true) diff --git a/tests/order-of-operations.rs b/tests/order-of-operations.rs index d6c1211..185b8c1 100644 --- a/tests/order-of-operations.rs +++ b/tests/order-of-operations.rs @@ -41,3 +41,8 @@ test!( "a {\n color: 1 / 2 * 1em;\n}\n", "a {\n color: 0.5em;\n}\n" ); +test!( + triple_bin_op_first_is_lower_precendence, + "a {\n color: 8 + 1 * 2 * 0;\n}\n", + "a {\n color: 8;\n}\n" +);