diff --git a/crates/generate/src/funcs.rs b/crates/generate/src/funcs.rs new file mode 100644 index 0000000000..6a6430cb80 --- /dev/null +++ b/crates/generate/src/funcs.rs @@ -0,0 +1,23 @@ +use proc_macro2::TokenStream; +use quote::quote; + +use crate::names::Names; + +pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { + let ident = names.func(&func.name); + let mut args = TokenStream::new(); + + for param in func.params.iter() { + let name = names.func_param(¶m.name); + let type_ = names.type_ref(¶m.tref); + args.extend(quote!(#name: #type_,)); + } + + let mut rets = TokenStream::new(); + for result in func.results.iter() { + let type_ = names.type_ref(&result.tref); + rets.extend(quote!(#type_,)); + } + + quote!(pub fn #ident(#args) -> (#rets) { unimplemented!() }) +} diff --git a/crates/generate/src/lib.rs b/crates/generate/src/lib.rs index f78a484153..7f9deb9687 100644 --- a/crates/generate/src/lib.rs +++ b/crates/generate/src/lib.rs @@ -1,33 +1,40 @@ extern crate proc_macro; +mod funcs; +mod names; mod parse; mod types; -use heck::SnakeCase; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; -use quote::{format_ident, quote}; +use quote::quote; + +use funcs::define_func; +use names::Names; use types::define_datatype; #[proc_macro] pub fn from_witx(args: TokenStream) -> TokenStream { let args = TokenStream2::from(args); let witx_paths = parse::witx_paths(args).expect("parsing macro arguments"); + + let names = Names::new(); // TODO parse the names from the invocation of the macro, or from a file? + let doc = witx::load(&witx_paths).expect("loading witx"); let mut types = TokenStream2::new(); for namedtype in doc.typenames() { - let def = define_datatype(&namedtype); + let def = define_datatype(&names, &namedtype); types.extend(def); } let mut modules = TokenStream2::new(); for module in doc.modules() { - let modname = format_ident!("{}", module.name.as_str().to_snake_case()); + let modname = names.module(&module.name); + let mut fs = TokenStream2::new(); for func in module.funcs() { - let ident = format_ident!("{}", func.name.as_str().to_snake_case()); - fs.extend(quote!(pub fn #ident() { unimplemented!() })); + fs.extend(define_func(&names, &func)); } modules.extend(quote!(mod #modname { use super::types::*; #fs })); } diff --git a/crates/generate/src/names.rs b/crates/generate/src/names.rs new file mode 100644 index 0000000000..a1ca1a0407 --- /dev/null +++ b/crates/generate/src/names.rs @@ -0,0 +1,68 @@ +use heck::{CamelCase, SnakeCase}; +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote}; +use witx::{BuiltinType, Id, TypeRef}; + +#[derive(Debug, Clone)] +pub struct Names { + // FIXME: overrides go in here, so we can map e.g. 2big => TooBig +} + +impl Names { + pub fn new() -> Names { + Names {} + } + pub fn type_(&self, id: &Id) -> Ident { + format_ident!("{}", id.as_str().to_camel_case()) + } + pub fn builtin_type(&self, b: BuiltinType) -> TokenStream { + match b { + BuiltinType::String => quote!(String), + BuiltinType::U8 => quote!(u8), + BuiltinType::U16 => quote!(u16), + BuiltinType::U32 => quote!(u32), + BuiltinType::U64 => quote!(u64), + BuiltinType::S8 => quote!(i8), + BuiltinType::S16 => quote!(i16), + BuiltinType::S32 => quote!(i32), + BuiltinType::S64 => quote!(i64), + BuiltinType::F32 => quote!(f32), + BuiltinType::F64 => quote!(f64), + BuiltinType::Char8 => quote!(char), + BuiltinType::USize => quote!(usize), + } + } + pub fn type_ref(&self, tref: &TypeRef) -> TokenStream { + match tref { + TypeRef::Name(nt) => { + let ident = self.type_(&nt.name); + quote!(#ident) + } + TypeRef::Value(ty) => match &**ty { + witx::Type::Builtin(builtin) => self.builtin_type(*builtin), + _ => unimplemented!("anonymous type ref"), + }, + } + } + + pub fn enum_variant(&self, id: &Id) -> Ident { + // FIXME this is a hack - just a proof of concept. + if id.as_str().starts_with('2') { + format_ident!("TooBig") + } else { + format_ident!("{}", id.as_str().to_camel_case()) + } + } + + pub fn module(&self, id: &Id) -> Ident { + format_ident!("{}", id.as_str().to_snake_case()) + } + + pub fn func(&self, id: &Id) -> Ident { + format_ident!("{}", id.as_str().to_snake_case()) + } + + pub fn func_param(&self, id: &Id) -> Ident { + format_ident!("{}", id.as_str().to_snake_case()) + } +} diff --git a/crates/generate/src/types.rs b/crates/generate/src/types.rs index f9c98b9234..22cc025c9b 100644 --- a/crates/generate/src/types.rs +++ b/crates/generate/src/types.rs @@ -1,18 +1,19 @@ -use heck::{CamelCase, MixedCase}; -use proc_macro2::TokenStream; -use quote::{format_ident, quote}; +use crate::names::Names; -pub fn define_datatype(namedtype: &witx::NamedType) -> TokenStream { +use proc_macro2::TokenStream; +use quote::quote; + +pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStream { match &namedtype.tref { - witx::TypeRef::Name(alias_to) => define_alias(&namedtype.name, &alias_to), + witx::TypeRef::Name(alias_to) => define_alias(names, &namedtype.name, &alias_to), witx::TypeRef::Value(v) => match &**v { - witx::Type::Enum(e) => define_enum(&namedtype.name, &e), + witx::Type::Enum(e) => define_enum(names, &namedtype.name, &e), witx::Type::Int(_) => unimplemented!("int types"), witx::Type::Flags(_) => unimplemented!("flag types"), witx::Type::Struct(_) => unimplemented!("struct types"), witx::Type::Union(_) => unimplemented!("union types"), witx::Type::Handle(_h) => unimplemented!("handle types"), - witx::Type::Builtin(b) => define_builtin(&namedtype.name, &b), + witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b), witx::Type::Pointer { .. } => unimplemented!("pointer types"), witx::Type::ConstPointer { .. } => unimplemented!("constpointer types"), witx::Type::Array { .. } => unimplemented!("array types"), @@ -20,15 +21,16 @@ pub fn define_datatype(namedtype: &witx::NamedType) -> TokenStream { } } -fn define_alias(name: &witx::Id, to: &witx::NamedType) -> TokenStream { - let ident = format_ident!("{}", name.as_str().to_camel_case()); - let to = format_ident!("{}", to.name.as_str().to_camel_case()); +fn define_alias(names: &Names, name: &witx::Id, to: &witx::NamedType) -> TokenStream { + let ident = names.type_(name); + let to = names.type_(&to.name); quote!(pub type #ident = #to;) } -fn define_enum(name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream { - let ident = format_ident!("{}", name.as_str().to_camel_case()); +fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream { + let ident = names.type_(&name); + let mut output = TokenStream::new(); let repr = int_repr_tokens(e.repr); output.extend(quote!(#[repr(#repr)])); @@ -36,13 +38,8 @@ fn define_enum(name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream { let mut inner = TokenStream::new(); for variant in &e.variants { - let value_name = if name.as_str() == "errno" { - // FIXME discussion point! - format_ident!("E{}", variant.name.as_str().to_mixed_case()) - } else { - format_ident!("{}", variant.name.as_str().to_camel_case()) - }; - inner.extend(quote!(#value_name,)); + let variant_name = names.enum_variant(&variant.name); + inner.extend(quote!(#variant_name,)); } output.extend(quote!(pub enum #ident { @@ -52,24 +49,10 @@ fn define_enum(name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream { output } -fn define_builtin(name: &witx::Id, builtin: &witx::BuiltinType) -> TokenStream { - let ident = format_ident!("{}", name.as_str().to_camel_case()); - let prim = match builtin { - witx::BuiltinType::String => quote!(String), - witx::BuiltinType::U8 => quote!(u8), - witx::BuiltinType::U16 => quote!(u16), - witx::BuiltinType::U32 => quote!(u32), - witx::BuiltinType::U64 => quote!(u64), - witx::BuiltinType::S8 => quote!(i8), - witx::BuiltinType::S16 => quote!(i16), - witx::BuiltinType::S32 => quote!(i32), - witx::BuiltinType::S64 => quote!(i64), - witx::BuiltinType::F32 => quote!(f32), - witx::BuiltinType::F64 => quote!(f64), - witx::BuiltinType::Char8 => quote!(char), - witx::BuiltinType::USize => quote!(usize), - }; - quote!(pub type #ident = #prim;) +fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> TokenStream { + let ident = names.type_(name); + let built = names.builtin_type(builtin); + quote!(pub type #ident = #built;) } fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { diff --git a/test.witx b/test.witx index 414b9617cd..1750ec3d15 100644 --- a/test.witx +++ b/test.witx @@ -8,7 +8,7 @@ (module $foo (@interface func (export "bar") - (param $an_int (@witx pointer u32)) - (param $an_float (@witx pointer f32)) + (param $an_int u32) + (param $an_float f32) (result $error $errno)) )