Implement quote::ToTokens for AST types

They were already implemented, just without the formalization ;)
This commit is contained in:
Nick Fitzgerald 2018-03-07 14:48:18 -08:00
parent 4c4d8dab26
commit c2e9a4b71e
2 changed files with 503 additions and 484 deletions

View File

@ -10,7 +10,7 @@ pub struct Program {
pub exports: Vec<Export>, pub exports: Vec<Export>,
pub imports: Vec<Import>, pub imports: Vec<Import>,
pub enums: Vec<Enum>, pub enums: Vec<Enum>,
pub imported_types: Vec<(syn::Visibility, syn::Ident)>, pub imported_types: Vec<ImportedType>,
pub structs: Vec<Struct>, pub structs: Vec<Struct>,
} }
@ -53,6 +53,11 @@ pub struct Enum {
pub variants: Vec<(syn::Ident, u32)> pub variants: Vec<(syn::Ident, u32)>
} }
pub struct ImportedType {
pub vis: syn::Visibility,
pub name: syn::Ident,
}
pub enum Type { pub enum Type {
// special // special
Vector(VectorType, bool), Vector(VectorType, bool),
@ -323,7 +328,10 @@ impl Program {
pub fn push_foreign_ty(&mut self, pub fn push_foreign_ty(&mut self,
f: syn::ForeignItemType, f: syn::ForeignItemType,
_module_opts: &BindgenAttrs) { _module_opts: &BindgenAttrs) {
self.imported_types.push((f.vis, f.ident)); self.imported_types.push(ImportedType {
vis: f.vis,
name: f.ident
});
} }
pub fn wbg_literal(&self, dst: &mut Tokens) -> usize { pub fn wbg_literal(&self, dst: &mut Tokens) -> usize {

View File

@ -34,7 +34,7 @@ pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
let mut ret = Tokens::new(); let mut ret = Tokens::new();
let mut program = ast::Program::default(); let mut program = ast::Program::default();
program.push_item(item, Some(opts), &mut ret); program.push_item(item, Some(opts), &mut ret);
generate_wrappers(program, &mut ret); program.to_tokens(&mut ret);
// println!("{}", ret); // println!("{}", ret);
@ -59,22 +59,23 @@ fn to_ident_name(s: &str) -> Cow<str> {
) )
} }
// Generate wrappers for all the items that we've found impl ToTokens for ast::Program {
fn generate_wrappers(program: ast::Program, tokens: &mut Tokens) { // Generate wrappers for all the items that we've found
for export in program.exports.iter() { fn to_tokens(&self, tokens: &mut Tokens) {
bindgen_export(export, tokens); for export in self.exports.iter() {
export.to_tokens(tokens);
} }
for s in program.structs.iter() { for s in self.structs.iter() {
bindgen_struct(s, tokens); s.to_tokens(tokens);
} }
for i in program.imports.iter() { for i in self.imports.iter() {
bindgen_import(i, tokens); i.to_tokens(tokens);
} }
for e in program.enums.iter() { for e in self.enums.iter() {
bindgen_enum(e, tokens); e.to_tokens(tokens);
} }
for &(ref vis, ref t) in program.imported_types.iter() { for it in self.imported_types.iter() {
bindgen_imported_type(vis, t, tokens); it.to_tokens(tokens);
} }
// Generate a static which will eventually be what lives in a custom section // Generate a static which will eventually be what lives in a custom section
@ -95,7 +96,7 @@ fn generate_wrappers(program: ast::Program, tokens: &mut Tokens) {
let generated_static_name = syn::Ident::from(generated_static_name); let generated_static_name = syn::Ident::from(generated_static_name);
let mut generated_static_value = Tokens::new(); let mut generated_static_value = Tokens::new();
let generated_static_length = program.wbg_literal(&mut generated_static_value); let generated_static_length = self.wbg_literal(&mut generated_static_value);
(my_quote! { (my_quote! {
#[no_mangle] #[no_mangle]
@ -103,11 +104,13 @@ fn generate_wrappers(program: ast::Program, tokens: &mut Tokens) {
pub static #generated_static_name: [u32; #generated_static_length] = pub static #generated_static_name: [u32; #generated_static_length] =
[#generated_static_value]; [#generated_static_value];
}).to_tokens(tokens); }).to_tokens(tokens);
}
} }
fn bindgen_struct(s: &ast::Struct, into: &mut Tokens) { impl ToTokens for ast::Struct {
let name = &s.name; fn to_tokens(&self, tokens: &mut Tokens) {
let free_fn = syn::Ident::from(shared::free_function(s.name.as_ref())); let name = &self.name;
let free_fn = syn::Ident::from(shared::free_function(self.name.as_ref()));
let c = shared::name_to_descriptor(name.as_ref()) as u32; let c = shared::name_to_descriptor(name.as_ref()) as u32;
(my_quote! { (my_quote! {
impl ::wasm_bindgen::convert::WasmBoundary for #name { impl ::wasm_bindgen::convert::WasmBoundary for #name {
@ -150,20 +153,22 @@ fn bindgen_struct(s: &ast::Struct, into: &mut Tokens) {
pub unsafe extern fn #free_fn(ptr: u32) { pub unsafe extern fn #free_fn(ptr: u32) {
<#name as ::wasm_bindgen::convert::WasmBoundary>::from_js(ptr); <#name as ::wasm_bindgen::convert::WasmBoundary>::from_js(ptr);
} }
}).to_tokens(into); }).to_tokens(tokens);
}
} }
fn bindgen_export(export: &ast::Export, into: &mut Tokens) { impl ToTokens for ast::Export {
let generated_name = export.rust_symbol(); fn to_tokens(self: &ast::Export, into: &mut Tokens) {
let export_name = export.export_name(); let generated_name = self.rust_symbol();
let export_name = self.export_name();
let mut args = vec![]; let mut args = vec![];
let mut arg_conversions = vec![]; let mut arg_conversions = vec![];
let mut converted_arguments = vec![]; let mut converted_arguments = vec![];
let ret = syn::Ident::from("_ret"); let ret = syn::Ident::from("_ret");
let mut offset = 0; let mut offset = 0;
if export.method { if self.method {
let class = export.class.unwrap(); let class = self.class.unwrap();
args.push(my_quote! { me: *mut ::wasm_bindgen::__rt::WasmRefCell<#class> }); args.push(my_quote! { me: *mut ::wasm_bindgen::__rt::WasmRefCell<#class> });
arg_conversions.push(my_quote! { arg_conversions.push(my_quote! {
::wasm_bindgen::__rt::assert_not_null(me); ::wasm_bindgen::__rt::assert_not_null(me);
@ -172,7 +177,7 @@ fn bindgen_export(export: &ast::Export, into: &mut Tokens) {
offset = 1; offset = 1;
} }
for (i, ty) in export.function.arguments.iter().enumerate() { for (i, ty) in self.function.arguments.iter().enumerate() {
let i = i + offset; let i = i + offset;
let ident = syn::Ident::from(format!("arg{}", i)); let ident = syn::Ident::from(format!("arg{}", i));
match *ty { match *ty {
@ -251,7 +256,7 @@ fn bindgen_export(export: &ast::Export, into: &mut Tokens) {
} }
let ret_ty; let ret_ty;
let convert_ret; let convert_ret;
match export.function.ret { match self.function.ret {
Some(ast::Type::Vector(ref ty, true)) => { Some(ast::Type::Vector(ref ty, true)) => {
ret_ty = my_quote! { -> *mut #ty }; ret_ty = my_quote! { -> *mut #ty };
convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) }; convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) };
@ -275,10 +280,10 @@ fn bindgen_export(export: &ast::Export, into: &mut Tokens) {
} }
} }
let name = export.function.name; let name = self.function.name;
let receiver = match export.class { let receiver = match self.class {
Some(_) if export.method => { Some(_) if self.method => {
if export.mutable { if self.mutable {
my_quote! { me.borrow_mut().#name } my_quote! { me.borrow_mut().#name }
} else { } else {
my_quote! { me.borrow().#name } my_quote! { me.borrow().#name }
@ -299,11 +304,13 @@ fn bindgen_export(export: &ast::Export, into: &mut Tokens) {
} }
}; };
tokens.to_tokens(into); tokens.to_tokens(into);
}
} }
fn bindgen_imported_type(vis: &syn::Visibility, impl ToTokens for ast::ImportedType {
name: &syn::Ident, fn to_tokens(&self, tokens: &mut Tokens) {
tokens: &mut Tokens) { let vis = &self.vis;
let name = &self.name;
(my_quote! { (my_quote! {
#vis struct #name { #vis struct #name {
obj: ::wasm_bindgen::JsValue, obj: ::wasm_bindgen::JsValue,
@ -330,14 +337,15 @@ fn bindgen_imported_type(vis: &syn::Visibility,
} }
} }
}).to_tokens(tokens); }).to_tokens(tokens);
}
} }
impl ToTokens for ast::Import {
fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut Tokens) {
let mut class_ty = None; let mut class_ty = None;
let mut is_method = false; let mut is_method = false;
let mut class_name = None; let mut class_name = None;
match import.kind { match self.kind {
ast::ImportKind::Method { ref ty, ref class } => { ast::ImportKind::Method { ref ty, ref class } => {
is_method = true; is_method = true;
class_ty = Some(ty); class_ty = Some(ty);
@ -352,18 +360,18 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
} }
let import_name = shared::mangled_import_name( let import_name = shared::mangled_import_name(
class_name.map(|s| &**s), class_name.map(|s| &**s),
import.function.name.as_ref(), self.function.name.as_ref(),
); );
let vis = &import.function.rust_vis; let vis = &self.function.rust_vis;
let ret = &import.function.rust_decl.output; let ret = &self.function.rust_decl.output;
let fn_token = &import.function.rust_decl.fn_token; let fn_token = &self.function.rust_decl.fn_token;
let mut abi_argument_names = Vec::new(); let mut abi_argument_names = Vec::new();
let mut abi_arguments = Vec::new(); let mut abi_arguments = Vec::new();
let mut arg_conversions = Vec::new(); let mut arg_conversions = Vec::new();
let ret_ident = syn::Ident::from("_ret"); let ret_ident = syn::Ident::from("_ret");
let names = import.function.rust_decl.inputs let names = self.function.rust_decl.inputs
.iter() .iter()
.map(|arg| { .map(|arg| {
match *arg { match *arg {
@ -385,7 +393,7 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
} }
}); });
for (i, (ty, name)) in import.function.arguments.iter().zip(names).enumerate() { for (i, (ty, name)) in self.function.arguments.iter().zip(names).enumerate() {
match *ty { match *ty {
ast::Type::Vector(ref ty, owned) => { ast::Type::Vector(ref ty, owned) => {
let ptr = syn::Ident::from(format!("{}_ptr", name)); let ptr = syn::Ident::from(format!("{}_ptr", name));
@ -440,7 +448,7 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
} }
let abi_ret; let abi_ret;
let mut convert_ret; let mut convert_ret;
match import.function.ret { match self.function.ret {
Some(ast::Type::ByValue(ref t)) => { Some(ast::Type::ByValue(ref t)) => {
abi_ret = my_quote! { abi_ret = my_quote! {
<#t as ::wasm_bindgen::convert::WasmBoundary>::Js <#t as ::wasm_bindgen::convert::WasmBoundary>::Js
@ -483,7 +491,7 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
} }
let mut exceptional_ret = my_quote! {}; let mut exceptional_ret = my_quote! {};
if import.function.opts.catch() { if self.function.opts.catch() {
let exn_data = syn::Ident::from("exn_data"); let exn_data = syn::Ident::from("exn_data");
let exn_data_ptr = syn::Ident::from("exn_data_ptr"); let exn_data_ptr = syn::Ident::from("exn_data_ptr");
abi_argument_names.push(exn_data_ptr); abi_argument_names.push(exn_data_ptr);
@ -501,11 +509,11 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
}; };
} }
let name = import.function.name; let name = self.function.name;
let import_name = syn::Ident::from(import_name); let import_name = syn::Ident::from(import_name);
let attrs = &import.function.rust_attrs; let attrs = &self.function.rust_attrs;
let arguments = import.function.rust_decl.inputs let arguments = self.function.rust_decl.inputs
.iter() .iter()
.skip(if is_method { 1 } else { 0 }) .skip(if is_method { 1 } else { 0 })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -541,14 +549,16 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
} else { } else {
invocation.to_tokens(tokens); invocation.to_tokens(tokens);
} }
}
} }
fn bindgen_enum(e: &ast::Enum, into: &mut Tokens) { impl ToTokens for ast::Enum {
let enum_name = &e.name; fn to_tokens(&self, into: &mut Tokens) {
let enum_name = &self.name;
let c = shared::TYPE_ENUM as u32; let c = shared::TYPE_ENUM as u32;
let incoming_u32 = quote! { n }; let incoming_u32 = quote! { n };
let enum_name_as_string = enum_name.to_string(); let enum_name_as_string = enum_name.to_string();
let cast_clauses = e.variants.iter().map(|variant| { let cast_clauses = self.variants.iter().map(|variant| {
let &(variant_name, _) = variant; let &(variant_name, _) = variant;
quote! { quote! {
if #incoming_u32 == #enum_name::#variant_name as u32 { if #incoming_u32 == #enum_name::#variant_name as u32 {
@ -578,4 +588,5 @@ fn bindgen_enum(e: &ast::Enum, into: &mut Tokens) {
} }
} }
}).to_tokens(into); }).to_tokens(into);
}
} }