} else {
quote! { cursor.match_keyword(#ident_string)}
};
- let construction = construct_fields(&variant.fields);
+ let construction = construct_fields(&variant.fields, true);
let check_equals = if struct_attrs.required_equals && !variant.fields.is_empty() {
- quote! { cursor.force(&Token::Punct(Punct::Equals))?; }
+ quote! { cursor.force(&Token::Punct(Punct::Equals)).map_err(ParseError::Error)?; }
} else {
quote!{}
};
body.extend(quote! { if #match_expr { #check_equals Self::#ident #construction } });
}
- body.extend(quote! { else { return Err(cursor.error("Syntax error.")); } });
+ body.extend(quote! { else { return Err(ParseError::Mismatch(cursor.error("Syntax error."))); } });
let name = &ast.ident;
let lifetime = struct_attrs.lifetime();
let output = quote! {
impl<'a> FromTokens<'a> for #name #lifetime {
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic> {
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self> {
Ok(#body)
}
}
Ok(output)
}
-fn construct_fields(fields: &Fields) -> impl ToTokens {
+fn construct_fields(fields: &Fields, mismatch_to_error: bool) -> impl ToTokens {
let mut construction = TokenStream2::new();
+ let convert = if mismatch_to_error {
+ quote! { .mismatch_to_error() }
+ } else {
+ quote! {}
+ };
for field in fields {
- let value = quote! { FromTokens::from_tokens(cursor)? };
+ let value = quote! { FromTokens::from_tokens(cursor) #convert ? };
if let Some(name) = field.ident.as_ref() {
construction.extend(quote! { #name: #value, });
} else {
fn derive_struct(ast: &DeriveInput, s: &DataStruct) -> Result<TokenStream2, Error> {
let struct_attrs = StructAttrs::parse(&ast.attrs)?;
let name = &ast.ident;
- let construction = construct_fields(&s.fields);
+ let construction = construct_fields(&s.fields, false);
let lifetime = struct_attrs.lifetime();
let output = quote! {
impl<'a> FromTokens<'a> for #name #lifetime {
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic> {
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self> {
Ok(#name #construction)
}
}
name: &str,
}*/
+#[derive(Debug)]
+enum ParseError {
+ Error(Diagnostic),
+ Mismatch(Diagnostic),
+}
+
+type ParseResult<T> = Result<T, ParseError>;
+
+trait MismatchToError {
+ fn mismatch_to_error(self) -> Self;
+}
+
+impl<T> MismatchToError for ParseResult<T> {
+ fn mismatch_to_error(self) -> Self {
+ match self {
+ Err(ParseError::Mismatch(diagnostic)) => Err(ParseError::Error(diagnostic)),
+ rest => rest
+ }
+ }
+}
+
trait FromTokens<'a> {
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized;
}
where
T: FromTokens<'a>,
{
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized,
{
where
T: FromTokens<'a>,
{
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized,
{
}
impl<'a> FromTokens<'a> for TokenSlice<'a> {
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized,
{
where
T: FromTokens<'a>,
{
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized,
{
cursor.advance_until(|token| token != &Token::Punct(Punct::Slash));
if cursor.at_end() {
- return Err(cursor.error("Syntax error at end of input."));
+ return Err(ParseError::Error(
+ cursor.error("Syntax error at end of input."),
+ ));
}
let start = cursor.get_pos();
cursor.advance_until(|token| token == &Token::Punct(Punct::Slash));
}
}
-/*
#[derive(FromTokens, Debug)]
-#[pspp(add_lifetime, required_equals)]*/
-#[derive(Debug)]
+#[pspp(add_lifetime, required_equals)]
enum DescriptivesSubcommand<'a> {
Variables(Vec<DescriptivesVarRange<'a>>),
Missing(Vec<Missing>),
Sort(Sort),
}
+/*
impl<'a> FromTokens<'a> for DescriptivesSubcommand<'a> {
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic> {
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self> {
println!("{}:{}", file!(), line!());
Ok(if cursor.match_keyword("Variables") {
println!("{}:{}", file!(), line!());
return Err(cursor.error("Syntax error."));
})
}
-}
+}*/
#[derive(FromTokens, Debug)]
enum Missing {
where
T: FromTokens<'a>,
{
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized,
{
- cursor.force(&Token::Punct(Punct::LParen))?;
+ cursor
+ .force(&Token::Punct(Punct::LParen))
+ .map_err(ParseError::Mismatch)?;
let inner = T::from_tokens(cursor)?;
- cursor.force(&Token::Punct(Punct::RParen))?;
+ cursor
+ .force(&Token::Punct(Punct::RParen))
+ .map_err(ParseError::Mismatch)?;
Ok(Self(inner))
}
}
}
impl<'a> FromTokens<'a> for VarRange<'a> {
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized,
{
Ok(Self {
- from: cursor.force_id()?,
+ from: cursor.force_id().map_err(ParseError::Mismatch)?,
to: cursor
.match_(&Token::Punct(Punct::To))
- .then(|| cursor.force_id())
+ .then(|| cursor.force_id().map_err(ParseError::Mismatch))
.transpose()?,
})
}
}
impl<'a> FromTokens<'a> for &'a Identifier {
- fn from_tokens(cursor: &Cursor<'a>) -> Result<Self, Diagnostic>
+ fn from_tokens(cursor: &Cursor<'a>) -> ParseResult<Self>
where
Self: Sized,
{
- cursor.force_id()
+ cursor.force_id().map_err(ParseError::Mismatch)
}
}