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> {
|
use std::mem;
|
||||||
children: Box<Vec<Node<T>>>
|
|
||||||
|
pub struct BExprTree<T: Default> {
|
||||||
|
root: Box<Node<T>>
|
||||||
}
|
}
|
||||||
|
|
||||||
type BinaryOp<T> = Box<dyn Fn(T, T) -> T>;
|
type BinaryOp<T> = dyn Fn(T, T) -> T;
|
||||||
type UnaryOp<T> = Box<dyn Fn(T) -> T>;
|
type UnaryOp<T> = dyn Fn(T) -> T;
|
||||||
|
|
||||||
enum Node<T> {
|
enum Node<T: Default> {
|
||||||
Binary(BinaryOp<T>, Box<Node<T>>, Box<Node<T>>),
|
Binary(Box<BinaryOp<T>>, Box<Node<T>>, Box<Node<T>>),
|
||||||
Unary(UnaryOp<T>, Box<Node<T>>),
|
Unary(Box<UnaryOp<T>>, Box<Node<T>>),
|
||||||
Token(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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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