Skip to content

Instantly share code, notes, and snippets.

@kamenchunathan
Created April 2, 2023 15:53
Show Gist options
  • Select an option

  • Save kamenchunathan/ddfcb43b751a4d95f5bd111be701ec8b to your computer and use it in GitHub Desktop.

Select an option

Save kamenchunathan/ddfcb43b751a4d95f5bd111be701ec8b to your computer and use it in GitHub Desktop.
A parser for arithmetic operations in rust
#[derive(Debug)]
pub enum Tree<T, U> {
Leaf(T),
Node(Box<Tree<T, U>>, U, Box<Tree<T, U>>),
}
pub trait Op<T> {
fn apply(&self, x: T, y: T) -> T;
}
impl<T, U> Tree<T, U> {
pub fn singleton(item: T) -> Tree<T, U> {
Tree::Leaf(item)
}
}
impl<T, U> Tree<T, U>
where
U: Ord,
{
pub fn insert(self, op: U, val: T) -> Self {
use Tree::*;
match self {
Leaf(curr) => Node(Box::new(Leaf(curr)), op, Box::new(Leaf(val))),
Node(lhs, curr_op, rhs) => {
if op <= curr_op {
Node(Box::new(Node(lhs, curr_op, rhs)), op, Box::new(Leaf(val)))
} else {
Node(lhs, curr_op, Box::new(Node(rhs, op, Box::new(Leaf(val)))))
}
}
}
}
}
impl<T, U> Tree<T, U>
where
U: Ord + Op<T>,
T: Clone,
{
pub fn eval(&self) -> T {
match self {
Tree::Leaf(val) => (*val).clone(),
Tree::Node(lhs, op, rhs) => (*op).apply(lhs.eval(), rhs.eval()),
}
}
}
#![allow(unused)]
use std::{cmp::Ordering, ops::Div};
use ast::{Op, Tree};
mod ast;
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
enum ArithmeticOp {
Add,
Sub,
Mul,
Div,
}
impl Ord for ArithmeticOp {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
use ArithmeticOp::*;
match (*self, *other) {
(_, Div) => Ordering::Less,
(_, Mul) => Ordering::Less,
_ => Ordering::Equal,
}
}
}
impl Op<f32> for ArithmeticOp {
fn apply(&self, x: f32, y: f32) -> f32 {
match *self {
ArithmeticOp::Add => x + y,
ArithmeticOp::Sub => x - y,
ArithmeticOp::Mul => x * y,
ArithmeticOp::Div => x / y,
}
}
}
#[cfg(test)]
mod tests {
use crate::{ast::Tree, ArithmeticOp};
#[test]
fn eval_test_2() {
use ArithmeticOp::*;
use Tree::*;
let tree = Leaf(3.0).insert(Add, 4.0).insert(Mul, 3.0);
dbg!(&tree);
assert_eq!(tree.eval(), 15.0);
}
#[test]
fn eval_test_5() {
use ArithmeticOp::*;
use Tree::*;
let tree = Leaf(3.0).insert(Mul, 3.0).insert(Mul, 3.0);
dbg!(&tree);
assert_eq!(tree.eval(), 27.0);
}
#[test]
fn eval_test_4() {
use ArithmeticOp::*;
use Tree::*;
let tree = Leaf(3.0).insert(Div, 3.0).insert(Div, 3.0);
dbg!(&tree);
assert_eq!(tree.eval(), 0.33333334);
}
#[test]
fn eval_test_3() {
use ArithmeticOp::*;
use Tree::*;
let tree = Leaf(3.0).insert(Mul, 3.0).insert(Add, 3.0).insert(Div, 3.0);
assert_eq!(tree.eval(), 10.0);
}
#[test]
fn eval_test_1() {
use ArithmeticOp::*;
use Tree::*;
let tree = Leaf(3.0).insert(Add, 3.0);
assert_eq!(tree.eval(), 6.0);
}
#[test]
fn eval_test() {
use Tree::*;
let tree: Tree<f32, ArithmeticOp> = Leaf(3f32);
assert_eq!(tree.eval(), 3f32);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment