webidl: add support for constructors

This commit is contained in:
R. Andrew Ohana 2018-06-14 15:35:48 -07:00
parent 400015a061
commit c65cb51fba
4 changed files with 200 additions and 26 deletions

View File

@ -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 {

File diff suppressed because one or more lines are too long

View File

@ -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;
};

View File

@ -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);
}
"#,
)