From: Ben Pfaff Date: Sun, 8 Sep 2024 18:24:44 +0000 (-0700) Subject: start to work on parsing structs X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=302dcd9b76119840803cb276bf2b745cf7a1d4de;p=pspp start to work on parsing structs --- diff --git a/rust/pspp-derive/src/lib.rs b/rust/pspp-derive/src/lib.rs index 17ba7e6189..58bcbd2c60 100644 --- a/rust/pspp-derive/src/lib.rs +++ b/rust/pspp-derive/src/lib.rs @@ -1,7 +1,7 @@ use proc_macro::TokenStream; use proc_macro2::{Literal, TokenStream as TokenStream2}; -use quote::quote; -use syn::{spanned::Spanned, Attribute, DeriveInput, Error, Token}; +use quote::{format_ident, quote}; +use syn::{spanned::Spanned, Attribute, DataEnum, DataStruct, DeriveInput, Error, Token}; #[proc_macro_derive(FromTokens, attributes(pspp))] pub fn from_tokens_derive(input: TokenStream) -> TokenStream { @@ -9,20 +9,27 @@ pub fn from_tokens_derive(input: TokenStream) -> TokenStream { // that we can manipulate let ast: DeriveInput = syn::parse(input).unwrap(); - match parse_derive_input(ast) { + match parse_derive_input(ast) { Ok(output) => output.into(), - Err(error) => error.to_compile_error().into() + Err(error) => error.to_compile_error().into(), } } fn parse_derive_input(ast: DeriveInput) -> Result { - let syn::Data::Enum(e) = &ast.data else { - return Err(Error::new(ast.span(), "Only enums may currently be derived")); - }; + match &ast.data { + syn::Data::Enum(e) => derive_enum(&ast, e), + syn::Data::Struct(s) => derive_struct(&ast, s), + syn::Data::Union(_) => Err(Error::new( + ast.span(), + "Only struct and enums may currently be derived", + )), + } +} +fn derive_enum(ast: &DeriveInput, e: &DataEnum) -> Result { let mut body = TokenStream2::new(); for (index, variant) in e.variants.iter().enumerate() { - let field_attrs = parse_attributes(&variant.attrs)?; + let field_attrs = parse_attributes(&variant.attrs)?; if index > 0 { body.extend(quote! { else }.into_iter()); } @@ -38,15 +45,39 @@ fn parse_derive_input(ast: DeriveInput) -> Result { }; } } - body.extend(quote! { else { return Err(tokens.error("Syntax error.")); } }); + body.extend(quote! { else { return Err(cursor.error("Syntax error.")); } }); + + let name = &ast.ident; + let output = quote! { + impl FromTokens for #name { + fn from_tokens<'a>(cursor: &Cursor<'a>) -> Result { + Ok(#body) + } + } + }; + println!("{output}"); + Ok(output) +} + +fn derive_struct(ast: &DeriveInput, s: &DataStruct) -> Result { + let mut construction = TokenStream2::new(); + let mut body = TokenStream2::new(); + for (index, field) in s.fields.iter().enumerate() { + let varname = format_ident!("field{}", index); + let ty = &field.ty; + body.extend(quote! { let #varname = <#ty>::from_tokens(cursor)?; }); + let name = field.ident.as_ref().unwrap(); + if index > 0 { + construction.extend(quote! { , }); + } + construction.extend(quote! { #name: #varname }); + } let name = &ast.ident; let output = quote! { impl FromTokens for #name { - fn from_tokens<'a>(tokens: &TokenSlice<'a>) -> Result { - let cursor = Cursor::new(&tokens); - let value = #body; - Ok(value) + fn from_tokens<'a>(cursor: &Cursor<'a>) -> Result { + #body Ok(#name { #construction }) } } }; diff --git a/rust/pspp/src/command.rs b/rust/pspp/src/command.rs index 8d9cae5fb3..2f43b1e93a 100644 --- a/rust/pspp/src/command.rs +++ b/rust/pspp/src/command.rs @@ -116,11 +116,27 @@ struct Subcommand { }*/ trait FromTokens { - fn from_tokens<'a>(tokens: &TokenSlice<'a>) -> Result + fn from_tokens<'a>(tokens: &Cursor<'a>) -> Result where Self: Sized; } +impl FromTokens for Option +where + T: FromTokens, +{ + fn from_tokens<'a>(tokens: &Cursor<'a>) -> Result + where + Self: Sized, + { + match T::from_tokens(tokens) { + Ok(result) => Ok(Some(result)), + Err(_error) => Ok(None) + } + } +} + +#[derive(FromTokens)] struct Sort { key: SortKey, direction: Option,