From: Ben Pfaff Date: Sun, 30 Mar 2025 03:38:46 +0000 (-0700) Subject: StrParser X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45b04ce8e84f05c1c00a81859af59763d4ee8dc8;p=pspp StrParser --- diff --git a/rust/pspp/src/format/parse.rs b/rust/pspp/src/format/parse.rs index 6ee2d3bea3..c6e05b6f12 100644 --- a/rust/pspp/src/format/parse.rs +++ b/rust/pspp/src/format/parse.rs @@ -192,22 +192,7 @@ impl<'a> ParseValue<'a> { if input.is_empty() || input == "." { return Ok(Value::sysmis()); } - fn strip_prefix<'a>(input: &'a str, prefix: &str) -> (bool, &'a str) { - if prefix.is_empty() { - (false, input) - } else if let Some(rest) = input.strip_prefix(prefix) { - (true, rest.trim_start()) - } else { - (false, input) - } - } - fn strip_one_of<'a>(input: &'a str, chars: &[char]) -> (Option, &'a str) { - let mut iter = input.chars(); - match iter.next() { - Some(c) if chars.contains(&c) => (Some(c), iter.as_str().trim_start()), - _ => (None, input), - } - } + let mut p = StrParser::new(input.trim()); fn strip_integer(mut input: &str, grouping: Option) -> &str { while let Some(rest) = input.strip_prefix(|c: char| c.is_ascii_digit()) { let rest = if let Some(grouping) = grouping { @@ -220,31 +205,34 @@ impl<'a> ParseValue<'a> { input } - let (_, input) = strip_prefix(input, &*style.prefix.s); - let (sign, input) = strip_one_of(input, &['-', '+']); - let input = if sign.is_some() { - strip_prefix(input, &*style.prefix.s).1 - } else { - input - }; - let (integer, input) = take(input, strip_integer(input, style.grouping.map(char::from))); - let (decimals, input) = if let Some(rest) = input.strip_prefix(style.decimal.as_str()) { - take(rest, rest.trim_start_matches(|c: char| c.is_ascii_digit())) + if p.strip_prefix(&*style.prefix.s) { + p.strip_ws(); + } + let sign = p.strip_one_of(&['-', '+']).inspect(|_| p.strip_ws()); + if sign.is_some() && p.strip_prefix(&*style.prefix.s) { + p.strip_ws(); + } + let integer = p.advance(strip_integer(p.0, style.grouping.map(char::from))); + let decimals = if p.strip_prefix(style.decimal.as_str()) { + p.strip_matches(|c| c.is_ascii_digit()) } else { - ("", input) + "" }; - let (exp_sign, exponent, input) = if input.starts_with(['e', 'E', 'd', 'D', '+', '-']) { - let (_e, rest) = strip_one_of(input, &['e', 'E', 'd', 'D']); - let (exp_sign, rest) = strip_one_of(rest, &['-', '+']); - let (exponent, rest) = - take(rest, rest.trim_start_matches(|c: char| c.is_ascii_digit())); - (exp_sign, exponent, rest) + let (exp_sign, exponent) = if p.0.starts_with(['e', 'E', 'd', 'D', '+', '-']) { + let _e = p + .strip_one_of(&['e', 'E', 'd', 'D']) + .inspect(|_| p.strip_ws()); + let exp_sign = p.strip_one_of(&['-', '+']).inspect(|_| p.strip_ws()); + let exponent = p.strip_matches(|c| c.is_ascii_digit()); + (exp_sign, exponent) } else { - (None, "", input) + (None, "") }; - let (_, input) = strip_prefix(input, &*style.suffix.s); + if p.strip_prefix(&*style.suffix.s) { + p.strip_ws(); + } - if !input.is_empty() { + if !p.0.is_empty() { return Err(ParseErrorKind::NotNumeric); } @@ -263,6 +251,7 @@ impl<'a> ParseValue<'a> { } write!(&mut number, "{exponent}").unwrap(); } + println!("{number}"); match f64::from_str(&number) { Ok(value) => Ok(Value::Number(Some(value))), @@ -440,6 +429,51 @@ where } } +#[derive(Copy, Clone, Debug)] +pub struct StrParser<'a>(pub &'a str); + +impl<'a> StrParser<'a> { + pub fn new(s: &'a str) -> Self { + Self(s) + } + + pub fn strip_prefix(&mut self, prefix: &'a str) -> bool { + if prefix.is_empty() { + false + } else if let Some(rest) = self.0.strip_prefix(prefix) { + self.0 = rest; + true + } else { + false + } + } + + fn strip_one_of(&mut self, chars: &[char]) -> Option { + let mut iter = self.0.chars(); + match iter.next() { + Some(c) if chars.contains(&c) => { + self.0 = iter.as_str(); + Some(c) + } + _ => None, + } + } + + fn strip_matches(&mut self, f: impl Fn(char) -> bool) -> &'a str { + self.advance(self.0.trim_start_matches(f)) + } + + fn strip_ws(&mut self) { + self.0 = self.0.trim_start(); + } + + fn advance(&mut self, rest: &'a str) -> &'a str { + let head = &self.0[..self.0.len() - rest.len()]; + self.0 = rest; + head + } +} + #[cfg(test)] mod test { use std::{