got all of ctables
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 15 Dec 2024 17:05:35 +0000 (09:05 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 15 Dec 2024 17:05:35 +0000 (09:05 -0800)
rust/pspp-derive/src/lib.rs
rust/pspp/src/command/crosstabs.rs
rust/pspp/src/command/ctables.rs
rust/pspp/src/command/data_list.rs
rust/pspp/src/command/descriptives.rs

index 8934b3d34c153011bab31b237b3e3a55771fab7c..d13b46b7082e1f7dd571f4406b1dd30ca1513012 100644 (file)
@@ -31,63 +31,42 @@ fn derive_enum(ast: &DeriveInput, e: &DataEnum) -> Result<TokenStream2, Error> {
     let mut body = TokenStream2::new();
     let name = &ast.ident;
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
-    if struct_attrs.selector {
-        let mut variants = Vec::new();
-        let mut default = None;
-        for (index, variant) in e.variants.iter().enumerate() {
-            let field_attrs = FieldAttrs::parse(&variant.attrs)?;
-            if field_attrs.default {
-                if default.is_none() {
-                    default = Some(index);
-                } else {
-                    return Err(Error::new(variant.span(), "Duplicate default variant"));
-                }
-            }
-            variants.push((variant, field_attrs));
-        }
-        for (index, (variant, field_attrs)) in variants.iter().enumerate() {
-            if index > 0 {
-                body.extend(quote! { else }.into_iter());
-            }
-            let ident = &variant.ident;
+    for variant in &e.variants {
+        let ident = &variant.ident;
+        let field_attrs = FieldAttrs::parse(&variant.attrs)?;
+        let selector = field_attrs.selector.unwrap_or(struct_attrs.selector);
+        let construction = construct_fields(&variant.fields, quote! { #name::#ident }, selector, None);
+        let fnname = format_ident!("construct_{ident}");
+        body.extend(quote! {
+            fn #fnname #impl_generics(input: &TokenSlice) -> ParseResult<#name #ty_generics> #where_clause { let input = input.clone();  #construction }
+        });
+    }
+
+    for  variant in &e.variants {
+        let ident = &variant.ident;
+        let fnname = format_ident!("construct_{ident}");
+        let field_attrs = FieldAttrs::parse(&variant.attrs)?;
+        let selector = field_attrs.selector.unwrap_or(struct_attrs.selector);
+        if selector {
             let ident_string = ident.to_string();
-            let match_expr = if let Some(syntax) = &field_attrs.syntax {
+            let select_expr = if let Some(syntax) = &field_attrs.syntax {
                 quote! { input.skip_syntax(#syntax) }
             } else if ident_string.eq_ignore_ascii_case("all") {
                 quote! { input.skip(&Token::Punct(Punct::All))}
             } else {
                 quote! { input.skip_keyword(#ident_string)}
             };
-            let construction =
-                construct_fields(&variant.fields, quote! { Self::#ident}, true, None);
-            body.extend(quote! { if let Some(input) = #match_expr { #construction } });
-        }
-        if let Some(default) = default {
-            let (variant, _field_attrs) = &variants[default];
-            let ident = &variant.ident;
-            let construction =
-                construct_fields(&variant.fields, quote! { Self::#ident}, true, None);
-            body.extend(quote! { else { #construction } });
+            body.extend(quote! { if let Some(input) = #select_expr { return #fnname(&input); } });
         } else {
-            body.extend(
-                quote! { else { Err(ParseError::Mismatch(input.error("Syntax error.").into())) } },
-            );
-        }
-    } else {
-        for (index, variant) in e.variants.iter().enumerate() {
-            let ident = &variant.ident;
-            let construction =
-                construct_fields(&variant.fields, quote! { #name::#ident }, false, None);
-            let fnname = format_ident!("construct{index}");
             body.extend(quote! {
-                fn #fnname #impl_generics(input: &TokenSlice) -> ParseResult<#name #ty_generics> #where_clause { let input = input.clone();  #construction }
-                if let Ok(p) = #fnname(input) {
-                    return Ok(p);
+                let result = #fnname(&input);
+                if let Ok(_) | Err(ParseError::Error(_)) = result {
+                    return result;
                 }
             });
         }
-        body.extend(quote! { Err(ParseError::Mismatch(input.error("Syntax error.").into())) });
     }
+    body.extend(quote! { Err(ParseError::Mismatch(input.error("Syntax error.").into())) });
 
     let output = quote! {
         impl #impl_generics FromTokens for #name #ty_generics #where_clause {
@@ -153,16 +132,11 @@ fn derive_struct(ast: &DeriveInput, s: &DataStruct) -> Result<TokenStream2, Erro
     let struct_attrs = StructAttrs::parse(&ast.attrs)?;
     let name = &ast.ident;
     let syntax = if let Some(syntax) = struct_attrs.syntax.as_ref() {
-      syntax .clone()
+        syntax.clone()
     } else {
         Literal::string(&name.to_string())
     };
-    let construction = construct_fields(
-        &s.fields,
-        quote! {#name},
-        false,
-        Some(&syntax)
-    );
+    let construction = construct_fields(&s.fields, quote! {#name}, false, Some(&syntax));
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
     let output = quote! {
         impl #impl_generics FromTokens for #name #ty_generics #where_clause {
@@ -178,7 +152,7 @@ fn derive_struct(ast: &DeriveInput, s: &DataStruct) -> Result<TokenStream2, Erro
 #[derive(Default)]
 struct FieldAttrs {
     syntax: Option<Literal>,
-    default: bool,
+    selector: Option<bool>,
 }
 
 impl FieldAttrs {
@@ -193,8 +167,8 @@ impl FieldAttrs {
                     meta.input.parse::<Token![=]>()?;
                     let syntax = meta.input.parse::<Literal>()?;
                     field_attrs.syntax = Some(syntax);
-                } else if meta.path.is_ident("default") {
-                    field_attrs.default = true;
+                } else if meta.path.is_ident("no_selector") {
+                    field_attrs.selector = Some(false);
                 } else {
                     return Err(Error::new(meta.path.span(), "Unknown attribute"));
                 }
index 3f6c3ab7f68e65b37c662564c9a2b4b6f8c1830a..201b122e3dedac646aa44b29dc561af53eb6878c 100644 (file)
@@ -42,12 +42,15 @@ mod keyword {
 
     #[derive(Debug, pspp_derive::FromTokens)]
     pub struct Count;
+
+    #[derive(Debug, pspp_derive::FromTokens)]
+    pub struct Tables;
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
 enum CrosstabsSubcommand {
-    #[pspp(default)]
-    Tables(Option<Equals>, Punctuated<VarList, By>),
+    #[pspp(no_selector)]
+    Tables(Option<(keyword::Tables, Equals)>, Punctuated<VarList, By>),
     Missing(Equals, Missing),
     Write(Option<(Equals, Write)>),
     HideSmallCounts(keyword::Count, Equals, Integer),
index ce6adf5d9a8023369d73641e0ab939bed4d6497b..e7360e1f68a1e7db0479517967ea29e9b9a6e346 100644 (file)
@@ -56,7 +56,7 @@ enum CTablesSubcommand {
     HideSmallCounts(keyword::Count, Equals, Integer),
     SLabels(Seq1<SLabel>),
     CLabels(CLabel),
-    Categories(Seq1<Category>),
+    Categories(Seq1<Categories>),
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
@@ -274,10 +274,15 @@ enum LabelDestination {
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
-enum Category {
+enum Categories {
     Variables(Equals, VarList),
     Order(Equals, Direction),
     Key(Equals, Key),
+    Missing(Equals, Include),
+    Total(Equals, Boolean),
+    Label(Equals, String),
+    Position(Equals, CategoryPosition),
+    Empty(Equals, Include),
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
@@ -292,7 +297,20 @@ enum Direction {
 enum Key {
     Value,
     Label,
-    
+    #[pspp(no_selector)]
+    Summary(Summary),
+}
+
+#[derive(Debug, pspp_derive::FromTokens)]
+enum Include {
+    Include,
+    Exclude,
+}
+
+#[derive(Debug, pspp_derive::FromTokens)]
+enum CategoryPosition {
+    After,
+    Before,
 }
 
 mod keyword {
index fb4a1896ee40d9ed59342dddc9bc2138d8c703dd..dff6f16f4b2ab02c7fffa8f1e0ecd2a81204f6ce 100644 (file)
@@ -53,7 +53,7 @@ enum Setting {
 
 #[derive(Debug, pspp_derive::FromTokens)]
 enum Delimiter {
-    #[pspp(default)] // XXX this allows `STRING "string"`
+    #[pspp(no_selector)]
     String(String),
     Tab,
 }
index 791de70054a221f92389bce3f360b4de50705c62..57cafe1733db7cf1faed451dc0c0b9c4ca5d5f81 100644 (file)
@@ -1,6 +1,6 @@
 use flagset::FlagSet;
 
-use super::{Comma, Command, Equals, Punctuated, Seq1, Subcommand};
+use super::{Comma, Command, Equals, Punctuated, Seq1, Subcommands};
 use crate::command::{
     FromTokens, Identifier, InParens, MismatchToError, ParseError, ParseResult, Parsed, Punct,
     Token, TokenSlice, VarRange,
@@ -14,24 +14,20 @@ pub(super) fn descriptives_command() -> Command {
         no_abbrev: false,
         name: "DESCRIPTIVES",
         run: Box::new(|context| {
-            let mut input = context.lexer.clone();
-            while !input.is_empty() {
-                match <Subcommand<DescriptivesSubcommand>>::from_tokens(&input) {
-                    Ok(Parsed {
-                        value: subcommand,
-                        rest,
-                        diagnostics,
-                    }) => {
-                        println!("\n{subcommand:?}");
-                        //println!("rest: {rest:?}");
-                        println!("warnings: {diagnostics:?}");
-                        //println!("{:?}", DescriptivesSubcommand::from_tokens(subcommand.0));
-                        input = rest;
-                    }
-                    Err(error) => {
-                        println!("{error:?}");
-                        break;
-                    }
+            let input = context.lexer.clone();
+            match <Descriptives>::from_tokens(&input) {
+                Ok(Parsed {
+                    value,
+                    rest: _,
+                    diagnostics,
+                }) => {
+                    println!("\n{value:#?}");
+                    //println!("rest: {rest:?}");
+                    println!("warnings: {diagnostics:?}");
+                    //println!("{:?}", DescriptivesSubcommand::from_tokens(subcommand.0));
+                }
+                Err(error) => {
+                    println!("{error:?}");
                 }
             }
         }),
@@ -40,18 +36,28 @@ pub(super) fn descriptives_command() -> Command {
 
 #[derive(Debug, pspp_derive::FromTokens)]
 struct Descriptives {
-    subcommands: Seq1<Subcommand<DescriptivesSubcommand>>,
+    subcommands: Subcommands<DescriptivesSubcommand>,
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]
 enum DescriptivesSubcommand {
-    #[pspp(default)]
-    Variables(Option<Equals>, Punctuated<DescriptivesVars>),
     Missing(Equals, Seq1<Missing>),
     Save,
     Statistics(Equals, Seq1<Statistic>),
     Sort(Equals, Sort),
     Format(Equals, Seq1<Format>),
+    #[pspp(no_selector)]
+    Variables(
+        Option<(keyword::Variables, Equals)>,
+        Punctuated<DescriptivesVars>,
+    ),
+}
+
+mod keyword {
+    use crate::command::{FromTokens, ParseResult, TokenSlice};
+
+    #[derive(Debug, pspp_derive::FromTokens)]
+    pub struct Variables;
 }
 
 #[derive(Debug, pspp_derive::FromTokens)]