use std::collections::VecDeque;
use std::sync::Mutex;
#[macro_use]
extern crate lazy_static;
__lazy_static_internal!(@MAKE TY, ,(pub),FACTORIAL_CACHE);
__lazy_static_internal!(@TAIL,FACTORIAL_CACHE:Mutex<Vec<f64>> = Mutex::new(vec![1.0,1.0]));
lazy_static!();
pub struct Expression {
pub expr: String,
pub post_fix: String,
pub result: Result<f64, ErrorKind>,
}
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
InvalidExpression,
InsufficientOperands,
DivisionByZero,
Overflow,
InvalidToken,
MalformedExpression,
FactorialNonInteger,
FactorialNegative,
LogarithmNegative,
}
impl ErrorKind {
pub fn as_str(&self) -> &'static str {
match *self {
ErrorKind::InvalidExpression => "Invalid expression",
ErrorKind::InsufficientOperands => "Insufficient operands",
ErrorKind::DivisionByZero => "Division by zero",
ErrorKind::Overflow => "Overflow",
ErrorKind::InvalidToken => "Invalid token",
ErrorKind::MalformedExpression => "Malformed postfix expression",
ErrorKind::FactorialNegative => "Factorial of a negative number",
ErrorKind::FactorialNonInteger => "Factorial of a non-integer",
ErrorKind::LogarithmNegative => "Log of a negative number",
}
}
}
impl std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Expression {
pub fn new(expr: &str) -> Expression {
Self {
expr: expr.to_string(),
post_fix: String::new(),
result: Err(ErrorKind::InvalidExpression),
}
}
pub fn precedence(operator: char) -> u8 {
match operator {
'+' | '-' => 1,
'*' | '/' => 2,
'^' => 3,
'&' | '|' | '~' => 0, _ => 0,
}
}
pub fn infix_to_postfix(&mut self) -> Result<(), ErrorKind> {
let mut output_queue = VecDeque::new();
let mut stack = Vec::new();
let mut number_buffer = Vec::new();
let mut tokens = self.expr.chars().peekable();
while let Some(&ch) = tokens.peek() {
match ch {
'0'..='9' | '.' => {
number_buffer.push(ch);
tokens.next();
}
'!' => {
Self::flush_num_buffer(&mut number_buffer, &mut output_queue);
output_queue.push_back(String::from("!"));
tokens.next();
}
' ' => {
Self::flush_num_buffer(&mut number_buffer, &mut output_queue);
tokens.next();
}
'+' | '-' | '*' | '/' | '^' | '&' | '|' | '~' => {
Self::flush_num_buffer(&mut number_buffer, &mut output_queue);
while let Some(&operation) = stack.last() {
if operation == '(' || !Self::has_higher_precedence(operation, ch) {
break;
}
output_queue.push_back(stack.pop().unwrap().to_string());
}
stack.push(ch);
tokens.next();
}
'(' => {
stack.push(ch);
tokens.next();
}
')' => {
Self::flush_num_buffer(&mut number_buffer, &mut output_queue);
while let Some(op) = stack.pop() {
if op == '(' {
break;
}
output_queue.push_back(op.to_string());
}
tokens.next();
}
_ => return Err(ErrorKind::InvalidToken),
}
}
Self::flush_num_buffer(&mut number_buffer, &mut output_queue);
while let Some(op) = stack.pop() {
if op == '(' {
return Err(ErrorKind::MalformedExpression); }
output_queue.push_back(op.to_string());
}
self.post_fix = output_queue.into_iter().collect::<Vec<_>>().join(" ");
Ok(())
}
fn flush_num_buffer(number_buffer: &mut Vec<char>, output: &mut VecDeque<String>) {
if !number_buffer.is_empty() {
let num = number_buffer.iter().collect::<String>();
output.push_back(num);
number_buffer.clear();
}
}
pub fn show_post_fix(&self) -> &str {
&self.post_fix
}
pub fn has_higher_precedence(op1: char, op2: char) -> bool {
Self::precedence(op1) > Self::precedence(op2)
}
pub fn compute_expression(&mut self) -> Result<(), ErrorKind> {
let post_fix_vector: Vec<&str> = self.post_fix.split_whitespace().collect();
let mut stack: Vec<f64> = Vec::new();
for token in post_fix_vector.iter() {
match *token {
"+" | "-" | "*" | "/" | "^" => {
if stack.len() < 2 {
return Err(ErrorKind::InsufficientOperands);
}
let operand2 = stack.pop().unwrap();
let operand1 = stack.pop().unwrap();
let result = match *token {
"+" => operand1 + operand2,
"-" => operand1 - operand2,
"*" => operand1 * operand2,
"/" => {
if operand2 == 0.0 {
return Err(ErrorKind::DivisionByZero);
}
operand1 / operand2
}
"^" => operand1.powf(operand2),
_ => unreachable!(), };
stack.push(result);
}
"!" => {
if let Some(a) = stack.pop() {
if a < 0.0 || a.fract() != 0.0 {
return Err(if a < 0.0 {
ErrorKind::FactorialNegative
} else {
ErrorKind::FactorialNonInteger
});
}
let fact = Self::factorial(a as usize)?;
stack.push(fact);
} else {
return Err(ErrorKind::InsufficientOperands);
}
}
"&" | "|" | "~" => {
if stack.len() < 2 {
return Err(ErrorKind::InsufficientOperands);
}
let operand1 = stack.pop().unwrap() as i64;
let operand2 = stack.pop().unwrap() as i64;
let result = match *token {
"&" => operand1 & operand2,
"|" => operand1 | operand2,
"~" => operand1 ^ operand2,
_ => unreachable!(), };
stack.push(result as f64);
}
_ => {
if let Ok(num) = token.parse::<f64>() {
stack.push(num);
} else {
return Err(ErrorKind::InvalidToken);
}
}
}
}
if stack.len() == 1 {
self.result = Ok(stack.pop().unwrap());
} else {
return Err(ErrorKind::MalformedExpression);
}
Ok(())
}
fn factorial(n: usize) -> Result<f64, ErrorKind> {
let mut cache = FACTORIAL_CACHE.lock().map_err(|_| ErrorKind::Overflow)?;
if n >= cache.len() {
for i in cache.len()..=n {
let last = *cache.last().unwrap();
let result = last * i as f64;
if result.is_infinite() {
return Err(ErrorKind::Overflow);
}
cache.push(result);
}
}
cache.get(n).copied().ok_or(ErrorKind::InvalidExpression)
}
pub fn get_result(&self) -> &Result<f64, ErrorKind> {
&self.result
}
pub fn process_expression(&mut self, compute: bool) -> Result<(), ErrorKind> {
self.infix_to_postfix()?;
if !compute {
println!("Postfix: [{}]", self.show_post_fix());
}
if compute {
self.compute_expression()?;
match self.get_result() {
Ok(result) => println!("Result = {}", result),
Err(e) => println!("Error: {}", e),
}
}
Ok(())
}
}