diff --git a/Cargo.toml b/Cargo.toml index f5d1369..610575d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust_command_line_calculator" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["Christoph J. Scherr "] license = "GPL3" diff --git a/src/expression_parser.rs b/src/expression_parser.rs index 79d0e81..b10d8c9 100644 --- a/src/expression_parser.rs +++ b/src/expression_parser.rs @@ -1,4 +1,4 @@ -use std::{fmt, error::Error, num::IntErrorKind}; +use std::fmt; use regex::Regex; pub mod shunting_yard; @@ -284,7 +284,7 @@ impl Expression { eprintln!( "Could not calculate result of child expression '{}': {}", child.text, - "error placeholder TODO" + err ); std::process::exit(2); } diff --git a/src/expression_parser/shunting_yard.rs b/src/expression_parser/shunting_yard.rs index ccc03fd..a7b7709 100644 --- a/src/expression_parser/shunting_yard.rs +++ b/src/expression_parser/shunting_yard.rs @@ -1,3 +1,4 @@ +use std::fmt; /* * Custom made implementation of the shunting yard algorithm. @@ -17,6 +18,15 @@ enum Associativity { Left } +impl fmt::Debug for Associativity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Associativity::Right => write!(f, "Right"), + Associativity::Left => write!(f, "Left"), + } + } +} + #[derive(PartialEq)] pub struct Operator { character: char, @@ -24,6 +34,16 @@ pub struct Operator { associativity: Associativity } +impl fmt::Debug for Operator { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Operator") + .field("character", &self.character) + .field("precedence", &self.precedence) + .field("associativity", &self.associativity) + .finish() + } +} + impl Operator { pub fn is_operator(c: char) -> bool { for op in OPERATORS { @@ -69,7 +89,7 @@ const DIVISION: Operator = Operator { }; const EXPONENTIATION: Operator = Operator { - character: '*', + character: '^', precedence: 2, associativity: Associativity::Right }; @@ -89,7 +109,7 @@ pub fn form_reverse_polish_notation(regular_math: &str) -> Result, S // read a token let token: char = input_queue.pop().unwrap(); dbg!(&token); - + // if the token is: // a number: if token.is_numeric() | (token == '.') { @@ -122,25 +142,25 @@ pub fn form_reverse_polish_notation(regular_math: &str) -> Result, S Some(valid_op) => valid_op, None => {panic!("Operator '{}' not found.", token);}, }; - + // while there is an operator o2 at the top of the stack if !operator_stack.is_empty() { dbg!(&operator_stack); let o2 = match Operator::get_operator(*(operator_stack.clone().last().clone().unwrap())) { Some(valid_op) => valid_op, - None => {panic!("Operator '{}' not found.", token);}, + None => {panic!("Operator '{}' not found.", token);}, }; // and // (o2 has greater precedence than o1 or (o1 and o2 have the same precedence and o1 // is left associative)) - while ((operator_stack.last().is_some()) & ((o2.precedence > o1.precedence) | ((o1.precedence == o2.precedence) & (o1.associativity == Associativity::Left)))) { + while (operator_stack.last().is_some()) & ((o2.precedence > o1.precedence) | ((o1.precedence == o2.precedence) & (o1.associativity == Associativity::Left))) { // pop o2 from the operator stack into the output queue. // after this debug statement, the operator_stack is empty for no reason!!!! // FIXME let my_c = match operator_stack.pop() { Some(c) => c, None => {panic!("weirdly gone!")}, - }; + }; output_queue.push(vec![my_c]); } } @@ -149,10 +169,10 @@ pub fn form_reverse_polish_notation(regular_math: &str) -> Result, S /* // Unnessecary, will be processed by the expression parser else if '(' == token { - println!("("); + println!("("); } else if ')' == token { - println!(")"); + println!(")"); } */ else { @@ -180,5 +200,91 @@ pub fn form_reverse_polish_notation(regular_math: &str) -> Result, S // after we have the rpn, we may want to calculate the values with it. pub fn calc_reverse_polish_notation(rpn: Vec) -> Result { - Ok(0.0) + + // # function to evaluate reverse polish notation + // def evaluate(expression): + // # splitting expression at whitespaces + // expression = expression.split() + // # stack + // stack = [] + // # iterating expression + // for ele in expression: + // # ele is a number + // if ele not in '/*+-': + // stack.append(int(ele)) + // # ele is an operator + // else: + // # getting operands + // right = stack.pop() + // left = stack.pop() + // # performing operation according to operator + // if ele == '+': + // stack.append(left + right) + // elif ele == '-': + // stack.append(left - right) + // elif ele == '*': + // stack.append(left * right) + // elif ele == '/': + // stack.append(int(left / right)) + // # return final answer. + // return stack.pop() + let mut stack: Vec = Vec::new(); + + for group in rpn { + dbg!(&group); + // find out what the group is, an operator, a number, or a variable. + // TODO add variables + if !Operator::is_operator(group.chars().last().unwrap()) { + let possible_num = group.parse::(); + match possible_num { + Ok(valid) => {stack.push(valid);}, + Err(_whatever) => { + eprint!("weird error happened, ending process..."); + std::process::exit(2); + }, + } + dbg!(&stack); + } + else { + let op: Operator = Operator::get_operator(group.chars().last().unwrap()).unwrap(); + dbg!(&op); + let right = stack.pop().unwrap(); + let left = stack.pop().unwrap(); + + if op == ADDITION { + stack.push(left + right); + } + + else if op == SUBTRACTION { + stack.push(left - right); + } + + else if op == MULTIPLICATION { + stack.push(left * right); + } + + else if op == DIVISION { + stack.push(left / right); + } + + else if op == EXPONENTIATION { + stack.push(left.powf(right)); + } + + else { + todo!(); + } + } + } + + + if stack.is_empty() { + return Err("result stack empty".to_string()); + } + if stack.len() > 1 { + dbg!(stack); + return Err("result stack has too many results.".to_string()); + } + return Ok(stack[0]); + } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..bdc1b37 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,7 @@ +// Make module public +pub mod expression_parser; + +// Make the function available at the root of the crate +pub use expression_parser::*; + + diff --git a/test.txt b/test.txt deleted file mode 100644 index ae08274..0000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -13 + 2525 + sqrt(15 + log_10(100)) + power_10(10) diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000..f113245 --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,94 @@ +use rust_command_line_calculator as rclc; + +#[test] +fn test_tests_are_loaded() { + assert_eq!("AA", "AA"); +} + +#[test] +fn test_main_sum_simple() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("40 + 33"), + String::from("40 + 33"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 73.0); +} + +#[test] +fn test_main_sum_chain() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("20340 + 32424 + 24 + 23"), + String::from("20340 + 32424 + 24 + 23"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 20340.0 + 32424.0 + 24.0 + 23.0); +} + +#[test] +fn test_main_difference_simple() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("33-13"), + String::from("33-13"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 33.0 - 13.0); +} + +#[test] +fn test_main_difference_chain() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("353535 - 2405 - 33 - 13 - 4"), + String::from("353535 - 2405 - 33 - 13 - 4"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 353535.0 - 2405.0 - 33.0 - 13.0 - 4.0); +} + +#[test] +fn test_main_product_simple() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("353* 13"), + String::from("353* 13"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 353.0 * 13.0); +} + +#[test] +fn test_main_procuct_chain() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("353535 * 2405 * 33 * 13 * 4"), + String::from("353535 * 2405 * 33 * 13 * 4"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 353535.0 * 2405.0 * 33.0 * 13.0 * 4.0); +} + +#[test] +fn test_main_quotient_simple() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("353 / 13"), + String::from("353 / 13"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 353.0 / 13.0); +} + +#[test] +fn test_main_quotient_chain() { + let my_expression: rclc::Expression = + rclc::Expression::new( + String::from("353535 / 2405 / 33 / 13 / 4"), + String::from("353535 / 2405 / 33 / 13 / 4"), + rclc::Task::None, + 0); + assert_eq!(my_expression.process().unwrap(), 353535.0 / 2405.0 / 33.0 / 13.0 / 4.0); +}