}
}
};
- //println!("{output}");
+ println!("{output}");
Ok(output)
}
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,
#[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)]
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>,
}
#[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.");
- }
}
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,
#[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)]
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)]
}
#[derive(Debug, pspp_derive::FromTokens)]
-#[pspp(syntax="/")]
+#[pspp(syntax = "/")]
pub struct Slash;
#[derive(Debug)]
}
}
-#[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);
}
}
+#[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>,
diagnostics: Diagnostics(warnings_vec),
})
}
-}
+}*/
impl<'a> FromTokens<'a> for TokenSlice<'a> {
fn from_tokens(input: TokenSlice<'a>) -> ParseResult<'a, Self>