use crate::MathParseErrors;
use crate::MathParseErrors::*;
use crate::BinaryOp;
use crate::UnaryOp;
use crate::RPN;
use crate::RPN::*;
pub fn pop_one<T>(number_stack: &mut Vec<T>) -> Result<T, MathParseErrors> {
if let Some(num) = number_stack.pop() {
Ok(num)
} else {
Err(UnbalancedStack)
}
}
pub fn pop_two<T>(number_stack: &mut Vec<T>) -> Result<(T, T), MathParseErrors> {
let num_1 = if let Some(n) = number_stack.pop() {
n
} else {
return Err(UnbalancedStack);
};
let num_2 = if let Some(n) = number_stack.pop() {
n
} else {
return Err(UnbalancedStack);
};
Ok((num_2, num_1))
}
type UnaryExecFn<T> = dyn Fn(T, UnaryOp) -> Result<T, MathParseErrors>;
pub fn execute_unary<T>(number_stack: &mut Vec<T>, op: UnaryOp, exec: &UnaryExecFn<T>) -> Result<(), MathParseErrors> {
let num = pop_one(number_stack)?;
let computed = exec(num, op)?;
number_stack.push(computed);
Ok(())
}
type BinaryExecFn<T> = dyn Fn(T, T, BinaryOp) -> Result<T, MathParseErrors>;
pub fn execute_binary<T>(number_stack: &mut Vec<T>, op: BinaryOp, exec: &BinaryExecFn<T>) -> Result<(), MathParseErrors> {
let (num_1, num_2) = pop_two(number_stack)?;
let computed = exec(num_1, num_2, op)?;
number_stack.push(computed);
Ok(())
}
type NameExecFc<'a, T> = dyn Fn(&str) -> Result<T, MathParseErrors> + 'a;
fn exec_rpn_one_action<T>(number_stack: &mut Vec<T>, action: &RPN,
compute_name: &NameExecFc<T>, compute_unary: &UnaryExecFn<T>, compute_binary: &BinaryExecFn<T>) -> Result<(), MathParseErrors> {
match action {
Name(x) => {
number_stack.push(compute_name(&x)?);
Ok(())
},
Unary(op) => execute_unary(number_stack, *op, compute_unary),
Binary(op) => execute_binary(number_stack, *op, compute_binary),
}
}
pub fn exec_rpn<T>(rpn_actions: &[RPN], compute_name: &NameExecFc<T>, compute_unary: &UnaryExecFn<T>, compute_binary: &BinaryExecFn<T>) -> Result<T, MathParseErrors> {
let mut number_stack = Vec::<T>::new();
for action in rpn_actions {
exec_rpn_one_action(&mut number_stack, action, compute_name, compute_unary, compute_binary)?;
}
if number_stack.len() == 1 {
pop_one(&mut number_stack)
} else {
Err(UnbalancedStack)
}
}
#[test]
fn test_pop() {
let mut vec = vec!['a', 'b', 'c', 'd', 'e'];
assert_eq!(pop_two(&mut vec), Ok(('d', 'e')));
assert_eq!(pop_two(&mut vec), Ok(('b', 'c')));
assert_eq!(pop_two(&mut vec), Err(UnbalancedStack));
vec.push('a');
assert_eq!(pop_one(&mut vec), Ok('a'));
assert_eq!(pop_two(&mut vec), Err(UnbalancedStack));
assert_eq!(pop_one(&mut vec), Err(UnbalancedStack));
}