data list
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 6 Dec 2024 17:45:26 +0000 (09:45 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 6 Dec 2024 17:45:26 +0000 (09:45 -0800)
rust/pspp-derive/src/lib.rs
rust/pspp/src/command/data_list.rs
rust/pspp/src/command/descriptives.rs
rust/pspp/src/command/mod.rs

index 26e1c64fd484bf8e2ea2af79b5a3de5825b9cf28..14e56ad4f0fbfa695b61f39d59c6f1b89937c66f 100644 (file)
@@ -166,7 +166,7 @@ fn derive_struct(ast: &DeriveInput, s: &DataStruct) -> Result<TokenStream2, Erro
             }
         }
     };
-    //println!("{output}");
+    println!("{output}");
     Ok(output)
 }
 
index b951ed614265f8fd7dc325918226d35b9f39e66a..9c1cb33ada7aa5c3d6186599163ce396b4cee1a8 100644 (file)
@@ -1,6 +1,6 @@
 use flagset::FlagSet;
 
-use super::{Comma, Command, Equals, Integer, Punctuated, Slash};
+use super::{Comma, Command, Equals, Integer, Punctuated, Seq0, Seq1, Slash};
 use crate::{
     command::{FromTokens, InParens, MismatchToError, ParseError, ParseResult, Parsed, TokenSlice},
     identifier::Identifier,
@@ -36,7 +36,7 @@ pub(super) fn data_list_command() -> Command {
 
 #[derive(Debug, pspp_derive::FromTokens)]
 #[pspp(add_lifetime)]
-struct DataList<'a>(Vec<Setting<'a>>);
+struct DataList<'a>(Seq1<Setting<'a>>, Seq1<Record<'a>>);
 
 #[derive(Debug, pspp_derive::FromTokens)]
 #[pspp(add_lifetime)]
@@ -67,18 +67,41 @@ enum File<'a> {
     Handle(&'a Identifier),
 }
 
-#[derive(Debug, pspp_derive::FromTokens)]
-#[pspp(add_lifetime)]
+#[derive(Debug)]
 struct Record<'a> {
     slash: Slash,
     record: Option<Integer>,
-    variables: Vec<Variable<'a>>,
+    variables: Seq0<Variable<'a>>,
+}
+
+impl<'a> FromTokens<'a> for Record<'a> {
+    fn from_tokens(input: TokenSlice<'a>) -> ParseResult<'a, Self> {
+        println!("{input:?}");
+        println!("{}:{}", file!(), line!());
+        let mut diagnostics = crate::command::Diagnostics::default();
+        println!("{}:{}", file!(), line!());
+        let (field0, input) = FromTokens::from_tokens(input)?.take_diagnostics(&mut diagnostics);
+        println!("{}:{}", file!(), line!());
+        let (field1, input) = FromTokens::from_tokens(input)?.take_diagnostics(&mut diagnostics);
+        println!("{}:{}", file!(), line!());
+        let (field2, input) = FromTokens::from_tokens(input)?.take_diagnostics(&mut diagnostics);
+        println!("{}:{}", file!(), line!());
+        Ok(Parsed::new(
+            Record {
+                slash: field0,
+                record: field1,
+                variables: field2,
+            },
+            input,
+            diagnostics,
+        ))
+    }
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
 #[pspp(add_lifetime)]
 struct Variable<'a> {
-    names: Vec<&'a Identifier>,
+    names: Seq1<&'a Identifier>,
     location: Location<'a>,
 }
 
@@ -119,15 +142,9 @@ mod tests {
     #[test]
     fn basics() {
         test(
-            "CROSSTABS r by c /STATISTICS=CHISQ
-/CELLS=COUNT EXPECTED RESID SRESID ASRESID
-/HIDESMALLCOUNTS COUNT=6.
-",
+            r#"DATA LIST FILE="/data/hubdata.txt" RECORDS=3
+/1 DEPT 19 SEX 20 MOHIRED YRHIRED 12-15
+/2 SALARY 21-25."#,
         );
     }
-
-    #[test]
-    fn integer_mode() {
-        test("CROSSTABS VARIABLES=X (1,7) Y (1,7) /TABLES=X BY Y/WRITE=CELLS.");
-    }
 }
index 20ab7587ff21a7fb395ec91a0acd345497fbce6b..604b02be41ff335f1c6b3bbbd791406928fc9e6e 100644 (file)
@@ -1,6 +1,6 @@
 use flagset::FlagSet;
 
