Keep signs when evaluating the expr tree
This commit is contained in:
@@ -5,8 +5,9 @@ use std::iter::Peekable;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Expression {
|
||||
Digit(u64),
|
||||
Digit(i64),
|
||||
Parentheses(Box<Expression>),
|
||||
Unary(Operator, Box<Expression>),
|
||||
Binary(Operator, Box<Expression>, Box<Expression>),
|
||||
}
|
||||
|
||||
@@ -15,6 +16,7 @@ impl fmt::Display for Expression {
|
||||
match self {
|
||||
Expression::Digit(value) => write!(f, "{value}"),
|
||||
Expression::Parentheses(expr) => write!(f, "({expr})"),
|
||||
Expression::Unary(operator, expr) => write!(f, "{operator}{expr}"),
|
||||
Expression::Binary(operator, left, right) => {
|
||||
write!(f, "{left} {operator} {right}")
|
||||
}
|
||||
@@ -50,11 +52,11 @@ fn parse_expression<'a>(
|
||||
fn parse_term<'a>(
|
||||
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
|
||||
) -> Result<Expression, ()> {
|
||||
let mut left = parse_factor(tokens)?;
|
||||
let mut left = parse_unary(tokens)?;
|
||||
while let Some(Token::Operator(operator)) = tokens.peek() {
|
||||
let operator = *operator;
|
||||
tokens.next();
|
||||
let right = parse_factor(tokens)?;
|
||||
let right = parse_unary(tokens)?;
|
||||
left = Expression::Binary(operator, Box::new(left), Box::new(right));
|
||||
}
|
||||
Ok(left)
|
||||
@@ -77,6 +79,18 @@ fn parse_factor<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_unary<'a>(
|
||||
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
|
||||
) -> Result<Expression, ()> {
|
||||
if let Some(Token::Operator(Operator::Subtract)) = tokens.peek() {
|
||||
tokens.next();
|
||||
let expression = parse_unary(tokens)?;
|
||||
Ok(Expression::Unary(Operator::Subtract, Box::new(expression)))
|
||||
} else {
|
||||
parse_factor(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -150,4 +164,70 @@ mod tests {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_unary_and_binary_minus() {
|
||||
let tokens = vec![
|
||||
Token::Operator(Operator::Subtract),
|
||||
Token::NumberLiteral(1),
|
||||
Token::Operator(Operator::Subtract),
|
||||
Token::NumberLiteral(2),
|
||||
];
|
||||
let expression = parse(&tokens).unwrap();
|
||||
assert_eq!(
|
||||
expression,
|
||||
vec![Expression::Binary(
|
||||
Operator::Subtract,
|
||||
Box::new(Expression::Unary(
|
||||
Operator::Subtract,
|
||||
Box::new(Expression::Digit(1)),
|
||||
)),
|
||||
Box::new(Expression::Digit(2)),
|
||||
)],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_unary_before_parenthesis() {
|
||||
let tokens = vec![
|
||||
Token::Operator(Operator::Subtract),
|
||||
Token::LeftParen,
|
||||
Token::NumberLiteral(9),
|
||||
Token::Operator(Operator::Multiply),
|
||||
Token::NumberLiteral(3),
|
||||
Token::RightParen,
|
||||
];
|
||||
let expression = parse(&tokens).unwrap();
|
||||
assert_eq!(
|
||||
expression,
|
||||
vec![Expression::Unary(
|
||||
Operator::Subtract,
|
||||
Box::new(Expression::Parentheses(Box::new(Expression::Binary(
|
||||
Operator::Multiply,
|
||||
Box::new(Expression::Digit(9)),
|
||||
Box::new(Expression::Digit(3)),
|
||||
)))),
|
||||
)],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_double_unary() {
|
||||
let tokens = vec![
|
||||
Token::Operator(Operator::Subtract),
|
||||
Token::Operator(Operator::Subtract),
|
||||
Token::NumberLiteral(7),
|
||||
];
|
||||
let expression = parse(&tokens).unwrap();
|
||||
assert_eq!(
|
||||
expression,
|
||||
vec![Expression::Unary(
|
||||
Operator::Subtract,
|
||||
Box::new(Expression::Unary(
|
||||
Operator::Subtract,
|
||||
Box::new(Expression::Digit(7))
|
||||
)),
|
||||
)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user