From c1c2fda1eb8405df1f741822d80c726809d3836a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 23 Dec 2024 15:01:09 -0800 Subject: [PATCH] file and variable attributes --- rust/pspp/src/cooked.rs | 25 +++++++++++++++++++ rust/pspp/src/dictionary.rs | 43 +++----------------------------- rust/pspp/src/identifier.rs | 49 ++++++++++++++++++++++++++++++++++--- rust/pspp/src/raw.rs | 2 +- 4 files changed, 74 insertions(+), 45 deletions(-) diff --git a/rust/pspp/src/cooked.rs b/rust/pspp/src/cooked.rs index 84b473fdf7..5cf07f67fa 100644 --- a/rust/pspp/src/cooked.rs +++ b/rust/pspp/src/cooked.rs @@ -647,6 +647,31 @@ pub fn decode( } } + for (k, v) in headers + .file_attributes + .iter() + .flat_map(|map| map.0 .0.iter()) + { + dictionary.attributes.insert(k.clone(), v.clone()); + } + + for attr_set in headers + .variable_attributes + .iter() + .flat_map(|record| record.0.iter()) + { + if let Some((_, variable)) = dictionary + .variables + .get_full_mut2(&attr_set.long_var_name.0) + { + for (k, v) in attr_set.attributes.0.iter() { + variable.attributes.insert(k.clone(), v.clone()); + } + } else { + warn(Error::TBD); + } + } + let metadata = Metadata::decode(&headers, warn); Ok((dictionary, metadata)) } diff --git a/rust/pspp/src/dictionary.rs b/rust/pspp/src/dictionary.rs index e8988ca2c1..ffe63571fa 100644 --- a/rust/pspp/src/dictionary.rs +++ b/rust/pspp/src/dictionary.rs @@ -417,31 +417,6 @@ pub enum Role { Split, } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum DictClass { - Ordinary, - System, - Scratch, -} - -impl DictClass { - pub fn must_leave(self) -> bool { - self == DictClass::Scratch - } -} - -impl From<&Identifier> for DictClass { - fn from(id: &Identifier) -> Self { - if id.0.starts_with('$') { - Self::System - } else if id.0.starts_with('#') { - Self::Scratch - } else { - Self::Ordinary - } - } -} - #[derive(Clone, Debug)] pub struct Variable { pub name: Identifier, @@ -457,13 +432,13 @@ pub struct Variable { pub alignment: Alignment, pub leave: bool, pub short_names: Vec, - pub attributes: HashSet>, + pub attributes: HashMap>, } impl Variable { pub fn new(name: Identifier, width: VarWidth) -> Self { let var_type = VarType::from_width(width); - let leave = DictClass::from(&name).must_leave(); + let leave = name.class().must_leave(); Self { name, width, @@ -478,7 +453,7 @@ impl Variable { alignment: Alignment::default_for_type(var_type), leave, short_names: Vec::new(), - attributes: HashSet::new(), + attributes: HashMap::new(), } } @@ -519,18 +494,6 @@ impl HasIdentifier for Vector { } } -#[derive(Clone, Debug)] -pub struct Attribute { - pub name: Identifier, - pub values: Vec, -} - -impl HasIdentifier for Attribute { - fn identifier(&self) -> &UniCase { - &self.name.0 - } -} - #[derive(Clone, Debug)] pub struct MultipleResponseSet { pub name: Identifier, diff --git a/rust/pspp/src/identifier.rs b/rust/pspp/src/identifier.rs index 1f6694b633..c4e21544ff 100644 --- a/rust/pspp/src/identifier.rs +++ b/rust/pspp/src/identifier.rs @@ -11,7 +11,40 @@ use finl_unicode::categories::{CharacterCategories, MajorCategory}; use thiserror::Error as ThisError; use unicase::UniCase; -use crate::dictionary::DictClass; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Class { + /// No distinguishing prefix. + Ordinary, + + /// Starting with `$`. + System, + + /// Starting with `#`. + Scratch, + + /// Starting with `!`. + Macro, +} + +impl Class { + pub fn must_leave(self) -> bool { + self == Self::Scratch + } +} + +impl From<&Identifier> for Class { + fn from(id: &Identifier) -> Self { + if id.0.starts_with('$') { + Self::System + } else if id.0.starts_with('#') { + Self::Scratch + } else if id.0.starts_with('!') { + Self::Macro + } else { + Self::Ordinary + } + } +} pub trait IdentifierChar { /// Returns true if `self` is an ASCII character that may be the first @@ -158,7 +191,11 @@ impl Identifier { pub fn new(s: impl Into>) -> Result { Self::from_encoding(s, UTF_8) } - pub fn from_encoding(s: impl Into>, encoding: &'static Encoding) -> Result { + + pub fn from_encoding( + s: impl Into>, + encoding: &'static Encoding, + ) -> Result { let s: UniCase = s.into(); Self::is_plausible(&s)?; let identifier = Identifier(s); @@ -246,8 +283,8 @@ impl Identifier { } pub fn must_be_ordinary(self) -> Result { - match DictClass::from(&self) { - DictClass::Ordinary => Ok(self), + match Class::from(&self) { + Class::Ordinary => Ok(self), _ => { let s = self.0.into_inner(); let first = s.chars().next().unwrap(); @@ -255,6 +292,10 @@ impl Identifier { } } } + + pub fn class(&self) -> Class { + self.into() + } } impl PartialEq for Identifier { diff --git a/rust/pspp/src/raw.rs b/rust/pspp/src/raw.rs index 63b7c04c3e..a34d05bbd8 100644 --- a/rust/pspp/src/raw.rs +++ b/rust/pspp/src/raw.rs @@ -2434,7 +2434,7 @@ impl VarAttributeSet { } #[derive(Clone, Debug)] -pub struct VariableAttributeRecord(Vec); +pub struct VariableAttributeRecord(pub Vec); impl VariableAttributeRecord { fn decode(source: &TextRecord, decoder: &Decoder) -> Self { -- 2.30.2