feat: implement an Expr trait

This commit is contained in:
Anand Balakrishnan 2023-03-19 23:15:54 -07:00
parent afe265eba2
commit 55894d55fb
No known key found for this signature in database
2 changed files with 85 additions and 0 deletions

View file

@ -4,9 +4,11 @@ mod bool_ops;
mod internal_macros; mod internal_macros;
pub mod iter; pub mod iter;
mod num_ops; mod num_ops;
mod traits;
pub use bool_ops::*; pub use bool_ops::*;
pub use num_ops::*; pub use num_ops::*;
pub use traits::*;
use crate::{ArgusResult, Error}; use crate::{ArgusResult, Error};
@ -26,6 +28,21 @@ pub enum NumExpr {
Div { dividend: Box<NumExpr>, divisor: Box<NumExpr> }, Div { dividend: Box<NumExpr>, divisor: Box<NumExpr> },
} }
impl Expr for NumExpr {
fn as_any(&self) -> &dyn Any {
self
}
fn args(&self) -> Vec<&dyn Expr> {
match self {
NumExpr::Neg { arg } => vec![arg.as_ref()],
NumExpr::Add { args } | NumExpr::Mul { args } => args.iter().map(|arg| arg as &dyn Expr).collect(),
NumExpr::Div { dividend, divisor } => vec![dividend.as_ref(), divisor.as_ref()],
_ => vec![],
}
}
}
/// Types of comparison operations /// Types of comparison operations
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum Ordering { pub enum Ordering {
@ -46,6 +63,21 @@ pub enum BoolExpr {
Or { args: Vec<BoolExpr> }, Or { args: Vec<BoolExpr> },
} }
impl Expr for BoolExpr {
fn args(&self) -> Vec<&dyn Expr> {
match self {
BoolExpr::Cmp { op: _, lhs, rhs } => vec![lhs.as_ref(), rhs.as_ref()],
BoolExpr::Not { arg } => vec![arg.as_ref()],
BoolExpr::And { args } | BoolExpr::Or { args } => args.iter().map(|arg| arg as &dyn Expr).collect(),
_ => vec![],
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
/// 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

@ -0,0 +1,53 @@
use std::any::Any;
use super::iter::AstIter;
/// A trait representing expressions
pub trait Expr {
fn args(&self) -> Vec<&dyn Expr>;
fn as_any(&self) -> &dyn Any;
fn iter(&self) -> AstIter<'_>
where
Self: Sized,
{
AstIter::new(self)
}
}
impl dyn Expr {
pub fn downcast_expr_ref<T>(&self) -> Option<&T>
where
T: Any,
{
self.as_any().downcast_ref::<T>()
}
}
#[cfg(test)]
mod tests {
use super::super::{arbitrary, BoolExpr, NumExpr};
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn downcast_expr_bool(bool_expr in arbitrary::bool_expr()) {
let expr_ref = bool_expr.as_ref() as &dyn Expr;
let downcast_ref = expr_ref.downcast_expr_ref::<BoolExpr>().unwrap();
assert_eq!(downcast_ref, bool_expr.as_ref());
}
}
proptest! {
#[test]
fn downcast_expr_num(num_expr in arbitrary::num_expr()) {
let expr_ref = num_expr.as_ref() as &dyn Expr;
let downcast_ref = expr_ref.downcast_expr_ref::<NumExpr>().unwrap();
assert_eq!(downcast_ref, num_expr.as_ref());
}
}
}