From: Ben Pfaff Date: Sun, 15 Sep 2024 01:20:10 +0000 (-0700) Subject: Introduce Mismatch versus Error distinction. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6130724e250bd4baa9d01e46ca4ccca5ad961548;p=pspp Introduce Mismatch versus Error distinction. --- diff --git a/rust/pspp-derive/src/lib.rs b/rust/pspp-derive/src/lib.rs index 6fd7a8678d..da1a879a14 100644 --- a/rust/pspp-derive/src/lib.rs +++ b/rust/pspp-derive/src/lib.rs @@ -43,21 +43,21 @@ fn derive_enum(ast: &DeriveInput, e: &DataEnum) -> Result { } 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 { + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult { Ok(#body) } } @@ -66,10 +66,15 @@ fn derive_enum(ast: &DeriveInput, e: &DataEnum) -> Result { 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 { @@ -87,11 +92,11 @@ fn construct_fields(fields: &Fields) -> impl ToTokens { fn derive_struct(ast: &DeriveInput, s: &DataStruct) -> Result { 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 { + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult { Ok(#name #construction) } } diff --git a/rust/pspp/src/command.rs b/rust/pspp/src/command.rs index 6a20e85473..fd79e62b0e 100644 --- a/rust/pspp/src/command.rs +++ b/rust/pspp/src/command.rs @@ -106,8 +106,29 @@ struct Subcommand { name: &str, }*/ +#[derive(Debug)] +enum ParseError { + Error(Diagnostic), + Mismatch(Diagnostic), +} + +type ParseResult = Result; + +trait MismatchToError { + fn mismatch_to_error(self) -> Self; +} + +impl MismatchToError for ParseResult { + 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 + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult where Self: Sized; } @@ -116,7 +137,7 @@ impl<'a, T> FromTokens<'a> for Option where T: FromTokens<'a>, { - fn from_tokens(cursor: &Cursor<'a>) -> Result + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult where Self: Sized, { @@ -135,7 +156,7 @@ impl<'a, T> FromTokens<'a> for Vec where T: FromTokens<'a>, { - fn from_tokens(cursor: &Cursor<'a>) -> Result + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult where Self: Sized, { @@ -148,7 +169,7 @@ where } impl<'a> FromTokens<'a> for TokenSlice<'a> { - fn from_tokens(cursor: &Cursor<'a>) -> Result + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult where Self: Sized, { @@ -183,13 +204,15 @@ impl<'a, T> FromTokens<'a> for Subcommand where T: FromTokens<'a>, { - fn from_tokens(cursor: &Cursor<'a>) -> Result + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult 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)); @@ -204,10 +227,8 @@ where } } -/* #[derive(FromTokens, Debug)] -#[pspp(add_lifetime, required_equals)]*/ -#[derive(Debug)] +#[pspp(add_lifetime, required_equals)] enum DescriptivesSubcommand<'a> { Variables(Vec>), Missing(Vec), @@ -216,8 +237,9 @@ enum DescriptivesSubcommand<'a> { Sort(Sort), } +/* impl<'a> FromTokens<'a> for DescriptivesSubcommand<'a> { - fn from_tokens(cursor: &Cursor<'a>) -> Result { + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult { println!("{}:{}", file!(), line!()); Ok(if cursor.match_keyword("Variables") { println!("{}:{}", file!(), line!()); @@ -239,7 +261,7 @@ impl<'a> FromTokens<'a> for DescriptivesSubcommand<'a> { return Err(cursor.error("Syntax error.")); }) } -} +}*/ #[derive(FromTokens, Debug)] enum Missing { @@ -262,13 +284,17 @@ impl<'a, T> FromTokens<'a> for InParens where T: FromTokens<'a>, { - fn from_tokens(cursor: &Cursor<'a>) -> Result + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult 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)) } } @@ -280,26 +306,26 @@ struct VarRange<'a> { } impl<'a> FromTokens<'a> for VarRange<'a> { - fn from_tokens(cursor: &Cursor<'a>) -> Result + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult 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 + fn from_tokens(cursor: &Cursor<'a>) -> ParseResult where Self: Sized, { - cursor.force_id() + cursor.force_id().map_err(ParseError::Mismatch) } }