Add a calculator parser

This commit is contained in:
Quentin Boyer 2023-11-12 13:05:12 +01:00
parent 94c5ddfae5
commit af6e1ef334
4 changed files with 113 additions and 0 deletions

28
Cargo.lock generated
View file

@ -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"

View file

@ -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"

82
src/calc.rs Normal file
View file

@ -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.));
}
}

View file

@ -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;