From c65cb51fba75daac386d21bde139367765f0a8af Mon Sep 17 00:00:00 2001 From: "R. Andrew Ohana" Date: Thu, 14 Jun 2018 15:35:48 -0700 Subject: [PATCH] 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 adec017de..b78e52a09 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 e19cabc54..51807c4db 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 8dea443a8..78ab021bd 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 d13a228e5..7b67d6cc0 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); } "#, )