use chumsky::{prelude::*, Parser}; use crate::{ expression::{BinaryOperation, Expression}, lexer::Token, statement::Statement, value::Value, }; fn parser() -> impl Parser, Error = Simple> { let operator = filter_map(|span, a| match a { Token::Operator(ref op) => match op.as_str() { "+" => Ok(BinaryOperation::Add), "-" => Ok(BinaryOperation::Sub), "*" => Ok(BinaryOperation::Mul), "/" => Ok(BinaryOperation::Div), "<" => Ok(BinaryOperation::LessThan), ">" => Ok(BinaryOperation::GreaterThan), "<=" => Ok(BinaryOperation::LessThanOrEqual), ">=" => Ok(BinaryOperation::GreaterThanOrEqual), "==" => Ok(BinaryOperation::Equal), "!=" => Ok(BinaryOperation::NotEqual), _ => Err(Simple::expected_input_found(span, None, Some(a))), }, _ => Err(Simple::expected_input_found(span, None, Some(a))), }); let tokens = filter_map(|span, a| match a { Token::ConstInt(i) => Ok(Expression::Constant(Value::Int(i))), Token::ConstFloat(f) => Ok(Expression::Constant(Value::Float(f))), Token::ConstString(s) => Ok(Expression::Constant(Value::String(s))), Token::ConstBool(b) => Ok(Expression::Constant(Value::Bool(b))), Token::ConstChar(c) => Ok(Expression::Constant(Value::Char(c))), _ => Err(chumsky::error::Error::expected_input_found( span, None, Some(a), )), }); let expr = recursive(|rec| { choice(( tokens .then(operator) .then(rec) .map(|((a, b), c)| Expression::Binary(Box::new(a), b, Box::new(c))), tokens, )) }); let val = expr.map(Statement::Expression); val.repeated() } #[cfg(test)] mod tests { use chumsky::Parser; use crate::{ expression::{BinaryOperation, Expression}, lexer::Token, parser::parser, statement::Statement, value::Value, }; #[test] fn parse_int() { let input = vec![Token::ConstInt(10)]; let expected = vec![Statement::Expression(Expression::Constant(Value::Int(10)))]; let result = parser().parse(input).unwrap(); assert_eq!(result, expected); } #[test] fn parse_10_plus_10() { let input = vec![ Token::ConstInt(10), Token::Operator("+".into()), Token::ConstInt(10), ]; let expected = vec![Statement::Expression(Expression::Binary( Box::new(Expression::Constant(Value::Int(10))), BinaryOperation::Add, Box::new(Expression::Constant(Value::Int(10))), ))]; let result = parser().parse(input).unwrap(); assert_eq!(result, expected); } }