mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-21 00:36:33 +00:00
webidl: add support for partial interfaces and mixins
This is a major change to how webidl is processed. This adds a two phase process, where the first phase records the names of various types and indexes the mixins (and might do more in the future). The actual program building happens in the second phase. As part of this, this also makes it so that interface objects are passed by reference, rather than by value. The spec isn't exactly clear on this, but Mozilla's C++ reflection suggestions seem to indicate that they should be passed by reference (see https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings).
This commit is contained in:
@ -24,6 +24,7 @@ use std::collections::BTreeSet;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
use std::mem;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
|
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
|
||||||
@ -32,10 +33,7 @@ use failure::ResultExt;
|
|||||||
use heck::CamelCase;
|
use heck::CamelCase;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
|
||||||
use util::{
|
use util::{public, FirstPass, TypePosition};
|
||||||
create_basic_method, create_function, create_getter, create_setter, webidl_ty_to_syn_ty,
|
|
||||||
TypePosition,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Either `Ok(t)` or `Err(failure::Error)`.
|
/// Either `Ok(t)` or `Err(failure::Error)`.
|
||||||
pub type Result<T> = ::std::result::Result<T, failure::Error>;
|
pub type Result<T> = ::std::result::Result<T, failure::Error>;
|
||||||
@ -96,45 +94,137 @@ trait WebidlParse<Ctx> {
|
|||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, context: Ctx) -> Result<()>;
|
fn webidl_parse(&self, program: &mut backend::ast::Program, context: Ctx) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebidlParse<()> for Vec<webidl::ast::Definition> {
|
fn first_pass<'a>(definitions: &'a [webidl::ast::Definition]) -> FirstPass<'a> {
|
||||||
|
use webidl::ast::*;
|
||||||
|
|
||||||
|
let mut first_pass = FirstPass::default();
|
||||||
|
for def in definitions {
|
||||||
|
if let Definition::Interface(Interface::NonPartial(NonPartialInterface { name, .. })) = def
|
||||||
|
{
|
||||||
|
if first_pass.interfaces.insert(name.clone()) {
|
||||||
|
warn!("Encountered multiple declarations of {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Definition::Dictionary(Dictionary::NonPartial(NonPartialDictionary {
|
||||||
|
name, ..
|
||||||
|
})) = def
|
||||||
|
{
|
||||||
|
if first_pass.dictionaries.insert(name.clone()) {
|
||||||
|
warn!("Encountered multiple declarations of {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Definition::Enum(Enum { name, .. }) = def {
|
||||||
|
if first_pass.enums.insert(name.clone()) {
|
||||||
|
warn!("Encountered multiple declarations of {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Definition::Mixin(mixin) = def {
|
||||||
|
match mixin {
|
||||||
|
Mixin::NonPartial(mixin) => {
|
||||||
|
let entry = first_pass
|
||||||
|
.mixins
|
||||||
|
.entry(mixin.name.clone())
|
||||||
|
.or_insert(Default::default());
|
||||||
|
if mem::replace(&mut entry.non_partial, Some(mixin)).is_some() {
|
||||||
|
warn!(
|
||||||
|
"Encounterd multiple declarations of {}, using last encountered",
|
||||||
|
mixin.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mixin::Partial(mixin) => {
|
||||||
|
let entry = first_pass
|
||||||
|
.mixins
|
||||||
|
.entry(mixin.name.clone())
|
||||||
|
.or_insert(Default::default());
|
||||||
|
entry.partials.push(mixin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first_pass
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebidlParse<()> for [webidl::ast::Definition] {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
||||||
|
let first_pass = first_pass(self);
|
||||||
for def in self {
|
for def in self {
|
||||||
def.webidl_parse(program, ())?;
|
def.webidl_parse(program, &first_pass)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebidlParse<()> for webidl::ast::Definition {
|
impl<'a, 'b> WebidlParse<&'a FirstPass<'b>> for webidl::ast::Definition {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
fn webidl_parse(
|
||||||
match *self {
|
&self,
|
||||||
webidl::ast::Definition::Interface(ref interface) => {
|
program: &mut backend::ast::Program,
|
||||||
interface.webidl_parse(program, ())
|
first_pass: &'a FirstPass<'b>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
webidl::ast::Definition::Enum(enumeration) => enumeration.webidl_parse(program, ())?,
|
||||||
|
webidl::ast::Definition::Includes(includes) => {
|
||||||
|
includes.webidl_parse(program, first_pass)?
|
||||||
}
|
}
|
||||||
webidl::ast::Definition::Typedef(ref typedef) => typedef.webidl_parse(program, ()),
|
webidl::ast::Definition::Interface(interface) => {
|
||||||
webidl::ast::Definition::Enum(ref enumeration) => enumeration.webidl_parse(program, ()),
|
interface.webidl_parse(program, first_pass)?
|
||||||
|
}
|
||||||
|
webidl::ast::Definition::Typedef(typedef) => typedef.webidl_parse(program, first_pass)?,
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::Definition::Callback(..)
|
webidl::ast::Definition::Callback(..)
|
||||||
| webidl::ast::Definition::Dictionary(..)
|
| webidl::ast::Definition::Dictionary(..)
|
||||||
| webidl::ast::Definition::Implements(..)
|
| webidl::ast::Definition::Implements(..)
|
||||||
| webidl::ast::Definition::Includes(..)
|
|
||||||
| webidl::ast::Definition::Mixin(..)
|
|
||||||
| webidl::ast::Definition::Namespace(..) => {
|
| webidl::ast::Definition::Namespace(..) => {
|
||||||
warn!("Unsupported WebIDL definition: {:?}", self);
|
warn!("Unsupported WebIDL definition: {:?}", self)
|
||||||
|
}
|
||||||
|
webidl::ast::Definition::Mixin(_) => {
|
||||||
|
// handled in the first pass
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> WebidlParse<&'a FirstPass<'b>> for webidl::ast::Includes {
|
||||||
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
first_pass: &'a FirstPass<'b>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match first_pass.mixins.get(&self.includee) {
|
||||||
|
Some(mixin) => {
|
||||||
|
if let Some(non_partial) = mixin.non_partial {
|
||||||
|
for member in &non_partial.members {
|
||||||
|
member.webidl_parse(program, (&self.includer, first_pass))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for partial in &mixin.partials {
|
||||||
|
for member in &partial.members {
|
||||||
|
member.webidl_parse(program, (&self.includer, first_pass))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => warn!("Tried to include missing mixin {}", self.includee),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebidlParse<()> for webidl::ast::Interface {
|
impl<'a, 'b> WebidlParse<&'a FirstPass<'b>> for webidl::ast::Interface {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
fn webidl_parse(
|
||||||
match *self {
|
&self,
|
||||||
webidl::ast::Interface::NonPartial(ref interface) => {
|
program: &mut backend::ast::Program,
|
||||||
interface.webidl_parse(program, ())
|
first_pass: &'a FirstPass<'b>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
webidl::ast::Interface::NonPartial(interface) => {
|
||||||
|
interface.webidl_parse(program, first_pass)
|
||||||
|
}
|
||||||
|
webidl::ast::Interface::Partial(interface) => {
|
||||||
|
interface.webidl_parse(program, first_pass)
|
||||||
}
|
}
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::Interface::Callback(..) | webidl::ast::Interface::Partial(..) => {
|
webidl::ast::Interface::Callback(..) => {
|
||||||
warn!("Unsupported WebIDL interface: {:?}", self);
|
warn!("Unsupported WebIDL interface: {:?}", self);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -142,14 +232,18 @@ impl WebidlParse<()> for webidl::ast::Interface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebidlParse<()> for webidl::ast::Typedef {
|
impl<'a, 'b> WebidlParse<&'a FirstPass<'b>> for webidl::ast::Typedef {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
first_pass: &'a FirstPass,
|
||||||
|
) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let dest = rust_ident(&self.name);
|
let dest = rust_ident(self.name.to_camel_case().as_str());
|
||||||
let src = match webidl_ty_to_syn_ty(&self.type_, TypePosition::Return) {
|
let src = match first_pass.webidl_ty_to_syn_ty(&self.type_, TypePosition::Return) {
|
||||||
Some(src) => src,
|
Some(src) => src,
|
||||||
None => {
|
None => {
|
||||||
warn!(
|
warn!(
|
||||||
@ -161,9 +255,7 @@ impl WebidlParse<()> for webidl::ast::Typedef {
|
|||||||
};
|
};
|
||||||
|
|
||||||
program.type_aliases.push(backend::ast::TypeAlias {
|
program.type_aliases.push(backend::ast::TypeAlias {
|
||||||
vis: syn::Visibility::Public(syn::VisPublic {
|
vis: public(),
|
||||||
pub_token: Default::default(),
|
|
||||||
}),
|
|
||||||
dest,
|
dest,
|
||||||
src,
|
src,
|
||||||
});
|
});
|
||||||
@ -172,8 +264,12 @@ impl WebidlParse<()> for webidl::ast::Typedef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebidlParse<()> for webidl::ast::NonPartialInterface {
|
impl<'a, 'b> WebidlParse<&'a FirstPass<'b>> for webidl::ast::NonPartialInterface {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
first_pass: &'a FirstPass<'b>,
|
||||||
|
) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -183,34 +279,59 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface {
|
|||||||
version: None,
|
version: None,
|
||||||
js_namespace: None,
|
js_namespace: None,
|
||||||
kind: backend::ast::ImportKind::Type(backend::ast::ImportType {
|
kind: backend::ast::ImportKind::Type(backend::ast::ImportType {
|
||||||
vis: syn::Visibility::Public(syn::VisPublic {
|
vis: public(),
|
||||||
pub_token: Default::default(),
|
|
||||||
}),
|
|
||||||
name: rust_ident(&self.name),
|
name: rust_ident(&self.name),
|
||||||
attrs: Vec::new(),
|
attrs: Vec::new(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
for extended_attribute in &self.extended_attributes {
|
for extended_attribute in &self.extended_attributes {
|
||||||
extended_attribute.webidl_parse(program, self)?;
|
extended_attribute.webidl_parse(program, (self, first_pass))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for member in &self.members {
|
for member in &self.members {
|
||||||
member.webidl_parse(program, &self.name)?;
|
member.webidl_parse(program, (&self.name, first_pass))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::ExtendedAttribute {
|
impl<'a, 'b> WebidlParse<&'a FirstPass<'b>> for webidl::ast::PartialInterface {
|
||||||
fn webidl_parse(
|
fn webidl_parse(
|
||||||
&self,
|
&self,
|
||||||
program: &mut backend::ast::Program,
|
program: &mut backend::ast::Program,
|
||||||
interface: &'a webidl::ast::NonPartialInterface,
|
first_pass: &'a FirstPass<'b>,
|
||||||
|
) -> Result<()> {
|
||||||
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if !first_pass.interfaces.contains(&self.name) {
|
||||||
|
warn!(
|
||||||
|
"Partial interface {} missing non-partial interface",
|
||||||
|
self.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for member in &self.members {
|
||||||
|
member.webidl_parse(program, (&self.name, first_pass))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, 'c> WebidlParse<(&'a webidl::ast::NonPartialInterface, &'b FirstPass<'c>)>
|
||||||
|
for webidl::ast::ExtendedAttribute
|
||||||
|
{
|
||||||
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
(interface, first_pass): (&'a webidl::ast::NonPartialInterface, &'b FirstPass<'c>),
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| {
|
let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| {
|
||||||
let self_ty = ident_ty(rust_ident(&interface.name));
|
let self_ty = ident_ty(rust_ident(interface.name.to_camel_case().as_str()));
|
||||||
|
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: class.to_string(),
|
class: class.to_string(),
|
||||||
@ -234,7 +355,8 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
|
|||||||
// > exception**.
|
// > exception**.
|
||||||
let throws = true;
|
let throws = true;
|
||||||
|
|
||||||
create_function(
|
first_pass
|
||||||
|
.create_function(
|
||||||
"new",
|
"new",
|
||||||
arguments
|
arguments
|
||||||
.iter()
|
.iter()
|
||||||
@ -243,28 +365,22 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
|
|||||||
kind,
|
kind,
|
||||||
structural,
|
structural,
|
||||||
throws,
|
throws,
|
||||||
).map(|function| {
|
)
|
||||||
program.imports.push(backend::ast::Import {
|
.map(wrap_import_function)
|
||||||
module: None,
|
.map(|import| program.imports.push(import));
|
||||||
version: None,
|
|
||||||
js_namespace: None,
|
|
||||||
kind: backend::ast::ImportKind::Function(function),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
webidl::ast::ExtendedAttribute::ArgumentList(
|
webidl::ast::ExtendedAttribute::ArgumentList(
|
||||||
webidl::ast::ArgumentListExtendedAttribute { arguments, name },
|
webidl::ast::ArgumentListExtendedAttribute { arguments, name },
|
||||||
)
|
) if name == "Constructor" =>
|
||||||
if name == "Constructor" =>
|
|
||||||
{
|
{
|
||||||
add_constructor(arguments, &interface.name);
|
add_constructor(arguments, &interface.name)
|
||||||
}
|
}
|
||||||
webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name))
|
webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name))
|
||||||
if name == "Constructor" =>
|
if name == "Constructor" =>
|
||||||
{
|
{
|
||||||
add_constructor(&[], &interface.name);
|
add_constructor(&[], &interface.name)
|
||||||
}
|
}
|
||||||
webidl::ast::ExtendedAttribute::NamedArgumentList(
|
webidl::ast::ExtendedAttribute::NamedArgumentList(
|
||||||
webidl::ast::NamedArgumentListExtendedAttribute {
|
webidl::ast::NamedArgumentListExtendedAttribute {
|
||||||
@ -272,10 +388,9 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
|
|||||||
rhs_arguments,
|
rhs_arguments,
|
||||||
rhs_name,
|
rhs_name,
|
||||||
},
|
},
|
||||||
)
|
) if lhs_name == "NamedConstructor" =>
|
||||||
if lhs_name == "NamedConstructor" =>
|
|
||||||
{
|
{
|
||||||
add_constructor(rhs_arguments, rhs_name);
|
add_constructor(rhs_arguments, rhs_name)
|
||||||
}
|
}
|
||||||
webidl::ast::ExtendedAttribute::ArgumentList(_)
|
webidl::ast::ExtendedAttribute::ArgumentList(_)
|
||||||
| webidl::ast::ExtendedAttribute::Identifier(_)
|
| webidl::ast::ExtendedAttribute::Identifier(_)
|
||||||
@ -290,13 +405,15 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember {
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::InterfaceMember {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(
|
||||||
match *self {
|
&self,
|
||||||
webidl::ast::InterfaceMember::Attribute(ref attr) => {
|
program: &mut backend::ast::Program,
|
||||||
attr.webidl_parse(program, self_name)
|
context: (&'a str, &'b FirstPass<'c>),
|
||||||
}
|
) -> Result<()> {
|
||||||
webidl::ast::InterfaceMember::Operation(ref op) => op.webidl_parse(program, self_name),
|
match self {
|
||||||
|
webidl::ast::InterfaceMember::Attribute(attr) => attr.webidl_parse(program, context),
|
||||||
|
webidl::ast::InterfaceMember::Operation(op) => op.webidl_parse(program, context),
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::InterfaceMember::Const(_)
|
webidl::ast::InterfaceMember::Const(_)
|
||||||
| webidl::ast::InterfaceMember::Iterable(_)
|
| webidl::ast::InterfaceMember::Iterable(_)
|
||||||
@ -309,11 +426,32 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute {
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::MixinMember {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
context: (&'a str, &'b FirstPass<'c>),
|
||||||
|
) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
webidl::ast::Attribute::Regular(attr) => attr.webidl_parse(program, self_name),
|
webidl::ast::MixinMember::Attribute(attr) => attr.webidl_parse(program, context),
|
||||||
webidl::ast::Attribute::Static(attr) => attr.webidl_parse(program, self_name),
|
webidl::ast::MixinMember::Operation(op) => op.webidl_parse(program, context),
|
||||||
|
// TODO
|
||||||
|
webidl::ast::MixinMember::Const(_) => {
|
||||||
|
warn!("Unsupported WebIDL interface member: {:?}", self);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::Attribute {
|
||||||
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
context: (&'a str, &'b FirstPass<'c>),
|
||||||
|
) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
webidl::ast::Attribute::Regular(attr) => attr.webidl_parse(program, context),
|
||||||
|
webidl::ast::Attribute::Static(attr) => attr.webidl_parse(program, context),
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::Attribute::Stringifier(_) => {
|
webidl::ast::Attribute::Stringifier(_) => {
|
||||||
warn!("Unsupported WebIDL attribute: {:?}", self);
|
warn!("Unsupported WebIDL attribute: {:?}", self);
|
||||||
@ -323,11 +461,15 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::Operation {
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::Operation {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
context: (&'a str, &'b FirstPass<'c>),
|
||||||
|
) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
webidl::ast::Operation::Regular(op) => op.webidl_parse(program, self_name),
|
webidl::ast::Operation::Regular(op) => op.webidl_parse(program, context),
|
||||||
webidl::ast::Operation::Static(op) => op.webidl_parse(program, self_name),
|
webidl::ast::Operation::Static(op) => op.webidl_parse(program, context),
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => {
|
webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => {
|
||||||
warn!("Unsupported WebIDL operation: {:?}", self);
|
warn!("Unsupported WebIDL operation: {:?}", self);
|
||||||
@ -337,8 +479,12 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Operation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::RegularAttribute {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
(self_name, first_pass): (&'a str, &'b FirstPass<'c>),
|
||||||
|
) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -346,25 +492,29 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
|||||||
let is_structural = util::is_structural(&self.extended_attributes);
|
let is_structural = util::is_structural(&self.extended_attributes);
|
||||||
let throws = util::throws(&self.extended_attributes);
|
let throws = util::throws(&self.extended_attributes);
|
||||||
|
|
||||||
create_getter(
|
first_pass
|
||||||
|
.create_getter(
|
||||||
&self.name,
|
&self.name,
|
||||||
&self.type_,
|
&self.type_,
|
||||||
self_name,
|
self_name,
|
||||||
false,
|
false,
|
||||||
is_structural,
|
is_structural,
|
||||||
throws,
|
throws,
|
||||||
).map(wrap_import_function)
|
)
|
||||||
|
.map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
if !self.read_only {
|
if !self.read_only {
|
||||||
create_setter(
|
first_pass
|
||||||
|
.create_setter(
|
||||||
&self.name,
|
&self.name,
|
||||||
&self.type_,
|
&self.type_,
|
||||||
self_name,
|
self_name,
|
||||||
false,
|
false,
|
||||||
is_structural,
|
is_structural,
|
||||||
throws,
|
throws,
|
||||||
).map(wrap_import_function)
|
)
|
||||||
|
.map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,8 +522,12 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::StaticAttribute {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
(self_name, first_pass): (&'a str, &'b FirstPass<'c>),
|
||||||
|
) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -381,25 +535,29 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
|
|||||||
let is_structural = util::is_structural(&self.extended_attributes);
|
let is_structural = util::is_structural(&self.extended_attributes);
|
||||||
let throws = util::throws(&self.extended_attributes);
|
let throws = util::throws(&self.extended_attributes);
|
||||||
|
|
||||||
create_getter(
|
first_pass
|
||||||
|
.create_getter(
|
||||||
&self.name,
|
&self.name,
|
||||||
&self.type_,
|
&self.type_,
|
||||||
self_name,
|
self_name,
|
||||||
true,
|
true,
|
||||||
is_structural,
|
is_structural,
|
||||||
throws,
|
throws,
|
||||||
).map(wrap_import_function)
|
)
|
||||||
|
.map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
if !self.read_only {
|
if !self.read_only {
|
||||||
create_setter(
|
first_pass
|
||||||
|
.create_setter(
|
||||||
&self.name,
|
&self.name,
|
||||||
&self.type_,
|
&self.type_,
|
||||||
self_name,
|
self_name,
|
||||||
true,
|
true,
|
||||||
is_structural,
|
is_structural,
|
||||||
throws,
|
throws,
|
||||||
).map(wrap_import_function)
|
)
|
||||||
|
.map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,44 +565,56 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::RegularOperation {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
(self_name, first_pass): (&'a str, &'b FirstPass<'c>),
|
||||||
|
) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let throws = util::throws(&self.extended_attributes);
|
let throws = util::throws(&self.extended_attributes);
|
||||||
|
|
||||||
create_basic_method(
|
first_pass
|
||||||
|
.create_basic_method(
|
||||||
&self.arguments,
|
&self.arguments,
|
||||||
self.name.as_ref(),
|
self.name.as_ref(),
|
||||||
&self.return_type,
|
&self.return_type,
|
||||||
self_name,
|
self_name,
|
||||||
false,
|
false,
|
||||||
throws,
|
throws,
|
||||||
).map(wrap_import_function)
|
)
|
||||||
|
.map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation {
|
impl<'a, 'b, 'c> WebidlParse<(&'a str, &'b FirstPass<'c>)> for webidl::ast::StaticOperation {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(
|
||||||
|
&self,
|
||||||
|
program: &mut backend::ast::Program,
|
||||||
|
(self_name, first_pass): (&'a str, &'b FirstPass<'c>),
|
||||||
|
) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let throws = util::throws(&self.extended_attributes);
|
let throws = util::throws(&self.extended_attributes);
|
||||||
|
|
||||||
create_basic_method(
|
first_pass
|
||||||
|
.create_basic_method(
|
||||||
&self.arguments,
|
&self.arguments,
|
||||||
self.name.as_ref(),
|
self.name.as_ref(),
|
||||||
&self.return_type,
|
&self.return_type,
|
||||||
self_name,
|
self_name,
|
||||||
true,
|
true,
|
||||||
throws,
|
throws,
|
||||||
).map(wrap_import_function)
|
)
|
||||||
|
.map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -458,9 +628,7 @@ impl<'a> WebidlParse<()> for webidl::ast::Enum {
|
|||||||
version: None,
|
version: None,
|
||||||
js_namespace: None,
|
js_namespace: None,
|
||||||
kind: backend::ast::ImportKind::Enum(backend::ast::ImportEnum {
|
kind: backend::ast::ImportKind::Enum(backend::ast::ImportEnum {
|
||||||
vis: syn::Visibility::Public(syn::VisPublic {
|
vis: public(),
|
||||||
pub_token: Default::default(),
|
|
||||||
}),
|
|
||||||
name: rust_ident(self.name.to_camel_case().as_str()),
|
name: rust_ident(self.name.to_camel_case().as_str()),
|
||||||
variants: self
|
variants: self
|
||||||
.variants
|
.variants
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::iter::{self, FromIterator};
|
use std::iter::{self, FromIterator};
|
||||||
|
|
||||||
use backend;
|
use backend;
|
||||||
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident, simple_path_ty};
|
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident, simple_path_ty};
|
||||||
use heck::SnakeCase;
|
use heck::{CamelCase, SnakeCase};
|
||||||
use proc_macro2::Ident;
|
use proc_macro2::Ident;
|
||||||
use syn;
|
use syn;
|
||||||
use webidl;
|
use webidl;
|
||||||
@ -17,13 +18,72 @@ fn shared_ref(ty: syn::Type) -> syn::Type {
|
|||||||
}.into()
|
}.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 unit_ty() -> syn::Type {
|
||||||
|
syn::Type::Tuple(syn::TypeTuple {
|
||||||
|
paren_token: Default::default(),
|
||||||
|
elems: syn::punctuated::Punctuated::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn result_ty(t: syn::Type) -> syn::Type {
|
||||||
|
let js_value = leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]);
|
||||||
|
|
||||||
|
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
||||||
|
colon2_token: None,
|
||||||
|
lt_token: Default::default(),
|
||||||
|
args: FromIterator::from_iter(vec![
|
||||||
|
syn::GenericArgument::Type(t),
|
||||||
|
syn::GenericArgument::Type(js_value),
|
||||||
|
]),
|
||||||
|
gt_token: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let ident = raw_ident("Result");
|
||||||
|
let seg = syn::PathSegment { ident, arguments };
|
||||||
|
let path: syn::Path = seg.into();
|
||||||
|
let ty = syn::TypePath { qself: None, path };
|
||||||
|
ty.into()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum TypePosition {
|
pub enum TypePosition {
|
||||||
Argument,
|
Argument,
|
||||||
Return,
|
Return,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webidl_ty_to_syn_ty(ty: &webidl::ast::Type, pos: TypePosition) -> Option<syn::Type> {
|
#[derive(Default)]
|
||||||
|
pub struct FirstPass<'a> {
|
||||||
|
pub interfaces: BTreeSet<String>,
|
||||||
|
pub dictionaries: BTreeSet<String>,
|
||||||
|
pub enums: BTreeSet<String>,
|
||||||
|
pub mixins: BTreeMap<String, MixinData<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MixinData<'a> {
|
||||||
|
pub non_partial: Option<&'a webidl::ast::NonPartialMixin>,
|
||||||
|
pub partials: Vec<&'a webidl::ast::PartialMixin>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FirstPass<'a> {
|
||||||
|
pub fn webidl_ty_to_syn_ty(
|
||||||
|
&self,
|
||||||
|
ty: &webidl::ast::Type,
|
||||||
|
pos: TypePosition,
|
||||||
|
) -> Option<syn::Type> {
|
||||||
// nullable types are not yet supported (see issue #14)
|
// nullable types are not yet supported (see issue #14)
|
||||||
if ty.nullable {
|
if ty.nullable {
|
||||||
return None;
|
return None;
|
||||||
@ -36,7 +96,23 @@ pub fn webidl_ty_to_syn_ty(ty: &webidl::ast::Type, pos: TypePosition) -> Option<
|
|||||||
|
|
||||||
// A reference to a type by name becomes the same thing in the
|
// A reference to a type by name becomes the same thing in the
|
||||||
// bindings.
|
// bindings.
|
||||||
webidl::ast::TypeKind::Identifier(ref id) => ident_ty(rust_ident(id)),
|
webidl::ast::TypeKind::Identifier(ref id) => {
|
||||||
|
let ty = ident_ty(rust_ident(id.to_camel_case().as_str()));
|
||||||
|
if self.interfaces.contains(id) {
|
||||||
|
if pos == TypePosition::Argument {
|
||||||
|
shared_ref(ty)
|
||||||
|
} else {
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
} else if self.dictionaries.contains(id) {
|
||||||
|
ty
|
||||||
|
} else if self.enums.contains(id) {
|
||||||
|
ty
|
||||||
|
} else {
|
||||||
|
warn!("unrecognized type {}", id);
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Scalars.
|
// Scalars.
|
||||||
webidl::ast::TypeKind::Boolean => ident_ty(raw_ident("bool")),
|
webidl::ast::TypeKind::Boolean => ident_ty(raw_ident("bool")),
|
||||||
@ -90,25 +166,13 @@ pub fn webidl_ty_to_syn_ty(ty: &webidl::ast::Type, pos: TypePosition) -> Option<
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured {
|
fn webidl_arguments_to_syn_arg_captured<'b, I>(
|
||||||
syn::ArgCaptured {
|
&self,
|
||||||
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,
|
arguments: I,
|
||||||
kind: &backend::ast::ImportFunctionKind,
|
kind: &backend::ast::ImportFunctionKind,
|
||||||
) -> Option<Vec<syn::ArgCaptured>>
|
) -> Option<Vec<syn::ArgCaptured>>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (&'a str, &'a webidl::ast::Type, bool)>,
|
I: Iterator<Item = (&'b str, &'b webidl::ast::Type, bool)>,
|
||||||
{
|
{
|
||||||
let estimate = arguments.size_hint();
|
let estimate = arguments.size_hint();
|
||||||
let len = estimate.1.unwrap_or(estimate.0);
|
let len = estimate.1.unwrap_or(estimate.0);
|
||||||
@ -134,7 +198,7 @@ where
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
match webidl_ty_to_syn_ty(ty, TypePosition::Argument) {
|
match self.webidl_ty_to_syn_ty(ty, TypePosition::Argument) {
|
||||||
None => {
|
None => {
|
||||||
warn!("Argument's type is not yet supported: {:?}", ty);
|
warn!("Argument's type is not yet supported: {:?}", ty);
|
||||||
return None;
|
return None;
|
||||||
@ -146,34 +210,8 @@ where
|
|||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unit_ty() -> syn::Type {
|
pub fn create_function<'b, I>(
|
||||||
syn::Type::Tuple(syn::TypeTuple {
|
&self,
|
||||||
paren_token: Default::default(),
|
|
||||||
elems: syn::punctuated::Punctuated::new(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result_ty(t: syn::Type) -> syn::Type {
|
|
||||||
let js_value = leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]);
|
|
||||||
|
|
||||||
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
|
||||||
colon2_token: None,
|
|
||||||
lt_token: Default::default(),
|
|
||||||
args: FromIterator::from_iter(vec![
|
|
||||||
syn::GenericArgument::Type(t),
|
|
||||||
syn::GenericArgument::Type(js_value),
|
|
||||||
]),
|
|
||||||
gt_token: Default::default(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let ident = raw_ident("Result");
|
|
||||||
let seg = syn::PathSegment { ident, arguments };
|
|
||||||
let path: syn::Path = seg.into();
|
|
||||||
let ty = syn::TypePath { qself: None, path };
|
|
||||||
ty.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_function<'a, I>(
|
|
||||||
name: &str,
|
name: &str,
|
||||||
arguments: I,
|
arguments: I,
|
||||||
mut ret: Option<syn::Type>,
|
mut ret: Option<syn::Type>,
|
||||||
@ -182,12 +220,12 @@ pub fn create_function<'a, I>(
|
|||||||
catch: bool,
|
catch: bool,
|
||||||
) -> Option<backend::ast::ImportFunction>
|
) -> Option<backend::ast::ImportFunction>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (&'a str, &'a webidl::ast::Type, bool)>,
|
I: Iterator<Item = (&'b str, &'b webidl::ast::Type, bool)>,
|
||||||
{
|
{
|
||||||
let rust_name = rust_ident(&name.to_snake_case());
|
let rust_name = rust_ident(&name.to_snake_case());
|
||||||
let name = raw_ident(name);
|
let name = raw_ident(name);
|
||||||
|
|
||||||
let arguments = webidl_arguments_to_syn_arg_captured(arguments, &kind)?;
|
let arguments = self.webidl_arguments_to_syn_arg_captured(arguments, &kind)?;
|
||||||
|
|
||||||
let js_ret = ret.clone();
|
let js_ret = ret.clone();
|
||||||
|
|
||||||
@ -210,9 +248,7 @@ where
|
|||||||
arguments,
|
arguments,
|
||||||
ret,
|
ret,
|
||||||
rust_attrs: vec![],
|
rust_attrs: vec![],
|
||||||
rust_vis: syn::Visibility::Public(syn::VisPublic {
|
rust_vis: public(),
|
||||||
pub_token: Default::default(),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
rust_name,
|
rust_name,
|
||||||
js_ret,
|
js_ret,
|
||||||
@ -224,6 +260,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_basic_method(
|
pub fn create_basic_method(
|
||||||
|
&self,
|
||||||
arguments: &[webidl::ast::Argument],
|
arguments: &[webidl::ast::Argument],
|
||||||
name: Option<&String>,
|
name: Option<&String>,
|
||||||
return_type: &webidl::ast::ReturnType,
|
return_type: &webidl::ast::ReturnType,
|
||||||
@ -241,7 +278,7 @@ pub fn create_basic_method(
|
|||||||
|
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: self_name.to_string(),
|
class: self_name.to_string(),
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
ty: ident_ty(rust_ident(self_name.to_camel_case().as_str())),
|
||||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
is_static,
|
is_static,
|
||||||
kind: backend::ast::OperationKind::Regular,
|
kind: backend::ast::OperationKind::Regular,
|
||||||
@ -250,17 +287,18 @@ pub fn create_basic_method(
|
|||||||
|
|
||||||
let ret = match return_type {
|
let ret = match return_type {
|
||||||
webidl::ast::ReturnType::Void => None,
|
webidl::ast::ReturnType::Void => None,
|
||||||
webidl::ast::ReturnType::NonVoid(ty) => match webidl_ty_to_syn_ty(ty, TypePosition::Return)
|
webidl::ast::ReturnType::NonVoid(ty) => {
|
||||||
{
|
match self.webidl_ty_to_syn_ty(ty, TypePosition::Return) {
|
||||||
None => {
|
None => {
|
||||||
warn!("Operation's return type is not yet supported: {:?}", ty);
|
warn!("Operation's return type is not yet supported: {:?}", ty);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(ty) => Some(ty),
|
Some(ty) => Some(ty),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
create_function(
|
self.create_function(
|
||||||
&name,
|
&name,
|
||||||
arguments
|
arguments
|
||||||
.iter()
|
.iter()
|
||||||
@ -273,6 +311,7 @@ pub fn create_basic_method(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_getter(
|
pub fn create_getter(
|
||||||
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
ty: &webidl::ast::Type,
|
ty: &webidl::ast::Type,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
@ -280,7 +319,7 @@ pub fn create_getter(
|
|||||||
is_structural: bool,
|
is_structural: bool,
|
||||||
catch: bool,
|
catch: bool,
|
||||||
) -> Option<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
let ret = match webidl_ty_to_syn_ty(ty, TypePosition::Return) {
|
let ret = match self.webidl_ty_to_syn_ty(ty, TypePosition::Return) {
|
||||||
None => {
|
None => {
|
||||||
warn!("Attribute's type does not yet support reading: {:?}", ty);
|
warn!("Attribute's type does not yet support reading: {:?}", ty);
|
||||||
return None;
|
return None;
|
||||||
@ -290,17 +329,18 @@ pub fn create_getter(
|
|||||||
|
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: self_name.to_string(),
|
class: self_name.to_string(),
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
ty: ident_ty(rust_ident(self_name.to_camel_case().as_str())),
|
||||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
is_static,
|
is_static,
|
||||||
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
|
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
create_function(name, iter::empty(), ret, kind, is_structural, catch)
|
self.create_function(name, iter::empty(), ret, kind, is_structural, catch)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_setter(
|
pub fn create_setter(
|
||||||
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
ty: &webidl::ast::Type,
|
ty: &webidl::ast::Type,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
@ -310,14 +350,14 @@ pub fn create_setter(
|
|||||||
) -> Option<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: self_name.to_string(),
|
class: self_name.to_string(),
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
ty: ident_ty(rust_ident(self_name.to_camel_case().as_str())),
|
||||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
is_static,
|
is_static,
|
||||||
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
create_function(
|
self.create_function(
|
||||||
&format!("set_{}", name),
|
&format!("set_{}", name),
|
||||||
iter::once((name, ty, false)),
|
iter::once((name, ty, false)),
|
||||||
None,
|
None,
|
||||||
@ -326,39 +366,36 @@ pub fn create_setter(
|
|||||||
catch,
|
catch,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ChromeOnly is for things that are only exposed to priveleged code in Firefox.
|
/// ChromeOnly is for things that are only exposed to priveleged code in Firefox.
|
||||||
pub fn is_chrome_only(ext_attrs: &[Box<ExtendedAttribute>]) -> bool {
|
pub fn is_chrome_only(ext_attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||||
ext_attrs.iter().any(|external_attribute| {
|
ext_attrs.iter().any(|attr| match &**attr {
|
||||||
return match &**external_attribute {
|
|
||||||
ExtendedAttribute::ArgumentList(al) => al.name == "ChromeOnly",
|
|
||||||
ExtendedAttribute::Identifier(i) => i.lhs == "ChromeOnly",
|
|
||||||
ExtendedAttribute::IdentifierList(il) => il.lhs == "ChromeOnly",
|
|
||||||
ExtendedAttribute::NamedArgumentList(nal) => nal.lhs_name == "ChromeOnly",
|
|
||||||
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => {
|
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => {
|
||||||
name == "ChromeOnly"
|
name == "ChromeOnly"
|
||||||
}
|
}
|
||||||
ExtendedAttribute::NoArguments(_na) => false,
|
_ => false,
|
||||||
};
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_structural(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
pub fn is_structural(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||||
attrs.iter().any(|attr| {
|
attrs.iter().any(|attr| match &**attr {
|
||||||
if let ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(ref name)) = **attr {
|
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => {
|
||||||
name == "Unforgeable"
|
name == "Unforgeable"
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
_ => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn throws(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
pub fn throws(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||||
attrs.iter().any(|attr| {
|
attrs.iter().any(|attr| match &**attr {
|
||||||
if let ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(ref name)) = **attr {
|
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => name == "Throws",
|
||||||
name == "Throws"
|
_ => false,
|
||||||
} else {
|
})
|
||||||
false
|
}
|
||||||
}
|
|
||||||
|
pub fn public() -> syn::Visibility {
|
||||||
|
syn::Visibility::Public(syn::VisPublic {
|
||||||
|
pub_token: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -44,14 +44,14 @@ fn method() {
|
|||||||
let pi = Foo::new(3.14159).unwrap();
|
let pi = Foo::new(3.14159).unwrap();
|
||||||
let e = Foo::new(2.71828).unwrap();
|
let e = Foo::new(2.71828).unwrap();
|
||||||
// TODO: figure out why the following doesn't fail
|
// TODO: figure out why the following doesn't fail
|
||||||
// assert!(!pi.my_cmp(Foo::new(3.14159).unwrap()));
|
// assert!(!pi.my_cmp(&pi));
|
||||||
let tmp = pi.my_cmp(Foo::new(3.14159).unwrap());
|
let tmp = pi.my_cmp(&pi);
|
||||||
assert!(tmp);
|
assert!(tmp);
|
||||||
let tmp =!pi.my_cmp(Foo::new(2.71828).unwrap());
|
let tmp =!pi.my_cmp(&e);
|
||||||
assert!(tmp);
|
assert!(tmp);
|
||||||
let tmp = !e.my_cmp(Foo::new(3.14159).unwrap());
|
let tmp = !e.my_cmp(&pi);
|
||||||
assert!(tmp);
|
assert!(tmp);
|
||||||
let tmp = e.my_cmp(Foo::new(2.71828).unwrap());
|
let tmp = e.my_cmp(&e);
|
||||||
assert!(tmp);
|
assert!(tmp);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
@ -370,3 +370,130 @@ fn unforgeable_is_structural() {
|
|||||||
)
|
)
|
||||||
.test();
|
.test();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_interface() {
|
||||||
|
project()
|
||||||
|
.file(
|
||||||
|
"foo.webidl",
|
||||||
|
r#"
|
||||||
|
[Constructor]
|
||||||
|
interface Foo {
|
||||||
|
readonly attribute short un;
|
||||||
|
short deux();
|
||||||
|
};
|
||||||
|
|
||||||
|
partial interface Foo {
|
||||||
|
readonly attribute short trois;
|
||||||
|
short quatre();
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"foo.js",
|
||||||
|
r#"
|
||||||
|
export class Foo {
|
||||||
|
get un() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
deux() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
get trois() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
quatre() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.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;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn test() {
|
||||||
|
let f = foo::Foo::new().unwrap();
|
||||||
|
assert_eq!(f.un(), 1);
|
||||||
|
assert_eq!(f.deux(), 2);
|
||||||
|
assert_eq!(f.trois(), 3);
|
||||||
|
assert_eq!(f.quatre(), 4);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mixin() {
|
||||||
|
project()
|
||||||
|
.file(
|
||||||
|
"foo.webidl",
|
||||||
|
r#"
|
||||||
|
[Constructor(short bar)]
|
||||||
|
interface Foo {
|
||||||
|
static attribute short defaultBar;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface mixin Bar {
|
||||||
|
readonly attribute short bar;
|
||||||
|
};
|
||||||
|
|
||||||
|
partial interface mixin Bar {
|
||||||
|
void addToBar(short other);
|
||||||
|
};
|
||||||
|
|
||||||
|
Foo includes Bar;
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"foo.js",
|
||||||
|
r#"
|
||||||
|
export class Foo {
|
||||||
|
constructor(bar) {
|
||||||
|
this._bar = bar | Foo.defaultBar;
|
||||||
|
}
|
||||||
|
static get defaultBar() {
|
||||||
|
return Foo._defaultBar;
|
||||||
|
}
|
||||||
|
static set defaultBar(defaultBar) {
|
||||||
|
Foo._defaultBar = defaultBar;
|
||||||
|
}
|
||||||
|
get bar() {
|
||||||
|
return this._bar;
|
||||||
|
}
|
||||||
|
addToBar(other) {
|
||||||
|
this._bar += other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.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 f = Foo::new(1).unwrap();
|
||||||
|
assert_eq!(f.bar(), 1);
|
||||||
|
Foo::set_default_bar(7);
|
||||||
|
f.add_to_bar(Foo::default_bar());
|
||||||
|
assert_eq!(f.bar(), 8);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.test();
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user