diff --git a/src/expr/bexpr_tree.rs b/src/expr/bexpr_tree.rs index 4456727..08d20a1 100644 --- a/src/expr/bexpr_tree.rs +++ b/src/expr/bexpr_tree.rs @@ -1,19 +1,103 @@ -pub struct BExprTree { - children: Box>> +use std::mem; + +pub struct BExprTree { + root: Box> } -type BinaryOp = Box T>; -type UnaryOp = Box T>; +type BinaryOp = dyn Fn(T, T) -> T; +type UnaryOp = dyn Fn(T) -> T; -enum Node { - Binary(BinaryOp, Box>, Box>), - Unary(UnaryOp, Box>), +enum Node { + Binary(Box>, Box>, Box>), + Unary(Box>, Box>), Token(T) } +impl Node { + fn new() -> Self { + Self::Token(T::default()) + } + + fn new_token(token: T) -> Self { + Self::Token(token) + } + + fn new_binary(op: &'static BinaryOp, left: Node, right: Node) -> Self { + Self::Binary( + Box::new(op), Box::new(left), Box::new(right) + ) + } + + fn new_unary(op: &'static UnaryOp, node: Node) -> Self { + Self::Unary( + Box::new(op), Box::new(node) + ) + } + + // TODO: replace recursive solution with an iterative one + fn eval(node: Node) -> T { + return match node { + Node::Token(token) => token, + Node::Unary(op, next) => { + op(Self::eval(*next)) + }, + Node::Binary(op, left, right) => { + op(Self::eval(*left), Self::eval(*right)) + } + }; + } +} + +impl BExprTree { + pub fn new() -> Self { + Self { root: Box::new(Node::new()) } + } + + pub fn new_token(token: T) -> Self { + Self { root: Box::new(Node::new_token(token)) } + } + + fn insert_bin_left(&mut self, op: &'static BinaryOp, left: BExprTree) { + let root = mem::take(self).root; + self.root = Box::new(Node::new_binary(op, *left.root, *root)); + } + + fn insert_bin_right(&mut self, op: &'static BinaryOp, right: BExprTree) { + let root = mem::take(self).root; + self.root = Box::new(Node::new_binary(op, *root, *right.root)); + } + + fn insert_unary(&mut self, op: &'static UnaryOp) { + let root = mem::take(self).root; + self.root = Box::new(Node::new_unary(op, *root)); + } + + pub fn eval(self) -> T { + Node::eval(*self.root) + } +} + +impl Default for BExprTree { + fn default() -> Self { + Self::new() + } +} + #[cfg(test)] mod tests { use super::*; + const ADD: &'static BinaryOp = &|x, y| x + y; + const SUB: &'static BinaryOp = &|x, y| x - y; + const NEG: &'static UnaryOp= &|x| -x; + #[test] + fn test_insert() { + let mut tree = BExprTree::new_token(5); + tree.insert_bin_left(ADD, BExprTree::new_token(2)); + tree.insert_bin_right(SUB, BExprTree::new_token(3)); + tree.insert_unary(NEG); + + assert_eq!(tree.eval(), -4); + } }