use toktok_macros::make_parser;
#[derive(Debug, PartialEq, Eq)]
pub enum Expression {
UnaryTerm(UnaryOperator, Box<Expression>),
BinaryTerm(Box<Expression>, BinaryOperator, Box<Expression>),
Number(u32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOperator {
Sign,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOperator {
Add,
Sub,
Mul,
Div,
}
fn expr_foldl(
lhs: Expression,
rest: impl IntoIterator<Item = (BinaryOperator, Expression)>,
) -> Expression {
rest.into_iter().fold(lhs, |lhs, (operator, rhs)| {
Expression::BinaryTerm(Box::new(lhs), operator, Box::new(rhs))
})
}
make_parser!(grammar = "tests/expression.toktok");
#[test]
fn simple() {
let source = "17 + 3";
let res = parser::expression(source).unwrap();
let expected = Expression::BinaryTerm(
Box::new(Expression::Number(17)),
BinaryOperator::Add,
Box::new(Expression::Number(3)),
);
assert_eq!(res, expected);
}
#[test]
fn comment() {
let source = "1 // comment\n - 2";
let res = parser::expression(source).unwrap();
let expected = Expression::BinaryTerm(
Box::new(Expression::Number(1)),
BinaryOperator::Sub,
Box::new(Expression::Number(2)),
);
assert_eq!(res, expected);
}
#[test]
fn associativity() {
let source = "4 - 3 - 2";
let res = parser::expression(source).unwrap();
let expected = Expression::BinaryTerm(
Box::new(Expression::BinaryTerm(
Box::new(Expression::Number(4)),
BinaryOperator::Sub,
Box::new(Expression::Number(3)),
)),
BinaryOperator::Sub,
Box::new(Expression::Number(2)),
);
assert_eq!(res, expected);
}
#[test]
fn misc() {
let source = "(1 + 2) - 3 / -4";
let res = parser::expression(source).unwrap();
let expected = Expression::BinaryTerm(
Box::new(Expression::BinaryTerm(
Box::new(Expression::Number(1)),
BinaryOperator::Add,
Box::new(Expression::Number(2)),
)),
BinaryOperator::Sub,
Box::new(Expression::BinaryTerm(
Box::new(Expression::Number(3)),
BinaryOperator::Div,
Box::new(Expression::UnaryTerm(UnaryOperator::Sign, Box::new(Expression::Number(4)))),
)),
);
assert_eq!(res, expected);
}