Added --debug flag, eval returns Result
This commit is contained in:
parent
55e7ef0a04
commit
5830904a45
@ -1,8 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cpc"
|
name = "cpc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Kasper <kasperkh.kh@gmail.com>"]
|
description = "evaluates math expressions, with support for units and conversion between units"
|
||||||
|
readme = 'README.md'
|
||||||
|
authors = ["Kasper Henningsen"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
repository = "https://github.com/probablykasper/cpc"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
decimal = "2.0.4"
|
decimal = "2.0.4"
|
||||||
|
|||||||
30
README.md
30
README.md
@ -3,6 +3,23 @@ calculation + conversion
|
|||||||
|
|
||||||
cpc parses and evaluates strings of math, with support for units and conversion. 128-bit decimal floating points are used for high accuracy.
|
cpc parses and evaluates strings of math, with support for units and conversion. 128-bit decimal floating points are used for high accuracy.
|
||||||
|
|
||||||
|
cpc lets you mix units, so for example `1 km - 1m` results in `Number { value: 999, unit: Meter }`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
```rs
|
||||||
|
use cpc::{eval, Unit::*}
|
||||||
|
|
||||||
|
match eval("3m + 1cm", true, Celcius) {
|
||||||
|
Ok(answer) => {
|
||||||
|
// answer: Number { value: 301, unit: Unit::cm }
|
||||||
|
println!("Evaluated value: {} {:?}", answer.value, answer.unit)
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
```
|
```
|
||||||
3 + 4 * 2
|
3 + 4 * 2
|
||||||
@ -20,7 +37,6 @@ cpc parses and evaluates strings of math, with support for units and conversion.
|
|||||||
round(sqrt(2)^4)! liters
|
round(sqrt(2)^4)! liters
|
||||||
|
|
||||||
10% of abs(sin(pi)) horsepower to watts
|
10% of abs(sin(pi)) horsepower to watts
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Supported unit types
|
## Supported unit types
|
||||||
@ -41,7 +57,10 @@ 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
|
||||||
In my case, I can expect `eval()` to take 100-200ms, and this scales pretty alright. However, putting numbers with a lot of digits into functions result in pretty poor performance. `log(e)` is one of the worst, and takes 500ms.
|
In my case, I can expect `eval()` to take 100-200ms, and this scales pretty alright. However, putting numbers with a lot of digits into functions result in pretty poor performance. `log(e)` is one of the worst, and takes 500ms for me.
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
cpc returns `Result`s with basic strings as errors. Just to be safe, you may want to handle panics (You can do that using `std::panic::catch_unwind`).
|
||||||
|
|
||||||
# Dev Instructions
|
# Dev Instructions
|
||||||
|
|
||||||
@ -54,6 +73,11 @@ Run cpc with a CLI argument as input:
|
|||||||
cargo run -- '100ms to s'
|
cargo run -- '100ms to s'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Run with debugging, which shows some extra logs:
|
||||||
|
```
|
||||||
|
cargo run -- '100ms to s' --debug
|
||||||
|
```
|
||||||
|
|
||||||
Run tests:
|
Run tests:
|
||||||
```
|
```
|
||||||
cargo test
|
cargo test
|
||||||
@ -99,7 +123,7 @@ match string {
|
|||||||
// ...
|
// ...
|
||||||
```
|
```
|
||||||
|
|
||||||
# Potential Improvements
|
## Potential Improvements
|
||||||
### General
|
### General
|
||||||
- Support for math in `6'4"` syntax, like `3'+2'4"`. Currently needs to be written like `3'+3'+4"`
|
- 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.
|
- The functions in units.rs have a lot of manual if statements. This could probably be replaced with a pretty advanced macro.
|
||||||
|
|||||||
41
src/main.rs
41
src/main.rs
@ -91,14 +91,27 @@ mod lookup;
|
|||||||
fn main() {
|
fn main() {
|
||||||
use std::env;
|
use std::env;
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
let mut debug = false;
|
||||||
|
if args.iter().any(|i| i=="--debug") {
|
||||||
|
debug = true;
|
||||||
|
}
|
||||||
if args.len() >= 2 {
|
if args.len() >= 2 {
|
||||||
eval(&args[1], true, Unit::Celcius);
|
match eval(&args[1], true, Unit::Celcius, debug) {
|
||||||
|
Ok(answer) => {
|
||||||
|
if !debug {
|
||||||
|
println!("Evaluated value: {} {:?}", answer.value, answer.unit)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("{}", e)
|
||||||
|
},
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("No argument supplied");
|
println!("No argument supplied");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(input: &str, allow_trailing_operators: bool, default_degree: Unit) {
|
pub fn eval(input: &str, allow_trailing_operators: bool, default_degree: Unit, debug: bool) -> Result<units::Number, String> {
|
||||||
|
|
||||||
let lex_start = Instant::now();
|
let lex_start = Instant::now();
|
||||||
|
|
||||||
@ -116,24 +129,26 @@ pub fn eval(input: &str, allow_trailing_operators: bool, default_degree: Unit) {
|
|||||||
Ok(answer) => {
|
Ok(answer) => {
|
||||||
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;
|
||||||
|
|
||||||
println!("Lexed TokenVector: {:?}", tokens);
|
if debug == true {
|
||||||
println!("Parsed AstNode: {:#?}", ast);
|
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);
|
println!("\u{23f1} {:.3}ms evaluation", eval_time/1000.0/1000.0);
|
||||||
println!("\u{23f1} {:.3}ms evaluation", eval_time/1000.0/1000.0);
|
}
|
||||||
|
|
||||||
|
return Ok(answer)
|
||||||
},
|
},
|
||||||
Err(e) => println!("Eval error: {}", e),
|
Err(e) => Err(format!("Eval error: {}", e)),
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
Err(e) => println!("Parsing error: {}", e),
|
Err(e) => Err(format!("Parsing error: {}", e)),
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
Err(e) => println!("Lexing error: {}", e),
|
Err(e) => Err(format!("Lexing error: {}", e)),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user