ableos_userland/programs/aidl/src/codegen.rs

131 lines
4.0 KiB
Rust

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<Box<Type>>) -> 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
}
}