use winnow::Parser; use winnow::ascii::multispace0; use winnow::combinator::{Infix, Prefix, peek}; use winnow::combinator::{delimited, dispatch, expression, fail}; use winnow::error::ContextError; use winnow::token::any; use crate::binary_repr::parse_binary_repr; use crate::expr::{BinOp, Expr, UnaryOp}; pub fn parser<'i>(size: usize) -> impl Parser<&'i str, Expr, ContextError> { move |i: &mut &str| { use Infix::Left; expression(delimited( multispace0, dispatch! {peek(any); '(' => delimited('(', parser(size).map(|e| Expr::Group(Box::new(e))), ')'), _ => parse_binary_repr(size).map(Expr::Constant), }, multispace0, )) .prefix(delimited( multispace0, dispatch! {any; '-' => Prefix(12, |_, a| Ok(Expr::UnaryOp(UnaryOp::Neg, Box::new(a)))), '!' => Prefix(12, |_, a| Ok(Expr::UnaryOp(UnaryOp::Not, Box::new(a)))), _ => fail, }, multispace0, )) .infix(delimited( multispace0, dispatch! {any; '+' => Left(5, |_, a, b| Ok(Expr::BinaryOp(Box::new(a), BinOp::Plus, Box::new(b)))), '-' => Left(5, |_, a, b| Ok(Expr::BinaryOp(Box::new(a), BinOp::Sub, Box::new(b)))), '*' => Left(7, |_, a, b| Ok(Expr::BinaryOp(Box::new(a), BinOp::Mul, Box::new(b)))), '/' => Left(7, |_, a, b| Ok(Expr::BinaryOp(Box::new(a), BinOp::Div, Box::new(b)))), _ => fail, }, multispace0, )) .parse_next(i) } }