use std::fmt; use std::fmt::{Debug, Display, Formatter}; use winnow::prelude::*; use winnow::Result; use winnow::{ ascii::{digit1 as digits, multispace0 as multispaces}, combinator::alt, combinator::dispatch, combinator::eof, combinator::fail, combinator::opt, combinator::peek, combinator::repeat, combinator::{delimited, preceded, terminated}, error::ContextError, stream::TokenSlice, token::any, token::literal, token::one_of, token::take_till, }; /// Lex and parse #[allow(dead_code)] pub(crate) fn expr2(i: &mut &str) -> Result { let tokens = tokens.parse_next(i)?; let mut tokens = Tokens::new(&tokens); expr.parse_next(&mut tokens) } #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct Token<'s> { kind: TokenKind, raw: &'s str, } impl PartialEq for Token<'_> { fn eq(&self, other: &TokenKind) -> bool { self.kind == *other } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum TokenKind { Value, Oper(Oper), OpenParen, CloseParen, Unknown, Eof, } impl<'i> Parser, &'i Token<'i>, ContextError> for TokenKind { fn parse_next(&mut self, input: &mut Tokens<'i>) -> Result<&'i Token<'i>> { literal(*self).parse_next(input).map(|t| &t[0]) } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum Oper { Add, Sub, Mul, Div, } impl winnow::stream::ContainsToken<&'_ Token<'_>> for TokenKind { #[inline(always)] fn contains_token(&self, token: &'_ Token<'_>) -> bool { *self == token.kind } } impl winnow::stream::ContainsToken<&'_ Token<'_>> for &'_ [TokenKind] { #[inline] fn contains_token(&self, token: &'_ Token<'_>) -> bool { self.iter().any(|t| *t == token.kind) } } impl winnow::stream::ContainsToken<&'_ Token<'_>> for &'_ [TokenKind; LEN] { #[inline] fn contains_token(&self, token: &'_ Token<'_>) -> bool { self.iter().any(|t| *t == token.kind) } } impl winnow::stream::ContainsToken<&'_ Token<'_>> for [TokenKind; LEN] { #[inline] fn contains_token(&self, token: &'_ Token<'_>) -> bool { self.iter().any(|t| *t == token.kind) } } /// Lex tokens /// /// See [`expr`] to parse the tokens pub(crate) fn tokens<'s>(i: &mut &'s str) -> Result>> { let mut tokens: Vec<_> = preceded(multispaces, repeat(1.., terminated(token, multispaces))).parse_next(i)?; if let Some(eof) = opt(eof.map(|raw| Token { kind: TokenKind::Eof, raw, })) .parse_next(i)? { tokens.push(eof); } Ok(tokens) } fn token<'s>(i: &mut &'s str) -> Result> { dispatch! {peek(any); '0'..='9' => digits.value(TokenKind::Value), '(' => '('.value(TokenKind::OpenParen), ')' => ')'.value(TokenKind::CloseParen), '+' => '+'.value(TokenKind::Oper(Oper::Add)), '-' => '-'.value(TokenKind::Oper(Oper::Sub)), '*' => '*'.value(TokenKind::Oper(Oper::Mul)), '/' => '/'.value(TokenKind::Oper(Oper::Div)), ' '| '\t'| '\r'| '\n' => fail, _ => take_till(.., ('0'..='9', '(', ')', '+', '-', '*', '/')).value(TokenKind::Unknown), } .with_taken() .map(|(kind, raw)| Token { kind, raw }) .parse_next(i) } #[derive(Debug, Clone)] pub(crate) enum Expr { Value(i64), Add(Box, Box), Sub(Box, Box), Mul(Box, Box), Div(Box, Box), Paren(Box), } impl Expr { pub(crate) fn eval(&self) -> i64 { match self { Self::Value(v) => *v, Self::Add(lhs, rhs) => lhs.eval() + rhs.eval(), Self::Sub(lhs, rhs) => lhs.eval() - rhs.eval(), Self::Mul(lhs, rhs) => lhs.eval() * rhs.eval(), Self::Div(lhs, rhs) => lhs.eval() / rhs.eval(), Self::Paren(expr) => expr.eval(), } } } impl Display for Expr { fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result { use Expr::{Add, Div, Mul, Paren, Sub, Value}; match *self { Value(val) => write!(format, "{val}"), Add(ref left, ref right) => write!(format, "{left} + {right}"), Sub(ref left, ref right) => write!(format, "{left} - {right}"), Mul(ref left, ref right) => write!(format, "{left} * {right}"), Div(ref left, ref right) => write!(format, "{left} / {right}"), Paren(ref expr) => write!(format, "({expr})"), } } } pub(crate) type Tokens<'i> = TokenSlice<'i, Token<'i>>; /// Parse the tokens lexed in [`tokens`] pub(crate) fn expr(i: &mut Tokens<'_>) -> Result { let init = term.parse_next(i)?; let expr = repeat( 0.., ( one_of([TokenKind::Oper(Oper::Add), TokenKind::Oper(Oper::Sub)]), term, ), ) .fold( move || init.clone(), |acc, (op, val): (&Token<'_>, Expr)| { if op.kind == TokenKind::Oper(Oper::Add) { Expr::Add(Box::new(acc), Box::new(val)) } else { Expr::Sub(Box::new(acc), Box::new(val)) } }, ) .parse_next(i)?; opt(TokenKind::Eof).parse_next(i)?; Ok(expr) } pub(crate) fn term(i: &mut Tokens<'_>) -> Result { let init = factor.parse_next(i)?; repeat( 0.., ( one_of([TokenKind::Oper(Oper::Mul), TokenKind::Oper(Oper::Div)]), factor, ), ) .fold( move || init.clone(), |acc, (op, val): (&Token<'_>, Expr)| { if op.kind == TokenKind::Oper(Oper::Mul) { Expr::Mul(Box::new(acc), Box::new(val)) } else { Expr::Div(Box::new(acc), Box::new(val)) } }, ) .parse_next(i) } pub(crate) fn factor(i: &mut Tokens<'_>) -> Result { alt(( TokenKind::Value.try_map(|t: &Token<'_>| t.raw.parse::().map(Expr::Value)), parens, )) .parse_next(i) } fn parens(i: &mut Tokens<'_>) -> Result { delimited(TokenKind::OpenParen, expr, TokenKind::CloseParen) .map(|e| Expr::Paren(Box::new(e))) .parse_next(i) }