diff --git a/Cargo.lock b/Cargo.lock index 2eeb8a2..edec213 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -711,6 +711,7 @@ dependencies = [ "iced", "iced_aw", "itertools", + "peg", "serde", "serde_json", ] @@ -1684,6 +1685,33 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "peg" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "400bcab7d219c38abf8bd7cc2054eb9bbbd4312d66f6a5557d572a203f646f61" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e61cce859b76d19090f62da50a9fe92bab7c2a5f09e183763559a2ac392c90" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36bae92c60fa2398ce4678b98b2c4b5a7c61099961ca1fa305aec04a9ad28922" + [[package]] name = "percent-encoding" version = "2.3.0" diff --git a/Cargo.toml b/Cargo.toml index efa75d0..7b9c4be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,5 +13,6 @@ iced_aw = { version = "0.7.0", default-features = false, features = [ "card", ] } itertools = "0.11.0" +peg = "0.8.2" serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.108" diff --git a/src/calc.rs b/src/calc.rs new file mode 100644 index 0000000..a22b2a5 --- /dev/null +++ b/src/calc.rs @@ -0,0 +1,82 @@ +peg::parser! { + pub grammar calc_parser() for str { + rule number() -> f64 = n:$(['0'..='9']+ ("." ['0'..='9']*)?) {? n.parse().or(Err("f64"))} + + rule _ = quiet!{[' ' | '\n' | '\t']*} + + pub rule calc() -> f64 = + _ v:precedence!{ + "-" _ x:(@) { std::ops::Neg::neg(x) } + "+" _ x:(@) { x } + -- + x:(@) _ "+" _ y:@ { x + y } + x:(@) _ "-" _ y:@ { x - y } + -- + x:(@) _ "*" _ y:@ { x * y } + x:(@) _ "/" _ y:@ { x / y } + -- + n:number() { n } + "(" _ e:calc() _ ")" { e } + } _ { v } + } +} + +#[cfg(test)] +mod test { + use super::calc_parser; + + #[test] + fn prefix_plus() { + assert_eq!(calc_parser::calc("+1"), Ok(1.)); + } + + #[test] + fn prefix_minus() { + assert_eq!(calc_parser::calc("-1"), Ok(-1.)); + } + + #[test] + fn sum() { + assert_eq!(calc_parser::calc("1+1"), Ok(2.)); + } + + #[test] + fn prod() { + assert_eq!(calc_parser::calc("2*2"), Ok(4.)); + } + + #[test] + fn div() { + assert_eq!(calc_parser::calc("6/3"), Ok(2.)); + } + + #[test] + fn sub() { + assert_eq!(calc_parser::calc("6-3"), Ok(3.)); + } + + #[test] + fn literal() { + assert_eq!(calc_parser::calc("2"), Ok(2.)); + assert_eq!(calc_parser::calc("2."), Ok(2.)); + assert_eq!(calc_parser::calc("2.0"), Ok(2.)); + } + + #[test] + fn whitespace_infix() { + assert_eq!( + calc_parser::calc("- (1+ ( 1 * 3) / 6-1)"), + Ok(-0.5) + ); + } + + #[test] + fn whitespace_prefix() { + assert_eq!(calc_parser::calc(" 1+1"), Ok(2.)); + } + + #[test] + fn whitespace_suffix() { + assert_eq!(calc_parser::calc("1+1 "), Ok(2.)); + } +} diff --git a/src/main.rs b/src/main.rs index 3d8d70f..083abcb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,8 @@ use serde::{Deserialize, Serialize}; type Element<'a> = iced::Element<'a, Message>; +mod calc; + const TEXT_H1: u16 = 30; const TEXT_H2: u16 = 25; const TEXT_EMPH1: u16 = 17;