diff options
author | Greg Brown <gmb60@cam.ac.uk> | 2021-04-20 11:54:40 +0100 |
---|---|---|
committer | Greg Brown <gmb60@cam.ac.uk> | 2021-04-20 11:54:40 +0100 |
commit | 15f5491028b11bd821bd141183e8b5bf8c1c46af (patch) | |
tree | 02a688b9baf9e4e6b11d83b9d76b95bb363e66ce | |
parent | 7934aa9af22e8fa3c33a45bc08e732a73c0cabf5 (diff) |
Add handwritten arithmetic parser.
-rw-r--r-- | chomp-bench/benches/arith.rs | 7 | ||||
-rw-r--r-- | chomp-bench/src/arith/mod.rs | 117 |
2 files changed, 124 insertions, 0 deletions
diff --git a/chomp-bench/benches/arith.rs b/chomp-bench/benches/arith.rs index 4ba6ea7..489a847 100644 --- a/chomp-bench/benches/arith.rs +++ b/chomp-bench/benches/arith.rs @@ -24,6 +24,10 @@ fn parse_chewed(input: &str) -> i64 { .into() } +fn parse_handwritten(input: &str) -> i64 { + parse_expr(&mut IterWrapper::new(input.chars())).unwrap() +} + fn bench_parse(c: &mut Criterion) { let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic); let mut group = c.benchmark_group("Arith"); @@ -33,6 +37,9 @@ fn bench_parse(c: &mut Criterion) { group.bench_with_input(BenchmarkId::new("Chewed", i), *input, |b, i| { b.iter(|| parse_chewed(i)) }); + group.bench_with_input(BenchmarkId::new("Handwritten", i), *input, |b, i| { + b.iter(|| parse_handwritten(i)) + }); } } diff --git a/chomp-bench/src/arith/mod.rs b/chomp-bench/src/arith/mod.rs index e7b7abd..37432d5 100644 --- a/chomp-bench/src/arith/mod.rs +++ b/chomp-bench/src/arith/mod.rs @@ -1 +1,118 @@ +use chewed::{ParseError, TakeError}; + pub mod nibble; + +pub fn take_number<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, TakeError> { + let mut out = None; + loop { + match input.next() { + Some('0') => { + out = Some(out.unwrap_or_default() * 10); + } + Some('1') => { + out = Some(out.unwrap_or_default() * 10 + 1); + } + Some('2') => { + out = Some(out.unwrap_or_default() * 10 + 2); + } + Some('3') => { + out = Some(out.unwrap_or_default() * 10 + 3); + } + Some('4') => { + out = Some(out.unwrap_or_default() * 10 + 4); + } + Some('5') => { + out = Some(out.unwrap_or_default() * 10 + 5); + } + Some('6') => { + out = Some(out.unwrap_or_default() * 10 + 6); + } + Some('7') => { + out = Some(out.unwrap_or_default() * 10 + 7); + } + Some('8') => { + out = Some(out.unwrap_or_default() * 10 + 8); + } + Some('9') => { + out = Some(out.unwrap_or_default() * 10 + 9); + } + Some(c) => { + return out.ok_or_else(|| { + TakeError::BadBranch( + input.pos(), + c, + &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + ) + }) + } + None => return out.ok_or_else(|| TakeError::EndOfStream(input.pos())), + } + } +} + +pub fn take_term<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, TakeError> { + let out = match input.peek() { + Some('-') => { + input.consume_str("-")?; + input.skip_while(|c| c == ' '); + take_number(input).map(|x| -x) + } + Some(c) if c.is_ascii_digit() => take_number(input), + Some('(') => { + input.consume_str("(")?; + input.skip_while(|c| c == ' '); + let o = take_expr(input); + input.consume_str(")")?; + o + } + Some(c) => Err(TakeError::BadBranch( + input.pos(), + c, + &['-', '(', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + )), + None => Err(TakeError::EndOfStream(input.pos())), + }?; + input.skip_while(|c| c == ' '); + Ok(out) +} + +pub fn take_product<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, TakeError> { + let mut out = take_term(input)?; + while let Some(c) = input.peek() { + if c == '*' { + input.skip_while(|c| c == ' '); + out *= take_term(input)?; + } else if c == '/' { + input.skip_while(|c| c == ' '); + out -= take_term(input)?; + } else { + return Err(TakeError::BadBranch(input.pos(), c, &['*', '/'])); + } + } + Ok(out) +} + +pub fn take_expr<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, TakeError> { + let mut out = take_product(input)?; + while let Some(c) = input.peek() { + if c == '+' { + input.skip_while(|c| c == ' '); + out += take_product(input)?; + } else if c == '-' { + input.skip_while(|c| c == ' '); + out -= take_product(input)?; + } else { + return Err(TakeError::BadBranch(input.pos(), c, &['+', '-'])); + } + } + Ok(out) +} + +pub fn parse_expr<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, ParseError> { + input.skip_while(|c| c == ' '); + let out = take_expr(input)?; + match input.peek() { + Some(_) => Err(ParseError::InputContinues(input.pos())), + None => Ok(out), + } +} |