Migrate from the webidl crate to weedle

This commit migrates the `wasm-bindgen-webidl` crate from the `webidl` parser to
`weedle`. The main rationale for doing this is that `webidl` depends on
`lalrpop`, which is quite a large dependency and takes a good deal of time to
compile. The `weedle` crate, however, depends on `nom` and is much faster to
compile.

Almost all translations were pretty straightforward. Some abstractions changed
and/or were introduced in this commit when moving to `weedle` like the
`ToSynType` trait, but otherwise the generated bindings should be the same. It's
been verified that the `weedle`-generated bindings are exactly the same as the
`webidl`-generated bindings, with the one exception of `weedle` generates one
more method, `WebGpuCommandEncoder::transition_buffer`. It's not clear currently
why `webidl` didn't generate this method, as its [idl] is pretty straightforward!

This commit is using a [fork] of `weedle` currently which has a number of fixes
for parsing our WebIDL, although all the fixes are quite minor!

Closes #620

[idl]: d66b834afd/crates/web-sys/webidls/enabled/WebGPU.webidl (L499)
[fork]: https://github.com/alexcrichton/weedle/tree/fix-for-web-sys
This commit is contained in:
Alex Crichton
2018-08-03 14:39:33 -07:00
parent 21c36d3902
commit e35295d376
5 changed files with 1225 additions and 1024 deletions

View File

