use std::default::default; use crate::{ast::{IDLModule, ItemInterface, TypeArguments, Type}, unwrap_match}; use itertools::Itertools; use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; use syn::{Attribute, ItemExternCrate, ItemTrait, ItemUse, LitStr, Meta, Path, UsePath, Generics, punctuated::Punctuated, TypeArray, LitInt}; fn attr_inner(meta: Meta) -> Attribute { Attribute { pound_token: default(), style: syn::AttrStyle::Inner(default()), bracket_token: default(), meta, } } fn attr_just(name: &'static str) -> Attribute { attr_inner(Meta::Path(Path::from(Ident::new(name, Span::call_site())))) } fn attr_inner_eq(name: &'static str, expr: &str) -> Attribute { attr_inner(Meta::NameValue(syn::MetaNameValue { path: Path::from(Ident::new(name, Span::call_site())), eq_token: default(), value: syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Str(LitStr::new(expr, Span::call_site())), }), })) } fn extern_crate(name: &str) -> ItemExternCrate { ItemExternCrate { attrs: vec![], vis: syn::Visibility::Inherited, extern_token: default(), crate_token: default(), ident: Ident::new(name, Span::call_site()), rename: None, semi_token: default(), } } fn make_use(a: &str, b: &str) -> ItemUse { ItemUse { attrs: vec![], vis: syn::Visibility::Inherited, use_token: default(), tree: syn::UseTree::Path(UsePath { tree: Box::new(syn::UseTree::Name(syn::UseName { ident: Ident::new(b, Span::call_site()), })), ident: Ident::new(a, Span::call_site()), colon2_token: default(), }), semi_token: default(), leading_colon: None, } } fn _gen_type(ty: Type) -> syn::Type { fn make_array(mut args: Vec>) -> TypeArray { let box arity = args.pop().unwrap(); let box real = args.pop().unwrap(); drop(args); TypeArray { bracket_token: default(), elem: Box::new(gen_type(real)), semi_token: default(), len: syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Int(LitInt::new(&arity.name, Span::call_site())) }) } } match ty.name.as_str() { "Array" => syn::Type::Array(make_array(unwrap_match!(ty.arguments, TypeArguments::AngleBracketed(angle) => angle))), name => syn::Type::Path(syn::TypePath { qself: None, path: Path::from(Ident::new(name, Span::call_site())) }) } } // fn gen_iface(interface: ItemInterface) -> ItemTrait { // ItemTrait { // attrs: default(), // vis: syn::Visibility::Public(default()), // unsafety: None, // auto_token: None, // restriction: None, // trait_token: default(), // ident: Ident::new(&interface.name, Span::call_site()), // generics: , // colon_token: (), // supertraits: (), // brace_token: (), // items: (), // } // } pub fn generate(module: IDLModule) -> TokenStream { let name = String::from("aidl_") + &module.name; let attrs: TokenStream = [ attr_inner_eq("crate_name", &name), attr_inner_eq("crate_type", "rlib"), attr_just("no_implicit_prelude"), ] .into_iter() .map(ToTokens::into_token_stream) .collect(); let uses: Vec<_> = module .uses .into_iter() .map(|a| a.path) .map(|(a, b)| (String::from("aidl_") + &a, b)) // aidl_core.Something .collect(); let extern_crates: TokenStream = uses .iter() .map(|(a, _)| a.as_str()) .unique() .map(extern_crate) .map(ToTokens::into_token_stream) .collect(); let use_defs: TokenStream = uses .iter() .filter_map(|(ref a, ref b)| b.as_ref().map(|b| make_use(a.as_str(), b.as_str()))) .map(ToTokens::into_token_stream) .collect(); quote! { #attrs #extern_crates #use_defs } }