You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
4.4 KiB

use crate::lexer::Token;
use crate::tile::Operator;
use std::fmt;
use std::iter::Peekable;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expression {
Digit(u64),
Parentheses(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::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_factor(tokens)?;
while let Some(Token::Operator(operator)) = tokens.peek() {
let operator = *operator;
tokens.next();
let right = parse_factor(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(()),
}
}
#[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),
],
);
}
}