add Expr type for union of BoolExpr or NumExpr

This commit is contained in:
Anand Balakrishnan 2023-09-29 13:59:39 -07:00
parent 7c81b30a8f
commit 6632e897ba
6 changed files with 32 additions and 22 deletions

View file

@ -17,7 +17,7 @@ use crate::{ArgusResult, Error};
/// All expressions that are numeric /// All expressions that are numeric
#[derive(Clone, Debug, PartialEq, argus_derive::NumExpr)] #[derive(Clone, Debug, PartialEq, argus_derive::NumExpr)]
#[enum_dispatch(Expr)] #[enum_dispatch(AnyExpr)]
pub enum NumExpr { pub enum NumExpr {
/// A signed integer literal /// A signed integer literal
IntLit(IntLit), IntLit(IntLit),
@ -54,7 +54,7 @@ impl NumExpr {
/// All expressions that are evaluated to be of type `bool` /// All expressions that are evaluated to be of type `bool`
#[derive(Clone, Debug, PartialEq, argus_derive::BoolExpr)] #[derive(Clone, Debug, PartialEq, argus_derive::BoolExpr)]
#[enum_dispatch(Expr)] #[enum_dispatch(AnyExpr)]
pub enum BoolExpr { pub enum BoolExpr {
/// A `bool` literal /// A `bool` literal
BoolLit(BoolLit), BoolLit(BoolLit),
@ -118,6 +118,15 @@ pub enum ExprRef<'a> {
Num(&'a NumExpr), Num(&'a NumExpr),
} }
/// An expression (either [`BoolExpr`] or [`NumExpr`])
#[derive(Clone, Debug, derive_more::From)]
pub enum Expr {
/// A reference to a [`BoolExpr`]
Bool(BoolExpr),
/// A reference to a [`NumExpr`]
Num(NumExpr),
}
/// Expression builder /// Expression builder
/// ///
/// The `ExprBuilder` is a factory structure that deals with the creation of /// The `ExprBuilder` is a factory structure that deals with the creation of

View file

@ -3,7 +3,7 @@
use std::ops::{Bound, RangeBounds}; use std::ops::{Bound, RangeBounds};
use std::time::Duration; use std::time::Duration;
use super::{BoolExpr, Expr, NumExpr}; use super::{AnyExpr, BoolExpr, NumExpr};
/// Types of comparison operations /// Types of comparison operations
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@ -142,7 +142,7 @@ where
// TODO(anand): Can I implement this within argus_derive? // TODO(anand): Can I implement this within argus_derive?
macro_rules! impl_bool_expr { macro_rules! impl_bool_expr {
($ty:ty$(, $($arg:ident),* )? ) => { ($ty:ty$(, $($arg:ident),* )? ) => {
impl Expr for $ty { impl AnyExpr for $ty {
fn is_numeric(&self) -> bool { fn is_numeric(&self) -> bool {
false false
} }
@ -157,7 +157,7 @@ macro_rules! impl_bool_expr {
} }
}; };
($ty:ty, [$args:ident]) => { ($ty:ty, [$args:ident]) => {
impl Expr for $ty { impl AnyExpr for $ty {
fn is_numeric(&self) -> bool { fn is_numeric(&self) -> bool {
false false
} }

View file

@ -2,19 +2,19 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use super::{Expr, ExprRef}; use super::{AnyExpr, ExprRef};
/// Iterator that starts from some root [`Expr`] and travels down to it's leaf /// Iterator that starts from some root [`AnyExpr`] and travels down to it's leaf
/// expressions. /// expressions.
/// ///
/// This essentially implements breadth-first search over the expression tree rooted at /// This essentially implements breadth-first search over the expression tree rooted at
/// the given [`Expr`]. /// the given [`AnyExpr`].
pub struct AstIter<'a> { pub struct AstIter<'a> {
queue: VecDeque<ExprRef<'a>>, queue: VecDeque<ExprRef<'a>>,
} }
impl<'a> AstIter<'a> { impl<'a> AstIter<'a> {
/// Create an iterator that traverses an [`Expr`] from root to leaf. /// Create an iterator that traverses an [`AnyExpr`] from root to leaf.
pub fn new(root: ExprRef<'a>) -> Self { pub fn new(root: ExprRef<'a>) -> Self {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
queue.push_back(root); queue.push_back(root);
@ -28,7 +28,7 @@ impl<'a> Iterator for AstIter<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let expr_ref = self.queue.pop_front()?; let expr_ref = self.queue.pop_front()?;
let expr: &dyn Expr = match expr_ref { let expr: &dyn AnyExpr = match expr_ref {
ExprRef::Bool(expr) => expr, ExprRef::Bool(expr) => expr,
ExprRef::Num(expr) => expr, ExprRef::Num(expr) => expr,
}; };

View file

@ -1,11 +1,11 @@
//! Numeric expression types //! Numeric expression types
use super::{Expr, NumExpr}; use super::{AnyExpr, NumExpr};
// TODO(anand): Can I implement this within argus_derive? // TODO(anand): Can I implement this within argus_derive?
macro_rules! impl_num_expr { macro_rules! impl_num_expr {
($ty:ty$(, $($arg:ident),* )? ) => { ($ty:ty$(, $($arg:ident),* )? ) => {
impl Expr for $ty { impl AnyExpr for $ty {
fn is_numeric(&self) -> bool { fn is_numeric(&self) -> bool {
true true
} }
@ -20,7 +20,7 @@ macro_rules! impl_num_expr {
} }
}; };
($ty:ty, [$args:ident]) => { ($ty:ty, [$args:ident]) => {
impl Expr for $ty { impl AnyExpr for $ty {
fn is_numeric(&self) -> bool { fn is_numeric(&self) -> bool {
false false
} }

View file

@ -4,7 +4,7 @@ use super::{BoolExpr, ExprRef, NumExpr};
/// A trait representing expressions /// A trait representing expressions
#[enum_dispatch] #[enum_dispatch]
pub trait Expr { pub trait AnyExpr {
/// Check if the given expression is a numeric expression /// Check if the given expression is a numeric expression
fn is_numeric(&self) -> bool; fn is_numeric(&self) -> bool;
/// Check if the given expression is a boolean expression /// Check if the given expression is a boolean expression
@ -17,7 +17,7 @@ pub trait Expr {
} }
/// Marker trait for numeric expressions /// Marker trait for numeric expressions
pub trait IsNumExpr: Expr + Into<NumExpr> {} pub trait IsNumExpr: AnyExpr + Into<NumExpr> {}
/// Marker trait for Boolean expressions /// Marker trait for Boolean expressions
pub trait IsBoolExpr: Expr + Into<BoolExpr> {} pub trait IsBoolExpr: AnyExpr + Into<BoolExpr> {}

View file

@ -1,18 +1,19 @@
use std::{env, fmt, fs}; use std::{env, fmt, fs};
use ariadne::{sources, Color, Label, Report, ReportKind}; use ariadne::{sources, Color, Label, Report, ReportKind};
use chumsky::{input::SpannedInput, prelude::*}; use chumsky::input::SpannedInput;
use chumsky::prelude::*;
use crate::lexer::{lexer, Span, Token}; use crate::lexer::{lexer, Error as LexError, Span, Token};
pub type Spanned<T> = (T, Span); pub type Spanned<T> = (T, Span);
// The type of the input that our parser operates on. The input is the `&[(Token, Span)]` token buffer generated by the // The type of the input that our parser operates on. The input is the `&[(Token,
// lexer, wrapped in a `SpannedInput` which 'splits' it apart into its constituent parts, tokens and spans, for chumsky // Span)]` token buffer generated by the lexer, wrapped in a `SpannedInput` which
// 'splits' it apart into its constituent parts, tokens and spans, for chumsky
// to understand. // to understand.
type ParserInput<'tokens, 'src> = SpannedInput<Token<'src>, Span, &'tokens [(Token<'src>, Span)]>; type ParserInput<'tokens, 'src> = SpannedInput<Token<'src>, Span, &'tokens [(Token<'src>, Span)]>;
pub fn parser<'tokens, 'src: 'tokens>( pub fn parser<'tokens, 'src: 'tokens>(
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, Spanned<Expr<'src>>, extra::Err<Rich<'tokens, Token<'src>, Span>>> ) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, Spanned<Expr<'src>>, LexError<'src>> + Clone {
+ Clone {
} }