46 lines
1.6 KiB
Rust
46 lines
1.6 KiB
Rust
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)
|
|
}
|
|
}
|