mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-13 04:51:23 +00:00
Classes are now working!
This commit is contained in:
@ -24,7 +24,6 @@ pub enum Type {
|
||||
|
||||
pub struct Struct {
|
||||
pub name: syn::Ident,
|
||||
pub ctor: Option<Function>,
|
||||
pub methods: Vec<Method>,
|
||||
pub functions: Vec<Function>,
|
||||
}
|
||||
@ -118,16 +117,30 @@ impl Function {
|
||||
Function { name: input.ident, arguments, ret }
|
||||
}
|
||||
|
||||
pub fn export_name(&self) -> syn::Lit {
|
||||
pub fn free_function_export_name(&self) -> syn::Lit {
|
||||
let name = self.shared().free_function_export_name();
|
||||
syn::Lit {
|
||||
value: syn::LitKind::Other(Literal::string(self.name.sym.as_str())),
|
||||
value: syn::LitKind::Other(Literal::string(&name)),
|
||||
span: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rust_symbol(&self) -> syn::Ident {
|
||||
let generated_name = format!("__wasm_bindgen_generated_{}",
|
||||
self.name.sym.as_str());
|
||||
pub fn struct_function_export_name(&self, s: syn::Ident) -> syn::Lit {
|
||||
let name = self.shared().struct_function_export_name(s.sym.as_str());
|
||||
syn::Lit {
|
||||
value: syn::LitKind::Other(Literal::string(&name)),
|
||||
span: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rust_symbol(&self, namespace: Option<syn::Ident>) -> syn::Ident {
|
||||
let mut generated_name = format!("__wasm_bindgen_generated");
|
||||
if let Some(ns) = namespace {
|
||||
generated_name.push_str("_");
|
||||
generated_name.push_str(ns.sym.as_str());
|
||||
}
|
||||
generated_name.push_str("_");
|
||||
generated_name.push_str(self.name.sym.as_str());
|
||||
syn::Ident::from(generated_name)
|
||||
}
|
||||
|
||||
@ -220,12 +233,15 @@ impl Struct {
|
||||
pub fn from(s: &syn::ItemStruct) -> Struct {
|
||||
Struct {
|
||||
name: s.ident,
|
||||
ctor: None,
|
||||
methods: Vec::new(),
|
||||
functions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn free_function(&self) -> syn::Ident {
|
||||
syn::Ident::from(self.shared().free_function())
|
||||
}
|
||||
|
||||
pub fn push_item(&mut self, item: &syn::ImplItem) {
|
||||
let method = match *item {
|
||||
syn::ImplItem::Const(_) => panic!("const definitions aren't supported"),
|
||||
@ -299,7 +315,6 @@ impl Struct {
|
||||
pub fn shared(&self) -> shared::Struct {
|
||||
shared::Struct {
|
||||
name: self.name.to_string(),
|
||||
ctor: self.ctor.as_ref().unwrap().shared(),
|
||||
functions: self.functions.iter().map(|f| f.shared()).collect(),
|
||||
methods: self.methods.iter().map(|f| f.shared()).collect(),
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
||||
static CNT: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
let generated_static_name = format!("__WASM_BINDGEN_GENERATED{}",
|
||||
CNT.fetch_add(1, Ordering::SeqCst));
|
||||
let generated_static_name = syn::Ident::from(generated_static_name);
|
||||
let mut generated_static = String::from("wbg:");
|
||||
generated_static.push_str(&serde_json::to_string(&program.shared()).unwrap());
|
||||
let generated_static_value = syn::Lit {
|
||||
@ -75,22 +76,89 @@ pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
||||
*#generated_static_value;
|
||||
}).to_tokens(&mut ret);
|
||||
|
||||
// println!("{}", ret);
|
||||
|
||||
ret.into()
|
||||
}
|
||||
|
||||
fn bindgen_fn(function: &ast::Function, into: &mut Tokens) {
|
||||
let export_name = function.export_name();
|
||||
let generated_name = function.rust_symbol();
|
||||
bindgen(&function.free_function_export_name(),
|
||||
function.rust_symbol(None),
|
||||
Receiver::FreeFunction(function.name),
|
||||
&function.arguments,
|
||||
function.ret.as_ref(),
|
||||
into)
|
||||
}
|
||||
|
||||
fn bindgen_struct(s: &ast::Struct, into: &mut Tokens) {
|
||||
for f in s.functions.iter() {
|
||||
bindgen_struct_fn(s, f, into);
|
||||
}
|
||||
for f in s.methods.iter() {
|
||||
bindgen_struct_method(s, f, into);
|
||||
}
|
||||
|
||||
let name = &s.name;
|
||||
let free_fn = s.free_function();
|
||||
(quote! {
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn #free_fn(ptr: *mut ::std::cell::RefCell<#name>) {
|
||||
assert!(!ptr.is_null());
|
||||
drop(Box::from_raw(ptr));
|
||||
}
|
||||
}).to_tokens(into);
|
||||
}
|
||||
|
||||
fn bindgen_struct_fn(s: &ast::Struct, f: &ast::Function, into: &mut Tokens) {
|
||||
bindgen(&f.struct_function_export_name(s.name),
|
||||
f.rust_symbol(Some(s.name)),
|
||||
Receiver::StructFunction(s.name, f.name),
|
||||
&f.arguments,
|
||||
f.ret.as_ref(),
|
||||
into)
|
||||
}
|
||||
|
||||
fn bindgen_struct_method(s: &ast::Struct, m: &ast::Method, into: &mut Tokens) {
|
||||
bindgen(&m.function.struct_function_export_name(s.name),
|
||||
m.function.rust_symbol(Some(s.name)),
|
||||
Receiver::StructMethod(s.name, m.mutable, m.function.name),
|
||||
&m.function.arguments,
|
||||
m.function.ret.as_ref(),
|
||||
into)
|
||||
}
|
||||
|
||||
enum Receiver {
|
||||
FreeFunction(syn::Ident),
|
||||
StructFunction(syn::Ident, syn::Ident),
|
||||
StructMethod(syn::Ident, bool, syn::Ident),
|
||||
}
|
||||
|
||||
fn bindgen(export_name: &syn::Lit,
|
||||
generated_name: syn::Ident,
|
||||
receiver: Receiver,
|
||||
arguments: &[ast::Type],
|
||||
ret_type: Option<&ast::Type>,
|
||||
into: &mut Tokens) {
|
||||
let mut args = vec![];
|
||||
let mut arg_conversions = vec![];
|
||||
let real_name = &function.name;
|
||||
let mut converted_arguments = vec![];
|
||||
let ret = syn::Ident::from("_ret");
|
||||
|
||||
let mut malloc = false;
|
||||
let mut boxed_str = false;
|
||||
|
||||
for (i, ty) in function.arguments.iter().enumerate() {
|
||||
let mut offset = 0;
|
||||
if let Receiver::StructMethod(class, _, _) = receiver {
|
||||
args.push(quote! { me: *mut ::std::cell::RefCell<#class> });
|
||||
arg_conversions.push(quote! {
|
||||
assert!(!me.is_null());
|
||||
let me = unsafe { &*me };
|
||||
});
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
for (i, ty) in arguments.iter().enumerate() {
|
||||
let i = i + offset;
|
||||
let ident = syn::Ident::from(format!("arg{}", i));
|
||||
match *ty {
|
||||
ast::Type::Integer(i) => {
|
||||
@ -153,23 +221,23 @@ fn bindgen_fn(function: &ast::Function, into: &mut Tokens) {
|
||||
}
|
||||
let ret_ty;
|
||||
let convert_ret;
|
||||
match function.ret {
|
||||
Some(ast::Type::Integer(i)) => {
|
||||
match ret_type {
|
||||
Some(&ast::Type::Integer(i)) => {
|
||||
ret_ty = quote! { -> #i };
|
||||
convert_ret = quote! { #ret };
|
||||
}
|
||||
Some(ast::Type::BorrowedStr) => panic!("can't return a borrowed string"),
|
||||
Some(ast::Type::ByRef(_)) => panic!("can't return a borrowed ref"),
|
||||
Some(ast::Type::ByMutRef(_)) => panic!("can't return a borrowed ref"),
|
||||
Some(ast::Type::String) => {
|
||||
Some(&ast::Type::BorrowedStr) => panic!("can't return a borrowed string"),
|
||||
Some(&ast::Type::ByRef(_)) => panic!("can't return a borrowed ref"),
|
||||
Some(&ast::Type::ByMutRef(_)) => panic!("can't return a borrowed ref"),
|
||||
Some(&ast::Type::String) => {
|
||||
boxed_str = !BOXED_STR_GENERATED.swap(true, Ordering::SeqCst);
|
||||
ret_ty = quote! { -> *mut String };
|
||||
convert_ret = quote! { Box::into_raw(Box::new(#ret)) };
|
||||
}
|
||||
Some(ast::Type::ByValue(name)) => {
|
||||
Some(&ast::Type::ByValue(name)) => {
|
||||
ret_ty = quote! { -> *mut ::std::cell::RefCell<#name> };
|
||||
convert_ret = quote! {
|
||||
Box::into_raw(Box::new(::std::cell::RefCell<#ret>))
|
||||
Box::into_raw(Box::new(::std::cell::RefCell::new(#ret)))
|
||||
};
|
||||
}
|
||||
None => {
|
||||
@ -224,20 +292,38 @@ fn bindgen_fn(function: &ast::Function, into: &mut Tokens) {
|
||||
#malloc
|
||||
#boxed_str
|
||||
|
||||
#[no_mangle]
|
||||
#[export_name = #export_name]
|
||||
#[allow(non_snake_case)]
|
||||
pub extern fn #generated_name(#(#args),*) #ret_ty {
|
||||
#(#arg_conversions)*
|
||||
let #ret = #real_name(#(#converted_arguments),*);
|
||||
let #ret = #receiver(#(#converted_arguments),*);
|
||||
#convert_ret
|
||||
}
|
||||
};
|
||||
// println!("{}", tokens);
|
||||
tokens.to_tokens(into);
|
||||
}
|
||||
|
||||
fn bindgen_struct(s: &ast::Struct, into: &mut Tokens) {
|
||||
if s.ctor.is_none() {
|
||||
panic!("struct `{}` needs a `new` function to construct it", s.name);
|
||||
impl ToTokens for Receiver {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
match *self {
|
||||
Receiver::FreeFunction(name) => name.to_tokens(tokens),
|
||||
Receiver::StructFunction(s, name) => {
|
||||
s.to_tokens(tokens);
|
||||
syn::tokens::Colon2::default().to_tokens(tokens);
|
||||
name.to_tokens(tokens);
|
||||
}
|
||||
Receiver::StructMethod(_, mutable, name) => {
|
||||
syn::Ident::from("me").to_tokens(tokens);
|
||||
syn::tokens::Dot::default().to_tokens(tokens);
|
||||
if mutable {
|
||||
syn::Ident::from("borrow_mut").to_tokens(tokens);
|
||||
} else {
|
||||
syn::Ident::from("borrow").to_tokens(tokens);
|
||||
}
|
||||
tokens.append_delimited("(", Default::default(), |_| ());
|
||||
syn::tokens::Dot::default().to_tokens(tokens);
|
||||
name.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user