//! Corresponds to `Expr::Neg` and `Expr::Not` in `ast::expr` use chumsky::prelude::*; use crate::ast::{Expr, Space}; use crate::span::{HasSpan, Span}; use super::basic::{EParser, Error}; enum Prefix { /// See [`Expr::Neg`]. Neg { minus: Span, s0: Space }, /// See [`Expr::Not`]. Not { not: Span, s0: Space }, } impl Prefix { fn into_expr(self, span: Span, expr: Expr) -> Expr { let expr = expr.boxed(); match self { Self::Neg { minus, s0 } => Expr::Neg { minus, s0, expr, span, }, Self::Not { not, s0 } => Expr::Not { not, s0, expr, span, }, } } } fn prefix_neg(space: EParser) -> impl Parser { just('-') .map_with_span(|_, span| span) .then(space) .map(|(minus, s0)| Prefix::Neg { minus, s0 }) } fn prefix_not(space: EParser) -> impl Parser { text::keyword("not") .map_with_span(|_, span| span) .then(space) .map(|(not, s0)| Prefix::Not { not, s0 }) } pub fn prefixed(space: EParser, suffixed: EParser) -> EParser { let prefix = prefix_neg(space.clone()) .or(prefix_not(space)) .map_with_span(|prefix, span| (prefix, span)); prefix .repeated() .then(suffixed) .foldr(|(prefix, span), expr| prefix.into_expr(expr.span().join(span), expr)) .boxed() }