2018-01-08 10:42:01 -08:00
|
|
|
use proc_macro2::Span;
|
2018-02-06 07:56:14 -08:00
|
|
|
use quote::{Tokens, ToTokens};
|
|
|
|
use shared;
|
2017-12-14 19:31:01 -08:00
|
|
|
use syn;
|
|
|
|
|
2017-12-18 12:39:14 -08:00
|
|
|
pub struct Program {
|
|
|
|
pub structs: Vec<Struct>,
|
|
|
|
pub free_functions: Vec<Function>,
|
2017-12-18 21:43:16 -08:00
|
|
|
pub imports: Vec<Import>,
|
2018-02-05 14:24:25 -08:00
|
|
|
pub imported_structs: Vec<ImportStruct>,
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
|
|
|
|
2017-12-14 19:31:01 -08:00
|
|
|
pub struct Function {
|
|
|
|
pub name: syn::Ident,
|
|
|
|
pub arguments: Vec<Type>,
|
|
|
|
pub ret: Option<Type>,
|
|
|
|
}
|
|
|
|
|
2017-12-18 21:43:16 -08:00
|
|
|
pub struct Import {
|
2018-01-29 21:20:38 -08:00
|
|
|
pub module: String,
|
2018-02-05 14:24:25 -08:00
|
|
|
pub function: ImportFunction,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ImportFunction {
|
2018-02-06 19:04:12 -08:00
|
|
|
pub catch: bool,
|
2017-12-18 21:43:16 -08:00
|
|
|
pub ident: syn::Ident,
|
2018-02-05 14:24:25 -08:00
|
|
|
pub wasm_function: Function,
|
|
|
|
pub rust_decl: Box<syn::FnDecl>,
|
|
|
|
pub rust_vis: syn::Visibility,
|
|
|
|
pub rust_attrs: Vec<syn::Attribute>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ImportStruct {
|
|
|
|
pub module: Option<String>,
|
|
|
|
pub name: syn::Ident,
|
2018-02-06 19:04:12 -08:00
|
|
|
pub functions: Vec<ImportStructFunction>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ImportStructFunction {
|
|
|
|
pub kind: ImportFunctionKind,
|
|
|
|
pub function: ImportFunction,
|
2018-02-06 15:19:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum ImportFunctionKind {
|
|
|
|
Method,
|
|
|
|
Static,
|
|
|
|
JsConstructor,
|
2017-12-18 21:43:16 -08:00
|
|
|
}
|
|
|
|
|
2017-12-14 19:31:01 -08:00
|
|
|
pub enum Type {
|
2018-02-06 07:56:14 -08:00
|
|
|
// special
|
2017-12-14 21:55:21 -08:00
|
|
|
BorrowedStr,
|
|
|
|
String,
|
2018-02-06 07:56:14 -08:00
|
|
|
|
|
|
|
ByRef(syn::Type),
|
|
|
|
ByMutRef(syn::Type),
|
|
|
|
ByValue(syn::Type),
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Struct {
|
|
|
|
pub name: syn::Ident,
|
|
|
|
pub methods: Vec<Method>,
|
|
|
|
pub functions: Vec<Function>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Method {
|
|
|
|
pub mutable: bool,
|
|
|
|
pub function: Function,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Program {
|
|
|
|
pub fn push_impl(&mut self, item: &syn::ItemImpl) {
|
2017-12-31 14:40:57 -08:00
|
|
|
if item.defaultness.is_some() {
|
|
|
|
panic!("default impls are not supported");
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
2017-12-31 14:40:57 -08:00
|
|
|
if item.unsafety.is_some() {
|
|
|
|
panic!("unsafe impls are not supported");
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
|
|
|
if item.trait_.is_some() {
|
|
|
|
panic!("trait impls are not supported");
|
|
|
|
}
|
|
|
|
if item.generics.params.len() > 0 {
|
|
|
|
panic!("generic impls aren't supported");
|
|
|
|
}
|
2018-02-06 07:56:14 -08:00
|
|
|
let name = match *item.self_ty {
|
|
|
|
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
|
|
|
match extract_path_ident(path) {
|
|
|
|
Some(ident) => ident,
|
|
|
|
None => panic!("unsupported self type in impl"),
|
|
|
|
}
|
|
|
|
}
|
2017-12-18 12:39:14 -08:00
|
|
|
_ => panic!("unsupported self type in impl"),
|
|
|
|
};
|
|
|
|
let dst = self.structs
|
|
|
|
.iter_mut()
|
|
|
|
.find(|s| s.name == name)
|
|
|
|
.expect(&format!("failed to definition of struct for impl of `{}`", name));
|
|
|
|
for item in item.items.iter() {
|
|
|
|
dst.push_item(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-18 21:43:16 -08:00
|
|
|
pub fn push_foreign_mod(&mut self, f: &syn::ItemForeignMod) {
|
2017-12-31 14:40:57 -08:00
|
|
|
match f.abi.name {
|
2018-01-08 10:42:01 -08:00
|
|
|
Some(ref l) if l.value() == "JS" => {}
|
2017-12-18 21:43:16 -08:00
|
|
|
_ => panic!("only foreign mods with the `JS` ABI are allowed"),
|
|
|
|
}
|
2018-01-29 21:20:38 -08:00
|
|
|
let module = f.attrs.iter()
|
|
|
|
.filter_map(|f| f.interpret_meta())
|
|
|
|
.filter_map(|i| {
|
|
|
|
match i {
|
|
|
|
syn::Meta::NameValue(i) => {
|
|
|
|
if i.ident == "wasm_module" {
|
|
|
|
Some(i.lit)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.next()
|
|
|
|
.and_then(|lit| {
|
|
|
|
match lit {
|
|
|
|
syn::Lit::Str(v) => Some(v.value()),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.expect("must specify `#[wasm_module = ...]` for module to import from");
|
2017-12-18 21:43:16 -08:00
|
|
|
for item in f.items.iter() {
|
2018-02-05 14:24:25 -08:00
|
|
|
let import = self.gen_foreign_item(item, false).0;
|
|
|
|
self.imports.push(Import {
|
|
|
|
module: module.clone(),
|
|
|
|
function: import,
|
|
|
|
});
|
2017-12-18 21:43:16 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-05 14:24:25 -08:00
|
|
|
pub fn gen_foreign_item(&mut self,
|
|
|
|
f: &syn::ForeignItem,
|
|
|
|
allow_self: bool) -> (ImportFunction, bool) {
|
2017-12-18 21:43:16 -08:00
|
|
|
let f = match *f {
|
|
|
|
syn::ForeignItem::Fn(ref f) => f,
|
|
|
|
_ => panic!("only foreign functions allowed for now, not statics"),
|
|
|
|
};
|
|
|
|
|
2018-02-06 19:04:12 -08:00
|
|
|
let (mut wasm, mutable) = Function::from_decl(f.ident, &f.decl, allow_self);
|
2018-02-05 14:24:25 -08:00
|
|
|
let is_method = match mutable {
|
|
|
|
Some(false) => true,
|
|
|
|
None => false,
|
|
|
|
Some(true) => {
|
|
|
|
panic!("mutable self methods not allowed in extern structs");
|
|
|
|
}
|
|
|
|
};
|
2018-02-06 19:04:12 -08:00
|
|
|
let opts = BindgenOpts::from(&f.attrs);
|
|
|
|
|
|
|
|
if opts.catch {
|
|
|
|
// TODO: this assumes a whole bunch:
|
|
|
|
//
|
|
|
|
// * The outer type is actually a `Result`
|
|
|
|
// * The error type is a `JsValue`
|
|
|
|
// * The actual type is the first type parameter
|
|
|
|
//
|
|
|
|
// should probably fix this one day...
|
|
|
|
wasm.ret = extract_first_ty_param(wasm.ret.as_ref())
|
|
|
|
.expect("can't `catch` without returning a Result");
|
|
|
|
}
|
2018-02-05 14:24:25 -08:00
|
|
|
|
|
|
|
(ImportFunction {
|
|
|
|
rust_attrs: f.attrs.clone(),
|
|
|
|
rust_vis: f.vis.clone(),
|
|
|
|
rust_decl: f.decl.clone(),
|
2017-12-18 21:43:16 -08:00
|
|
|
ident: f.ident.clone(),
|
2018-02-05 14:24:25 -08:00
|
|
|
wasm_function: wasm,
|
2018-02-06 19:04:12 -08:00
|
|
|
catch: opts.catch,
|
2018-02-05 14:24:25 -08:00
|
|
|
}, is_method)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn push_extern_class(&mut self, class: &ExternClass) {
|
|
|
|
let functions = class.functions.iter()
|
|
|
|
.map(|f| {
|
|
|
|
let (f, method) = self.gen_foreign_item(f, true);
|
2018-02-06 15:19:47 -08:00
|
|
|
let kind = if method {
|
|
|
|
ImportFunctionKind::Method
|
|
|
|
} else {
|
2018-02-06 19:04:12 -08:00
|
|
|
let opts = BindgenOpts::from(&f.rust_attrs);
|
|
|
|
if opts.constructor {
|
2018-02-06 15:19:47 -08:00
|
|
|
ImportFunctionKind::JsConstructor
|
|
|
|
} else {
|
|
|
|
ImportFunctionKind::Static
|
|
|
|
}
|
|
|
|
};
|
2018-02-06 19:04:12 -08:00
|
|
|
ImportStructFunction { kind, function: f }
|
2018-02-05 14:24:25 -08:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
self.imported_structs.push(ImportStruct {
|
|
|
|
module: class.module.as_ref().map(|s| s.value()),
|
|
|
|
name: class.name,
|
|
|
|
functions,
|
2017-12-18 21:43:16 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-06 07:56:14 -08:00
|
|
|
pub fn wbg_literal(&self, dst: &mut Tokens) -> usize {
|
|
|
|
let mut a = LiteralBuilder {
|
|
|
|
dst,
|
|
|
|
cnt: 0,
|
|
|
|
};
|
|
|
|
a.append("wbg:");
|
|
|
|
a.fields(&[
|
|
|
|
("structs", &|a| a.list(&self.structs, Struct::wbg_literal)),
|
|
|
|
("free_functions", &|a| a.list(&self.free_functions, Function::wbg_literal)),
|
|
|
|
("imports", &|a| a.list(&self.imports, Import::wbg_literal)),
|
|
|
|
("imported_structs", &|a| a.list(&self.imported_structs, ImportStruct::wbg_literal)),
|
2018-02-06 16:06:21 -08:00
|
|
|
("custom_type_names", &|a| {
|
|
|
|
a.list(&self.structs, |s, a| {
|
|
|
|
let val = shared::name_to_descriptor(s.name.as_ref());
|
|
|
|
a.fields(&[
|
|
|
|
("descriptor", &|a| a.char(val)),
|
|
|
|
("name", &|a| a.str(s.name.as_ref()))
|
|
|
|
]);
|
|
|
|
})
|
|
|
|
}),
|
2018-02-06 07:56:14 -08:00
|
|
|
]);
|
|
|
|
return a.cnt
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Function {
|
|
|
|
pub fn from(input: &syn::ItemFn) -> Function {
|
|
|
|
match input.vis {
|
|
|
|
syn::Visibility::Public(_) => {}
|
|
|
|
_ => panic!("can only bindgen public functions"),
|
|
|
|
}
|
2017-12-31 14:40:57 -08:00
|
|
|
if input.constness.is_some() {
|
|
|
|
panic!("can only bindgen non-const functions");
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
2017-12-31 14:40:57 -08:00
|
|
|
if input.unsafety.is_some() {
|
|
|
|
panic!("can only bindgen safe functions");
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
if !input.abi.is_none() {
|
|
|
|
panic!("can only bindgen Rust ABI functions")
|
|
|
|
}
|
|
|
|
if !input.abi.is_none() {
|
|
|
|
panic!("can only bindgen Rust ABI functions")
|
|
|
|
}
|
2017-12-18 12:39:14 -08:00
|
|
|
|
2018-02-05 14:24:25 -08:00
|
|
|
Function::from_decl(input.ident, &input.decl, false).0
|
2017-12-18 21:43:16 -08:00
|
|
|
}
|
|
|
|
|
2018-02-05 14:24:25 -08:00
|
|
|
pub fn from_decl(name: syn::Ident,
|
|
|
|
decl: &syn::FnDecl,
|
|
|
|
allow_self: bool) -> (Function, Option<bool>) {
|
2017-12-31 14:40:57 -08:00
|
|
|
if decl.variadic.is_some() {
|
2017-12-14 19:31:01 -08:00
|
|
|
panic!("can't bindgen variadic functions")
|
|
|
|
}
|
2017-12-18 21:43:16 -08:00
|
|
|
if decl.generics.params.len() > 0 {
|
2017-12-14 19:31:01 -08:00
|
|
|
panic!("can't bindgen functions with lifetime or type parameters")
|
|
|
|
}
|
|
|
|
|
2018-02-05 14:24:25 -08:00
|
|
|
let mut mutable = None;
|
2017-12-18 21:43:16 -08:00
|
|
|
let arguments = decl.inputs.iter()
|
2018-02-05 14:24:25 -08:00
|
|
|
.filter_map(|arg| {
|
2017-12-14 19:31:01 -08:00
|
|
|
match *arg {
|
2018-02-05 14:24:25 -08:00
|
|
|
syn::FnArg::Captured(ref c) => Some(c),
|
|
|
|
syn::FnArg::SelfValue(_) => {
|
|
|
|
panic!("by-value `self` not yet supported");
|
|
|
|
}
|
|
|
|
syn::FnArg::SelfRef(ref a) if allow_self => {
|
|
|
|
assert!(mutable.is_none());
|
|
|
|
mutable = Some(a.mutability.is_some());
|
|
|
|
None
|
|
|
|
}
|
2017-12-14 19:31:01 -08:00
|
|
|
_ => panic!("arguments cannot be `self` or ignored"),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.map(|arg| Type::from(&arg.ty))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2017-12-18 21:43:16 -08:00
|
|
|
let ret = match decl.output {
|
2017-12-14 19:31:01 -08:00
|
|
|
syn::ReturnType::Default => None,
|
2017-12-31 14:40:57 -08:00
|
|
|
syn::ReturnType::Type(_, ref t) => Some(Type::from(t)),
|
2017-12-14 19:31:01 -08:00
|
|
|
};
|
|
|
|
|
2018-02-05 14:24:25 -08:00
|
|
|
(Function { name, arguments, ret }, mutable)
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
|
2018-01-08 10:42:01 -08:00
|
|
|
pub fn free_function_export_name(&self) -> syn::LitStr {
|
2018-02-06 07:56:14 -08:00
|
|
|
let name = shared::free_function_export_name(self.name.as_ref());
|
2018-01-08 10:42:01 -08:00
|
|
|
syn::LitStr::new(&name, Span::def_site())
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
|
2018-01-08 10:42:01 -08:00
|
|
|
pub fn struct_function_export_name(&self, s: syn::Ident) -> syn::LitStr {
|
2018-02-06 07:56:14 -08:00
|
|
|
let name = shared::struct_function_export_name(
|
|
|
|
s.as_ref(),
|
|
|
|
self.name.as_ref(),
|
|
|
|
);
|
2018-01-08 10:42:01 -08:00
|
|
|
syn::LitStr::new(&name, Span::def_site())
|
2017-12-18 14:31:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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("_");
|
2017-12-31 14:40:57 -08:00
|
|
|
generated_name.push_str(ns.as_ref());
|
2017-12-18 14:31:01 -08:00
|
|
|
}
|
|
|
|
generated_name.push_str("_");
|
2017-12-31 14:40:57 -08:00
|
|
|
generated_name.push_str(self.name.as_ref());
|
2017-12-14 19:31:01 -08:00
|
|
|
syn::Ident::from(generated_name)
|
|
|
|
}
|
|
|
|
|
2018-02-06 07:56:14 -08:00
|
|
|
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
|
|
|
a.fields(&[
|
|
|
|
("name", &|a| a.str(self.name.as_ref())),
|
|
|
|
("arguments", &|a| a.list(&self.arguments, Type::wbg_literal)),
|
|
|
|
("ret", &|a| {
|
|
|
|
match self.ret {
|
|
|
|
Some(ref s) => s.wbg_literal(a),
|
|
|
|
None => a.append("null"),
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
]);
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-06 07:56:14 -08:00
|
|
|
pub fn extract_path_ident(path: &syn::Path) -> Option<syn::Ident> {
|
2017-12-18 21:43:16 -08:00
|
|
|
if path.leading_colon.is_some() {
|
2018-02-06 07:56:14 -08:00
|
|
|
return None
|
2017-12-18 21:43:16 -08:00
|
|
|
}
|
|
|
|
if path.segments.len() != 1 {
|
2018-02-06 07:56:14 -08:00
|
|
|
return None
|
2017-12-18 21:43:16 -08:00
|
|
|
}
|
2018-01-08 10:42:01 -08:00
|
|
|
match path.segments.first().unwrap().value().arguments {
|
2017-12-18 21:43:16 -08:00
|
|
|
syn::PathArguments::None => {}
|
2018-02-06 07:56:14 -08:00
|
|
|
_ => return None,
|
2017-12-18 21:43:16 -08:00
|
|
|
}
|
2018-02-06 07:56:14 -08:00
|
|
|
path.segments.first().map(|v| v.value().ident)
|
2017-12-18 21:43:16 -08:00
|
|
|
}
|
|
|
|
|
2017-12-14 19:31:01 -08:00
|
|
|
impl Type {
|
|
|
|
pub fn from(ty: &syn::Type) -> Type {
|
|
|
|
match *ty {
|
2017-12-14 21:55:21 -08:00
|
|
|
syn::Type::Reference(ref r) => {
|
2017-12-31 14:40:57 -08:00
|
|
|
match *r.elem {
|
2017-12-14 21:55:21 -08:00
|
|
|
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
|
|
|
let ident = extract_path_ident(path);
|
2018-02-06 07:56:14 -08:00
|
|
|
match ident.as_ref().map(|s| s.as_ref()) {
|
|
|
|
Some("str") => return Type::BorrowedStr,
|
|
|
|
_ => {}
|
2017-12-14 21:55:21 -08:00
|
|
|
}
|
|
|
|
}
|
2018-02-06 07:56:14 -08:00
|
|
|
_ => {}
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
2018-02-06 07:56:14 -08:00
|
|
|
return if r.mutability.is_some() {
|
|
|
|
Type::ByMutRef((*r.elem).clone())
|
2017-12-20 07:35:14 -08:00
|
|
|
} else {
|
2018-02-06 07:56:14 -08:00
|
|
|
Type::ByRef((*r.elem).clone())
|
2017-12-20 07:35:14 -08:00
|
|
|
}
|
|
|
|
}
|
2017-12-14 21:55:21 -08:00
|
|
|
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
|
|
|
let ident = extract_path_ident(path);
|
2018-02-06 07:56:14 -08:00
|
|
|
match ident.as_ref().map(|s| s.as_ref()) {
|
|
|
|
Some("String") => return Type::String,
|
|
|
|
_ => {}
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
}
|
2018-02-06 07:56:14 -08:00
|
|
|
_ => {}
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
2018-02-06 07:56:14 -08:00
|
|
|
|
|
|
|
Type::ByValue(ty.clone())
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
|
2018-02-06 07:56:14 -08:00
|
|
|
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
2017-12-14 19:31:01 -08:00
|
|
|
match *self {
|
2018-02-06 07:56:14 -08:00
|
|
|
Type::BorrowedStr => a.char(shared::TYPE_BORROWED_STR),
|
|
|
|
Type::String => a.char(shared::TYPE_STRING),
|
|
|
|
Type::ByValue(ref t) => {
|
|
|
|
a.as_char(my_quote! {
|
2018-02-06 16:06:21 -08:00
|
|
|
<#t as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR
|
2018-02-06 07:56:14 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Type::ByRef(ref ty) |
|
|
|
|
Type::ByMutRef(ref ty) => {
|
|
|
|
a.as_char(my_quote! {
|
2018-02-06 16:06:21 -08:00
|
|
|
(<#ty as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR |
|
|
|
|
::wasm_bindgen::convert::DESCRIPTOR_CUSTOM_REF_FLAG)
|
2018-02-06 07:56:14 -08:00
|
|
|
});
|
|
|
|
}
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-18 12:39:14 -08:00
|
|
|
impl Struct {
|
|
|
|
pub fn from(s: &syn::ItemStruct) -> Struct {
|
|
|
|
Struct {
|
|
|
|
name: s.ident,
|
|
|
|
methods: Vec::new(),
|
|
|
|
functions: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-18 14:31:01 -08:00
|
|
|
pub fn free_function(&self) -> syn::Ident {
|
2018-02-06 07:56:14 -08:00
|
|
|
syn::Ident::from(shared::free_function(self.name.as_ref()))
|
2017-12-18 14:31:01 -08:00
|
|
|
}
|
|
|
|
|
2017-12-18 12:39:14 -08:00
|
|
|
pub fn push_item(&mut self, item: &syn::ImplItem) {
|
|
|
|
let method = match *item {
|
|
|
|
syn::ImplItem::Const(_) => panic!("const definitions aren't supported"),
|
|
|
|
syn::ImplItem::Type(_) => panic!("type definitions in impls aren't supported"),
|
|
|
|
syn::ImplItem::Method(ref m) => m,
|
|
|
|
syn::ImplItem::Macro(_) => panic!("macros in impls aren't supported"),
|
2017-12-31 14:40:57 -08:00
|
|
|
syn::ImplItem::Verbatim(_) => panic!("unparsed impl item?"),
|
2017-12-18 12:39:14 -08:00
|
|
|
};
|
|
|
|
match method.vis {
|
|
|
|
syn::Visibility::Public(_) => {}
|
|
|
|
_ => return,
|
|
|
|
}
|
2017-12-31 14:40:57 -08:00
|
|
|
if method.defaultness.is_some() {
|
|
|
|
panic!("default methods are not supported");
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
2017-12-31 14:40:57 -08:00
|
|
|
if method.sig.constness.is_some() {
|
|
|
|
panic!("can only bindgen non-const functions");
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
2017-12-31 14:40:57 -08:00
|
|
|
if method.sig.unsafety.is_some() {
|
|
|
|
panic!("can only bindgen safe functions");
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
|
|
|
|
2018-02-05 14:24:25 -08:00
|
|
|
let (function, mutable) = Function::from_decl(method.sig.ident,
|
|
|
|
&method.sig.decl,
|
|
|
|
true);
|
2017-12-18 12:39:14 -08:00
|
|
|
match mutable {
|
|
|
|
Some(mutable) => {
|
|
|
|
self.methods.push(Method { mutable, function });
|
2017-12-14 21:55:21 -08:00
|
|
|
}
|
2017-12-18 12:39:14 -08:00
|
|
|
None => {
|
|
|
|
self.functions.push(function);
|
2017-12-14 21:55:21 -08:00
|
|
|
}
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
|
|
|
}
|
2017-12-18 12:39:14 -08:00
|
|
|
|
2018-02-06 07:56:14 -08:00
|
|
|
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
|
|
|
a.fields(&[
|
|
|
|
("name", &|a| a.str(self.name.as_ref())),
|
|
|
|
("functions", &|a| a.list(&self.functions, Function::wbg_literal)),
|
|
|
|
("methods", &|a| a.list(&self.methods, Method::wbg_literal)),
|
|
|
|
]);
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Method {
|
2018-02-06 07:56:14 -08:00
|
|
|
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
|
|
|
a.fields(&[
|
|
|
|
("mutable", &|a| a.bool(self.mutable)),
|
|
|
|
("function", &|a| self.function.wbg_literal(a)),
|
|
|
|
]);
|
2017-12-18 12:39:14 -08:00
|
|
|
}
|
2017-12-14 19:31:01 -08:00
|
|
|
}
|
2018-02-05 14:24:25 -08:00
|
|
|
|
|
|
|
impl ImportStruct {
|
2018-02-06 07:56:14 -08:00
|
|
|
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
|
|
|
a.fields(&[
|
|
|
|
("module", &|a| {
|
|
|
|
match self.module {
|
|
|
|
Some(ref s) => a.str(s),
|
|
|
|
None => a.append("null"),
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
("name", &|a| a.str(self.name.as_ref())),
|
|
|
|
("functions", &|a| {
|
|
|
|
a.list(&self.functions,
|
2018-02-06 19:04:12 -08:00
|
|
|
|f, a| {
|
|
|
|
let (method, new) = match f.kind {
|
2018-02-06 15:19:47 -08:00
|
|
|
ImportFunctionKind::Method => (true, false),
|
|
|
|
ImportFunctionKind::JsConstructor => (false, true),
|
|
|
|
ImportFunctionKind::Static => (false, false),
|
|
|
|
};
|
2018-02-06 07:56:14 -08:00
|
|
|
a.fields(&[
|
2018-02-06 15:19:47 -08:00
|
|
|
("method", &|a| a.bool(method)),
|
|
|
|
("js_new", &|a| a.bool(new)),
|
2018-02-06 19:04:12 -08:00
|
|
|
("catch", &|a| a.bool(f.function.catch)),
|
|
|
|
("function", &|a| f.function.wasm_function.wbg_literal(a)),
|
2018-02-06 07:56:14 -08:00
|
|
|
]);
|
|
|
|
})
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Import {
|
|
|
|
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
|
|
|
a.fields(&[
|
|
|
|
("module", &|a| a.str(&self.module)),
|
2018-02-06 19:04:12 -08:00
|
|
|
("catch", &|a| a.bool(self.function.catch)),
|
2018-02-06 07:56:14 -08:00
|
|
|
("function", &|a| self.function.wasm_function.wbg_literal(a)),
|
|
|
|
]);
|
2018-02-05 14:24:25 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct File {
|
|
|
|
pub items: Vec<MyItem>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl syn::synom::Synom for File {
|
|
|
|
named!(parse -> Self, map!(many0!(syn!(MyItem)), |items| File { items }));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum MyItem {
|
|
|
|
Normal(syn::Item),
|
|
|
|
ExternClass(ExternClass),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl syn::synom::Synom for MyItem {
|
|
|
|
named!(parse -> Self, alt!(
|
|
|
|
syn!(syn::Item) => { MyItem::Normal }
|
|
|
|
|
|
|
|
|
syn!(ExternClass) => { MyItem::ExternClass }
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ExternClass {
|
|
|
|
name: syn::Ident,
|
|
|
|
module: Option<syn::LitStr>,
|
|
|
|
functions: Vec<syn::ForeignItem>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl syn::synom::Synom for ExternClass {
|
|
|
|
named!(parse -> Self, do_parse!(
|
|
|
|
module: option!(do_parse!(
|
|
|
|
punct!(#) >>
|
|
|
|
name: brackets!(do_parse!(
|
|
|
|
call!(term, "wasm_module") >>
|
|
|
|
punct!(=) >>
|
|
|
|
val: syn!(syn::LitStr) >>
|
|
|
|
(val)
|
|
|
|
)) >>
|
|
|
|
(name.1)
|
|
|
|
)) >>
|
|
|
|
keyword!(extern) >>
|
|
|
|
keyword!(struct) >>
|
|
|
|
name: syn!(syn::Ident) >>
|
|
|
|
items: braces!(many0!(syn!(syn::ForeignItem))) >>
|
|
|
|
(ExternClass {
|
|
|
|
name,
|
|
|
|
module,
|
|
|
|
functions: items.1,
|
|
|
|
})
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str)
|
|
|
|
-> syn::synom::PResult<'a, ()>
|
|
|
|
{
|
|
|
|
if let Some((_span, term, next)) = cursor.term() {
|
|
|
|
if term.as_str() == name {
|
|
|
|
return Ok(((), next))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
syn::parse_error()
|
|
|
|
}
|
2018-02-06 07:56:14 -08:00
|
|
|
|
|
|
|
struct LiteralBuilder<'a> {
|
|
|
|
dst: &'a mut Tokens,
|
|
|
|
cnt: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> LiteralBuilder<'a> {
|
2018-02-06 16:06:21 -08:00
|
|
|
fn char_lit(&mut self, c: char) {
|
2018-02-06 07:56:14 -08:00
|
|
|
if self.cnt > 0 {
|
|
|
|
::syn::token::Comma::default().to_tokens(self.dst);
|
|
|
|
}
|
|
|
|
self.cnt += 1;
|
2018-02-06 16:06:21 -08:00
|
|
|
(c as u32).to_tokens(self.dst);
|
2018-02-06 07:56:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn append(&mut self, s: &str) {
|
2018-02-06 16:06:21 -08:00
|
|
|
for c in s.chars() {
|
|
|
|
self.char_lit(c);
|
2018-02-06 07:56:14 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn str(&mut self, s: &str) {
|
|
|
|
self.append("\"");
|
|
|
|
self.append(s);
|
|
|
|
self.append("\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bool(&mut self, v: bool) {
|
|
|
|
if v {
|
|
|
|
self.append("true")
|
|
|
|
} else {
|
|
|
|
self.append("false")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn char(&mut self, s: char) {
|
|
|
|
self.append("\"");
|
2018-02-06 16:06:21 -08:00
|
|
|
self.char_lit(s);
|
|
|
|
self.append("\"");
|
2018-02-06 07:56:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn as_char(&mut self, tokens: Tokens) {
|
|
|
|
self.append("\"");
|
|
|
|
::syn::token::Comma::default().to_tokens(self.dst);
|
|
|
|
tokens.to_tokens(self.dst);
|
|
|
|
self.cnt += 1;
|
|
|
|
self.append("\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fields(&mut self, fields: &[(&str, &Fn(&mut Self))]) {
|
|
|
|
self.append("{");
|
|
|
|
for (i, &(field, cb)) in fields.iter().enumerate() {
|
|
|
|
if i > 0 {
|
|
|
|
self.append(",");
|
|
|
|
}
|
|
|
|
self.str(field);
|
|
|
|
self.append(":");
|
|
|
|
cb(self);
|
|
|
|
}
|
|
|
|
self.append("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
fn list<T, F>(&mut self, list: T, mut cb: F)
|
|
|
|
where F: FnMut(T::Item, &mut Self),
|
|
|
|
T: IntoIterator,
|
|
|
|
{
|
|
|
|
self.append("[");
|
|
|
|
for (i, element) in list.into_iter().enumerate() {
|
|
|
|
if i > 0 {
|
|
|
|
self.append(",");
|
|
|
|
}
|
|
|
|
cb(element, self);
|
|
|
|
}
|
|
|
|
self.append("]");
|
|
|
|
}
|
|
|
|
}
|
2018-02-06 19:04:12 -08:00
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct BindgenOpts {
|
|
|
|
catch: bool,
|
|
|
|
constructor: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BindgenOpts {
|
|
|
|
fn from(attrs: &[syn::Attribute]) -> BindgenOpts {
|
|
|
|
let mut opts = BindgenOpts::default();
|
|
|
|
let attrs = attrs.iter()
|
|
|
|
.filter_map(|a| a.interpret_meta())
|
|
|
|
.filter_map(|m| {
|
|
|
|
match m {
|
|
|
|
syn::Meta::List(i) => {
|
|
|
|
if i.ident == "wasm_bindgen" {
|
|
|
|
Some(i.nested)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.flat_map(|a| a)
|
|
|
|
.filter_map(|a| {
|
|
|
|
match a {
|
|
|
|
syn::NestedMeta::Meta(a) => Some(a),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
for attr in attrs {
|
|
|
|
match attr {
|
|
|
|
syn::Meta::Word(a) => {
|
|
|
|
if a == "constructor" {
|
|
|
|
opts.constructor = true;
|
|
|
|
} else if a == "catch" {
|
|
|
|
opts.catch = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return opts
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extract_first_ty_param(ty: Option<&Type>) -> Option<Option<Type>> {
|
|
|
|
let ty = match ty {
|
|
|
|
Some(t) => t,
|
|
|
|
None => return Some(None)
|
|
|
|
};
|
|
|
|
let ty = match *ty {
|
|
|
|
Type::ByValue(ref t) => t,
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
let path = match *ty {
|
|
|
|
syn::Type::Path(syn::TypePath { qself: None, ref path }) => path,
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
let seg = path.segments.last()?.into_value();
|
|
|
|
let generics = match seg.arguments {
|
|
|
|
syn::PathArguments::AngleBracketed(ref t) => t,
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
let ty = match *generics.args.first()?.into_value() {
|
|
|
|
syn::GenericArgument::Type(ref t) => t,
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
match *ty {
|
|
|
|
syn::Type::Tuple(ref t) if t.elems.len() == 0 => return Some(None),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
Some(Some(Type::from(ty)))
|
|
|
|
}
|