diff --git a/src/evaluator.rs b/src/evaluator.rs index 03ffbed..fab0795 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -3,7 +3,8 @@ use crate::Token; use crate::units::Unit; use crate::parser::AstNode; #[allow(unused_imports)] -use crate::Operator::{Percent, Caret, Divide, Factorial, LeftParen, Minus, Modulo, Multiply, Plus, RightParen}; +use crate::Operator::{Caret, Divide, LeftParen, Minus, Modulo, Multiply, Plus, RightParen}; +use crate::UnaryOperator::{Percent, Factorial}; #[derive(Clone, Debug)] pub struct Answer { @@ -25,6 +26,14 @@ pub fn evaluate(ast: &AstNode) -> Result { Ok(answer) } +fn factorial(n: d128) -> d128 { + if n < d128!(2) { + d128!(1) + } else { + n * factorial(n - d128!(1)) + } +} + fn evaluate_node(ast_node: &AstNode) -> Result { let token = &ast_node.token; let children = &ast_node.children; @@ -33,14 +42,32 @@ fn evaluate_node(ast_node: &AstNode) -> Result { Ok(Answer::new(number.clone(), Unit::NoUnit)) }, Token::Unit(unit) => { - let child_node = ast_node.children.get(0).expect("Unit has no child[0]"); + let child_node = children.get(0).expect("Unit has no child[0]"); let child_answer = evaluate_node(child_node)?; Ok(Answer::new(child_answer.value, unit.clone())) }, Token::Paren => { - let child_node = ast_node.children.get(0).expect("Paren has no child[0]"); + let child_node = children.get(0).expect("Paren has no child[0]"); return evaluate_node(child_node) }, + Token::UnaryOperator(operator) => { + let child_node = children.get(0).expect(format!("Token {:?} has no child[0]", token).as_str()); + let child_answer = evaluate_node(child_node)?; + match operator { + Percent => { + Ok(Answer::new(child_answer.value / d128!(100), child_answer.unit)) + }, + Factorial => { + if child_answer.value.is_negative() || child_answer.value.is_signed() { + Err("Cannot perform factorial of floats or negative".to_string()) + } else if child_answer.value > d128!(1000) { + Err("Cannot perform factorial of numbers above 1000".to_string()) + } else { + Ok(Answer::new(factorial(child_answer.value), child_answer.unit)) + } + }, + } + }, Token::Operator(operator) => { let left_child = children.get(0).expect(format!("Token {:?} has no child[0]", token).as_str()); let right_child = children.get(1).expect(format!("Token {:?} has no child[1]", token).as_str()); @@ -64,7 +91,54 @@ fn evaluate_node(ast_node: &AstNode) -> Result { let result = left.value * left.unit.weight() - right.value * right.unit.weight(); Ok(Answer::new(result, Unit::Millimeter)) } else { - return Err(format!("Cannot subtract {:?} and {:?}", left.unit, right.unit)) + return Err(format!("Cannot subtract {:?} by {:?}", left.unit, right.unit)) + } + }, + Multiply => { + if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { + // 3 * 2 + return Ok(Answer::new(left.value * right.value, left.unit)) + } else if left.unit == Unit::NoUnit && right.unit != Unit::NoUnit { + // 3 * 1 km + return Ok(Answer::new(left.value * right.value, right.unit)) + } else if right.unit == Unit::NoUnit && left.unit != Unit::NoUnit { + // 1 km * 3 + return Ok(Answer::new(left.value * right.value, left.unit)) + } else { + return Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit)) + } + }, + Divide => { + if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { + // 3 / 2 + return Ok(Answer::new(left.value / right.value, left.unit)) + } else if left.unit != Unit::NoUnit && right.unit == Unit::NoUnit { + // 1 km / 2 + return Ok(Answer::new(left.value / right.value, right.unit)) + } else { + return Err(format!("Cannot divide {:?} by {:?}", left.unit, right.unit)) + } + }, + Modulo => { + if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { + // 3 / 2 + return Ok(Answer::new(left.value % right.value, left.unit)) + } else if left.unit != Unit::NoUnit && right.unit == Unit::NoUnit { + // 1 km / 2 + return Ok(Answer::new(left.value % right.value, right.unit)) + } else { + return Err(format!("Cannot modulo {:?} by {:?}", left.unit, right.unit)) + } + }, + Caret => { + if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { + // 3 ^ 2 + return Ok(Answer::new(left.value ^ right.value, left.unit)) + } else if right.unit == Unit::NoUnit && left.unit != Unit::NoUnit { + // 1 km ^ 3 + return Ok(Answer::new(left.value ^ right.value, left.unit)) + } else { + return Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit)) } }, _ => { diff --git a/src/lexer.rs b/src/lexer.rs index 20fb96c..cf0440d 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,7 +1,8 @@ use std::str::FromStr; use decimal::d128; use crate::{Token, TokenVector}; -use crate::Operator::{Percent, Caret, Divide, Factorial, LeftParen, Minus, Modulo, Multiply, Plus, RightParen}; +use crate::Operator::{Caret, Divide, LeftParen, Minus, Modulo, Multiply, Plus, RightParen}; +use crate::UnaryOperator::{Percent, Factorial}; use crate::TextOperator::{Of, To}; use crate::Constant::{E, Pi}; use crate::FunctionIdentifier::{Acos, Acosh, Asin, Asinh, Atan, Atanh, Cbrt, Ceil, Cos, Cosh, Exp, Fabs, Floor, Ln, Log, Round, Sin, Sinh, Sqrt, Tan, Tanh}; @@ -25,7 +26,7 @@ pub fn lex(input: &str) -> Result { '/' => tokens.push(Token::Operator(Divide)), '%' => tokens.push(Token::Operator(Modulo)), '^' => tokens.push(Token::Operator(Caret)), - '!' => tokens.push(Token::Operator(Factorial)), + '!' => tokens.push(Token::UnaryOperator(Factorial)), '(' => { left_paren_count += 1; tokens.push(Token::Operator(LeftParen)); @@ -233,17 +234,21 @@ pub fn lex(input: &str) -> Result { match &tokens[token_index + 1] { Token::TextOperator(Of) => { // for example "10% of 1km" should be a percentage, not modulo - tokens[token_index] = Token::Operator(Percent); + tokens[token_index] = Token::UnaryOperator(Percent); }, Token::Operator(operator) => { match operator { LeftParen => {}, _ => { // for example "10%*2" should be a percentage, but "10%(2)" should be modulo - tokens[token_index] = Token::Operator(Percent); + tokens[token_index] = Token::UnaryOperator(Percent); } } }, + Token::UnaryOperator(_operator) => { + // for example "10%!" should be a percentage, but "10%(2)" should be modulo + tokens[token_index] = Token::UnaryOperator(Percent); + }, _ => {}, } } diff --git a/src/main.rs b/src/main.rs index 458d2f0..9b56295 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,12 +9,18 @@ pub enum Operator { Divide, Modulo, Caret, - Percent, - Factorial, + // Percent, + // Factorial, LeftParen, // lexer only RightParen, // lexer only } +#[derive(Clone, Debug)] +pub enum UnaryOperator { + Percent, + Factorial, +} + #[derive(Clone, Debug)] pub enum TextOperator { To, @@ -60,6 +66,7 @@ mod units; #[derive(Clone, Debug)] pub enum Token { Operator(Operator), + UnaryOperator(UnaryOperator), Number(d128), FunctionIdentifier(FunctionIdentifier), Constant(Constant), diff --git a/src/parser.rs b/src/parser.rs index aa1dd2f..7696244 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,6 @@ use crate::{Token, TokenVector}; -use crate::Operator::{Percent, Caret, Divide, Factorial, LeftParen, Minus, Modulo, Multiply, Plus, RightParen}; +use crate::Operator::{Caret, Divide, LeftParen, Minus, Modulo, Multiply, Plus, RightParen}; +use crate::UnaryOperator::{Percent, Factorial}; use crate::TextOperator::{To, Of}; #[derive(Debug)] @@ -121,7 +122,7 @@ fn parse_level_5(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), S loop { let token = tokens.get(pos); match token { - Some(&Token::Operator(Factorial)) | Some(&Token::Operator(Percent)) => { + Some(&Token::UnaryOperator(Factorial)) | Some(&Token::UnaryOperator(Percent)) => { // Here we are handling unary operators, aka stuff written as // "Number Operator" (3!) instead of "Number Operator Number" (3+3). // Therefore, if we find a match, we don't parse what comes after it.