From: Ben Pfaff Date: Sat, 22 Mar 2025 16:44:15 +0000 (-0700) Subject: work on testing CCx X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9ad788401c4b62de75ba328da28474363bdc95f4;p=pspp work on testing CCx --- diff --git a/rust/pspp/src/format/mod.rs b/rust/pspp/src/format/mod.rs index a3cb174944..9f85588eed 100644 --- a/rust/pspp/src/format/mod.rs +++ b/rust/pspp/src/format/mod.rs @@ -4,7 +4,7 @@ use std::{ fmt::{Display, Error as FmtError, Formatter, Result as FmtResult, Write}, io::Write as _, ops::{Not, RangeInclusive}, - str::{from_utf8_unchecked, FromStr}, + str::{from_utf8_unchecked, Chars, FromStr}, sync::LazyLock, }; @@ -777,6 +777,18 @@ impl From for u8 { } } +impl TryFrom for Decimal { + type Error = (); + + fn try_from(c: char) -> Result { + match c { + '.' => Ok(Self::Dot), + ',' => Ok(Self::Comma), + _ => Err(()), + } + } +} + impl Not for Decimal { type Output = Self; @@ -982,21 +994,100 @@ pub struct Affix { } impl Affix { - fn new(s: &str) -> Self { + fn new(s: impl Into) -> Self { + let s = s.into(); Self { - s: s.to_string(), width: s.width(), + s, } } + + fn extra_bytes(&self) -> usize { + self.s.len().checked_sub(self.width).unwrap() + } } -pub struct DisplayValue<'a> { +impl FromStr for NumberStyle { + type Err = (); + + fn from_str(s: &str) -> Result { + fn find_separator(s: &str) -> Option { + // Count commas and periods. There must be exactly three of one or + // the other, except that an apostrophe escapes a following comma or + // period. + let mut n_commas = 0; + let mut n_periods = 0; + let s = s.as_bytes(); + for i in 0..s.len() { + if i > 0 && s[i - 1] == b'\'' { + } else if s[i] == b',' { + n_commas += 1; + } else if s[i] == b'.' { + n_periods += 1; + } + } + + if n_commas == 3 && n_periods != 3 { + Some(',') + } else if n_periods == 3 && n_commas != 3 { + Some('.') + } else { + None + } + } + + fn take_cc_token(iter: &mut Chars<'_>, grouping: char) -> Affix { + let mut s = String::new(); + let mut quote = false; + for c in iter { + if c == '\'' { + quote = true; + } else { + if c == grouping && !quote { + break; + } + s.push(c); + quote = false; + } + } + Affix::new(s) + } + + let Some(grouping) = find_separator(s) else { + return Err(()); + }; + let mut iter = s.chars(); + let neg_prefix = take_cc_token(&mut iter, grouping); + let prefix = take_cc_token(&mut iter, grouping); + let suffix = take_cc_token(&mut iter, grouping); + let neg_suffix = take_cc_token(&mut iter, grouping); + let grouping: Decimal = grouping.try_into().unwrap(); + let decimal = !grouping; + let extra_bytes = neg_prefix.extra_bytes() + + prefix.extra_bytes() + + suffix.extra_bytes() + + neg_suffix.extra_bytes(); + Ok(Self { + neg_prefix, + prefix, + suffix, + neg_suffix, + decimal, + grouping: Some(grouping), + leading_zero: false, + extra_bytes, + }) + } +} + +pub struct DisplayValue<'a, 'b> { format: Format, + settings: &'b Settings, value: &'a Value, encoding: &'static Encoding, } -impl<'a> Display for DisplayValue<'a> { +impl<'a, 'b> Display for DisplayValue<'a, 'b> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { let number = match self.value { Value::Number(number) => *number, @@ -1055,19 +1146,21 @@ impl<'a> Display for DisplayValue<'a> { } } -impl<'a> DisplayValue<'a> { +impl<'a, 'b> DisplayValue<'a, 'b> { pub fn new(format: Format, value: &'a Value, encoding: &'static Encoding) -> Self { Self { format, value, encoding, + settings: &PsppSettings::global().formats, } } + pub fn with_settings(self, settings: &'b Settings) -> Self { + Self { settings, ..self } + } fn number(&self, f: &mut Formatter<'_>, number: f64) -> FmtResult { if number.is_finite() { - let style = PsppSettings::global() - .formats - .number_style(self.format.type_); + let style = self.settings.number_style(self.format.type_); if self.format.type_ != Type::E && number.abs() < 1.5 * power10(self.format.w()) { let rounder = Rounder::new(style, number, self.format.d); if self.decimal(f, &rounder, style, true)? @@ -1419,7 +1512,7 @@ impl<'a> DisplayValue<'a> { } } b'y' => { - let epoch = PsppSettings::global().formats.epoch.0; + let epoch = self.settings.epoch.0; let offset = date.year() - epoch; if offset < 0 || offset > 99 { return self.overflow(f); @@ -1470,7 +1563,7 @@ impl<'a> DisplayValue<'a> { let d = min(self.format.d(), excess_width as usize); let w = d + 3; write!(&mut output, ":{:02$.*}", d, number, w).unwrap(); - if PsppSettings::global().formats.decimal == Decimal::Comma { + if self.settings.decimal == Decimal::Comma { fix_decimal_point(&mut output); } } @@ -1876,7 +1969,7 @@ mod test { use crate::{ dictionary::Value, - format::{AbstractFormat, Format, UncheckedFormat}, + format::{AbstractFormat, Format, Settings, UncheckedFormat}, lex::{ scan::StringScanner, segment::Syntax, @@ -1889,6 +1982,7 @@ mod test { .join("src/format/testdata") .join(name); let input = BufReader::new(File::open(&filename).unwrap()); + let settings = Settings::default(); let mut value = 0.0; let mut value_name = String::new(); for (line_number, line) in input.lines().map(|r| r.unwrap()).enumerate() {