Fix unary operator precedence.

Before, unary operators that appeared after an operator with higher precedence would be executed after that operator.

However, in evalexpr, the two unary operators are prefix operators negation and not, and prefix operators always happen before operators directly left of them.
This commit is contained in:
Sebastian Schmidt 2023-04-13 14:42:39 +03:00
parent 9d0a776346
commit 4fd86751dc
3 changed files with 25 additions and 11 deletions

View File

@ -173,6 +173,11 @@ impl Operator {
} }
} }
/// Returns true if this operator is unary, i.e. it requires exactly one argument.
pub(crate) fn is_unary(&self) -> bool {
self.max_argument_amount() == Some(1) && *self != Operator::RootNode
}
/// Evaluates the operator with the given arguments and context. /// Evaluates the operator with the given arguments and context.
pub(crate) fn eval<C: Context>( pub(crate) fn eval<C: Context>(
&self, &self,

View File

@ -459,8 +459,13 @@ impl Node {
} }
fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> EvalexprResult<()> { fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> EvalexprResult<()> {
// println!("Inserting {:?} into {:?}", node.operator, self.operator()); println!(
if self.operator().precedence() < node.operator().precedence() || is_root_node "Inserting {:?} into {:?}, is_root_node = {is_root_node}",
node.operator(),
self.operator()
);
println!("Self is {:?}", self);
if self.operator().precedence() < node.operator().precedence() || node.operator().is_unary() || is_root_node
// Right-to-left chaining // Right-to-left chaining
|| (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right()) || (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right())
{ {
@ -471,19 +476,22 @@ impl Node {
let last_child_operator = self.children.last().unwrap().operator(); let last_child_operator = self.children.last().unwrap().operator();
if last_child_operator.precedence() if last_child_operator.precedence()
< node.operator().precedence() < node.operator().precedence() || node.operator().is_unary()
// Right-to-left chaining // Right-to-left chaining
|| (last_child_operator.precedence() || (last_child_operator.precedence()
== node.operator().precedence() && !last_child_operator.is_left_to_right() && !node.operator().is_left_to_right()) == node.operator().precedence() && !last_child_operator.is_left_to_right() && !node.operator().is_left_to_right())
{ {
// println!("Recursing into {:?}", self.children.last().unwrap().operator()); println!(
"Recursing into {:?}",
self.children.last().unwrap().operator()
);
// Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child // Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child
self.children self.children
.last_mut() .last_mut()
.unwrap() .unwrap()
.insert_back_prioritized(node, false) .insert_back_prioritized(node, false)
} else { } else {
// println!("Rotating"); println!("Rotating");
if node.operator().is_leaf() { if node.operator().is_leaf() {
return Err(EvalexprError::AppendedToLeafNode); return Err(EvalexprError::AppendedToLeafNode);
} }
@ -521,7 +529,7 @@ impl Node {
Ok(()) Ok(())
} }
} else { } else {
// println!("Inserting as specified"); println!("Inserting as specified");
self.children.push(node); self.children.push(node);
Ok(()) Ok(())
} }

View File

@ -2148,6 +2148,7 @@ fn test_variable_assignment_and_iteration() {
#[test] #[test]
fn test_negative_power() { fn test_negative_power() {
println!("{:?}", build_operator_tree("3^-2").unwrap());
assert_eq!(eval("3^-2"), Ok(Value::Float(1.0 / 9.0))); assert_eq!(eval("3^-2"), Ok(Value::Float(1.0 / 9.0)));
assert_eq!(eval("3^(-2)"), Ok(Value::Float(1.0 / 9.0))); assert_eq!(eval("3^(-2)"), Ok(Value::Float(1.0 / 9.0)));
assert_eq!(eval("-3^2"), Ok(Value::Float(-9.0))); assert_eq!(eval("-3^2"), Ok(Value::Float(-9.0)));