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.
|
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
|
## 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()`.
|
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) {
|
match lexer::lex(input, allow_trailing_operators, default_degree) {
|
||||||
Ok(tokens) => {
|
Ok(tokens) => {
|
||||||
let lex_time = Instant::now().duration_since(lex_start).as_nanos() as f32;
|
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();
|
let parse_start = Instant::now();
|
||||||
match parser::parse(&tokens) {
|
match parser::parse(&tokens) {
|
||||||
Ok(ast) => {
|
Ok(ast) => {
|
||||||
let parse_time = Instant::now().duration_since(parse_start).as_nanos() as f32;
|
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();
|
let eval_start = Instant::now();
|
||||||
match evaluator::evaluate(&ast) {
|
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;
|
let eval_time = Instant::now().duration_since(eval_start).as_nanos() as f32;
|
||||||
|
|
||||||
if debug == true {
|
if debug == true {
|
||||||
println!("Lexed TokenVector: {:?}", tokens);
|
|
||||||
println!("Parsed AstNode: {:#?}", ast);
|
|
||||||
println!("Evaluated value: {} {:?}", answer.value, answer.unit);
|
println!("Evaluated value: {} {:?}", answer.value, answer.unit);
|
||||||
println!("\u{23f1} {:.3}ms lexing", lex_time/1000.0/1000.0);
|
println!("\u{23f1} {:.3}ms lexing", lex_time/1000.0/1000.0);
|
||||||
println!("\u{23f1} {:.3}ms parsing", parse_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;
|
node = new_node;
|
||||||
pos = next_pos;
|
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));
|
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`)
|
/// 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> {
|
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)?;
|
let (mut node, mut pos) = parse_level_4(tokens, pos)?;
|
||||||
|
|
||||||
loop {
|
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)
|
/// 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> {
|
pub fn parse_level_6(tokens: &TokenVector, pos: usize) -> Result<(AstNode, usize), String> {
|
||||||
let (mut node, mut pos) = parse_level_7(tokens, pos)?;
|
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),
|
/// Parse [`Number`](../enum.Token.html#variant.Number),
|
||||||
/// [`Unit`](../units/enum.Unit.html),
|
/// [`Unit`](../units/enum.Unit.html),
|
||||||
/// [`Constant`](../enum.Constant.html),
|
/// [`Constant`](../enum.Constant.html),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user