#![allow(warnings)]
use proc_macro::TokenStream;
use quote::quote;
use std::fmt::format;
use syn::{
parse::{Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
spanned::Spanned,
AngleBracketedGenericArguments, DataEnum, DataStruct, DeriveInput, GenericArgument, Ident,
PathArguments, Token, Type, TypePath,
};
#[proc_macro_derive(RTS)]
pub fn derive_rts(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let struct_id = &ast.ident;
let struct_name = struct_id.to_string();
let vis = match ast.vis {
syn::Visibility::Public(_) => "export ",
syn::Visibility::Restricted(_) => "",
syn::Visibility::Inherited => "",
};
if let syn::Data::Struct(DataStruct {
fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
..
}) = ast.data
{
let field_id: Vec<_> = named.iter().map(|v| &v.ident).collect();
let field_ty: Vec<_> = named.iter().map(|v| &v.ty).collect();
let builder_fields = {
quote!(
#(#field_id: ::std::option::Option<#field_ty>)*
)
};
let builder_fields_none: Vec<_> = named
.iter()
.map(|v| {
let id = &v.ident;
quote!(
#id: ::std::option::Option::None,
)
})
.collect();
let setter = {
let mut ts = proc_macro2::TokenStream::new();
for (id, ty) in field_id.iter().zip(field_ty.iter()) {
let s = quote!(
fn #id(&mut self, #id: #ty) -> &mut Self {
self.#id = ::std::option::Option::Some(#id);
self
}
);
ts.extend(s);
}
ts
};
let field_set = {
quote!(
#(s+= (" ".to_string() + stringify!(#field_id) + ": " + self.#field_id.to_type_name().as_str() + ";\n").as_str(););*
)
};
return quote!(
impl RTS for #struct_id{
fn to_type_string(&self) -> String {
let mut s = #vis.into();
s+= "type ".into();
s += stringify!(#struct_id);
s += " = {\n";
#field_set;
s += "}\n";
s
}
fn to_type_name(&self)->String{
stringify!(#struct_id).into()
}
}
)
.into();
} else {
if let syn::Data::Enum(DataEnum {
variants,
..
}) = ast.data
{
let vars: Vec<_> = variants.iter().map(|v| &v.ident).collect();
let vars_id: Vec<_> = (0..vars.len()).map(|i| i.to_string()).collect();
let field_set = {
quote!(
#(s+= (" ".to_string() + stringify!(#vars) + " = "+ #vars_id+ ",\n").as_str(););*
)
};
return quote!(
impl RTS for #struct_id{
fn to_type_string(&self) -> String {
let mut s = #vis.into();
s += "declare enum ".into();
s += stringify!(#struct_id);
s += " {\n";
#field_set;
s += "}\n";
s
}
fn to_type_name(&self)->String{
stringify!(#struct_id).into()
}
}
)
.into();
} else {
}
}
"".parse().unwrap()
}
#[derive(Debug)]
struct Args {
vars: Vec<Ident>,
}
impl Parse for Args {
fn parse(input: ParseStream) -> syn::parse::Result<Self> {
let vars = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
Ok(Args {
vars: vars.into_iter().collect(),
})
}
}
#[proc_macro]
pub fn rts_to_string(input: TokenStream) -> TokenStream {
let args: Args = syn::parse_macro_input!(input as Args);
let s: Vec<_> = args
.vars
.iter()
.map(|i| {
let id = i.to_string();
let stmt = if id.chars().next().unwrap().is_uppercase() {
quote!(
v.push(#i::default().to_type_string());
)
} else {
quote!(
v.push(#i.to_type_string());
)
};
stmt
})
.collect();
quote!({
let mut v: Vec<String> = Vec::new();
#(#s)*;
v.join("\n")
})
.into()
}