put names all in one place. some stub code for funcs!

This commit is contained in:
Pat Hickey
2020-01-19 19:33:41 -08:00
parent cd686915aa
commit 9291495e57
5 changed files with 126 additions and 45 deletions

View File

@@ -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(&param.name);
let type_ = names.type_ref(&param.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!() })
}

View File

@@ -1,33 +1,40 @@
extern crate proc_macro; extern crate proc_macro;
mod funcs;
mod names;
mod parse; mod parse;
mod types; mod types;
use heck::SnakeCase;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2; 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; use types::define_datatype;
#[proc_macro] #[proc_macro]
pub fn from_witx(args: TokenStream) -> TokenStream { pub fn from_witx(args: TokenStream) -> TokenStream {
let args = TokenStream2::from(args); let args = TokenStream2::from(args);
let witx_paths = parse::witx_paths(args).expect("parsing macro arguments"); 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 doc = witx::load(&witx_paths).expect("loading witx");
let mut types = TokenStream2::new(); let mut types = TokenStream2::new();
for namedtype in doc.typenames() { for namedtype in doc.typenames() {
let def = define_datatype(&namedtype); let def = define_datatype(&names, &namedtype);
types.extend(def); types.extend(def);
} }
let mut modules = TokenStream2::new(); let mut modules = TokenStream2::new();
for module in doc.modules() { 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(); let mut fs = TokenStream2::new();
for func in module.funcs() { for func in module.funcs() {
let ident = format_ident!("{}", func.name.as_str().to_snake_case()); fs.extend(define_func(&names, &func));
fs.extend(quote!(pub fn #ident() { unimplemented!() }));
} }
modules.extend(quote!(mod #modname { use super::types::*; #fs })); modules.extend(quote!(mod #modname { use super::types::*; #fs }));
} }

View File

@@ -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())
}
}

View File

@@ -1,18 +1,19 @@
use heck::{CamelCase, MixedCase}; use crate::names::Names;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
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 { 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::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::Int(_) => unimplemented!("int types"),
witx::Type::Flags(_) => unimplemented!("flag types"), witx::Type::Flags(_) => unimplemented!("flag types"),
witx::Type::Struct(_) => unimplemented!("struct types"), witx::Type::Struct(_) => unimplemented!("struct types"),
witx::Type::Union(_) => unimplemented!("union types"), witx::Type::Union(_) => unimplemented!("union types"),
witx::Type::Handle(_h) => unimplemented!("handle 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::Pointer { .. } => unimplemented!("pointer types"),
witx::Type::ConstPointer { .. } => unimplemented!("constpointer types"), witx::Type::ConstPointer { .. } => unimplemented!("constpointer types"),
witx::Type::Array { .. } => unimplemented!("array 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 { fn define_alias(names: &Names, name: &witx::Id, to: &witx::NamedType) -> TokenStream {
let ident = format_ident!("{}", name.as_str().to_camel_case()); let ident = names.type_(name);
let to = format_ident!("{}", to.name.as_str().to_camel_case()); let to = names.type_(&to.name);
quote!(pub type #ident = #to;) quote!(pub type #ident = #to;)
} }
fn define_enum(name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream { fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream {
let ident = format_ident!("{}", name.as_str().to_camel_case()); let ident = names.type_(&name);
let mut output = TokenStream::new(); let mut output = TokenStream::new();
let repr = int_repr_tokens(e.repr); let repr = int_repr_tokens(e.repr);
output.extend(quote!(#[repr(#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(); let mut inner = TokenStream::new();
for variant in &e.variants { for variant in &e.variants {
let value_name = if name.as_str() == "errno" { let variant_name = names.enum_variant(&variant.name);
// FIXME discussion point! inner.extend(quote!(#variant_name,));
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,));
} }
output.extend(quote!(pub enum #ident { output.extend(quote!(pub enum #ident {
@@ -52,24 +49,10 @@ fn define_enum(name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream {
output output
} }
fn define_builtin(name: &witx::Id, builtin: &witx::BuiltinType) -> TokenStream { fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> TokenStream {
let ident = format_ident!("{}", name.as_str().to_camel_case()); let ident = names.type_(name);
let prim = match builtin { let built = names.builtin_type(builtin);
witx::BuiltinType::String => quote!(String), quote!(pub type #ident = #built;)
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 int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream {

View File

@@ -8,7 +8,7 @@
(module $foo (module $foo
(@interface func (export "bar") (@interface func (export "bar")
(param $an_int (@witx pointer u32)) (param $an_int u32)
(param $an_float (@witx pointer f32)) (param $an_float f32)
(result $error $errno)) (result $error $errno))
) )