feat: add ExprRef sumtype with better expression iteration
This commit is contained in:
parent
79384d436d
commit
0359029741
5 changed files with 93 additions and 19 deletions
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
derive_more = "0.99.17"
|
||||||
thiserror = "1.0.39"
|
thiserror = "1.0.39"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ pub use traits::*;
|
||||||
|
|
||||||
use crate::{ArgusResult, Error};
|
use crate::{ArgusResult, Error};
|
||||||
|
|
||||||
|
use self::iter::AstIter;
|
||||||
|
|
||||||
/// All expressions that are numeric
|
/// All expressions that are numeric
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum NumExpr {
|
pub enum NumExpr {
|
||||||
|
|
@ -29,17 +31,29 @@ pub enum NumExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr for NumExpr {
|
impl Expr for NumExpr {
|
||||||
|
fn is_numeric(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_boolean(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn args(&self) -> Vec<ExprRef<'_>> {
|
||||||
|
match self {
|
||||||
|
NumExpr::Neg { arg } => vec![arg.as_ref().into()],
|
||||||
|
NumExpr::Add { args } | NumExpr::Mul { args } => args.iter().map(|arg| arg.into()).collect(),
|
||||||
|
NumExpr::Div { dividend, divisor } => vec![dividend.as_ref().into(), divisor.as_ref().into()],
|
||||||
|
_ => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn args(&self) -> Vec<&dyn Expr> {
|
fn iter(&self) -> iter::AstIter<'_> {
|
||||||
match self {
|
AstIter::new(self.into())
|
||||||
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![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,11 +78,19 @@ pub enum BoolExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr for BoolExpr {
|
impl Expr for BoolExpr {
|
||||||
fn args(&self) -> Vec<&dyn Expr> {
|
fn is_numeric(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_boolean(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn args(&self) -> Vec<ExprRef<'_>> {
|
||||||
match self {
|
match self {
|
||||||
BoolExpr::Cmp { op: _, lhs, rhs } => vec![lhs.as_ref(), rhs.as_ref()],
|
BoolExpr::Cmp { op: _, lhs, rhs } => vec![lhs.as_ref().into(), rhs.as_ref().into()],
|
||||||
BoolExpr::Not { arg } => vec![arg.as_ref()],
|
BoolExpr::Not { arg } => vec![arg.as_ref().into()],
|
||||||
BoolExpr::And { args } | BoolExpr::Or { args } => args.iter().map(|arg| arg as &dyn Expr).collect(),
|
BoolExpr::And { args } | BoolExpr::Or { args } => args.iter().map(|arg| arg.into()).collect(),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +98,16 @@ impl Expr for BoolExpr {
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iter(&self) -> AstIter<'_> {
|
||||||
|
AstIter::new(self.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, derive_more::From)]
|
||||||
|
pub enum ExprRef<'a> {
|
||||||
|
Bool(&'a BoolExpr),
|
||||||
|
Num(&'a NumExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expression builder
|
/// Expression builder
|
||||||
|
|
|
||||||
42
argus-core/src/expr/iter.rs
Normal file
42
argus-core/src/expr/iter.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use super::{Expr, ExprRef};
|
||||||
|
|
||||||
|
/// Iterator that starts from some root [`Expr`] and travels down to it's leaf
|
||||||
|
/// expressions.
|
||||||
|
///
|
||||||
|
/// This essentially implements breadth-first search over the expression tree rooted at
|
||||||
|
/// the given [`Expr`].
|
||||||
|
pub struct AstIter<'a> {
|
||||||
|
queue: VecDeque<ExprRef<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AstIter<'a> {
|
||||||
|
/// Create an iterator that traverses an [`Expr`] from root to leaf.
|
||||||
|
pub fn new(root: ExprRef<'a>) -> Self {
|
||||||
|
let mut queue = VecDeque::new();
|
||||||
|
queue.push_back(root);
|
||||||
|
Self { queue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for AstIter<'a> {
|
||||||
|
type Item = ExprRef<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let expr_ref = self.queue.pop_front()?;
|
||||||
|
|
||||||
|
let expr: &dyn Expr = match expr_ref {
|
||||||
|
ExprRef::Bool(expr) => expr,
|
||||||
|
ExprRef::Num(expr) => expr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// We need to get all the arguments of the current expression (not including
|
||||||
|
// any intervals), and push them into the queue.
|
||||||
|
for arg in expr.args().into_iter() {
|
||||||
|
self.queue.push_back(arg);
|
||||||
|
}
|
||||||
|
// 4. Give the user their expr
|
||||||
|
Some(expr_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use super::iter::AstIter;
|
use super::{iter::AstIter, ExprRef};
|
||||||
|
|
||||||
/// A trait representing expressions
|
/// A trait representing expressions
|
||||||
pub trait Expr {
|
pub trait Expr {
|
||||||
fn args(&self) -> Vec<&dyn Expr>;
|
fn is_numeric(&self) -> bool;
|
||||||
|
fn is_boolean(&self) -> bool;
|
||||||
|
|
||||||
|
fn args(&self) -> Vec<ExprRef<'_>>;
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
fn iter(&self) -> AstIter<'_>
|
fn iter(&self) -> AstIter<'_>;
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
AstIter::new(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn Expr {
|
impl dyn Expr {
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,4 @@ pub enum Error {
|
||||||
|
|
||||||
pub type ArgusError = Error;
|
pub type ArgusError = Error;
|
||||||
pub type ArgusResult<T> = Result<T, Error>;
|
pub type ArgusResult<T> = Result<T, Error>;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue