From 63f8026007231d6e58e1ea3da3079ac34284c922 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 19 Nov 2022 11:58:52 +0100 Subject: [PATCH] Parse arithmetic and logical negation --- src/parser.rs | 1 + src/parser/expr.rs | 8 +++--- src/parser/prefix.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/parser/prefix.rs diff --git a/src/parser.rs b/src/parser.rs index 3d81aa9..e7c1a64 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,7 @@ mod basic; mod expr; mod lit; +mod prefix; mod suffix; mod table_constr; mod table_destr; diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 7c8a876..8c3c316 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -6,6 +6,7 @@ use crate::ast::Expr; use super::basic::{space, Error}; use super::lit::lit; +use super::prefix::prefixed; use super::suffix::suffixed; use super::table_constr::table_constr; use super::table_destr::table_destr; @@ -34,13 +35,14 @@ fn atom( let var = var(expr.clone()).map(Expr::Var); let table_constr = table_constr(expr.clone()).map(Expr::TableConstr); let table_destr = table_destr(expr.clone()).map(Expr::TableDestr); - let paren = atom_paren(expr); + let paren = atom_paren(expr.clone()); - lit.or(paren).or(table_destr).or(table_constr).or(var) + let base = lit.or(paren).or(table_destr).or(table_constr).or(var); + prefixed(suffixed(base, expr)) } pub fn expr( expr: impl Parser + Clone, ) -> impl Parser { - suffixed(atom(expr.clone()), expr) + atom(expr) } diff --git a/src/parser/prefix.rs b/src/parser/prefix.rs new file mode 100644 index 0000000..81727d6 --- /dev/null +++ b/src/parser/prefix.rs @@ -0,0 +1,63 @@ +//! 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::{space, 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 = Box::new(expr); + 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() -> impl Parser { + just('-') + .map_with_span(|_, span| span) + .then(space()) + .map(|(minus, s0)| Prefix::Neg { minus, s0 }) +} + +fn prefix_not() -> impl Parser { + text::keyword("not") + .map_with_span(|_, span| span) + .then(space()) + .map(|(not, s0)| Prefix::Not { not, s0 }) +} + +pub fn prefixed( + suffixed: impl Parser, +) -> impl Parser { + let prefix = prefix_neg() + .or(prefix_not()) + .map_with_span(|prefix, span| (prefix, span)); + + prefix + .repeated() + .then(suffixed) + .foldr(|(prefix, span), expr| prefix.into_expr(expr.span().join(span), expr)) +}