From 961daae9d5f90abcb84a71a680c4a058e3313aa3 Mon Sep 17 00:00:00 2001 From: Kasper Date: Sat, 14 Nov 2020 04:08:27 +0100 Subject: [PATCH] Added named numbers (hundred, quadrillion etc) --- README.md | 1 - src/evaluator.rs | 9 ++++++++- src/lexer.rs | 26 ++++++++++++++++++++++++++ src/lib.rs | 30 ++++++++++++++++++++++++++++++ src/lookup.rs | 32 ++++++++++++++++++++++++++++++++ src/parser.rs | 2 +- 6 files changed, 97 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d7a60b8..8f99c82 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,6 @@ match string { ### Potential Improvements #### General -- Support for math in `6'4"` syntax, like `3'+2'4"`. Currently needs to be written like `3'+3'+4"` - The functions in units.rs have a lot of manual if statements. This could probably be replaced with a pretty advanced macro. - Support for lexing words, like `one billion` #### Potential unit types diff --git a/src/evaluator.rs b/src/evaluator.rs index 16c7377..c2136cf 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -7,7 +7,7 @@ use crate::Constant::{Pi, E}; use crate::UnaryOperator::{Percent, Factorial}; use crate::TextOperator::{To, Of}; use crate::FunctionIdentifier::*; -use crate::lookup::lookup_factorial; +use crate::lookup::{lookup_factorial, lookup_named_number}; /// Evaluate an [`AstNode`](struct.AstNode.html) into a [`Number`](struct.Number.html) pub fn evaluate(ast: &AstNode) -> Result { @@ -219,6 +219,13 @@ fn evaluate_node(ast_node: &AstNode) -> Result { }, } }, + Token::NamedNumber(named_number) => { + let child_node = children.get(0).ok_or(format!("Token {:?} has no child[0]", token))?; + let child_answer = evaluate_node(child_node)?; + let named_number_value = lookup_named_number(named_number); + let result = child_answer.value * named_number_value; + Ok(Number::new(result, child_answer.unit)) + } Token::TextOperator(operator) => { let left_child = children.get(0).ok_or(format!("Token {:?} has no child[0]", token))?; let right_child = children.get(1).ok_or(format!("Token {:?} has no child[1]", token))?; diff --git a/src/lexer.rs b/src/lexer.rs index 8ca3ecf..9034f47 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -4,6 +4,7 @@ use crate::{Token, TokenVector}; use crate::Operator::{Caret, Divide, LeftParen, Minus, Modulo, Multiply, Plus, RightParen}; use crate::UnaryOperator::{Percent, Factorial}; use crate::TextOperator::{Of, To}; +use crate::NamedNumber::*; use crate::Constant::{E, Pi}; use crate::LexerKeyword::{In, PercentChar, Per, Mercury, Hg, PoundForce, PoundWord, Force, DoubleQuotes}; use crate::FunctionIdentifier::{Cbrt, Ceil, Cos, Exp, Abs, Floor, Ln, Log, Round, Sin, Sqrt, Tan}; @@ -130,6 +131,31 @@ pub fn lex(input: &str, allow_trailing_operators: bool, default_degree: Unit) -> "to" => tokens.push(Token::TextOperator(To)), "of" => tokens.push(Token::TextOperator(Of)), + "hundred" => tokens.push(Token::NamedNumber(Hundred)), + "thousand" => tokens.push(Token::NamedNumber(Thousand)), + "mil" | "mill" | "million" => tokens.push(Token::NamedNumber(Million)), + "bil" | "bill" | "billion" => tokens.push(Token::NamedNumber(Billion)), + "tri" | "tril" | "trillion" => tokens.push(Token::NamedNumber(Trillion)), + "quadrillion" => tokens.push(Token::NamedNumber(Quadrillion)), + "quintillion" => tokens.push(Token::NamedNumber(Quintillion)), + "sextillion" => tokens.push(Token::NamedNumber(Sextillion)), + "septillion" => tokens.push(Token::NamedNumber(Septillion)), + "octillion" => tokens.push(Token::NamedNumber(Octillion)), + "nonillion" => tokens.push(Token::NamedNumber(Nonillion)), + "decillion" => tokens.push(Token::NamedNumber(Decillion)), + "undecillion" => tokens.push(Token::NamedNumber(Undecillion)), + "duodecillion" => tokens.push(Token::NamedNumber(Duodecillion)), + "tredecillion" => tokens.push(Token::NamedNumber(Tredecillion)), + "quattuordecillion" => tokens.push(Token::NamedNumber(Quattuordecillion)), + "quindecillion" => tokens.push(Token::NamedNumber(Quindecillion)), + "sexdecillion" => tokens.push(Token::NamedNumber(Sexdecillion)), + "septendecillion" => tokens.push(Token::NamedNumber(Septendecillion)), + "octodecillion" => tokens.push(Token::NamedNumber(Octodecillion)), + "novemdecillion" => tokens.push(Token::NamedNumber(Novemdecillion)), + "vigintillion" => tokens.push(Token::NamedNumber(Vigintillion)), + "centillion" => tokens.push(Token::NamedNumber(Centillion)), + "googol" => tokens.push(Token::NamedNumber(Googol)), + "pi" => tokens.push(Token::Constant(Pi)), "e" => tokens.push(Token::Constant(E)), diff --git a/src/lib.rs b/src/lib.rs index 9a75c7f..2318cda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,6 +93,35 @@ pub enum TextOperator { Of, } +#[derive(Clone, Debug)] +/// A named number like [`Million`](enum.NamedNumber.html#variant.Million). +pub enum NamedNumber { + Hundred, + Thousand, + Million, + Billion, + Trillion, + Quadrillion, + Quintillion, + Sextillion, + Septillion, + Octillion, + Nonillion, + Decillion, + Undecillion, + Duodecillion, + Tredecillion, + Quattuordecillion, + Quindecillion, + Sexdecillion, + Septendecillion, + Octodecillion, + Novemdecillion, + Vigintillion, + Centillion, + Googol, +} + #[derive(Clone, Debug)] /// A constants like [`Pi`](enum.Constant.html#variant.Pi) or [`E`](enum.Constant.html#variant.E). pub enum Constant { @@ -157,6 +186,7 @@ pub enum Token { /// Used by the parser only LexerKeyword(LexerKeyword), TextOperator(TextOperator), + NamedNumber(NamedNumber), /// The `-` symbol, specifically when used as `-5` and not `5-5`. Used by the parser only Negative, Unit(units::Unit), diff --git a/src/lookup.rs b/src/lookup.rs index b0a2ab3..331c6db 100644 --- a/src/lookup.rs +++ b/src/lookup.rs @@ -1,5 +1,37 @@ +use crate::NamedNumber::*; +use crate::NamedNumber; use decimal::d128; +/// Returns the number of a [`NamedNumber`](decimal/struct.d128.html) [`to`](../enum.NamedNumber.html) as a [`d128`](decimal/struct.d128.html) +pub fn lookup_named_number(named_number: &NamedNumber) -> d128 { + return match named_number { + Hundred => d128!(100), + Thousand => d128!(1000), + Million => d128!(1000000), + Billion => d128!(1000000000), + Trillion => d128!(1000000000000), + Quadrillion => d128!(1000000000000000), + Quintillion => d128!(1000000000000000000), + Sextillion => d128!(1000000000000000000000), + Septillion => d128!(1000000000000000000000000), + Octillion => d128!(1000000000000000000000000000), + Nonillion => d128!(1000000000000000000000000000000), + Decillion => d128!(1000000000000000000000000000000000), + Undecillion => d128!(1000000000000000000000000000000000000), + Duodecillion => d128!(10E+39), + Tredecillion => d128!(10E+42), + Quattuordecillion => d128!(10E+45), + Quindecillion => d128!(10E+48), + Sexdecillion => d128!(10E+51), + Septendecillion => d128!(10E+54), + Octodecillion => d128!(10E+57), + Novemdecillion => d128!(10E+60), + Vigintillion => d128!(10E+63), + Centillion => d128!(10E+303), + Googol => d128!(10E+100), + } +} + /// Returns the factorial of an `i32` as a [`d128`](decimal/struct.d128.html) pub fn lookup_factorial(n: i32) -> d128 { return match n { diff --git a/src/parser.rs b/src/parser.rs index 025da5d..d4e7835 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -269,7 +269,7 @@ pub fn parse_level_6(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize loop { let token = tokens.get(pos); match token { - Some(&Token::UnaryOperator(Factorial)) | Some(&Token::UnaryOperator(Percent)) => { + Some(&Token::UnaryOperator(Factorial)) | Some(&Token::UnaryOperator(Percent)) | Some(&Token::NamedNumber(_)) => { // 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.