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 {
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 {
#[derive(Default)]
struct FieldAttrs {
syntax: Option<Literal>,
- default: bool,
+ selector: Option<bool>,
}
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"));
}
#[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),
HideSmallCounts(keyword::Count, Equals, Integer),
SLabels(Seq1<SLabel>),
CLabels(CLabel),
- Categories(Seq1<Category>),
+ Categories(Seq1<Categories>),
}
#[derive(Debug, pspp_derive::FromTokens)]
}
#[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)]
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 {
#[derive(Debug, pspp_derive::FromTokens)]
enum Delimiter {
- #[pspp(default)] // XXX this allows `STRING "string"`
+ #[pspp(no_selector)]
String(String),
Tab,
}
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,
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:?}");
}
}
}),
#[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)]