diff --git a/src/nodes/eval.rs b/src/nodes/eval.rs index 7be6bf7..2ebfee0 100644 --- a/src/nodes/eval.rs +++ b/src/nodes/eval.rs @@ -41,6 +41,31 @@ fn collapse_toplevel(nodes: &mut Vec, mut end: usize) -> Result<(), Error> .rposition(|n| *n == Node::ParenthesisStart) .unwrap_or(0); + let mut i = start; + while i < end { + if let Node::Operator(operator) = nodes[i] + && matches!(operator, Operator::Plus | Operator::Minus) + && matches!( + i.checked_sub(1).and_then(|i| nodes.get(i)), + None | Some(Node::ParenthesisStart) + ) + { + match nodes.get_mut(i + 1) { + None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), i + 1)), + + Some(Node::Number(n)) => { + if operator == Operator::Minus { + n.mul_from(-1); + } + nodes.remove(i); + end -= 1; + } + Some(n) => return Err(Error::InvalidOperand(n.clone())), + } + } + i += 1; + } + while let Some((index, function)) = nodes[start..end] .iter() .enumerate() diff --git a/src/nodes/parse.rs b/src/nodes/parse.rs index f4375f5..96d4236 100644 --- a/src/nodes/parse.rs +++ b/src/nodes/parse.rs @@ -157,17 +157,9 @@ impl FromStr for Nodes { } else if c == ')' { nodes.push(Node::ParenthesisEnd); } else { - if matches!( - nodes.last(), - Some(Node::Operator(_) | Node::ParenthesisStart) | None - ) { - // it must be a unary operator - state = ParsingState::ReadingNumber(i); - } else { - nodes.push(Node::Operator( - c.try_into().map_err(Error::InvalidOperator)?, - )); - } + nodes.push(Node::Operator( + c.try_into().map_err(Error::InvalidOperator)?, + )); } } } @@ -241,7 +233,8 @@ mod tests { Node::from(5), Node::Operator(Operator::Mult), Node::ParenthesisStart, - Node::from(-5), + Node::Operator(Operator::Minus), + Node::from(5), Node::ParenthesisEnd, ], ) diff --git a/src/nodes/tests.rs b/src/nodes/tests.rs index d7cbd59..15b6c21 100644 --- a/src/nodes/tests.rs +++ b/src/nodes/tests.rs @@ -38,6 +38,13 @@ fn unary_operators() { assert_eq!(eval("-10"), -10.); assert_eq!(eval("+10"), 10.); } +#[test] +fn unary_operators_with_parenthesis() { + assert_eq!(eval("-(10)"), -10.); + assert_eq!(eval("+(10)"), 10.); + assert_eq!(eval("(-10)"), -10.); + assert_eq!(eval("(+10)"), 10.); +} #[test] fn constant_implicit_mult() {