fix: plus evaluated before minus

This commit is contained in:
electria 2026-09-28 12:58:12 -07:00
commit 5f25c92404
Signed by: electria
SSH key fingerprint: SHA256:8LlB3ucPbBHqozqkhsNbaV5oG3SlzzqUj8FZDL6IPQs
2 changed files with 22 additions and 4 deletions

View file

@ -112,24 +112,6 @@ fn collapse_toplevel(nodes: &mut Vec<Node>, mut end: usize) {
end -= 1; end -= 1;
} }
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Operator(Operator::Plus))
{
let lhs = match nodes.remove(start + operator - 1) {
Node::Number(n) => n,
n => panic!("operator has an invalid operand: {n:?}"),
};
end -= 1;
match &mut nodes[start..end][operator] {
Node::Number(n) => n.add_from(lhs),
n => panic!("operator has an invalid operand: {n:?}"),
};
nodes.remove(start + operator - 1);
end -= 1;
}
while let Some(operator) = nodes[start..end] while let Some(operator) = nodes[start..end]
.iter() .iter()
.position(|n| *n == Node::Operator(Operator::Minus)) .position(|n| *n == Node::Operator(Operator::Minus))
@ -148,6 +130,24 @@ fn collapse_toplevel(nodes: &mut Vec<Node>, mut end: usize) {
end -= 1; end -= 1;
} }
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Operator(Operator::Plus))
{
let lhs = match nodes.remove(start + operator - 1) {
Node::Number(n) => n,
n => panic!("operator has an invalid operand: {n:?}"),
};
end -= 1;
match &mut nodes[start..end][operator] {
Node::Number(n) => n.add_from(lhs),
n => panic!("operator has an invalid operand: {n:?}"),
};
nodes.remove(start + operator - 1);
end -= 1;
}
if nodes.len() > 1 { if nodes.len() > 1 {
nodes.remove(end); nodes.remove(end);
nodes.remove(start); nodes.remove(start);

View file

@ -5,6 +5,24 @@ use rug::Float;
use crate::nodes::{Function, Node, Nodes, Operator, PREC}; use crate::nodes::{Function, Node, Nodes, Operator, PREC};
#[test]
fn plus_minus_order() {
assert_eq!(
Nodes::from_str("1 - 4 - 5").unwrap().evaluate().to_f64(),
-8.
);
assert_eq!(
Nodes::from_str("1 - 4 + 5").unwrap().evaluate().to_f64(),
2.
);
assert_eq!(
Nodes::from_str("1 + 4 - 5").unwrap().evaluate().to_f64(),
0.
);
}
#[test] #[test]
fn e_edge_case() { fn e_edge_case() {
assert_eq!(Nodes::from_str("1e-1").unwrap().evaluate().to_f64(), 0.1) assert_eq!(Nodes::from_str("1e-1").unwrap().evaluate().to_f64(), 0.1)