Somewhat working binary expression tree

This commit is contained in:
Egor 2024-05-30 12:05:57 +03:00
parent ab5fa70b7b
commit b53ec32c7d

View file

@ -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);
}
}