234 lines
6.8 KiB
Rust
234 lines
6.8 KiB
Rust
use crate::lexer::Token;
|
|
use crate::tile::Operator;
|
|
use std::fmt;
|
|
use std::iter::Peekable;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum Expression {
|
|
Digit(i64),
|
|
Parentheses(Box<Expression>),
|
|
Unary(Operator, Box<Expression>),
|
|
Binary(Operator, Box<Expression>, Box<Expression>),
|
|
}
|
|
|
|
impl fmt::Display for Expression {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
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}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type Expressions = Vec<Expression>;
|
|
|
|
pub fn parse(tokens: &[Token]) -> Result<Expressions, ()> {
|
|
let mut tokens = tokens.iter().peekable();
|
|
let mut expressions = Vec::new();
|
|
while tokens.peek().is_some() {
|
|
expressions.push(parse_expression(&mut tokens)?);
|
|
tokens.next();
|
|
}
|
|
Ok(expressions)
|
|
}
|
|
|
|
fn parse_expression<'a>(
|
|
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
|
|
) -> Result<Expression, ()> {
|
|
let mut left = parse_term(tokens)?;
|
|
while let Some(Token::Operator(operator)) = tokens.peek() {
|
|
let operator = *operator;
|
|
tokens.next();
|
|
let right = parse_term(tokens)?;
|
|
left = Expression::Binary(operator, Box::new(left), Box::new(right));
|
|
}
|
|
Ok(left)
|
|
}
|
|
|
|
fn parse_term<'a>(
|
|
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
|
|
) -> Result<Expression, ()> {
|
|
let mut left = parse_unary(tokens)?;
|
|
while let Some(Token::Operator(operator)) = tokens.peek() {
|
|
let operator = *operator;
|
|
tokens.next();
|
|
let right = parse_unary(tokens)?;
|
|
left = Expression::Binary(operator, Box::new(left), Box::new(right));
|
|
}
|
|
Ok(left)
|
|
}
|
|
|
|
fn parse_factor<'a>(
|
|
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
|
|
) -> Result<Expression, ()> {
|
|
match tokens.next() {
|
|
Some(Token::NumberLiteral(value)) => Ok(Expression::Digit(*value)),
|
|
Some(Token::LeftParen) => {
|
|
let expression = parse_expression(tokens)?;
|
|
if let Some(Token::RightParen) = tokens.next() {
|
|
Ok(Expression::Parentheses(Box::new(expression)))
|
|
} else {
|
|
Err(())
|
|
}
|
|
}
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
|
|
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::*;
|
|
|
|
#[test]
|
|
fn test_parse() {
|
|
let tokens = vec![
|
|
Token::NumberLiteral(1),
|
|
Token::Operator(Operator::Add),
|
|
Token::NumberLiteral(2),
|
|
Token::Operator(Operator::Multiply),
|
|
Token::NumberLiteral(3),
|
|
];
|
|
let expression = parse(&tokens).unwrap();
|
|
assert_eq!(
|
|
expression,
|
|
vec![Expression::Binary(
|
|
Operator::Multiply,
|
|
Box::new(Expression::Binary(
|
|
Operator::Add,
|
|
Box::new(Expression::Digit(1)),
|
|
Box::new(Expression::Digit(2)),
|
|
)),
|
|
Box::new(Expression::Digit(3)),
|
|
)],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_parentheses() {
|
|
let tokens = vec![
|
|
Token::LeftParen,
|
|
Token::NumberLiteral(1),
|
|
Token::Operator(Operator::Add),
|
|
Token::NumberLiteral(2),
|
|
Token::RightParen,
|
|
Token::Operator(Operator::Multiply),
|
|
Token::NumberLiteral(3),
|
|
];
|
|
let expression = parse(&tokens).unwrap();
|
|
assert_eq!(
|
|
expression,
|
|
vec![Expression::Binary(
|
|
Operator::Multiply,
|
|
Box::new(Expression::Parentheses(Box::new(Expression::Binary(
|
|
Operator::Add,
|
|
Box::new(Expression::Digit(1)),
|
|
Box::new(Expression::Digit(2)),
|
|
)))),
|
|
Box::new(Expression::Digit(3)),
|
|
)],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_equals() {
|
|
let tokens = vec![
|
|
Token::NumberLiteral(1),
|
|
Token::Equals,
|
|
Token::NumberLiteral(2),
|
|
Token::Equals,
|
|
Token::NumberLiteral(3),
|
|
];
|
|
let expression = parse(&tokens).unwrap();
|
|
assert_eq!(
|
|
expression,
|
|
vec![
|
|
Expression::Digit(1),
|
|
Expression::Digit(2),
|
|
Expression::Digit(3),
|
|
],
|
|
);
|
|
}
|
|
|
|
#[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))
|
|
)),
|
|
)],
|
|
);
|
|
}
|
|
}
|