sunflower/src/parser.rs

89 lines
2.8 KiB
Rust

use chumsky::{prelude::*, Parser};
use crate::{
expression::{BinaryOperation, Expression},
lexer::Token,
statement::Statement,
value::Value,
};
fn parser() -> impl Parser<Token, Vec<Statement>, Error = Simple<Token>> {
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);
}
}