@ -1,4 +1,5 @@
extern crate env_logger; extern crate env_logger;
#[macro_use]
extern crate failure; extern crate failure;
extern crate wasm_bindgen_webidl; extern crate wasm_bindgen_webidl;
extern crate sourcefile; extern crate sourcefile;
@ -8,9 +9,8 @@ use sourcefile::SourceFile;
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fs; use std::fs;
use std::io::Write;
use std::path; use std::path;
use std::process; use std::process::{self, Command};
fn main() { fn main() {
if let Err(e) = try_main() { if let Err(e) = try_main() {
@ -32,12 +32,14 @@ fn try_main() -> Result<(), failure::Error> {
let mut source = SourceFile::default(); let mut source = SourceFile::default();
for entry in entries { for entry in entries {
let entry = entry.context("getting webidls/enabled/*.webidl entry")?; let entry = entry.context("getting webidls/enabled/*.webidl entry")?;
if entry.path().extension() == Some(OsStr::new("webidl")) { let path = entry.path();
println!("cargo:rerun-if-changed={}", entry.path().display()); if path.extension() != Some(OsStr::new("webidl")) {
source = source.add_file(entry.path()) continue
.with_context(|_| format!("reading contents of file \"{}\"",
entry.path().display()))?;
} }
println!("cargo:rerun-if-changed={}", path.display());
source = source.add_file(&path)
.with_context(|_| format!("reading contents of file \"{}\"",
path.display()))?;
} }
let bindings = match wasm_bindgen_webidl::compile(&source.contents) { let bindings = match wasm_bindgen_webidl::compile(&source.contents) {
@ -60,17 +62,19 @@ fn try_main() -> Result<(), failure::Error> {
let out_dir = env::var("OUT_DIR").context("reading OUT_DIR environment variable")?; let out_dir = env::var("OUT_DIR").context("reading OUT_DIR environment variable")?;
let out_file_path = path::Path::new(&out_dir).join("bindings.rs"); let out_file_path = path::Path::new(&out_dir).join("bindings.rs");
let mut out_file = fs::File::create(&out_file_path) fs::write(&out_file_path, bindings)
.context("creating output bindings file")?;
out_file
.write_all(bindings.as_bytes())
.context("writing bindings to output file")?; .context("writing bindings to output file")?;
// run rustfmt on the generated file - really handy for debugging // run rustfmt on the generated file - really handy for debugging
//if ! process::Command::new("rustfmt").arg(&out_file_path).status() if env::var("WEBIDL_RUSTFMT_BINDINGS").is_ok() {
// .context("running rustfmt")?.success() { let status = Command::new("rustfmt")
// return Err(format_err!("rustfmt failed to format {}", out_file_path.display())); .arg(&out_file_path)
//} .status()
.context("running rustfmt")?;
if !status.success() {
bail!("rustfmt failed: {}", status)
}
}
Ok(()) Ok(())
} }

View File

@ -20,4 +20,4 @@ proc-macro2 = "0.4.8"
quote = '0.6' quote = '0.6'
syn = { version = '0.14', features = ['full'] } syn = { version = '0.14', features = ['full'] }
wasm-bindgen-backend = { version = "=0.2.15", path = "../backend" } wasm-bindgen-backend = { version = "=0.2.15", path = "../backend" }
webidl = "0.7.0" weedle = "0.6"

View File

@ -7,66 +7,58 @@
//! Only `interface`s, `dictionary`s, `enum`s and `mixin`s can //! Only `interface`s, `dictionary`s, `enum`s and `mixin`s can
//! be partial. //! be partial.
use std::{ use std::collections::{BTreeMap, BTreeSet};
collections::{BTreeMap, BTreeSet}, mem,
};
use webidl; use weedle::argument::Argument;
use weedle::attribute::ExtendedAttribute;
use weedle::interface::StringifierOrStatic;
use weedle::mixin::MixinMembers;
use weedle;
use super::Result; use super::Result;
use util;
/// Collection of constructs that may use partial. /// Collection of constructs that may use partial.
#[derive(Default)] #[derive(Default)]
pub(crate) struct FirstPassRecord<'a> { pub(crate) struct FirstPassRecord<'src> {
pub(crate) interfaces: BTreeMap<String, InterfaceData>, pub(crate) interfaces: BTreeMap<&'src str, InterfaceData<'src>>,
pub(crate) dictionaries: BTreeSet<String>, pub(crate) dictionaries: BTreeSet<&'src str>,
pub(crate) enums: BTreeSet<String>, pub(crate) enums: BTreeSet<&'src str>,
/// The mixins, mapping their name to the webidl ast node for the mixin. /// The mixins, mapping their name to the webidl ast node for the mixin.
pub(crate) mixins: BTreeMap<String, MixinData<'a>>, pub(crate) mixins: BTreeMap<&'src str, Vec<&'src MixinMembers<'src>>>,
pub(crate) typedefs: BTreeMap<String, webidl::ast::Type>, pub(crate) typedefs: BTreeMap<&'src str, &'src weedle::types::Type<'src>>,
} }
/// We need to collect interface data during the first pass, to be used later. /// We need to collect interface data during the first pass, to be used later.
#[derive(Default)] #[derive(Default)]
pub(crate) struct InterfaceData { pub(crate) struct InterfaceData<'src> {
/// Whether only partial interfaces were encountered /// Whether only partial interfaces were encountered
pub(crate) partial: bool, pub(crate) partial: bool,
pub(crate) operations: BTreeMap<OperationId, OperationData>,
pub(crate) global: bool, pub(crate) global: bool,
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
} }
#[derive(PartialEq, Eq, PartialOrd, Ord)] #[derive(PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum OperationId { pub(crate) enum OperationId<'src> {
Constructor, Constructor,
Operation(Option<String>) Operation(Option<&'src str>)
} }
#[derive(Default)] #[derive(Default)]
pub(crate) struct OperationData { pub(crate) struct OperationData<'src> {
pub(crate) overloaded: bool, pub(crate) overloaded: bool,
/// Map from argument names to whether they are the same for multiple overloads /// Map from argument names to whether they are the same for multiple overloads
pub(crate) argument_names_same: BTreeMap<Vec<String>, bool>, pub(crate) argument_names_same: BTreeMap<Vec<&'src str>, bool>,
}
/// We need to collect mixin data during the first pass, to be used later.
#[derive(Default)]
pub(crate) struct MixinData<'a> {
/// The non partial mixin, if present. If there is more than one, we are
/// parsing is a malformed WebIDL file, but the parser will recover by
/// using the last parsed mixin.
pub(crate) non_partial: Option<&'a webidl::ast::NonPartialMixin>,
/// 0 or more partial mixins.
pub(crate) partials: Vec<&'a webidl::ast::PartialMixin>,
} }
/// Implemented on an AST node to populate the `FirstPassRecord` struct. /// Implemented on an AST node to populate the `FirstPassRecord` struct.
pub(crate) trait FirstPass<Ctx> { pub(crate) trait FirstPass<'src, Ctx> {
/// Populate `record` with any constructs in `self`. /// Populate `record` with any constructs in `self`.
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, ctx: Ctx) -> Result<()>; fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, ctx: Ctx) -> Result<()>;
} }
impl FirstPass<()> for [webidl::ast::Definition] { impl<'src> FirstPass<'src, ()> for [weedle::Definition<'src>] {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
for def in self { for def in self {
def.first_pass(record, ())?; def.first_pass(record, ())?;
} }
@ -75,15 +67,17 @@ impl FirstPass<()> for [webidl::ast::Definition] {
} }
} }
impl FirstPass<()> for webidl::ast::Definition { impl<'src> FirstPass<'src, ()> for weedle::Definition<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
use webidl::ast::Definition::*; use weedle::Definition::*;
match self { match self {
Dictionary(dictionary) => dictionary.first_pass(record, ()), Dictionary(dictionary) => dictionary.first_pass(record, ()),
Enum(enum_) => enum_.first_pass(record, ()), Enum(enum_) => enum_.first_pass(record, ()),
Interface(interface) => interface.first_pass(record, ()), Interface(interface) => interface.first_pass(record, ()),
Mixin(mixin) => mixin.first_pass(record, ()), PartialInterface(interface) => interface.first_pass(record, ()),
InterfaceMixin(mixin) => mixin.first_pass(record, ()),
PartialInterfaceMixin(mixin) => mixin.first_pass(record, ()),
Typedef(typedef) => typedef.first_pass(record, ()), Typedef(typedef) => typedef.first_pass(record, ()),
_ => { _ => {
// Other definitions aren't currently used in the first pass // Other definitions aren't currently used in the first pass
@ -93,46 +87,38 @@ impl FirstPass<()> for webidl::ast::Definition {
} }
} }
impl FirstPass<()> for webidl::ast::Dictionary { impl<'src> FirstPass<'src, ()> for weedle::DictionaryDefinition<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
use webidl::ast::Dictionary::*; if !record.dictionaries.insert(self.identifier.0) {
warn!("encountered multiple dictionary declarations of {}", self.identifier.0);
match self { }
NonPartial(dictionary) => dictionary.first_pass(record, ()),
_ => {
// Other dictionaries aren't currently used in the first pass
Ok(()) Ok(())
} }
}
}
} }
impl FirstPass<()> for webidl::ast::NonPartialDictionary { impl<'src> FirstPass<'src, ()> for weedle::EnumDefinition<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
if record.dictionaries.insert(self.name.clone()) { if !record.enums.insert(self.identifier.0) {
warn!("Encountered multiple declarations of {}", self.name); warn!("Encountered multiple enum declarations of {}", self.identifier.0);
} }
Ok(()) Ok(())
} }
} }
impl FirstPass<()> for webidl::ast::Enum { fn first_pass_operation<'src>(
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { record: &mut FirstPassRecord<'src>,
if record.enums.insert(self.name.clone()) { self_name: &'src str,
warn!("Encountered multiple declarations of {}", self.name); id: OperationId<'src>,
} arguments: &[Argument<'src>],
Ok(())
}
}
fn first_pass_operation<'a>(
record: &mut FirstPassRecord<'a>,
self_name: &str,
id: OperationId,
arguments: &[webidl::ast::Argument],
) -> Result<()> { ) -> Result<()> {
let mut names = Vec::with_capacity(arguments.len());
for argument in arguments {
match argument {
Argument::Single(arg) => names.push(arg.identifier.0),
Argument::Variadic(_) => return Ok(()),
}
}
record record
.interfaces .interfaces
.get_mut(self_name) .get_mut(self_name)
@ -140,77 +126,48 @@ fn first_pass_operation<'a>(
.operations .operations
.entry(id) .entry(id)
.and_modify(|operation_data| operation_data.overloaded = true) .and_modify(|operation_data| operation_data.overloaded = true)
.or_insert_with(|| .or_insert_with(Default::default)
OperationData {
overloaded: false,
argument_names_same: Default::default(),
}
)
.argument_names_same .argument_names_same
.entry(arguments.iter().map(|argument| argument.name.clone()).collect()) .entry(names)
.and_modify(|same_argument_names| *same_argument_names = true) .and_modify(|same_argument_names| *same_argument_names = true)
.or_insert(false); .or_insert(false);
Ok(()) Ok(())
} }
impl FirstPass<()> for webidl::ast::Interface { impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
use webidl::ast::Interface::*; {
let interface = record
match self {
Partial(interface) => interface.first_pass(record, ()),
NonPartial(interface) => interface.first_pass(record, ()),
// TODO
Callback(..) => {
warn!("Unsupported WebIDL interface: {:?}", self);
Ok(())
}
}
}
}
impl FirstPass<()> for webidl::ast::NonPartialInterface {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
record
.interfaces .interfaces
.entry(self.name.clone()) .entry(self.identifier.0)
.and_modify(|interface_data| { .or_insert_with(Default::default);
if interface_data.partial { interface.partial = false;
interface_data.partial = false;
} else {
warn!("Encountered multiple declarations of {}", self.name);
} }
})
.or_insert_with(||
InterfaceData {
partial: false,
operations: Default::default(),
global: false,
},
);
if ::util::is_chrome_only(&self.extended_attributes) { if util::is_chrome_only(&self.attributes) {
return Ok(()) return Ok(())
} }
for extended_attribute in &self.extended_attributes { if let Some(attrs) = &self.attributes {
extended_attribute.first_pass(record, &self.name)?; for attr in &attrs.body.list {
attr.first_pass(record, self.identifier.0)?;
}
} }
for member in &self.members { for member in &self.members.body {
member.first_pass(record, &self.name)?; member.first_pass(record, self.identifier.0)?;
} }
Ok(()) Ok(())
} }
} }
impl FirstPass<()> for webidl::ast::PartialInterface { impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceDefinition<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
record record
.interfaces .interfaces
.entry(self.name.clone()) .entry(self.identifier.0)
.or_insert_with(|| .or_insert_with(||
InterfaceData { InterfaceData {
partial: true, partial: true,
@ -219,36 +176,30 @@ impl FirstPass<()> for webidl::ast::PartialInterface {
}, },
); );
if ::util::is_chrome_only(&self.extended_attributes) { if util::is_chrome_only(&self.attributes) {
return Ok(()) return Ok(())
} }
for member in &self.members { for member in &self.members.body {
member.first_pass(record, &self.name)?; member.first_pass(record, self.identifier.0)?;
} }
Ok(()) Ok(())
} }
} }
impl<'b> FirstPass<&'b str> for webidl::ast::ExtendedAttribute { impl<'src> FirstPass<'src, &'src str> for ExtendedAttribute<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
match self { match self {
webidl::ast::ExtendedAttribute::ArgumentList( ExtendedAttribute::ArgList(list) if list.identifier.0 == "Constructor" => {
webidl::ast::ArgumentListExtendedAttribute { arguments, name },
)
if name == "Constructor" =>
{
first_pass_operation( first_pass_operation(
record, record,
self_name, self_name,
OperationId::Constructor, OperationId::Constructor,
&arguments, &list.args.body.list,
) )
} }
webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) ExtendedAttribute::NoArgs(name) if (name.0).0 == "Constructor" => {
if name == "Constructor" =>
{
first_pass_operation( first_pass_operation(
record, record,
self_name, self_name,
@ -256,30 +207,21 @@ impl<'b> FirstPass<&'b str> for webidl::ast::ExtendedAttribute {
&[], &[],
) )
} }
webidl::ast::ExtendedAttribute::NamedArgumentList( ExtendedAttribute::NamedArgList(list)
webidl::ast::NamedArgumentListExtendedAttribute { if list.lhs_identifier.0 == "NamedConstructor" =>
lhs_name,
rhs_arguments,
..
},
)
if lhs_name == "NamedConstructor" =>
{ {
first_pass_operation( first_pass_operation(
record, record,
self_name, self_name,
OperationId::Constructor, OperationId::Constructor,
&rhs_arguments, &list.args.body.list,
) )
}, }
webidl::ast::ExtendedAttribute::Identifier( ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "Global" => {
webidl::ast::IdentifierExtendedAttribute { lhs, .. } record.interfaces.get_mut(self_name).unwrap().global = true;
) Ok(())
| webidl::ast::ExtendedAttribute::IdentifierList( }
webidl::ast::IdentifierListExtendedAttribute { lhs, .. } ExtendedAttribute::IdentList(id) if id.identifier.0 == "Global" => {
)
if lhs == "Global" =>
{
record.interfaces.get_mut(self_name).unwrap().global = true; record.interfaces.get_mut(self_name).unwrap().global = true;
Ok(()) Ok(())
} }
@ -288,99 +230,66 @@ impl<'b> FirstPass<&'b str> for webidl::ast::ExtendedAttribute {
} }
} }
impl<'b> FirstPass<&'b str> for webidl::ast::InterfaceMember { impl<'src> FirstPass<'src, &'src str> for weedle::interface::InterfaceMember<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
match self { match self {
webidl::ast::InterfaceMember::Operation(op) => op.first_pass(record, self_name), weedle::interface::InterfaceMember::Operation(op) => {
op.first_pass(record, self_name)
}
_ => Ok(()), _ => Ok(()),
} }
} }
} }
impl<'b> FirstPass<&'b str> for webidl::ast::Operation { impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceMember<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
match self { if self.specials.len() > 0 {
webidl::ast::Operation::Regular(op) => op.first_pass(record, self_name), warn!("Unsupported webidl operation {:?}", self);
webidl::ast::Operation::Static(op) => op.first_pass(record, self_name), return Ok(())
// TODO
webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => {
warn!("Unsupported WebIDL operation: {:?}", self);
Ok(())
} }
if let Some(StringifierOrStatic::Stringifier(_)) = self.modifier {
warn!("Unsupported webidl operation {:?}", self);
return Ok(())
} }
}
}
impl<'b> FirstPass<&'b str> for webidl::ast::RegularOperation {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> {
first_pass_operation( first_pass_operation(
record, record,
self_name, self_name,
OperationId::Operation(self.name.clone()), OperationId::Operation(self.identifier.map(|s| s.0)),
&self.arguments, &self.args.body.list,
) )
} }
} }
impl<'b> FirstPass<&'b str> for webidl::ast::StaticOperation { impl<'src> FirstPass<'src, ()> for weedle::InterfaceMixinDefinition<'src>{
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
first_pass_operation( record
record,
self_name,
OperationId::Operation(self.name.clone()),
&self.arguments,
)
}
}
impl FirstPass<()> for webidl::ast::Mixin {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
use webidl::ast::Mixin::*;
match self {
NonPartial(mixin) => mixin.first_pass(record, ()),
Partial(mixin) => mixin.first_pass(record, ()),
}
}
}
impl FirstPass<()> for webidl::ast::NonPartialMixin {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
let entry = record
.mixins .mixins
.entry(self.name.clone()) .entry(self.identifier.0)
.or_insert_with(Default::default); .or_insert_with(Default::default)
if mem::replace(&mut entry.non_partial, Some(self)).is_some() { .push(&self.members.body);
warn!(
"Encounterd multiple declarations of {}, using last encountered",
self.name
);
}
Ok(()) Ok(())
} }
} }
impl FirstPass<()> for webidl::ast::PartialMixin { impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceMixinDefinition<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
let entry = record record
.mixins .mixins
.entry(self.name.clone()) .entry(self.identifier.0)
.or_insert_with(Default::default); .or_insert_with(Default::default)
entry.partials.push(self); .push(&self.members.body);
Ok(()) Ok(())
} }
} }
impl FirstPass<()> for webidl::ast::Typedef { impl<'src> FirstPass<'src, ()> for weedle::TypedefDefinition<'src> {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
if ::util::is_chrome_only(&self.extended_attributes) { if util::is_chrome_only(&self.attributes) {
return Ok(()); return Ok(());
} }
if record.typedefs.insert(self.name.clone(), *self.type_.clone()).is_some() { if record.typedefs.insert(self.identifier.0, &self.type_.type_).is_some() {
warn!("Encountered multiple declarations of {}", self.name); warn!("Encountered multiple declarations of {}", self.identifier.0);
} }
Ok(()) Ok(())

View File

@ -9,6 +9,7 @@ emitted for the types and methods described in the WebIDL.
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/wasm-bindgen-webidl/0.2")] #![doc(html_root_url = "https://docs.rs/wasm-bindgen-webidl/0.2")]
#[macro_use]
extern crate failure; extern crate failure;
#[macro_use] #[macro_use]
extern crate failure_derive; extern crate failure_derive;
@ -21,7 +22,7 @@ extern crate quote;
#[macro_use] #[macro_use]
extern crate syn; extern crate syn;
extern crate wasm_bindgen_backend as backend; extern crate wasm_bindgen_backend as backend;
extern crate webidl; extern crate weedle;
mod first_pass; mod first_pass;
mod util; mod util;
@ -36,11 +37,14 @@ use std::path::Path;
use backend::TryToTokens; use backend::TryToTokens;
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports}; use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
use backend::util::{ident_ty, rust_ident, wrap_import_function}; use backend::util::{ident_ty, rust_ident, wrap_import_function};
use failure::{ResultExt, Fail}; use failure::ResultExt;
use heck::{ShoutySnakeCase}; use heck::{ShoutySnakeCase};
use weedle::argument::Argument;
use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList};
use first_pass::{FirstPass, FirstPassRecord}; use first_pass::{FirstPass, FirstPassRecord};
use util::{ApplyTypedefs, public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, camel_case_ident, mdn_doc}; use util::{public, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, mdn_doc};
use util::ToSynType;
pub use error::{Error, ErrorKind, Result}; pub use error::{Error, ErrorKind, Result};
@ -55,22 +59,31 @@ fn parse_file(webidl_path: &Path) -> Result<backend::ast::Program> {
/// Parse a string of WebIDL source text into a wasm-bindgen AST. /// Parse a string of WebIDL source text into a wasm-bindgen AST.
fn parse(webidl_source: &str) -> Result<backend::ast::Program> { fn parse(webidl_source: &str) -> Result<backend::ast::Program> {
let definitions = match webidl::parse_string(webidl_source) { let definitions = match weedle::parse(webidl_source) {
Ok(def) => def, Ok(def) => def,
Err(e) => { Err(e) => {
let kind = match &e { return Err(match &e {
webidl::ParseError::InvalidToken { location } => { weedle::Err::Incomplete(needed) => {
ErrorKind::ParsingWebIDLSourcePos(*location) format_err!("needed {:?} more bytes", needed)
.context(ErrorKind::ParsingWebIDLSource).into()
} }
webidl::ParseError::UnrecognizedToken { token: Some((start, ..)), .. } => { weedle::Err::Error(cx) |
ErrorKind::ParsingWebIDLSourcePos(*start) weedle::Err::Failure(cx) => {
} let remaining = match cx {
webidl::ParseError::ExtraToken { token: (start, ..) } => { weedle::Context::Code(remaining, _) => remaining,
ErrorKind::ParsingWebIDLSourcePos(*start)
},
_ => ErrorKind::ParsingWebIDLSource
}; };
return Err(e.context(kind).into()); let pos = webidl_source.len() - remaining.len();
format_err!("failed to parse WebIDL")
.context(ErrorKind::ParsingWebIDLSourcePos(pos)).into()
}
// webidl::ParseError::UnrecognizedToken { token: Some((start, ..)), .. } => {
// ErrorKind::ParsingWebIDLSourcePos(*start)
// }
// webidl::ParseError::ExtraToken { token: (start, ..) } => {
// ErrorKind::ParsingWebIDLSourcePos(*start)
// },
// _ => ErrorKind::ParsingWebIDLSource
});
} }
}; };
@ -119,21 +132,21 @@ fn compile_ast(mut ast: backend::ast::Program) -> String {
} }
/// The main trait for parsing WebIDL AST into wasm-bindgen AST. /// The main trait for parsing WebIDL AST into wasm-bindgen AST.
trait WebidlParse<Ctx> { trait WebidlParse<'src, Ctx> {
/// Parse `self` into wasm-bindgen AST, and insert it into `program`. /// Parse `self` into wasm-bindgen AST, and insert it into `program`.
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
context: Ctx, context: Ctx,
) -> Result<()>; ) -> Result<()>;
} }
impl WebidlParse<()> for [webidl::ast::Definition] { impl<'src> WebidlParse<'src, ()> for [weedle::Definition<'src>] {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
(): (), (): (),
) -> Result<()> { ) -> Result<()> {
for def in self { for def in self {
@ -143,104 +156,85 @@ impl WebidlParse<()> for [webidl::ast::Definition] {
} }
} }
impl WebidlParse<()> for webidl::ast::Definition { impl<'src> WebidlParse<'src, ()> for weedle::Definition<'src> {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
(): (), (): (),
) -> Result<()> { ) -> Result<()> {
match self { match self {
webidl::ast::Definition::Enum(enumeration) => { weedle::Definition::Enum(enumeration) => {
enumeration.webidl_parse(program, first_pass, ())? enumeration.webidl_parse(program, first_pass, ())?
} }
webidl::ast::Definition::Includes(includes) => { weedle::Definition::IncludesStatement(includes) => {
includes.webidl_parse(program, first_pass, ())? includes.webidl_parse(program, first_pass, ())?
} }
webidl::ast::Definition::Interface(interface) => { weedle::Definition::Interface(interface) => {
interface.webidl_parse(program, first_pass, ())? interface.webidl_parse(program, first_pass, ())?
} }
// TODO weedle::Definition::PartialInterface(interface) => {
webidl::ast::Definition::Callback(..) interface.webidl_parse(program, first_pass, ())?
| webidl::ast::Definition::Dictionary(..)
| webidl::ast::Definition::Implements(..)
| webidl::ast::Definition::Namespace(..) => {
warn!("Unsupported WebIDL definition: {:?}", self)
} }
webidl::ast::Definition::Mixin(_) weedle::Definition::Typedef(_) |
| webidl::ast::Definition::Typedef(_) => { weedle::Definition::InterfaceMixin(_) |
weedle::Definition::PartialInterfaceMixin(_) => {
// handled in the first pass // handled in the first pass
} }
}
Ok(())
}
}
impl WebidlParse<()> for webidl::ast::Includes {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>,
(): (),
) -> 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, first_pass, &self.includer)?;
}
}
for partial in &mixin.partials {
for member in &partial.members {
member.webidl_parse(program, first_pass, &self.includer)?;
}
}
}
None => warn!("Tried to include missing mixin {}", self.includee),
}
Ok(())
}
}
impl WebidlParse<()> for webidl::ast::Interface {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>,
(): (),
) -> 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(..) => { weedle::Definition::Callback(..)
warn!("Unsupported WebIDL interface: {:?}", self); | weedle::Definition::CallbackInterface(..)
| weedle::Definition::Dictionary(..)
| weedle::Definition::PartialDictionary(..)
| weedle::Definition::Implements(..)
| weedle::Definition::Namespace(..)
| weedle::Definition::PartialNamespace(..) => {
warn!("Unsupported WebIDL definition: {:?}", self)
}
}
Ok(()) Ok(())
} }
}
}
} }
impl WebidlParse<()> for webidl::ast::NonPartialInterface { impl<'src> WebidlParse<'src, ()> for weedle::IncludesStatementDefinition<'src> {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
(): (), (): (),
) -> Result<()> { ) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) { match first_pass.mixins.get(self.rhs_identifier.0) {
Some(member_lists) => {
for member in member_lists.iter().flat_map(|list| list.iter()) {
member.webidl_parse(program, first_pass, self.lhs_identifier.0)?;
}
}
None => warn!("Tried to include missing mixin {}", self.rhs_identifier.0),
}
Ok(())
}
}
impl<'src> WebidlParse<'src, ()> for weedle::InterfaceDefinition<'src> {
fn webidl_parse(
&'src self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'src>,
(): (),
) -> Result<()> {
if util::is_chrome_only(&self.attributes) {
return Ok(()); return Ok(());
} }
if util::is_no_interface_object(&self.extended_attributes) { if util::is_no_interface_object(&self.attributes) {
return Ok(()); return Ok(());
} }
let doc_comment = Some(format!("The `{}` object\n\n{}", &self.name, mdn_doc(&self.name, None))); let doc_comment = Some(format!(
"The `{}` object\n\n{}",
self.identifier.0,
mdn_doc(self.identifier.0, None),
));
program.imports.push(backend::ast::Import { program.imports.push(backend::ast::Import {
module: None, module: None,
@ -248,70 +242,67 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface {
js_namespace: None, js_namespace: None,
kind: backend::ast::ImportKind::Type(backend::ast::ImportType { kind: backend::ast::ImportKind::Type(backend::ast::ImportType {
vis: public(), vis: public(),
name: rust_ident(camel_case_ident(&self.name).as_str()), name: rust_ident(camel_case_ident(self.identifier.0).as_str()),
attrs: Vec::new(), attrs: Vec::new(),
doc_comment, doc_comment,
}), }),
}); });
for extended_attribute in &self.extended_attributes { if let Some(attrs) = &self.attributes {
extended_attribute.webidl_parse(program, first_pass, self)?; for attr in &attrs.body.list {
attr.webidl_parse(program, first_pass, self)?;
}
} }
for member in &self.members { for member in &self.members.body {
member.webidl_parse(program, first_pass, &self.name)?; member.webidl_parse(program, first_pass, self.identifier.0)?;
} }
Ok(()) Ok(())
} }
} }
impl WebidlParse<()> for webidl::ast::PartialInterface { impl<'src> WebidlParse<'src, ()> for weedle::PartialInterfaceDefinition<'src> {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
(): (), (): (),
) -> Result<()> { ) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) { if util::is_chrome_only(&self.attributes) {
return Ok(()); return Ok(());
} }
if !first_pass.interfaces.contains_key(&self.name) { if !first_pass.interfaces.contains_key(self.identifier.0) {
warn!( warn!(
"Partial interface {} missing non-partial interface", "Partial interface {} missing non-partial interface",
self.name self.identifier.0
); );
} }
for member in &self.members { for member in &self.members.body {
member.webidl_parse(program, first_pass, &self.name)?; member.webidl_parse(program, first_pass, self.identifier.0)?;
} }
Ok(()) Ok(())
} }
} }
impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::ExtendedAttribute { impl<'src> WebidlParse<'src, &'src weedle::InterfaceDefinition<'src>> for ExtendedAttribute<'src> {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
interface: &'a webidl::ast::NonPartialInterface, interface: &'src weedle::InterfaceDefinition<'src>,
) -> Result<()> { ) -> Result<()> {
let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| { let mut add_constructor = |arguments: &[Argument], class: &str| {
let arguments = &arguments
.iter()
.map(|argument| argument.apply_typedefs(first_pass))
.collect::<Vec<_>>();
let (overloaded, same_argument_names) = first_pass.get_operation_overloading( let (overloaded, same_argument_names) = first_pass.get_operation_overloading(
arguments, arguments,
::first_pass::OperationId::Constructor, ::first_pass::OperationId::Constructor,
&interface.name, interface.identifier.0,
); );
let self_ty = ident_ty(rust_ident(camel_case_ident(&interface.name).as_str())); let self_ty = ident_ty(rust_ident(camel_case_ident(interface.identifier.0).as_str()));
let kind = backend::ast::ImportFunctionKind::Method { let kind = backend::ast::ImportFunctionKind::Method {
class: class.to_string(), class: class.to_string(),
@ -340,9 +331,7 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
"new", "new",
overloaded, overloaded,
same_argument_names, same_argument_names,
arguments arguments,
.iter()
.map(|arg| (&*arg.name, &*arg.type_, arg.variadic)),
Some(self_ty), Some(self_ty),
kind, kind,
structural, structural,
@ -354,34 +343,24 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
}; };
match self { match self {
webidl::ast::ExtendedAttribute::ArgumentList( ExtendedAttribute::ArgList(list)
webidl::ast::ArgumentListExtendedAttribute { arguments, name }, if list.identifier.0 == "Constructor" =>
)
if name == "Constructor" =>
{ {
add_constructor(arguments, &interface.name) add_constructor(&list.args.body.list, interface.identifier.0)
} }
webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) ExtendedAttribute::NoArgs(other) if (other.0).0 == "Constructor" => {
if name == "Constructor" => add_constructor(&[], interface.identifier.0)
}
ExtendedAttribute::NamedArgList(list)
if list.lhs_identifier.0 == "NamedConstructor" =>
{ {
add_constructor(&[], &interface.name) add_constructor(&list.args.body.list, list.rhs_identifier.0)
} }
webidl::ast::ExtendedAttribute::NamedArgumentList( ExtendedAttribute::ArgList(_)
webidl::ast::NamedArgumentListExtendedAttribute { | ExtendedAttribute::Ident(_)
lhs_name, | ExtendedAttribute::IdentList(_)
rhs_arguments, | ExtendedAttribute::NamedArgList(_)
rhs_name, | ExtendedAttribute::NoArgs(_) => {
},
)
if lhs_name == "NamedConstructor" =>
{
add_constructor(rhs_arguments, rhs_name)
}
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); warn!("Unsupported WebIDL extended attribute: {:?}", self);
} }
} }
@ -390,29 +369,32 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
} }
} }
impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember { impl<'src> WebidlParse<'src, &'src str> for weedle::interface::InterfaceMember<'src> {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
self_name: &'a str, self_name: &'src str,
) -> Result<()> { ) -> Result<()> {
use weedle::interface::InterfaceMember::*;
match self { match self {
webidl::ast::InterfaceMember::Attribute(attr) => { Attribute(attr) => {
attr.webidl_parse(program, first_pass, self_name) attr.webidl_parse(program, first_pass, self_name)
} }
webidl::ast::InterfaceMember::Operation(op) => { Operation(op) => {
op.webidl_parse(program, first_pass, self_name) op.webidl_parse(program, first_pass, self_name)
} }
webidl::ast::InterfaceMember::Const(cnst) => { Const(cnst) => {
cnst.webidl_parse(program, first_pass, self_name) cnst.webidl_parse(program, first_pass, self_name)
} }
webidl::ast::InterfaceMember::Iterable(iterable) => { Iterable(iterable) => {
iterable.webidl_parse(program, first_pass, self_name) iterable.webidl_parse(program, first_pass, self_name)
} }
// TODO // TODO
| webidl::ast::InterfaceMember::Maplike(_) | Maplike(_)
| webidl::ast::InterfaceMember::Setlike(_) => { | Stringifier(_)
| Setlike(_) => {
warn!("Unsupported WebIDL interface member: {:?}", self); warn!("Unsupported WebIDL interface member: {:?}", self);
Ok(()) Ok(())
} }
@ -420,103 +402,127 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember {
} }
} }
impl<'a> WebidlParse<&'a str> for webidl::ast::MixinMember { impl<'a, 'src> WebidlParse<'src, &'a str> for weedle::mixin::MixinMember<'src> {
fn webidl_parse( fn webidl_parse(
&self, &self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
self_name: &'a str, self_name: &'a str,
) -> Result<()> { ) -> Result<()> {
match self { match self {
webidl::ast::MixinMember::Attribute(attr) => { weedle::mixin::MixinMember::Attribute(attr) => {
attr.webidl_parse(program, first_pass, self_name) attr.webidl_parse(program, first_pass, self_name)
} }
webidl::ast::MixinMember::Operation(op) => { weedle::mixin::MixinMember::Operation(op) => {
op.webidl_parse(program, first_pass, self_name) op.webidl_parse(program, first_pass, self_name)
} }
// TODO // TODO
webidl::ast::MixinMember::Const(_) => { weedle::mixin::MixinMember::Stringifier(_) |
warn!("Unsupported WebIDL interface member: {:?}", self); weedle::mixin::MixinMember::Const(_) => {
Ok(()) warn!("Unsupported WebIDL mixin member: {:?}", self);
}
}
}
}
impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>,
self_name: &'a str,
) -> Result<()> {
match self {
webidl::ast::Attribute::Regular(attr) => {
attr.webidl_parse(program, first_pass, self_name)
}
webidl::ast::Attribute::Static(attr) => {
attr.webidl_parse(program, first_pass, self_name)
}
// TODO
webidl::ast::Attribute::Stringifier(_) => {
warn!("Unsupported WebIDL attribute: {:?}", self);
Ok(()) Ok(())
} }
} }
} }
} }
impl<'a> WebidlParse<&'a str> for webidl::ast::Operation { impl<'src> WebidlParse<'src, &'src str> for weedle::interface::AttributeInterfaceMember<'src> {
fn webidl_parse( fn webidl_parse(
&self, &self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
self_name: &'a str, self_name: &'src str,
) -> Result<()> { ) -> Result<()> {
match self { member_attribute(
webidl::ast::Operation::Regular(op) => op.webidl_parse(program, first_pass, self_name), program,
webidl::ast::Operation::Static(op) => op.webidl_parse(program, first_pass, self_name), first_pass,
// TODO self_name,
webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => { &self.attributes,
warn!("Unsupported WebIDL operation: {:?}", self); self.modifier,
Ok(()) self.readonly.is_some(),
} &self.type_,
} self.identifier.0,
)
} }
} }
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute { impl<'src> WebidlParse<'src, &'src str> for weedle::mixin::AttributeMixinMember<'src> {
fn webidl_parse( fn webidl_parse(
&self, &self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, first_pass: &FirstPassRecord<'src>,
self_name: &'a str, self_name: &'src str,
) -> Result<()> { ) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) { member_attribute(
program,
first_pass,
self_name,
&self.attributes,
if let Some(s) = self.stringifier {
Some(weedle::interface::StringifierOrInheritOrStatic::Stringifier(s))
} else {
None
},
self.readonly.is_some(),
&self.type_,
self.identifier.0,
)
}
}
fn member_attribute<'src>(
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'src>,
self_name: &'src str,
attrs: &'src Option<ExtendedAttributeList>,
modifier: Option<weedle::interface::StringifierOrInheritOrStatic>,
readonly: bool,
type_: &'src weedle::types::AttributedType<'src>,
identifier: &'src str,
) -> Result<()> {
use weedle::interface::StringifierOrInheritOrStatic::*;
if util::is_chrome_only(attrs) {
return Ok(()); return Ok(());
} }
let is_structural = util::is_structural(&self.extended_attributes); let statik = match modifier {
let throws = util::throws(&self.extended_attributes); Some(Stringifier(_)) => {
warn!("Unsupported stringifier on type {:?}", (self_name, identifier));
return Ok(())
}
Some(Inherit(_)) => false,
Some(Static(_)) => true,
None => false,
};
if type_.attributes.is_some() {
warn!("Unsupported attributes on type {:?}", (self_name, identifier));
return Ok(())
}
let is_structural = util::is_structural(attrs);
let throws = util::throws(attrs);
first_pass first_pass
.create_getter( .create_getter(
&self.name, identifier,
&self.type_.apply_typedefs(first_pass), &type_.type_,
self_name, self_name,
false, statik,
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 !readonly {
first_pass first_pass
.create_setter( .create_setter(
&self.name, identifier,
&self.type_.apply_typedefs(first_pass), type_.type_.clone(),
self_name, self_name,
false, statik,
is_structural, is_structural,
throws, throws,
) )
@ -525,23 +531,107 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
} }
Ok(()) Ok(())
}
impl<'src> WebidlParse<'src, &'src str> for weedle::interface::OperationInterfaceMember<'src> {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'src>,
self_name: &'src str,
) -> Result<()> {
member_operation(
program,
first_pass,
self_name,
&self.attributes,
self.modifier,
&self.specials,
&self.return_type,
&self.args.body.list,
&self.identifier,
)
} }
} }
impl<'a> WebidlParse<&'a str> for webidl::ast::Iterable { impl<'src> WebidlParse<'src, &'src str> for weedle::mixin::OperationMixinMember<'src> {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'src>,
self_name: &'src str,
) -> Result<()> {
member_operation(
program,
first_pass,
self_name,
&self.attributes,
None,
&[],
&self.return_type,
&self.args.body.list,
&self.identifier,
)
}
}
fn member_operation<'src>(
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'src>,
self_name: &'src str,
attrs: &'src Option<ExtendedAttributeList>,
modifier: Option<weedle::interface::StringifierOrStatic>,
specials: &[weedle::interface::Special],
return_type: &'src weedle::types::ReturnType<'src>,
args: &'src [Argument],
identifier: &Option<weedle::common::Identifier<'src>>,
) -> Result<()> {
use weedle::interface::StringifierOrStatic::*;
if util::is_chrome_only(attrs) {
return Ok(());
}
let statik = match modifier {
Some(Stringifier(_)) => {
warn!("Unsupported stringifier on type {:?}", (self_name, identifier));
return Ok(())
}
Some(Static(_)) => true,
None => false,
};
if specials.len() > 0 {
warn!("Unsupported specials on type {:?}", (self_name, identifier));
return Ok(())
}
first_pass
.create_basic_method(
args,
identifier.map(|s| s.0),
return_type,
self_name,
statik,
util::throws(attrs),
)
.map(wrap_import_function)
.map(|import| program.imports.push(import));
Ok(())
}
impl<'src> WebidlParse<'src, &'src str> for weedle::interface::IterableInterfaceMember<'src> {
fn webidl_parse( fn webidl_parse(
&self, &self,
_program: &mut backend::ast::Program, _program: &mut backend::ast::Program,
_first_pass: &FirstPassRecord<'_>, _first_pass: &FirstPassRecord<'src>,
_self_name: &'a str, _self_name: &'src str,
) -> Result<()> { ) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) { // if util::is_chrome_only(&self.attributes) {
return Ok(()); // return Ok(());
} // }
/* TODO /* TODO
let throws = util::throws(&self.extended_attributes); let throws = util::throws(&self.extended_attributes);
let return_value = webidl::ast::ReturnType::NonVoid(self.value_type.clone()); let return_value = weedle::ReturnType::NonVoid(self.value_type.clone());
let args = []; let args = [];
first_pass first_pass
.create_basic_method( .create_basic_method(
@ -572,142 +662,32 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Iterable {
} }
} }
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute { impl<'src> WebidlParse<'src, ()> for weedle::EnumDefinition<'src> {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, _: &FirstPassRecord<'src>,
self_name: &'a str,
) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) {
return Ok(());
}
let is_structural = util::is_structural(&self.extended_attributes);
let throws = util::throws(&self.extended_attributes);
first_pass
.create_getter(
&self.name,
&self.type_.apply_typedefs(first_pass),
self_name,
true,
is_structural,
throws,
)
.map(wrap_import_function)
.map(|import| program.imports.push(import));
if !self.read_only {
first_pass
.create_setter(
&self.name,
&self.type_.apply_typedefs(first_pass),
self_name,
true,
is_structural,
throws,
)
.map(wrap_import_function)
.map(|import| program.imports.push(import));
}
Ok(())
}
}
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>,
self_name: &'a str,
) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) {
return Ok(());
}
let throws = util::throws(&self.extended_attributes);
first_pass
.create_basic_method(
&self
.arguments
.iter()
.map(|argument| argument.apply_typedefs(first_pass))
.collect::<Vec<_>>(),
self.name.as_ref(),
&self.return_type.apply_typedefs(first_pass),
self_name,
false,
throws,
)
.map(wrap_import_function)
.map(|import| program.imports.push(import));
Ok(())
}
}
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>,
self_name: &'a str,
) -> Result<()> {
if util::is_chrome_only(&self.extended_attributes) {
return Ok(());
}
let throws = util::throws(&self.extended_attributes);
first_pass
.create_basic_method(
&self
.arguments
.iter()
.map(|argument| argument.apply_typedefs(first_pass))
.collect::<Vec<_>>(),
self.name.as_ref(),
&self.return_type.apply_typedefs(first_pass),
self_name,
true,
throws,
)
.map(wrap_import_function)
.map(|import| program.imports.push(import));
Ok(())
}
}
impl<'a> WebidlParse<()> for webidl::ast::Enum {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
_: &FirstPassRecord<'_>,
(): (), (): (),
) -> Result<()> { ) -> Result<()> {
let variants = &self.values.body.list;
program.imports.push(backend::ast::Import { program.imports.push(backend::ast::Import {
module: None, module: None,
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: public(), vis: public(),
name: rust_ident(camel_case_ident(&self.name).as_str()), name: rust_ident(camel_case_ident(self.identifier.0).as_str()),
variants: self variants: variants
.variants
.iter() .iter()
.map(|v| .map(|v| {
if !v.is_empty() { if !v.0.is_empty() {
rust_ident(camel_case_ident(&v).as_str()) rust_ident(camel_case_ident(&v.0).as_str())
} else { } else {
rust_ident("None") rust_ident("None")
} }
) })
.collect(), .collect(),
variant_values: self.variants.clone(), variant_values: variants.iter().map(|v| v.0.to_string()).collect(),
rust_attrs: vec![parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])], rust_attrs: vec![parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])],
}), }),
}); });
@ -716,21 +696,24 @@ impl<'a> WebidlParse<()> for webidl::ast::Enum {
} }
} }
impl<'a> WebidlParse<&'a str> for webidl::ast::Const { impl<'src> WebidlParse<'src, &'src str> for weedle::interface::ConstMember<'src> {
fn webidl_parse( fn webidl_parse(
&self, &'src self,
program: &mut backend::ast::Program, program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'_>, record: &FirstPassRecord<'src>,
self_name: &'a str, self_name: &'src str,
) -> Result<()> { ) -> Result<()> {
let ty = webidl_const_ty_to_syn_ty(&self.type_.apply_typedefs(first_pass)); let ty = match self.const_type.to_syn_type(record, TypePosition::Return) {
Some(s) => s,
None => return Ok(()),
};
program.consts.push(backend::ast::Const { program.consts.push(backend::ast::Const {
vis: public(), vis: public(),
name: rust_ident(self.name.to_shouty_snake_case().as_str()), name: rust_ident(self.identifier.0.to_shouty_snake_case().as_str()),
class: Some(rust_ident(camel_case_ident(&self_name).as_str())), class: Some(rust_ident(camel_case_ident(&self_name).as_str())),
ty, ty,
value: webidl_const_v_to_backend_const_v(&self.value), value: webidl_const_v_to_backend_const_v(&self.const_value),
}); });
Ok(()) Ok(())

File diff suppressed because it is too large Load Diff