From 400015a061baa5f10ec3c49f6f3d3183ab0dd1ac Mon Sep 17 00:00:00 2001 From: "R. Andrew Ohana" Date: Thu, 14 Jun 2018 02:03:52 -0700 Subject: [PATCH 1/3] webidl: refactor method/getter/getter generation --- crates/backend/src/ast.rs | 44 +-- crates/backend/src/codegen.rs | 85 +++-- crates/webidl/src/lib.rs | 434 +++++--------------------- crates/webidl/src/util.rs | 241 ++++++++++++++ crates/webidl/tests/expected/Event.rs | 95 +++--- 5 files changed, 422 insertions(+), 477 deletions(-) create mode 100644 crates/webidl/src/util.rs diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 4e761889..c7c3cf35 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -41,6 +41,7 @@ pub enum ImportKind { pub struct ImportFunction { pub function: Function, pub rust_name: Ident, + pub js_ret: Option, pub kind: ImportFunctionKind, pub shim: Ident, } @@ -70,11 +71,10 @@ pub struct ImportType { #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] pub struct Function { pub name: Ident, - pub arguments: Vec, + pub arguments: Vec, pub ret: Option, pub opts: BindgenAttrs, pub rust_attrs: Vec, - pub rust_decl: Box, pub rust_vis: syn::Visibility, } @@ -139,7 +139,8 @@ impl Program { syn::Item::Fn(mut f) => { let opts = opts.unwrap_or_else(|| BindgenAttrs::find(&mut f.attrs)); - let no_mangle = f.attrs + let no_mangle = f + .attrs .iter() .enumerate() .filter_map(|(i, m)| m.interpret_meta().map(|m| (i, m))) @@ -268,7 +269,8 @@ impl Program { _ => panic!("only public enums are allowed"), } - let variants = item.variants + let variants = item + .variants .iter() .enumerate() .map(|(i, v)| { @@ -345,8 +347,8 @@ impl Program { pub fn push_foreign_fn(&mut self, f: syn::ForeignItemFn, opts: BindgenAttrs) -> ImportKind { let js_name = opts.js_name().unwrap_or(&f.ident).clone(); - let mut wasm = Function::from_decl(&js_name, f.decl, f.attrs, opts, f.vis, false).0; - if wasm.opts.catch() { + let wasm = Function::from_decl(&js_name, f.decl, f.attrs, opts, f.vis, false).0; + let js_ret = if wasm.opts.catch() { // TODO: this assumes a whole bunch: // // * The outer type is actually a `Result` @@ -354,15 +356,18 @@ impl Program { // * 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"); - } + extract_first_ty_param(wasm.ret.as_ref()) + .expect("can't `catch` without returning a Result") + } else { + wasm.ret.clone() + }; let kind = if wasm.opts.method() { - let class = wasm.arguments + let class = wasm + .arguments .get(0) .expect("methods must have at least one argument"); - let class = match *class { + let class = match class.ty { syn::Type::Reference(syn::TypeReference { mutability: None, ref elem, @@ -418,6 +423,7 @@ impl Program { ImportKind::Function(ImportFunction { function: wasm, kind, + js_ret, rust_name: f.ident.clone(), shim: Ident::new(&shim, Span::call_site()), }) @@ -501,11 +507,13 @@ impl Function { assert_no_lifetimes(&mut decl); + let syn::FnDecl { inputs, output, .. } = { *decl }; + let mut mutable = None; - let arguments = decl.inputs - .iter() - .filter_map(|arg| match *arg { - syn::FnArg::Captured(ref c) => Some(c), + let arguments = inputs + .into_iter() + .filter_map(|arg| match arg { + syn::FnArg::Captured(c) => Some(c), syn::FnArg::SelfValue(_) => { panic!("by-value `self` not yet supported"); } @@ -516,12 +524,11 @@ impl Function { } _ => panic!("arguments cannot be `self` or ignored"), }) - .map(|arg| arg.ty.clone()) .collect::>(); - let ret = match decl.output { + let ret = match output { syn::ReturnType::Default => None, - syn::ReturnType::Type(_, ref t) => Some((**t).clone()), + syn::ReturnType::Type(_, ty) => Some(*ty), }; ( @@ -531,7 +538,6 @@ impl Function { ret, opts, rust_vis: vis, - rust_decl: decl, rust_attrs: attrs, }, mutable, diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index e1ed09b7..96275b82 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -1,10 +1,10 @@ use std::borrow::Cow; use std::collections::HashSet; use std::env; -use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use ast; -use proc_macro2::{Span, Ident, TokenStream}; +use proc_macro2::{Ident, Span, TokenStream}; use quote::ToTokens; use serde_json; use shared; @@ -50,7 +50,7 @@ impl ToTokens for ast::Program { if types.contains(ns) && i.kind.fits_on_impl() { let kind = &i.kind; (quote! { impl #ns { #kind } }).to_tokens(tokens); - continue + continue; } } @@ -240,7 +240,10 @@ impl ToTokens for ast::StructField { let ty = &self.ty; let getter = &self.getter; let setter = &self.setter; - let desc = Ident::new(&format!("__wbindgen_describe_{}", getter), Span::call_site()); + let desc = Ident::new( + &format!("__wbindgen_describe_{}", getter), + Span::call_site(), + ); (quote! { #[no_mangle] #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] @@ -270,7 +273,7 @@ impl ToTokens for ast::StructField { }).to_tokens(tokens); if self.opts.readonly() { - return + return; } (quote! { @@ -315,7 +318,7 @@ impl ToTokens for ast::Export { offset = 1; } - for (i, ty) in self.function.arguments.iter().enumerate() { + for (i, syn::ArgCaptured { ty, .. }) in self.function.arguments.iter().enumerate() { let i = i + offset; let ident = Ident::new(&format!("arg{}", i), Span::call_site()); match *ty { @@ -377,8 +380,8 @@ impl ToTokens for ast::Export { }; } None => { - ret_ty = quote!{}; - convert_ret = quote!{}; + ret_ty = quote!(); + convert_ret = quote!(); } } let describe_ret = match &self.function.ret { @@ -406,7 +409,7 @@ impl ToTokens for ast::Export { let descriptor_name = format!("__wbindgen_describe_{}", export_name); let descriptor_name = Ident::new(&descriptor_name, Span::call_site()); let nargs = self.function.arguments.len() as u32; - let argtys = self.function.arguments.iter(); + let argtys = self.function.arguments.iter().map(|arg| &arg.ty); let tokens = quote! { #[export_name = #export_name] @@ -559,37 +562,27 @@ impl ToTokens for ast::ImportFunction { ast::ImportFunctionKind::Normal => {} } let vis = &self.function.rust_vis; - let ret = &self.function.rust_decl.output; - let fn_token = &self.function.rust_decl.fn_token; + let ret = match &self.function.ret { + Some(ty) => quote! { -> #ty }, + None => quote!(), + }; let mut abi_argument_names = Vec::new(); let mut abi_arguments = Vec::new(); let mut arg_conversions = Vec::new(); let ret_ident = Ident::new("_ret", Span::call_site()); - let names = self.function - .rust_decl - .inputs - .iter() - .map(|arg| { - match arg { - syn::FnArg::Captured(c) => c, - _ => panic!("arguments cannot be `self` or ignored"), - } - }) - .map(|arg| { - match &arg.pat { - syn::Pat::Ident(syn::PatIdent { - by_ref: None, - ident, - subpat: None, - .. - }) => ident.clone(), - _ => panic!("unsupported pattern in foreign function"), - } - }); + for (i, syn::ArgCaptured { pat, ty, .. }) in self.function.arguments.iter().enumerate() { + let name = match pat { + syn::Pat::Ident(syn::PatIdent { + by_ref: None, + ident, + subpat: None, + .. + }) => ident.clone(), + _ => panic!("unsupoported pattern in foreign function"), + }; - for (i, (ty, name)) in self.function.arguments.iter().zip(names).enumerate() { abi_argument_names.push(name.clone()); abi_arguments.push(quote! { #name: <#ty as ::wasm_bindgen::convert::IntoWasmAbi>::Abi @@ -606,7 +599,7 @@ impl ToTokens for ast::ImportFunction { } let abi_ret; let mut convert_ret; - match self.function.ret { + match &self.js_ret { Some(syn::Type::Reference(_)) => { panic!("cannot return references in imports yet"); } @@ -628,7 +621,7 @@ impl ToTokens for ast::ImportFunction { } } - let mut exceptional_ret = quote!{}; + let mut exceptional_ret = quote!(); let exn_data = if self.function.opts.catch() { let exn_data = Ident::new("exn_data", Span::call_site()); let exn_data_ptr = Ident::new("exn_data_ptr", Span::call_site()); @@ -649,20 +642,18 @@ impl ToTokens for ast::ImportFunction { let #exn_data_ptr = #exn_data.as_mut_ptr(); } } else { - quote! {} + quote!() }; let rust_name = &self.rust_name; let import_name = &self.shim; let attrs = &self.function.rust_attrs; - let arguments = self.function - .rust_decl - .inputs - .iter() - .skip(if is_method { 1 } else { 0 }) - .collect::>(); - let arguments = &arguments[..]; + let arguments = if is_method { + &self.function.arguments[1..] + } else { + &self.function.arguments[..] + }; let me = if is_method { quote! { &self, } @@ -674,7 +665,7 @@ impl ToTokens for ast::ImportFunction { #(#attrs)* #[allow(bad_style)] #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] - #vis extern #fn_token #rust_name(#me #(#arguments),*) #ret { + #vis extern fn #rust_name(#me #(#arguments),*) #ret { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern { @@ -695,7 +686,7 @@ impl ToTokens for ast::ImportFunction { #(#attrs)* #[allow(bad_style, unused_variables)] #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] - #vis extern #fn_token #rust_name(#me #(#arguments),*) #ret { + #vis extern fn #rust_name(#me #(#arguments),*) #ret { panic!("cannot call wasm-bindgen imported functions on \ non-wasm targets"); } @@ -726,9 +717,9 @@ impl<'a> ToTokens for DescribeImport<'a> { }; let describe_name = format!("__wbindgen_describe_{}", f.shim); let describe_name = Ident::new(&describe_name, Span::call_site()); - let argtys = f.function.arguments.iter(); + let argtys = f.function.arguments.iter().map(|arg| &arg.ty); let nargs = f.function.arguments.len() as u32; - let inform_ret = match f.function.ret { + let inform_ret = match &f.js_ret { Some(ref t) => quote! { inform(1); <#t as WasmDescribe>::describe(); }, None => quote! { inform(0); }, }; diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 86bc4edf..adec017d 100755 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -18,15 +18,19 @@ extern crate syn; extern crate wasm_bindgen_backend as backend; extern crate webidl; -use failure::ResultExt; -use heck::SnakeCase; -use proc_macro2::Ident; -use quote::ToTokens; use std::fs; use std::io::{self, Read}; -use std::iter::FromIterator; +use std::iter; use std::path::Path; +use failure::ResultExt; +use heck::CamelCase; +use quote::ToTokens; + +mod util; + +use util::{create_function, ident_ty, raw_ident, rust_ident, webidl_ty_to_syn_ty, TypePosition}; + /// Either `Ok(t)` or `Err(failure::Error)`. pub type Result = ::std::result::Result; @@ -70,43 +74,11 @@ fn compile_ast(ast: &backend::ast::Program) -> String { tokens.to_string() } -fn is_rust_keyword(name: &str) -> bool { - match name { - "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" - | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if" - | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" - | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return" - | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true" - | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while" - | "yield" | "bool" | "_" => true, - _ => false, - } +trait WebidlParse { + fn webidl_parse(&self, program: &mut backend::ast::Program, context: Ctx) -> Result<()>; } -// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword. -fn rust_ident(name: &str) -> Ident { - if is_rust_keyword(name) { - Ident::new(&format!("{}_", name), proc_macro2::Span::call_site()) - } else { - raw_ident(name) - } -} - -// Create an `Ident` without checking to see if it conflicts with a Rust -// keyword. -fn raw_ident(name: &str) -> Ident { - Ident::new(name, proc_macro2::Span::call_site()) -} - -trait WebidlParse<'a> { - type Extra; - - fn webidl_parse(&self, program: &mut backend::ast::Program, extra: Self::Extra) -> Result<()>; -} - -impl<'a> WebidlParse<'a> for Vec { - type Extra = (); - +impl WebidlParse<()> for Vec { fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> { for def in self { def.webidl_parse(program, ())?; @@ -115,9 +87,7 @@ impl<'a> WebidlParse<'a> for Vec { } } -impl<'a> WebidlParse<'a> for webidl::ast::Definition { - type Extra = (); - +impl WebidlParse<()> for webidl::ast::Definition { fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> { match *self { webidl::ast::Definition::Interface(ref interface) => { @@ -139,9 +109,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::Definition { } } -impl<'a> WebidlParse<'a> for webidl::ast::Interface { - type Extra = (); - +impl WebidlParse<()> for webidl::ast::Interface { fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> { match *self { webidl::ast::Interface::NonPartial(ref interface) => { @@ -156,9 +124,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::Interface { } } -impl<'a> WebidlParse<'a> for webidl::ast::Typedef { - type Extra = (); - +impl WebidlParse<()> for webidl::ast::Typedef { fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> { let dest = rust_ident(&self.name); let src = match webidl_ty_to_syn_ty(&self.type_, TypePosition::Return) { @@ -184,9 +150,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::Typedef { } } -impl<'a> WebidlParse<'a> for webidl::ast::NonPartialInterface { - type Extra = (); - +impl WebidlParse<()> for webidl::ast::NonPartialInterface { fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> { program.imports.push(backend::ast::Import { module: None, @@ -208,9 +172,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::NonPartialInterface { } } -impl<'a> WebidlParse<'a> for webidl::ast::InterfaceMember { - type Extra = &'a str; - +impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember { fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> { match *self { webidl::ast::InterfaceMember::Attribute(ref attr) => { @@ -229,9 +191,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::InterfaceMember { } } -impl<'a> WebidlParse<'a> for webidl::ast::Attribute { - type Extra = &'a str; - +impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute { fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> { match *self { webidl::ast::Attribute::Regular(ref attr) => attr.webidl_parse(program, self_name), @@ -244,9 +204,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::Attribute { } } -impl<'a> WebidlParse<'a> for webidl::ast::Operation { - type Extra = &'a str; - +impl<'a> WebidlParse<&'a str> for webidl::ast::Operation { fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> { match *self { webidl::ast::Operation::Regular(ref op) => op.webidl_parse(program, self_name), @@ -261,192 +219,39 @@ impl<'a> WebidlParse<'a> for webidl::ast::Operation { } } -fn simple_path_ty(segments: I) -> syn::Type -where - I: IntoIterator, -{ - let segments: Vec<_> = segments - .into_iter() - .map(|i| syn::PathSegment { - ident: i, - arguments: syn::PathArguments::None, - }) - .collect(); - - syn::TypePath { - qself: None, - path: syn::Path { - leading_colon: None, - segments: syn::punctuated::Punctuated::from_iter(segments), - }, - }.into() -} - -fn ident_ty(ident: Ident) -> syn::Type { - simple_path_ty(Some(ident)) -} - -fn shared_ref(ty: syn::Type) -> syn::Type { - syn::TypeReference { - and_token: Default::default(), - lifetime: None, - mutability: None, - elem: Box::new(ty), - }.into() -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum TypePosition { - Argument, - Return, -} - -fn webidl_ty_to_syn_ty(ty: &webidl::ast::Type, pos: TypePosition) -> Option { - // nullable types are not yet supported (see issue #14) - if ty.nullable { - return None; - } - Some(match ty.kind { - // `any` becomes `::wasm_bindgen::JsValue`. - webidl::ast::TypeKind::Any => { - simple_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]) - } - - // A reference to a type by name becomes the same thing in the - // bindings. - webidl::ast::TypeKind::Identifier(ref id) => ident_ty(rust_ident(id)), - - // Scalars. - webidl::ast::TypeKind::Boolean => ident_ty(raw_ident("bool")), - webidl::ast::TypeKind::Byte => ident_ty(raw_ident("i8")), - webidl::ast::TypeKind::Octet => ident_ty(raw_ident("u8")), - webidl::ast::TypeKind::RestrictedDouble | webidl::ast::TypeKind::UnrestrictedDouble => { - ident_ty(raw_ident("f64")) - } - webidl::ast::TypeKind::RestrictedFloat | webidl::ast::TypeKind::UnrestrictedFloat => { - ident_ty(raw_ident("f32")) - } - webidl::ast::TypeKind::SignedLong => ident_ty(raw_ident("i32")), - webidl::ast::TypeKind::SignedLongLong => ident_ty(raw_ident("i64")), - webidl::ast::TypeKind::SignedShort => ident_ty(raw_ident("i16")), - webidl::ast::TypeKind::UnsignedLong => ident_ty(raw_ident("u32")), - webidl::ast::TypeKind::UnsignedLongLong => ident_ty(raw_ident("u64")), - webidl::ast::TypeKind::UnsignedShort => ident_ty(raw_ident("u16")), - - // `DOMString -> `&str` for arguments - webidl::ast::TypeKind::DOMString if pos == TypePosition::Argument => { - shared_ref(ident_ty(raw_ident("str"))) - } - // `DOMString` is not supported yet in other positions. - webidl::ast::TypeKind::DOMString => return None, - - // Support for these types is not yet implemented, so skip - // generating any bindings for this function. - webidl::ast::TypeKind::ArrayBuffer - | webidl::ast::TypeKind::ByteString - | webidl::ast::TypeKind::DataView - | webidl::ast::TypeKind::Error - | webidl::ast::TypeKind::Float32Array - | webidl::ast::TypeKind::Float64Array - | webidl::ast::TypeKind::FrozenArray(_) - | webidl::ast::TypeKind::Int16Array - | webidl::ast::TypeKind::Int32Array - | webidl::ast::TypeKind::Int8Array - | webidl::ast::TypeKind::Object - | webidl::ast::TypeKind::Promise(_) - | webidl::ast::TypeKind::Record(..) - | webidl::ast::TypeKind::Sequence(_) - | webidl::ast::TypeKind::Symbol - | webidl::ast::TypeKind::USVString - | webidl::ast::TypeKind::Uint16Array - | webidl::ast::TypeKind::Uint32Array - | webidl::ast::TypeKind::Uint8Array - | webidl::ast::TypeKind::Uint8ClampedArray - | webidl::ast::TypeKind::Union(_) => { - return None; - } - }) -} - -fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::FnArg { - syn::FnArg::Captured(syn::ArgCaptured { - pat: syn::Pat::Ident(syn::PatIdent { - by_ref: None, - mutability: None, - ident, - subpat: None, - }), - colon_token: Default::default(), - ty, - }) -} - -impl<'a> WebidlParse<'a> for webidl::ast::RegularAttribute { - type Extra = &'a str; - +impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute { fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> { fn create_getter( this: &webidl::ast::RegularAttribute, self_name: &str, ) -> Option { - let name = raw_ident(&this.name); - let rust_name = rust_ident(&this.name.to_snake_case()); - - let (output, ret) = match webidl_ty_to_syn_ty(&this.type_, TypePosition::Return) { + let ret = match webidl_ty_to_syn_ty(&this.type_, TypePosition::Return) { None => { warn!("Attribute's type does not yet support reading: {:?}. Skipping getter binding for {:?}", this.type_, this); return None; } - Some(ty) => ( - syn::ReturnType::Type(Default::default(), Box::new(ty.clone())), - Some(ty), - ), + Some(ty) => Some(ty), }; - let self_ty = ident_ty(rust_ident(self_name)); - let self_ref_ty = shared_ref(self_ty.clone()); + let kind = backend::ast::ImportFunctionKind::Method { + class: self_name.to_string(), + ty: ident_ty(rust_ident(self_name)), + }; - let shim = rust_ident(&format!("__wbg_f_{}_{}_{}", name, rust_name, self_name)); - - Some(backend::ast::Import { + create_function( + &this.name, + iter::empty(), + kind, + ret, + vec![backend::ast::BindgenAttr::Getter(Some(raw_ident( + &this.name, + )))], + ).map(|function| backend::ast::Import { module: None, version: None, js_namespace: None, - kind: backend::ast::ImportKind::Function(backend::ast::ImportFunction { - function: backend::ast::Function { - name: name.clone(), - arguments: vec![self_ref_ty.clone()], - ret, - opts: backend::ast::BindgenAttrs { - attrs: vec![ - backend::ast::BindgenAttr::Method, - backend::ast::BindgenAttr::Getter(Some(name.clone())), - ], - }, - rust_attrs: vec![], - rust_decl: Box::new(syn::FnDecl { - fn_token: Default::default(), - generics: Default::default(), - paren_token: Default::default(), - inputs: syn::punctuated::Punctuated::from_iter(vec![simple_fn_arg( - raw_ident("self_"), - self_ref_ty, - )]), - variadic: None, - output, - }), - rust_vis: syn::Visibility::Public(syn::VisPublic { - pub_token: Default::default(), - }), - }, - rust_name, - kind: backend::ast::ImportFunctionKind::Method { - class: self_name.to_string(), - ty: self_ty, - }, - shim, - }), + kind: backend::ast::ImportKind::Function(function), }) } @@ -454,65 +259,24 @@ impl<'a> WebidlParse<'a> for webidl::ast::RegularAttribute { this: &webidl::ast::RegularAttribute, self_name: &str, ) -> Option { - let name = raw_ident(&this.name); - let rust_attr_name = rust_ident(&this.name.to_snake_case()); - let rust_name = rust_ident(&format!("set_{}", rust_attr_name)); - - let self_ty = ident_ty(rust_ident(self_name)); - - let (inputs, arguments) = match webidl_ty_to_syn_ty(&this.type_, TypePosition::Argument) - { - None => { - warn!("Attribute's type does not yet support writing: {:?}. Skipping setter binding for {:?}", - this.type_, this); - return None; - } - Some(ty) => { - let self_ref_ty = shared_ref(self_ty.clone()); - let mut inputs = syn::punctuated::Punctuated::new(); - inputs.push(simple_fn_arg(raw_ident("self_"), self_ref_ty.clone())); - inputs.push(simple_fn_arg(rust_attr_name, ty.clone())); - (inputs, vec![self_ref_ty, ty]) - } + let kind = backend::ast::ImportFunctionKind::Method { + class: self_name.to_string(), + ty: ident_ty(rust_ident(self_name)), }; - let shim = rust_ident(&format!("__wbg_f_{}_{}_{}", name, rust_name, self_name)); - - Some(backend::ast::Import { + create_function( + &format!("set_{}", this.name.to_camel_case()), + iter::once((&*this.name, &*this.type_, false)), + kind, + None, + vec![backend::ast::BindgenAttr::Setter(Some(raw_ident( + &this.name, + )))], + ).map(|function| backend::ast::Import { module: None, version: None, js_namespace: None, - kind: backend::ast::ImportKind::Function(backend::ast::ImportFunction { - function: backend::ast::Function { - name: name.clone(), - arguments, - ret: None, - opts: backend::ast::BindgenAttrs { - attrs: vec![ - backend::ast::BindgenAttr::Method, - backend::ast::BindgenAttr::Setter(Some(name)), - ], - }, - rust_attrs: vec![], - rust_decl: Box::new(syn::FnDecl { - fn_token: Default::default(), - generics: Default::default(), - paren_token: Default::default(), - inputs, - variadic: None, - output: syn::ReturnType::Default, - }), - rust_vis: syn::Visibility::Public(syn::VisPublic { - pub_token: Default::default(), - }), - }, - rust_name, - kind: backend::ast::ImportFunctionKind::Method { - class: self_name.to_string(), - ty: self_ty, - }, - shim, - }), + kind: backend::ast::ImportKind::Function(function), }) } @@ -526,9 +290,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::RegularAttribute { } } -impl<'a> WebidlParse<'a> for webidl::ast::RegularOperation { - type Extra = &'a str; - +impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation { fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> { let name = match self.name { None => { @@ -541,11 +303,13 @@ impl<'a> WebidlParse<'a> for webidl::ast::RegularOperation { Some(ref name) => name, }; - let rust_name = rust_ident(&name.to_snake_case()); - let name = raw_ident(name); + let kind = backend::ast::ImportFunctionKind::Method { + class: self_name.to_string(), + ty: ident_ty(rust_ident(self_name)), + }; - let (output, ret) = match self.return_type { - webidl::ast::ReturnType::Void => (syn::ReturnType::Default, None), + let ret = match self.return_type { + webidl::ast::ReturnType::Void => None, webidl::ast::ReturnType::NonVoid(ref ty) => { match webidl_ty_to_syn_ty(ty, TypePosition::Return) { None => { @@ -555,80 +319,26 @@ impl<'a> WebidlParse<'a> for webidl::ast::RegularOperation { ); return Ok(()); } - Some(ty) => ( - syn::ReturnType::Type(Default::default(), Box::new(ty.clone())), - Some(ty), - ), + Some(ty) => Some(ty), } } }; - let mut inputs = Vec::with_capacity(self.arguments.len() + 1); - let mut arguments = Vec::with_capacity(self.arguments.len() + 1); - - let self_ty = ident_ty(rust_ident(self_name)); - let self_ref_ty = shared_ref(self_ty.clone()); - inputs.push(simple_fn_arg(raw_ident("self_"), self_ref_ty.clone())); - arguments.push(self_ref_ty); - - for arg in &self.arguments { - if arg.variadic { - warn!( - "Variadic arguments are not supported yet. Skipping bindings for {:?}", - self - ); - return Ok(()); - } - - match webidl_ty_to_syn_ty(&arg.type_, TypePosition::Argument) { - None => { - warn!( - "Argument's type is not yet supported: {:?}. Skipping bindings for {:?}", - arg.type_, self - ); - return Ok(()); - } - Some(ty) => { - inputs.push(simple_fn_arg(rust_ident(&arg.name), ty.clone())); - arguments.push(ty); - } - } - } - - let shim = rust_ident(&format!("__wbg_f_{}_{}_{}", name, rust_name, self_name)); - - program.imports.push(backend::ast::Import { - module: None, - version: None, - js_namespace: None, - kind: backend::ast::ImportKind::Function(backend::ast::ImportFunction { - function: backend::ast::Function { - name, - arguments, - ret, - opts: backend::ast::BindgenAttrs { - attrs: vec![backend::ast::BindgenAttr::Method], - }, - rust_attrs: vec![], - rust_decl: Box::new(syn::FnDecl { - fn_token: Default::default(), - generics: Default::default(), - paren_token: Default::default(), - inputs: syn::punctuated::Punctuated::from_iter(inputs), - variadic: None, - output, - }), - rust_vis: syn::Visibility::Public(syn::VisPublic { - pub_token: Default::default(), - }), - }, - rust_name, - kind: backend::ast::ImportFunctionKind::Method { - class: self_name.to_string(), - ty: self_ty, - }, - shim, - }), + create_function( + &name, + self.arguments + .iter() + .map(|arg| (&*arg.name, &*arg.type_, arg.variadic)), + kind, + ret, + Vec::new(), + ).map(|function| { + program.imports.push(backend::ast::Import { + module: None, + version: None, + js_namespace: None, + kind: backend::ast::ImportKind::Function(function), + }) }); Ok(()) diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs new file mode 100644 index 00000000..7d07569e --- /dev/null +++ b/crates/webidl/src/util.rs @@ -0,0 +1,241 @@ +use std::iter::FromIterator; + +use backend; +use heck::SnakeCase; +use proc_macro2::{self, Ident}; +use syn; +use webidl; + +fn is_rust_keyword(name: &str) -> bool { + match name { + "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" + | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if" + | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" + | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return" + | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true" + | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while" + | "yield" | "bool" | "_" => true, + _ => false, + } +} + +// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword. +pub fn rust_ident(name: &str) -> Ident { + if is_rust_keyword(name) { + Ident::new(&format!("{}_", name), proc_macro2::Span::call_site()) + } else { + raw_ident(name) + } +} + +// Create an `Ident` without checking to see if it conflicts with a Rust +// keyword. +pub fn raw_ident(name: &str) -> Ident { + Ident::new(name, proc_macro2::Span::call_site()) +} + +fn simple_path_ty(segments: I) -> syn::Type +where + I: IntoIterator, +{ + let segments: Vec<_> = segments + .into_iter() + .map(|i| syn::PathSegment { + ident: i, + arguments: syn::PathArguments::None, + }) + .collect(); + + syn::TypePath { + qself: None, + path: syn::Path { + leading_colon: None, + segments: syn::punctuated::Punctuated::from_iter(segments), + }, + }.into() +} + +pub fn ident_ty(ident: Ident) -> syn::Type { + simple_path_ty(Some(ident)) +} + +fn shared_ref(ty: syn::Type) -> syn::Type { + syn::TypeReference { + and_token: Default::default(), + lifetime: None, + mutability: None, + elem: Box::new(ty), + }.into() +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum TypePosition { + Argument, + Return, +} + +pub fn webidl_ty_to_syn_ty(ty: &webidl::ast::Type, pos: TypePosition) -> Option { + // nullable types are not yet supported (see issue #14) + if ty.nullable { + return None; + } + Some(match ty.kind { + // `any` becomes `::wasm_bindgen::JsValue`. + webidl::ast::TypeKind::Any => { + simple_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]) + } + + // A reference to a type by name becomes the same thing in the + // bindings. + webidl::ast::TypeKind::Identifier(ref id) => ident_ty(rust_ident(id)), + + // Scalars. + webidl::ast::TypeKind::Boolean => ident_ty(raw_ident("bool")), + webidl::ast::TypeKind::Byte => ident_ty(raw_ident("i8")), + webidl::ast::TypeKind::Octet => ident_ty(raw_ident("u8")), + webidl::ast::TypeKind::RestrictedDouble | webidl::ast::TypeKind::UnrestrictedDouble => { + ident_ty(raw_ident("f64")) + } + webidl::ast::TypeKind::RestrictedFloat | webidl::ast::TypeKind::UnrestrictedFloat => { + ident_ty(raw_ident("f32")) + } + webidl::ast::TypeKind::SignedLong => ident_ty(raw_ident("i32")), + webidl::ast::TypeKind::SignedLongLong => ident_ty(raw_ident("i64")), + webidl::ast::TypeKind::SignedShort => ident_ty(raw_ident("i16")), + webidl::ast::TypeKind::UnsignedLong => ident_ty(raw_ident("u32")), + webidl::ast::TypeKind::UnsignedLongLong => ident_ty(raw_ident("u64")), + webidl::ast::TypeKind::UnsignedShort => ident_ty(raw_ident("u16")), + + // `DOMString -> `&str` for arguments + webidl::ast::TypeKind::DOMString if pos == TypePosition::Argument => { + shared_ref(ident_ty(raw_ident("str"))) + } + // `DOMString` is not supported yet in other positions. + webidl::ast::TypeKind::DOMString => return None, + + // Support for these types is not yet implemented, so skip + // generating any bindings for this function. + webidl::ast::TypeKind::ArrayBuffer + | webidl::ast::TypeKind::ByteString + | webidl::ast::TypeKind::DataView + | webidl::ast::TypeKind::Error + | webidl::ast::TypeKind::Float32Array + | webidl::ast::TypeKind::Float64Array + | webidl::ast::TypeKind::FrozenArray(_) + | webidl::ast::TypeKind::Int16Array + | webidl::ast::TypeKind::Int32Array + | webidl::ast::TypeKind::Int8Array + | webidl::ast::TypeKind::Object + | webidl::ast::TypeKind::Promise(_) + | webidl::ast::TypeKind::Record(..) + | webidl::ast::TypeKind::Sequence(_) + | webidl::ast::TypeKind::Symbol + | webidl::ast::TypeKind::USVString + | webidl::ast::TypeKind::Uint16Array + | webidl::ast::TypeKind::Uint32Array + | webidl::ast::TypeKind::Uint8Array + | webidl::ast::TypeKind::Uint8ClampedArray + | webidl::ast::TypeKind::Union(_) => { + return None; + } + }) +} + +fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured { + syn::ArgCaptured { + pat: syn::Pat::Ident(syn::PatIdent { + by_ref: None, + mutability: None, + ident, + subpat: None, + }), + colon_token: Default::default(), + ty, + } +} + +fn webidl_arguments_to_syn_arg_captured<'a, I>( + arguments: I, + kind: &backend::ast::ImportFunctionKind, +) -> Option> +where + I: Iterator, +{ + let estimate = arguments.size_hint(); + let len = estimate.1.unwrap_or(estimate.0); + let mut res = if let backend::ast::ImportFunctionKind::Method { ty, .. } = kind { + let mut res = Vec::with_capacity(len + 1); + res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone()))); + res + } else { + Vec::with_capacity(len) + }; + + for (name, ty, variadic) in arguments { + if variadic { + warn!("Variadic arguments are not supported yet",); + return None; + } + + match webidl_ty_to_syn_ty(ty, TypePosition::Argument) { + None => { + warn!("Argument's type is not yet supported: {:?}", ty); + return None; + } + Some(ty) => res.push(simple_fn_arg(rust_ident(&name.to_snake_case()), ty)), + } + } + + Some(res) +} + +pub fn create_function<'a, 'b, I>( + name: &str, + arguments: I, + kind: backend::ast::ImportFunctionKind, + ret: Option, + mut attrs: Vec, +) -> Option +where + I: Iterator, +{ + let rust_name = rust_ident(&name.to_snake_case()); + let name = raw_ident(name); + + let arguments = webidl_arguments_to_syn_arg_captured(arguments, &kind)?; + + let js_ret = ret.clone(); + + if let backend::ast::ImportFunctionKind::Method { .. } = kind { + attrs.push(backend::ast::BindgenAttr::Method); + } + + let opts = backend::ast::BindgenAttrs { attrs }; + + let shim = { + let ns = match kind { + backend::ast::ImportFunctionKind::Normal => "", + backend::ast::ImportFunctionKind::Method { ref class, .. } => class, + backend::ast::ImportFunctionKind::JsConstructor { ref class, .. } => class, + }; + + raw_ident(&format!("__widl_f_{}_{}", rust_name, ns)) + }; + + Some(backend::ast::ImportFunction { + function: backend::ast::Function { + name, + arguments, + ret, + opts, + rust_attrs: vec![], + rust_vis: syn::Visibility::Public(syn::VisPublic { + pub_token: Default::default(), + }), + }, + rust_name, + js_ret, + kind, + shim, + }) +} diff --git a/crates/webidl/tests/expected/Event.rs b/crates/webidl/tests/expected/Event.rs index 6cc4fd66..e19cabc5 100644 --- a/crates/webidl/tests/expected/Event.rs +++ b/crates/webidl/tests/expected/Event.rs @@ -55,7 +55,7 @@ impl From for ::wasm_bindgen::JsValue { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_eventPhase_event_phase_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_event_phase_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -70,7 +70,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_eventPhase_event_phase_Event( + fn __widl_f_event_phase_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -79,7 +79,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_eventPhase_event_phase_Event(self_) + __widl_f_event_phase_Event(self_) }; ::from_abi( _ret, @@ -98,7 +98,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_stopPropagation_stop_propagation_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_stop_propagation_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -112,7 +112,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_stopPropagation_stop_propagation_Event( + fn __widl_f_stop_propagation_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> (); } @@ -121,7 +121,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_stopPropagation_stop_propagation_Event(self_) + __widl_f_stop_propagation_Event(self_) }; () } @@ -137,8 +137,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_stopImmediatePropagation_stop_immediate_propagation_Event( -) { +pub extern "C" fn __wbindgen_describe___widl_f_stop_immediate_propagation_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -152,7 +151,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_stopImmediatePropagation_stop_immediate_propagation_Event( + fn __widl_f_stop_immediate_propagation_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> (); } @@ -161,7 +160,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_stopImmediatePropagation_stop_immediate_propagation_Event(self_) + __widl_f_stop_immediate_propagation_Event(self_) }; () } @@ -177,7 +176,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_bubbles_bubbles_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_bubbles_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -192,7 +191,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_bubbles_bubbles_Event( + fn __widl_f_bubbles_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -201,7 +200,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_bubbles_bubbles_Event(self_) + __widl_f_bubbles_Event(self_) }; ::from_abi( _ret, @@ -220,7 +219,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_cancelable_cancelable_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_cancelable_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -235,7 +234,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_cancelable_cancelable_Event( + fn __widl_f_cancelable_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -244,7 +243,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_cancelable_cancelable_Event(self_) + __widl_f_cancelable_Event(self_) }; ::from_abi( _ret, @@ -263,7 +262,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_preventDefault_prevent_default_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_prevent_default_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -277,7 +276,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_preventDefault_prevent_default_Event( + fn __widl_f_prevent_default_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> (); } @@ -286,7 +285,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_preventDefault_prevent_default_Event(self_) + __widl_f_prevent_default_Event(self_) }; () } @@ -302,7 +301,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_defaultPrevented_default_prevented_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_default_prevented_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -317,7 +316,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_defaultPrevented_default_prevented_Event( + fn __widl_f_default_prevented_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -326,7 +325,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_defaultPrevented_default_prevented_Event(self_) + __widl_f_default_prevented_Event(self_) }; ::from_abi( _ret, @@ -345,8 +344,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_defaultPreventedByChrome_default_prevented_by_chrome_Event( -) { +pub extern "C" fn __wbindgen_describe___widl_f_default_prevented_by_chrome_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -361,7 +359,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_defaultPreventedByChrome_default_prevented_by_chrome_Event( + fn __widl_f_default_prevented_by_chrome_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -370,7 +368,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_defaultPreventedByChrome_default_prevented_by_chrome_Event(self_) + __widl_f_default_prevented_by_chrome_Event(self_) }; ::from_abi( _ret, @@ -389,8 +387,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_defaultPreventedByContent_default_prevented_by_content_Event( -) { +pub extern "C" fn __wbindgen_describe___widl_f_default_prevented_by_content_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -405,7 +402,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_defaultPreventedByContent_default_prevented_by_content_Event( + fn __widl_f_default_prevented_by_content_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -414,7 +411,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_defaultPreventedByContent_default_prevented_by_content_Event(self_) + __widl_f_default_prevented_by_content_Event(self_) }; ::from_abi( _ret, @@ -433,7 +430,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_composed_composed_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_composed_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -448,7 +445,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_composed_composed_Event( + fn __widl_f_composed_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -457,7 +454,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_composed_composed_Event(self_) + __widl_f_composed_Event(self_) }; ::from_abi( _ret, @@ -476,7 +473,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_isTrusted_is_trusted_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_is_trusted_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -491,7 +488,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_isTrusted_is_trusted_Event( + fn __widl_f_is_trusted_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -500,7 +497,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_isTrusted_is_trusted_Event(self_) + __widl_f_is_trusted_Event(self_) }; ::from_abi( _ret, @@ -519,7 +516,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_timeStamp_time_stamp_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_time_stamp_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -534,7 +531,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_timeStamp_time_stamp_Event( + fn __widl_f_time_stamp_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -543,7 +540,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_timeStamp_time_stamp_Event(self_) + __widl_f_time_stamp_Event(self_) }; ::from_abi( _ret, @@ -562,7 +559,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_initEvent_init_event_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_init_event_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(4u32); @@ -579,7 +576,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_initEvent_init_event_Event( + fn __widl_f_init_event_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, type_: <&str as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, bubbles: ::Abi, @@ -599,7 +596,7 @@ impl Event { cancelable, &mut __stack, ); - __wbg_f_initEvent_init_event_Event(self_, type_, bubbles, cancelable) + __widl_f_init_event_Event(self_, type_, bubbles, cancelable) }; () } @@ -615,7 +612,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_cancelBubble_cancel_bubble_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_cancel_bubble_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(1u32); @@ -630,7 +627,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_cancelBubble_cancel_bubble_Event( + fn __widl_f_cancel_bubble_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, ) -> ::Abi; } @@ -639,7 +636,7 @@ impl Event { let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); let self_ = <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(self, &mut __stack); - __wbg_f_cancelBubble_cancel_bubble_Event(self_) + __widl_f_cancel_bubble_Event(self_) }; ::from_abi( _ret, @@ -658,7 +655,7 @@ impl Event { } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn __wbindgen_describe___wbg_f_cancelBubble_set_cancel_bubble_Event() { +pub extern "C" fn __wbindgen_describe___widl_f_set_cancel_bubble_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); inform(2u32); @@ -673,7 +670,7 @@ impl Event { ::wasm_bindgen::__rt::link_this_library(); #[wasm_import_module = "__wbindgen_placeholder__"] extern "C" { - fn __wbg_f_cancelBubble_set_cancel_bubble_Event( + fn __widl_f_set_cancel_bubble_Event( self_: <&Event as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, cancel_bubble: ::Abi, ) -> (); @@ -687,7 +684,7 @@ impl Event { cancel_bubble, &mut __stack, ); - __wbg_f_cancelBubble_set_cancel_bubble_Event(self_, cancel_bubble) + __widl_f_set_cancel_bubble_Event(self_, cancel_bubble) }; () } @@ -705,4 +702,4 @@ impl Event { pub type DOMHighResTimeStamp = f64; #[allow(non_upper_case_globals)] #[wasm_custom_section = "__wasm_bindgen_unstable"] -const __WASM_BINDGEN_GENERATED_wasm_bindgen_webidl_0_2_11_0 : [ u8 ; 4413usize ] = * b"9\x11\0\0{\"exports\":[],\"enums\":[],\"imports\":[{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"type\"}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_eventPhase_event_phase_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"eventPhase\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"eventPhase\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_stopPropagation_stop_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopPropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_stopImmediatePropagation_stop_immediate_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopImmediatePropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_bubbles_bubbles_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"bubbles\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"bubbles\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_cancelable_cancelable_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelable\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelable\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_preventDefault_prevent_default_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"preventDefault\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_defaultPrevented_default_prevented_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPrevented\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPrevented\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_defaultPreventedByChrome_default_prevented_by_chrome_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByChrome\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByChrome\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_defaultPreventedByContent_default_prevented_by_content_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByContent\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByContent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_composed_composed_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"composed\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"composed\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_isTrusted_is_trusted_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"isTrusted\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"isTrusted\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_timeStamp_time_stamp_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"timeStamp\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"timeStamp\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_initEvent_init_event_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"initEvent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_cancelBubble_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelBubble\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelBubble\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__wbg_f_cancelBubble_set_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":\"cancelBubble\",\"class\":\"Event\",\"function\":{\"name\":\"cancelBubble\"}}}],\"structs\":[],\"version\":\"0.2.11 (71107b8e8)\",\"schema_version\":\"4\"}" ; +const __WASM_BINDGEN_GENERATED_wasm_bindgen_webidl_0_2_11_0 : [ u8 ; 4213usize ] = * b"q\x10\0\0{\"exports\":[],\"enums\":[],\"imports\":[{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"type\"}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_event_phase_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"eventPhase\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"eventPhase\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_stop_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopPropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_stop_immediate_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopImmediatePropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_bubbles_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"bubbles\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"bubbles\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_cancelable_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelable\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelable\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_prevent_default_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"preventDefault\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPrevented\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPrevented\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_by_chrome_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByChrome\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByChrome\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_by_content_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByContent\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByContent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_composed_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"composed\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"composed\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_is_trusted_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"isTrusted\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"isTrusted\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_time_stamp_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"timeStamp\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"timeStamp\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_init_event_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"initEvent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelBubble\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelBubble\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_set_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":\"cancelBubble\",\"class\":\"Event\",\"function\":{\"name\":\"set_CancelBubble\"}}}],\"structs\":[],\"version\":\"0.2.11 (0cd767c9d)\",\"schema_version\":\"4\"}" ; From c65cb51fba75daac386d21bde139367765f0a8af Mon Sep 17 00:00:00 2001 From: "R. Andrew Ohana" Date: Thu, 14 Jun 2018 15:35:48 -0700 Subject: [PATCH 2/3] webidl: add support for constructors --- crates/webidl/src/lib.rs | 59 ++++++++++++ crates/webidl/tests/expected/Event.rs | 53 ++++++++++- crates/webidl/tests/fixtures/Event.webidl | 9 ++ tests/all/webidl/simple.rs | 105 ++++++++++++++++------ 4 files changed, 200 insertions(+), 26 deletions(-) diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index adec017d..b78e52a0 100755 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -164,6 +164,10 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface { }), }); + for extended_attribute in &self.extended_attributes { + extended_attribute.webidl_parse(program, self)?; + } + for member in &self.members { member.webidl_parse(program, &self.name)?; } @@ -172,6 +176,61 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface { } } +impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::ExtendedAttribute { + fn webidl_parse( + &self, + program: &mut backend::ast::Program, + interface: &'a webidl::ast::NonPartialInterface, + ) -> Result<()> { + let mut add_constructor = |arguments: &[webidl::ast::Argument]| { + let self_ty = ident_ty(rust_ident(&interface.name)); + let kind = backend::ast::ImportFunctionKind::JsConstructor { + class: interface.name.to_string(), + ty: self_ty.clone(), + }; + create_function( + "new", + arguments + .iter() + .map(|arg| (&*arg.name, &*arg.type_, arg.variadic)), + kind, + Some(self_ty), + vec![backend::ast::BindgenAttr::Constructor], + ).map(|function| { + program.imports.push(backend::ast::Import { + module: None, + version: None, + js_namespace: None, + kind: backend::ast::ImportKind::Function(function), + }) + }) + }; + + match self { + webidl::ast::ExtendedAttribute::ArgumentList( + webidl::ast::ArgumentListExtendedAttribute { arguments, name }, + ) if name == "Constructor" => + { + add_constructor(&*arguments); + } + webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) + if name == "Constructor" => + { + add_constructor(&[] as &[_]); + } + webidl::ast::ExtendedAttribute::ArgumentList(_) + | webidl::ast::ExtendedAttribute::Identifier(_) + | webidl::ast::ExtendedAttribute::IdentifierList(_) + | webidl::ast::ExtendedAttribute::NamedArgumentList(_) + | webidl::ast::ExtendedAttribute::NoArguments(_) => { + warn!("Unsupported WebIDL extended attribute: {:?}", self); + } + } + + Ok(()) + } +} + impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember { fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> { match *self { diff --git a/crates/webidl/tests/expected/Event.rs b/crates/webidl/tests/expected/Event.rs index e19cabc5..51807c4d 100644 --- a/crates/webidl/tests/expected/Event.rs +++ b/crates/webidl/tests/expected/Event.rs @@ -55,6 +55,55 @@ impl From for ::wasm_bindgen::JsValue { } #[no_mangle] #[allow(non_snake_case)] +pub extern "C" fn __wbindgen_describe___widl_f_new_Event() { + use wasm_bindgen::describe::*; + inform(FUNCTION); + inform(2u32); + <&str as WasmDescribe>::describe(); + ::describe(); + inform(1); + ::describe(); +} +impl Event { + #[allow(bad_style)] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] + pub extern "C" fn new(type_: &str, event_init_dict: EventInit) -> Event { + ::wasm_bindgen::__rt::link_this_library(); + #[wasm_import_module = "__wbindgen_placeholder__"] + extern "C" { + fn __widl_f_new_Event( + type_: <&str as ::wasm_bindgen::convert::IntoWasmAbi>::Abi, + event_init_dict: ::Abi, + ) -> ::Abi; + } + unsafe { + let _ret = { + let mut __stack = ::wasm_bindgen::convert::GlobalStack::new(); + let type_ = + <&str as ::wasm_bindgen::convert::IntoWasmAbi>::into_abi(type_, &mut __stack); + let event_init_dict = ::into_abi( + event_init_dict, + &mut __stack, + ); + __widl_f_new_Event(type_, event_init_dict) + }; + ::from_abi( + _ret, + &mut ::wasm_bindgen::convert::GlobalStack::new(), + ) + } + } + #[allow(bad_style, unused_variables)] + #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] + pub extern "C" fn new(type_: &str, event_init_dict: EventInit) -> Event { + panic!( + "cannot call wasm-bindgen imported functions on \ + non-wasm targets" + ); + } +} +#[no_mangle] +#[allow(non_snake_case)] pub extern "C" fn __wbindgen_describe___widl_f_event_phase_Event() { use wasm_bindgen::describe::*; inform(FUNCTION); @@ -700,6 +749,8 @@ impl Event { } #[allow(non_camel_case_types)] pub type DOMHighResTimeStamp = f64; +#[allow(non_camel_case_types)] +pub type EventInit = bool; #[allow(non_upper_case_globals)] #[wasm_custom_section = "__wasm_bindgen_unstable"] -const __WASM_BINDGEN_GENERATED_wasm_bindgen_webidl_0_2_11_0 : [ u8 ; 4213usize ] = * b"q\x10\0\0{\"exports\":[],\"enums\":[],\"imports\":[{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"type\"}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_event_phase_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"eventPhase\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"eventPhase\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_stop_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopPropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_stop_immediate_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopImmediatePropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_bubbles_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"bubbles\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"bubbles\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_cancelable_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelable\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelable\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_prevent_default_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"preventDefault\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPrevented\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPrevented\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_by_chrome_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByChrome\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByChrome\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_by_content_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByContent\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByContent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_composed_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"composed\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"composed\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_is_trusted_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"isTrusted\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"isTrusted\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_time_stamp_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"timeStamp\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"timeStamp\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_init_event_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"initEvent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelBubble\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelBubble\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_set_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":\"cancelBubble\",\"class\":\"Event\",\"function\":{\"name\":\"set_CancelBubble\"}}}],\"structs\":[],\"version\":\"0.2.11 (0cd767c9d)\",\"schema_version\":\"4\"}" ; +const __WASM_BINDGEN_GENERATED_wasm_bindgen_webidl_0_2_11_0 : [ u8 ; 4451usize ] = * b"_\x11\0\0{\"exports\":[],\"enums\":[],\"imports\":[{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"type\"}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_new_Event\",\"catch\":false,\"method\":false,\"js_new\":true,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"new\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_event_phase_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"eventPhase\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"eventPhase\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_stop_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopPropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_stop_immediate_propagation_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"stopImmediatePropagation\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_bubbles_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"bubbles\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"bubbles\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_cancelable_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelable\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelable\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_prevent_default_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"preventDefault\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPrevented\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPrevented\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_by_chrome_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByChrome\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByChrome\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_default_prevented_by_content_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"defaultPreventedByContent\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"defaultPreventedByContent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_composed_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"composed\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"composed\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_is_trusted_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"isTrusted\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"isTrusted\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_time_stamp_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"timeStamp\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"timeStamp\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_init_event_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"initEvent\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":\"cancelBubble\",\"setter\":null,\"class\":\"Event\",\"function\":{\"name\":\"cancelBubble\"}}},{\"module\":null,\"version\":null,\"js_namespace\":null,\"kind\":{\"kind\":\"function\",\"shim\":\"__widl_f_set_cancel_bubble_Event\",\"catch\":false,\"method\":true,\"js_new\":false,\"structural\":false,\"getter\":null,\"setter\":\"cancelBubble\",\"class\":\"Event\",\"function\":{\"name\":\"set_CancelBubble\"}}}],\"structs\":[],\"version\":\"0.2.11 (0cd767c9d)\",\"schema_version\":\"4\"}" ; diff --git a/crates/webidl/tests/fixtures/Event.webidl b/crates/webidl/tests/fixtures/Event.webidl index 8dea443a..78ab021b 100644 --- a/crates/webidl/tests/fixtures/Event.webidl +++ b/crates/webidl/tests/fixtures/Event.webidl @@ -13,6 +13,9 @@ // TODO: don't include this here, use Performance.webidl instead typedef double DOMHighResTimeStamp; +// TODO: remove this when dicts are resolved +typedef boolean EventInit; + [Constructor(DOMString type, optional EventInit eventInitDict), Exposed=(Window,Worker,System), ProbablyShortLivingWrapper] interface Event { @@ -60,3 +63,9 @@ interface Event { optional boolean cancelable = false); attribute boolean cancelBubble; }; + +dictionary EventInit { + boolean bubbles = false; + boolean cancelable = false; + boolean composed = false; +}; diff --git a/tests/all/webidl/simple.rs b/tests/all/webidl/simple.rs index d13a228e..7b67d6cc 100644 --- a/tests/all/webidl/simple.rs +++ b/tests/all/webidl/simple.rs @@ -1,15 +1,15 @@ use super::project; #[test] -fn webidl() { +fn method() { project() .file( "foo.webidl", r#" - [Constructor(float value)] + [Constructor(double value)] interface Foo { [Pure] - boolean my_cmp(Foo bar); + boolean myCmp(Foo bar); }; "#, ) @@ -17,11 +17,10 @@ fn webidl() { "foo.ts", r#" export class Foo { - value: number; - constructor(value: number) { + constructor(private value: number) { this.value = value; } - my_cmp(other: Foo): boolean { + myCmp(other: Foo): boolean { return this.value === other.value; } } @@ -38,26 +37,82 @@ fn webidl() { pub mod foo; - #[wasm_bindgen] - pub fn call_my_cmp(first: &foo::Foo, second: foo::Foo) -> bool { - first.my_cmp(second) - } - "#, - ) - .file( - "test.ts", - r#" - import * as assert from 'assert'; - import * as wasm from './out'; - import {Foo} from './foo'; + use foo::Foo; - export function test() { - const pi = new Foo(3.14159); - const e = new Foo(2.71828); - assert.strictEqual(wasm.call_my_cmp(pi, pi), true); - assert.strictEqual(wasm.call_my_cmp(pi, e), false); - assert.strictEqual(wasm.call_my_cmp(e, pi), false); - assert.strictEqual(wasm.call_my_cmp(e, e), true); + #[wasm_bindgen] + pub fn test() { + let pi = Foo::new(3.14159); + let e = Foo::new(2.71828); + let tmp = pi.my_cmp(Foo::new(3.14159)); + assert!(tmp); + let tmp =!pi.my_cmp(Foo::new(2.71828)); + assert!(tmp); + let tmp = !e.my_cmp(Foo::new(3.14159)); + assert!(tmp); + let tmp = e.my_cmp(Foo::new(2.71828)); + assert!(tmp); + } + "#, + ) + .test(); +} + +#[test] +fn property() { + project() + .file( + "foo.webidl", + r#" + [Constructor(double value)] + interface Foo { + [Pure] + attribute double value; + }; + "#, + ) + .file( + "foo.ts", + r#" + export class Foo { + constructor(private _value: number) { + this._value = _value; + } + + get value(): number { + return this._value; + } + + set value(_value: number) { + this._value = _value; + } + } + "#, + ) + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + pub mod foo; + + use foo::Foo; + + #[wasm_bindgen] + pub fn test() { + let x = Foo::new(3.14159); + let tmp = x.value() == 3.14159; + assert!(tmp); + let tmp = x.value() != 2.71828; + assert!(tmp); + x.set_value(2.71828); + let tmp = x.value() != 3.14159; + assert!(tmp); + let tmp = x.value() == 2.71828; + assert!(tmp); } "#, ) From cbec42e86c24e754d2fe73abb11792328eaf7913 Mon Sep 17 00:00:00 2001 From: "R. Andrew Ohana" Date: Thu, 14 Jun 2018 16:20:20 -0700 Subject: [PATCH 3/3] webidl: add support for named constructors --- crates/webidl/src/lib.rs | 18 +++++++++--- tests/all/webidl/simple.rs | 58 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index b78e52a0..04f409cc 100755 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -182,10 +182,10 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte program: &mut backend::ast::Program, interface: &'a webidl::ast::NonPartialInterface, ) -> Result<()> { - let mut add_constructor = |arguments: &[webidl::ast::Argument]| { + let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| { let self_ty = ident_ty(rust_ident(&interface.name)); let kind = backend::ast::ImportFunctionKind::JsConstructor { - class: interface.name.to_string(), + class: class.to_string(), ty: self_ty.clone(), }; create_function( @@ -211,12 +211,22 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte webidl::ast::ArgumentListExtendedAttribute { arguments, name }, ) if name == "Constructor" => { - add_constructor(&*arguments); + add_constructor(arguments, &interface.name); } webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) if name == "Constructor" => { - add_constructor(&[] as &[_]); + add_constructor(&[] as &[_], &interface.name); + } + webidl::ast::ExtendedAttribute::NamedArgumentList( + webidl::ast::NamedArgumentListExtendedAttribute { + lhs_name, + rhs_arguments, + rhs_name, + }, + ) if lhs_name == "NamedConstructor" => + { + add_constructor(rhs_arguments, rhs_name); } webidl::ast::ExtendedAttribute::ArgumentList(_) | webidl::ast::ExtendedAttribute::Identifier(_) diff --git a/tests/all/webidl/simple.rs b/tests/all/webidl/simple.rs index 7b67d6cc..767f25d6 100644 --- a/tests/all/webidl/simple.rs +++ b/tests/all/webidl/simple.rs @@ -118,3 +118,61 @@ fn property() { ) .test(); } + +#[test] +fn named_constructor() { + project() + .file( + "foo.webidl", + r#" + [NamedConstructor=Bar(double value)] + interface Foo { + [Pure] + readonly attribute double value; + }; + "#, + ) + .file( + // Not a perfect test, but it gets the job done. + "foo.ts", + r#" + export class Foo { + protected _value: number = 0; + get value(): number { + return this._value; + } + } + + export class Bar extends Foo { + constructor(_value: number) { + super(); + this._value = _value; + } + } + "#, + ) + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + pub mod foo; + + use foo::Foo; + + #[wasm_bindgen] + pub fn test() { + let x = Foo::new(3.14159); + let tmp = x.value() == 3.14159; + assert!(tmp); + let tmp = x.value() != 0.; + assert!(tmp); + } + "#, + ) + .test(); +}