diff --git a/README.md b/README.md index 31e7e84..d7a60b8 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ round(sqrt(2)^4)! liters cpc Uses 128-bit Decimal Floating Point (d128) numbers instead of Binary Coded Decimals for better accuracy. The result cpc gives will still not always be 100% accurate. I would recommend rounding the result to 20 decimals or less. ## Performance -It's pretty fast and scales well. In my case, `eval()` usually runs under 0.1ms. The biggest performance hit is functions like `log()`. `log(12345)` evaluates in 0.12ms, and `log(e)` in 0.24ms. +It's pretty fast and scales well. In my case, `eval()` usually runs under 0.1ms. The biggest performance hit is functions like `log()`. `log(12345)` evaluates in 0.12ms, and `log(e)` in 0.25ms. To see how fast it is, you can pass the `--debug` flag in CLI, or the `debug` argument to `eval()`. diff --git a/src/lib.rs b/src/lib.rs index 06718d4..9a75c7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,11 +189,13 @@ pub fn eval(input: &str, allow_trailing_operators: bool, default_degree: Unit, d match lexer::lex(input, allow_trailing_operators, default_degree) { Ok(tokens) => { let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32; + if debug == true { println!("Lexed TokenVector: {:?}", tokens); } let parse_start = Instant::now(); match parser::parse(&tokens) { Ok(ast) => { let parse_time = Instant::now().duration_since(parse_start).as_nanos() as f32; + if debug == true { println!("Parsed AstNode: {:#?}", ast); } let eval_start = Instant::now(); match evaluator::evaluate(&ast) { @@ -201,8 +203,6 @@ pub fn eval(input: &str, allow_trailing_operators: bool, default_degree: Unit, d let eval_time = Instant::now().duration_since(eval_start).as_nanos() as f32; if debug == true { - println!("Lexed TokenVector: {:?}", tokens); - println!("Parsed AstNode: {:#?}", ast); println!("Evaluated value: {} {:?}", answer.value, answer.unit); println!("\u{23f1} {:.3}ms lexing", lex_time/1000.0/1000.0); println!("\u{23f1} {:.3}ms parsing", parse_time/1000.0/1000.0); diff --git a/src/parser.rs b/src/parser.rs index 822f4fc..025da5d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -74,20 +74,6 @@ pub fn parse_level_2(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize node = new_node; pos = next_pos; }, - Some(&Token::Number(_)) => { - // parse 6'4" - let (right_node, next_pos) = parse_level_3(tokens, pos)?; - if let Token::Unit(Foot) = node.token { - if let Token::Unit(Inch) = right_node.token { - let mut new_node = AstNode::new(Token::Operator(Plus)); - new_node.children.push(node); - new_node.children.push(right_node); - node = new_node; - pos = next_pos; - } - } - return Ok((node, pos)); - }, _ => { return Ok((node, pos)); }, @@ -95,9 +81,42 @@ pub fn parse_level_2(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize } } -// level 3 precedence: *, /, modulo, implicative multiplication +// level 3 precedence: *, /, modulo, implicative multiplication, foot-inch 6'4" /// Parse [`Multiply`](../enum.Operator.html#variant.Multiply), [`Divide`](../enum.Operator.html#variant.Divide), [`Modulo`](../enum.Operator.html#variant.Modulo) and implicative multiplication (for example`2pi`) pub fn parse_level_3(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), String> { + + // parse foot-inch syntax 6'4" + let token0 = tokens.get(pos); + if let Some(Token::Number(_number)) = token0 { + let token1 = tokens.get(pos + 1); + if let Some(Token::Unit(Foot)) = token1 { + let token2 = tokens.get(pos + 2); + if let Some(Token::Number(_number)) = token2 { + let token3 = tokens.get(pos + 3); + if let Some(Token::Unit(Inch)) = token3 { + let new_node = AstNode { + children: vec![ + AstNode { + children: vec![ + AstNode::new(token0.unwrap().clone()), + ], + token: Token::Unit(Foot), + }, + AstNode { + children: vec![ + AstNode::new(token2.unwrap().clone()), + ], + token: Token::Unit(Inch), + }, + ], + token: Token::Operator(Plus), + }; + return Ok((new_node, pos + 4)) + } + } + } + } + let (mut node, mut pos) = parse_level_4(tokens, pos)?; loop { @@ -243,7 +262,7 @@ pub fn parse_level_5(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize } } -// level 6 precedence: !, percent +// level 6 precedence: !, percent, units attached to values /// Parse [`Factorial`](../enum.UnaryOperator.html#variant.Factorial) and [`Percent`](../enum.UnaryOperator.html#variant.Percent) pub fn parse_level_6(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), String> { let (mut node, mut pos) = parse_level_7(tokens, pos)?; @@ -275,7 +294,7 @@ pub fn parse_level_6(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize } } -// level 7 precedence: numbers, units, constants, functions, parens +// level 7 precedence: numbers, standalone units, constants, functions, parens /// Parse [`Number`](../enum.Token.html#variant.Number), /// [`Unit`](../units/enum.Unit.html), /// [`Constant`](../enum.Constant.html),