Improved parsing of foot-inch syntax
- Added support using foot-inch syntax with addition, like `2"+6'4"` - Unsupported foot-inch syntax like `(6)'4"` and `6'4!"` now cause errors
This commit is contained in:
parent
8378364dff
commit
34de6af711
@ -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()`.
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user