mod mark_as_ci_command; mod struct_to_ci_enum; use mark_as_ci_command::generate_final_function; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{format_ident, quote}; use struct_to_ci_enum::{generate_command_enum, generate_generate_ci_function, generate_help_function}; use syn::{self, parse_quote, parse_str, DeriveInput, FieldMutability, ItemFn, Token, Visibility}; #[proc_macro_attribute] pub fn turn_struct_to_ci_command_enum(_attrs: TokenStream, input: TokenStream) -> TokenStream { // Construct a representation of Rust code as a syntax tree // that we can manipulate let mut input: DeriveInput = syn::parse(input).expect("This should always be valid rust code, as it's extracted from direct code"); let mut named_fields = match &input.data { syn::Data::Struct(input) => match &input.fields { syn::Fields::Named(named_fields) => named_fields, _ => unimplemented!("The macro only works for named fields (e.g.: `Name: Type`)"), }, _ => unimplemented!("The macro only works for structs"), } .to_owned(); let attr_parsed = parse_quote! { /// This is a help function }; named_fields.named.push(syn::Field { attrs: vec![attr_parsed], // attrs: attr_parser // .parse("#[doc = r\"This is a help function\"]".to_token_stream().into()) // .expect("See reason for other one"), vis: Visibility::Inherited, mutability: FieldMutability::None, ident: Some(format_ident!("help")), colon_token: Some(Token![:](Span::call_site())), ty: parse_str("fn(Option) -> String").expect("This is static and valid rust code"), }); match &mut input.data { syn::Data::Struct(input) => input.fields = syn::Fields::Named(named_fields.clone()), _ => unreachable!("This was a DataStruct before"), }; // Build the trait implementation let generate_ci_function: TokenStream2 = generate_generate_ci_function(&input); let command_enum = generate_command_enum(&named_fields); let help_function = generate_help_function(&named_fields); quote! { #command_enum #generate_ci_function //#help_function } .into() } #[proc_macro_attribute] pub fn ci_command(_attrs: TokenStream, input: TokenStream) -> TokenStream { let mut input: ItemFn = syn::parse(input).expect("This should always be valid rust code, as it's extracted from direct code"); let output_function = generate_final_function(&mut input); output_function.into() }