From 15f5491028b11bd821bd141183e8b5bf8c1c46af Mon Sep 17 00:00:00 2001 From: Greg Brown Date: Tue, 20 Apr 2021 11:54:40 +0100 Subject: Add handwritten arithmetic parser. --- chomp-bench/src/arith/mod.rs | 117 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) (limited to 'chomp-bench/src/arith/mod.rs') 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(input: &mut P) -> Result { + 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(input: &mut P) -> Result { + 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(input: &mut P) -> Result { + 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(input: &mut P) -> Result { + 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(input: &mut P) -> Result { + input.skip_while(|c| c == ' '); + let out = take_expr(input)?; + match input.peek() { + Some(_) => Err(ParseError::InputContinues(input.pos())), + None => Ok(out), + } +} -- cgit v1.2.3