-use super::{Comma, Command, Equals, Punctuated, Subcommand};
+use super::{Comma, Command, Equals, Punctuated, Seq1, Subcommand};
 use crate::command::{
     FromTokens, Identifier, InParens, MismatchToError, ParseError, ParseResult, Parsed, Punct,
     Token, TokenSlice, VarRange,
@@ -41,7 +41,7 @@ pub(super) fn descriptives_command() -> Command {
 #[derive(Debug, pspp_derive::FromTokens)]
 #[pspp(add_lifetime)]
 struct Descriptives<'a> {
-    subcommands: Vec<Subcommand<DescriptivesSubcommand<'a>>>,
+    subcommands: Seq1<Subcommand<DescriptivesSubcommand<'a>>>,
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
@@ -49,11 +49,11 @@ struct Descriptives<'a> {
 enum DescriptivesSubcommand<'a> {
     #[pspp(default)]
     Variables(Option<Equals>, Punctuated<DescriptivesVars<'a>>),
-    Missing(Equals, Vec<Missing>),
+    Missing(Equals, Seq1<Missing>),
     Save,
-    Statistics(Equals, Vec<Statistic>),
+    Statistics(Equals, Seq1<Statistic>),
     Sort(Equals, Sort),
-    Format(Equals, Vec<Format>),
+    Format(Equals, Seq1<Format>),
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
index 7b8ac31ce564c887e7cb66537c6d01da2dc70a3a..3c6871bd4facb63dff66ac6a6337f7dffeffbee1 100644 (file)
@@ -189,7 +189,7 @@ where
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
-#[pspp(syntax="/")]
+#[pspp(syntax = "/")]
 pub struct Slash;
 
 #[derive(Debug)]
@@ -204,17 +204,9 @@ impl<'a> FromTokens<'a> for Comma {
     }
 }
 
-#[derive(Debug)]
-pub struct Equals(Token);
-
-impl<'a> FromTokens<'a> for Equals {
-    fn from_tokens(input: TokenSlice<'a>) -> ParseResult<'a, Self>
-    where
-        Self: Sized,
-    {
-        _parse_token(input, &Token::Punct(Punct::Equals)).map(|p| p.map(|token| Equals(token)))
-    }
-}
+#[derive(Debug, pspp_derive::FromTokens)]
+#[pspp(syntax = "=")]
+pub struct Equals;
 
 #[derive(Debug)]
 struct By(Token);
@@ -362,6 +354,88 @@ where
     }
 }
 
+#[derive(Debug)]
+pub struct Seq0<T>(Vec<T>);
+
+impl<'a, T> FromTokens<'a> for Seq0<T>
+where
+    T: FromTokens<'a>,
+{
+    fn from_tokens(mut input: TokenSlice<'a>) -> ParseResult<'a, Self>
+    where
+        Self: Sized,
+    {
+        let mut values_vec = Vec::new();
+        let mut warnings_vec = Vec::new();
+        while !input.is_empty() {
+            match T::from_tokens(input) {
+                Ok(Parsed {
+                    value,
+                    rest,
+                    diagnostics: mut warnings,
+                }) => {
+                    warnings_vec.append(&mut warnings.0);
+                    if input.len() == rest.len() {
+                        break;
+                    }
+                    values_vec.push(value);
+                    input = rest;
+                }
+                Err(ParseError::Mismatch(_)) => break,
+                Err(ParseError::Error(e)) => return Err(ParseError::Error(e)),
+            }
+        }
+        Ok(Parsed {
+            value: Seq0(values_vec),
+            rest: input,
+            diagnostics: Diagnostics(warnings_vec),
+        })
+    }
+}
+
+#[derive(Debug)]
+pub struct Seq1<T>(Vec<T>);
+
+impl<'a, T> FromTokens<'a> for Seq1<T>
+where
+    T: FromTokens<'a>,
+{
+    fn from_tokens(mut input: TokenSlice<'a>) -> ParseResult<'a, Self>
+    where
+        Self: Sized,
+    {
+        let mut values_vec = Vec::new();
+        let mut warnings_vec = Vec::new();
+        while !input.is_empty() {
+            match T::from_tokens(input) {
+                Ok(Parsed {
+                    value,
+                    rest,
+                    diagnostics: mut warnings,
+                }) => {
+                    warnings_vec.append(&mut warnings.0);
+                    if input.len() == rest.len() {
+                        break;
+                    }
+                    values_vec.push(value);
+                    input = rest;
+                }
+                Err(ParseError::Mismatch(_)) => break,
+                Err(ParseError::Error(e)) => return Err(ParseError::Error(e)),
+            }
+        }
+        if values_vec.is_empty() {
+            return Err(ParseError::Mismatch(input.error("Syntax error.").into()));
+        }
+        Ok(Parsed {
+            value: Seq1(values_vec),
+            rest: input,
+            diagnostics: Diagnostics(warnings_vec),
+        })
+    }
+}
+
+/*
 impl<'a, T> FromTokens<'a> for Vec<T>
 where
     T: FromTokens<'a>,
@@ -393,7 +467,7 @@ where
             diagnostics: Diagnostics(warnings_vec),
         })
     }
-}
+}*/
 
 impl<'a> FromTokens<'a> for TokenSlice<'a> {
     fn from_tokens(input: TokenSlice<'a>) -> ParseResult<'a, Self>