Created
February 1, 2024 17:25
-
-
Save hilios/4cd9c89afe2140505225c87a5c7e267b to your computer and use it in GitHub Desktop.
RPN Calculator in RUST
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::VecDeque; | |
use crate::expr::Expr::*; | |
#[derive(Debug, Clone)] | |
enum Expr { | |
Number(f64), | |
Add(Box<Expr>, Box<Expr>), | |
Subtract(Box<Expr>, Box<Expr>), | |
Divide(Box<Expr>, Box<Expr>), | |
Multiply(Box<Expr>, Box<Expr>), | |
Sqrt(Box<Expr>), | |
} | |
impl Expr { | |
pub fn eval(&self) -> f64 { | |
match self { | |
Number(value) => *value, | |
Add(x, y) => x.eval() + y.eval(), | |
Subtract(x, y) => x.eval() - y.eval(), | |
Divide(x, y) => x.eval() / y.eval(), | |
Multiply(x, y) => x.eval() * y.eval(), | |
Sqrt(x) => x.eval().sqrt(), | |
} | |
} | |
pub fn parse_exprs(tokens: &str) -> Result<VecDeque<Expr>, String> { | |
let mut memory = VecDeque::with_capacity(100); | |
for token in tokens.split_ascii_whitespace() { | |
let expr = Expr::parse_expr(token, &mut memory)?; | |
memory.push_front(expr); | |
} | |
Ok(memory) | |
} | |
fn parse_expr(token: &str, memory: &mut VecDeque<Expr>) -> Result<Expr, String> { | |
match token { | |
"+" => { | |
let x = memory.pop_back().ok_or("Missing right operand")?; | |
let y = memory.pop_back().ok_or("Missing left operand")?; | |
Ok(Add(Box::from(x), Box::from(y))) | |
}, | |
"-" => { | |
let x = memory.pop_back().ok_or("Missing right operand")?; | |
let y = memory.pop_back().ok_or("Missing left operand")?; | |
Ok(Subtract(Box::from(x), Box::from(y))) | |
}, | |
"/" => { | |
let x = memory.pop_back().ok_or("Missing right operand")?; | |
let y = memory.pop_back().ok_or("Missing left operand")?; | |
Ok(Divide(Box::from(x), Box::from(y))) | |
}, | |
"*" => { | |
let x = memory.pop_back().ok_or("Missing right operand")?; | |
let y = memory.pop_back().ok_or("Missing left operand")?; | |
Ok(Multiply(Box::from(x), Box::from(y))) | |
}, | |
"sqrt" => { | |
let x = memory.pop_back().ok_or("Missing right operand")?; | |
Ok(Sqrt(Box::from(x))) | |
}, | |
_ => { | |
let n = token.parse::<f64>() | |
.map_err(|_| format!("Invalid number: {}", token))?; | |
Ok(Number(n)) | |
} | |
} | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use std::collections::VecDeque; | |
use crate::expr::Expr; | |
use crate::expr::Expr::*; | |
#[test] | |
fn add() { | |
let expr = Add(Box::from(Number(2.0)), Box::from(Number(2.0))); | |
assert_eq!(expr.eval(), 4.0); | |
} | |
#[test] | |
fn subtract() { | |
let expr = Subtract(Box::from(Number(2.0)), Box::from(Number(1.0))); | |
assert_eq!(expr.eval(), 1.0); | |
} | |
#[test] | |
fn multiply() { | |
let expr = Multiply(Box::from(Number(2.0)), Box::from(Number(4.0))); | |
assert_eq!(expr.eval(), 8.0); | |
} | |
#[test] | |
fn divide() { | |
let expr = Divide(Box::from(Number(4.0)), Box::from(Number(2.0))); | |
assert_eq!(expr.eval(), 2.0); | |
} | |
#[test] | |
fn sqrt() { | |
let expr = Sqrt(Box::from(Number(25.0))); | |
assert_eq!(expr.eval(), 5.0); | |
} | |
#[test] | |
fn parse_number() { | |
let mut memory: VecDeque<Expr> = VecDeque::with_capacity(100); | |
let expr = Expr::parse_expr("1", &mut memory).unwrap(); | |
assert_eq!(expr.eval(), 1.0); | |
} | |
#[test] | |
fn parse_add() { | |
let mut mem = Expr::parse_exprs("1 1 +").unwrap(); | |
let expr = mem.pop_front().unwrap(); | |
assert_eq!(expr.eval(), 2.0); | |
} | |
#[test] | |
fn parse_sub() { | |
let mut mem = Expr::parse_exprs("2 1 -").unwrap(); | |
let expr = mem.pop_front().unwrap(); | |
assert_eq!(expr.eval(), 1.0); | |
} | |
#[test] | |
fn parse_mult() { | |
let mut mem = Expr::parse_exprs("2 2 *").unwrap(); | |
let expr = mem.pop_front().unwrap(); | |
assert_eq!(expr.eval(), 4.0); | |
} | |
#[test] | |
fn parse_div() { | |
let mut mem = Expr::parse_exprs("4 2 /").unwrap(); | |
let expr = mem.pop_front().unwrap(); | |
assert_eq!(expr.eval(), 2.0); | |
} | |
#[test] | |
fn parse_sqrt() { | |
let mut mem = Expr::parse_exprs("25 sqrt").unwrap(); | |
let expr = mem.pop_front().unwrap(); | |
assert_eq!(expr.eval(), 5.0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment