Somewhat working binary expression tree
This commit is contained in:
parent
ab5fa70b7b
commit
b53ec32c7d
1 changed files with 91 additions and 7 deletions
|
@ -1,19 +1,103 @@
|
|||
pub struct BExprTree<T> {
|
||||
children: Box<Vec<Node<T>>>
|
||||
use std::mem;
|
||||
|
||||
pub struct BExprTree<T: Default> {
|
||||
root: Box<Node<T>>
|
||||
}
|
||||
|
||||
type BinaryOp<T> = Box<dyn Fn(T, T) -> T>;
|
||||
type UnaryOp<T> = Box<dyn Fn(T) -> T>;
|
||||
type BinaryOp<T> = dyn Fn(T, T) -> T;
|
||||
type UnaryOp<T> = dyn Fn(T) -> T;
|
||||
|
||||
enum Node<T> {
|
||||
Binary(BinaryOp<T>, Box<Node<T>>, Box<Node<T>>),
|
||||
Unary(UnaryOp<T>, Box<Node<T>>),
|
||||
enum Node<T: Default> {
|
||||
Binary(Box<BinaryOp<T>>, Box<Node<T>>, Box<Node<T>>),
|
||||
Unary(Box<UnaryOp<T>>, Box<Node<T>>),
|
||||
Token(T)
|
||||
}
|
||||
|
||||
impl<T: Default> Node<T> {
|
||||
fn new() -> Self {
|
||||
Self::Token(T::default())
|
||||
}
|
||||
|
||||
fn new_token(token: T) -> Self {
|
||||
Self::Token(token)
|
||||
}
|
||||
|
||||
fn new_binary(op: &'static BinaryOp<T>, left: Node<T>, right: Node<T>) -> Self {
|
||||
Self::Binary(
|
||||
Box::new(op), Box::new(left), Box::new(right)
|
||||
)
|
||||
}
|
||||
|
||||
fn new_unary(op: &'static UnaryOp<T>, node: Node<T>) -> Self {
|
||||
Self::Unary(
|
||||
Box::new(op), Box::new(node)
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: replace recursive solution with an iterative one
|
||||
fn eval(node: Node<T>) -> 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<T: Default> BExprTree<T> {
|
||||
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<T>, left: BExprTree<T>) {
|
||||
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<T>, right: BExprTree<T>) {
|
||||
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<T>) {
|
||||
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<T: Default> Default for BExprTree<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const ADD: &'static BinaryOp<i32> = &|x, y| x + y;
|
||||
const SUB: &'static BinaryOp<i32> = &|x, y| x - y;
|
||||
const NEG: &'static UnaryOp<i32>= &|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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue