fix: correctly evaluate unary operators with parenthesis
This commit is contained in:
parent
a520177183
commit
7182e29512
3 changed files with 37 additions and 12 deletions
|
|
@ -41,6 +41,31 @@ fn collapse_toplevel(nodes: &mut Vec<Node>, mut end: usize) -> Result<(), Error>
|
||||||
.rposition(|n| *n == Node::ParenthesisStart)
|
.rposition(|n| *n == Node::ParenthesisStart)
|
||||||
.unwrap_or(0);
|
.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]
|
while let Some((index, function)) = nodes[start..end]
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|
|
||||||
|
|
@ -156,13 +156,6 @@ impl FromStr for Nodes {
|
||||||
nodes.push(Node::ParenthesisStart);
|
nodes.push(Node::ParenthesisStart);
|
||||||
} else if c == ')' {
|
} else if c == ')' {
|
||||||
nodes.push(Node::ParenthesisEnd);
|
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 {
|
} else {
|
||||||
nodes.push(Node::Operator(
|
nodes.push(Node::Operator(
|
||||||
c.try_into().map_err(Error::InvalidOperator)?,
|
c.try_into().map_err(Error::InvalidOperator)?,
|
||||||
|
|
@ -170,7 +163,6 @@ impl FromStr for Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// wrap up any unfinished parsing
|
// wrap up any unfinished parsing
|
||||||
let i = filtered_string.len();
|
let i = filtered_string.len();
|
||||||
|
|
@ -241,7 +233,8 @@ mod tests {
|
||||||
Node::from(5),
|
Node::from(5),
|
||||||
Node::Operator(Operator::Mult),
|
Node::Operator(Operator::Mult),
|
||||||
Node::ParenthesisStart,
|
Node::ParenthesisStart,
|
||||||
Node::from(-5),
|
Node::Operator(Operator::Minus),
|
||||||
|
Node::from(5),
|
||||||
Node::ParenthesisEnd,
|
Node::ParenthesisEnd,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,13 @@ fn unary_operators() {
|
||||||
assert_eq!(eval("-10"), -10.);
|
assert_eq!(eval("-10"), -10.);
|
||||||
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]
|
#[test]
|
||||||
fn constant_implicit_mult() {
|
fn constant_implicit_mult() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue