2018-05-25 17:51:48 -07:00
|
|
|
/*!
|
|
|
|
# `wasm_bindgen_webidl`
|
|
|
|
|
|
|
|
Converts WebIDL into wasm-bindgen's internal AST form, so that bindings can be
|
|
|
|
emitted for the types and methods described in the WebIDL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#![deny(missing_docs)]
|
|
|
|
#![deny(missing_debug_implementations)]
|
2018-07-19 14:57:04 -05:00
|
|
|
#![doc(html_root_url = "https://docs.rs/wasm-bindgen-webidl/0.2")]
|
2018-05-25 17:51:48 -07:00
|
|
|
|
2018-09-26 08:26:00 -07:00
|
|
|
mod error;
|
2018-07-13 21:46:36 -07:00
|
|
|
mod first_pass;
|
2018-08-11 23:46:33 +03:00
|
|
|
mod idl_type;
|
2018-06-25 10:41:33 -07:00
|
|
|
mod util;
|
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
use crate::first_pass::{CallbackInterfaceData, OperationData};
|
|
|
|
use crate::first_pass::{FirstPass, FirstPassRecord, InterfaceData, OperationId};
|
|
|
|
use crate::idl_type::ToIdlType;
|
|
|
|
use crate::util::{
|
|
|
|
camel_case_ident, mdn_doc, public, shouty_snake_case_ident, snake_case_ident,
|
|
|
|
webidl_const_v_to_backend_const_v, TypePosition,
|
|
|
|
};
|
|
|
|
use failure::format_err;
|
|
|
|
use proc_macro2::{Ident, Span};
|
|
|
|
use quote::{quote, ToTokens};
|
2018-09-10 09:52:35 -07:00
|
|
|
use std::collections::{BTreeSet, HashSet};
|
2018-09-05 12:55:30 -07:00
|
|
|
use std::env;
|
2018-05-25 17:51:48 -07:00
|
|
|
use std::fs;
|
2018-07-26 18:09:04 +01:00
|
|
|
use std::iter::FromIterator;
|
2019-03-26 08:00:16 -07:00
|
|
|
use wasm_bindgen_backend::ast;
|
|
|
|
use wasm_bindgen_backend::defined::ImportedTypeReferences;
|
|
|
|
use wasm_bindgen_backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
|
|
|
|
use wasm_bindgen_backend::util::{ident_ty, raw_ident, rust_ident, wrap_import_function};
|
|
|
|
use wasm_bindgen_backend::TryToTokens;
|
2018-09-26 08:26:00 -07:00
|
|
|
use weedle::attribute::ExtendedAttributeList;
|
2018-08-14 10:16:18 -07:00
|
|
|
use weedle::dictionary::DictionaryMember;
|
2018-09-10 11:16:55 -07:00
|
|
|
use weedle::interface::InterfaceMember;
|
2018-06-14 02:03:52 -07:00
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
pub use crate::error::{Error, ErrorKind, Result};
|
2018-05-25 17:51:48 -07:00
|
|
|
|
2018-09-17 13:46:18 -07:00
|
|
|
struct Program {
|
2019-03-26 08:00:16 -07:00
|
|
|
main: ast::Program,
|
|
|
|
submodules: Vec<(String, ast::Program)>,
|
2018-09-17 13:46:18 -07:00
|
|
|
}
|
|
|
|
|
2018-05-25 17:51:48 -07:00
|
|
|
/// Parse a string of WebIDL source text into a wasm-bindgen AST.
|
2018-09-26 08:26:00 -07:00
|
|
|
fn parse(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result<Program> {
|
2018-08-03 14:39:33 -07:00
|
|
|
let definitions = match weedle::parse(webidl_source) {
|
2018-07-26 18:09:04 +01:00
|
|
|
Ok(def) => def,
|
|
|
|
Err(e) => {
|
2018-08-03 14:39:33 -07:00
|
|
|
return Err(match &e {
|
2018-09-26 08:26:00 -07:00
|
|
|
weedle::Err::Incomplete(needed) => format_err!("needed {:?} more bytes", needed)
|
|
|
|
.context(ErrorKind::ParsingWebIDLSource)
|
|
|
|
.into(),
|
|
|
|
weedle::Err::Error(cx) | weedle::Err::Failure(cx) => {
|
2019-03-12 12:22:24 -07:00
|
|
|
// Note that #[allow] here is a workaround for Geal/nom#843
|
|
|
|
// because the `Context` type here comes from `nom` and if
|
|
|
|
// something else in our crate graph enables the
|
|
|
|
// `verbose-errors` feature then we need to still compiled
|
|
|
|
// against the changed enum definition.
|
|
|
|
#[allow(unreachable_patterns)]
|
2018-08-03 14:39:33 -07:00
|
|
|
let remaining = match cx {
|
2019-03-12 12:22:24 -07:00
|
|
|
weedle::Context::Code(remaining, _) => remaining.len(),
|
|
|
|
_ => 0,
|
2018-08-03 14:39:33 -07:00
|
|
|
};
|
2019-03-12 12:22:24 -07:00
|
|
|
let pos = webidl_source.len() - remaining;
|
2018-08-03 14:39:33 -07:00
|
|
|
format_err!("failed to parse WebIDL")
|
2018-09-26 08:26:00 -07:00
|
|
|
.context(ErrorKind::ParsingWebIDLSourcePos(pos))
|
|
|
|
.into()
|
2018-07-26 18:09:04 +01:00
|
|
|
}
|
2018-08-03 14:39:33 -07:00
|
|
|
});
|
2018-07-26 18:09:04 +01:00
|
|
|
}
|
|
|
|
};
|
2018-05-25 17:51:48 -07:00
|
|
|
|
2018-09-05 12:55:30 -07:00
|
|
|
let mut first_pass_record: FirstPassRecord = Default::default();
|
|
|
|
first_pass_record.builtin_idents = builtin_idents();
|
2019-03-08 15:12:41 -08:00
|
|
|
first_pass_record.immutable_slice_whitelist = immutable_slice_whitelist();
|
2019-02-07 07:14:33 -05:00
|
|
|
|
2018-07-30 17:41:22 +03:00
|
|
|
definitions.first_pass(&mut first_pass_record, ())?;
|
2018-07-13 21:46:36 -07:00
|
|
|
let mut program = Default::default();
|
2018-09-17 13:46:18 -07:00
|
|
|
let mut submodules = Vec::new();
|
2018-08-28 16:32:31 -07:00
|
|
|
|
2018-09-26 08:26:00 -07:00
|
|
|
let allowed_types = allowed_types.map(|list| list.iter().cloned().collect::<HashSet<_>>());
|
|
|
|
let filter = |name: &str| match &allowed_types {
|
|
|
|
Some(set) => set.contains(name),
|
|
|
|
None => true,
|
2018-09-10 09:52:35 -07:00
|
|
|
};
|
2018-09-05 12:55:30 -07:00
|
|
|
|
2018-09-10 09:52:35 -07:00
|
|
|
for (name, e) in first_pass_record.enums.iter() {
|
2018-09-25 11:25:14 -07:00
|
|
|
if filter(&camel_case_ident(name)) {
|
2018-09-10 09:52:35 -07:00
|
|
|
first_pass_record.append_enum(&mut program, e);
|
|
|
|
}
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
2018-09-10 09:52:35 -07:00
|
|
|
for (name, d) in first_pass_record.dictionaries.iter() {
|
2018-09-25 11:25:14 -07:00
|
|
|
if filter(&camel_case_ident(name)) {
|
2018-09-10 09:52:35 -07:00
|
|
|
first_pass_record.append_dictionary(&mut program, d);
|
|
|
|
}
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
|
|
|
for (name, n) in first_pass_record.namespaces.iter() {
|
2018-09-25 11:25:14 -07:00
|
|
|
if filter(&snake_case_ident(name)) {
|
|
|
|
let prog = first_pass_record.append_ns(name, n);
|
|
|
|
submodules.push((snake_case_ident(name).to_string(), prog));
|
|
|
|
}
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
|
|
|
for (name, d) in first_pass_record.interfaces.iter() {
|
2018-09-25 11:25:14 -07:00
|
|
|
if filter(&camel_case_ident(name)) {
|
2018-09-10 09:52:35 -07:00
|
|
|
first_pass_record.append_interface(&mut program, name, d);
|
|
|
|
}
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
2018-09-10 11:16:55 -07:00
|
|
|
for (name, d) in first_pass_record.callback_interfaces.iter() {
|
2018-09-25 11:25:14 -07:00
|
|
|
if filter(&camel_case_ident(name)) {
|
2018-09-10 11:16:55 -07:00
|
|
|
first_pass_record.append_callback_interface(&mut program, d);
|
|
|
|
}
|
|
|
|
}
|
2018-05-25 17:51:48 -07:00
|
|
|
|
2018-09-10 09:52:35 -07:00
|
|
|
// Prune out `extends` annotations that aren't defined as these shouldn't
|
|
|
|
// prevent the type from being usable entirely. They're just there for
|
|
|
|
// `AsRef` and such implementations.
|
|
|
|
for import in program.imports.iter_mut() {
|
2019-03-26 08:00:16 -07:00
|
|
|
if let ast::ImportKind::Type(t) = &mut import.kind {
|
2018-10-03 00:04:43 -07:00
|
|
|
t.extends.retain(|n| {
|
|
|
|
let ident = &n.segments.last().unwrap().value().ident;
|
2018-11-27 12:07:59 -08:00
|
|
|
first_pass_record.builtin_idents.contains(ident) || filter(&ident.to_string())
|
2018-10-03 00:04:43 -07:00
|
|
|
});
|
2018-09-05 12:55:30 -07:00
|
|
|
}
|
|
|
|
}
|
2018-09-10 09:52:35 -07:00
|
|
|
|
2018-09-17 13:46:18 -07:00
|
|
|
Ok(Program {
|
|
|
|
main: program,
|
|
|
|
submodules: submodules,
|
|
|
|
})
|
2018-05-30 14:30:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Compile the given WebIDL source text into Rust source text containing
|
|
|
|
/// `wasm-bindgen` bindings to the things described in the WebIDL.
|
2018-09-26 08:26:00 -07:00
|
|
|
pub fn compile(webidl_source: &str, allowed_types: Option<&[&str]>) -> Result<String> {
|
2018-09-05 12:55:30 -07:00
|
|
|
let ast = parse(webidl_source, allowed_types)?;
|
2018-07-09 16:35:25 -07:00
|
|
|
Ok(compile_ast(ast))
|
2018-05-30 14:30:40 -07:00
|
|
|
}
|
|
|
|
|
2018-09-05 12:55:30 -07:00
|
|
|
fn builtin_idents() -> BTreeSet<Ident> {
|
|
|
|
BTreeSet::from_iter(
|
2018-07-09 16:35:25 -07:00
|
|
|
vec![
|
2018-09-26 08:26:00 -07:00
|
|
|
"str",
|
|
|
|
"char",
|
|
|
|
"bool",
|
|
|
|
"JsValue",
|
|
|
|
"u8",
|
|
|
|
"i8",
|
|
|
|
"u16",
|
|
|
|
"i16",
|
|
|
|
"u32",
|
|
|
|
"i32",
|
|
|
|
"u64",
|
|
|
|
"i64",
|
|
|
|
"usize",
|
|
|
|
"isize",
|
|
|
|
"f32",
|
|
|
|
"f64",
|
|
|
|
"Result",
|
|
|
|
"String",
|
|
|
|
"Vec",
|
|
|
|
"Option",
|
|
|
|
"Array",
|
|
|
|
"ArrayBuffer",
|
|
|
|
"Object",
|
|
|
|
"Promise",
|
|
|
|
"Function",
|
|
|
|
"Clamped",
|
2018-11-27 12:07:59 -08:00
|
|
|
]
|
|
|
|
.into_iter()
|
2018-09-26 08:26:00 -07:00
|
|
|
.map(|id| proc_macro2::Ident::new(id, proc_macro2::Span::call_site())),
|
2018-09-05 12:55:30 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-03-08 15:12:41 -08:00
|
|
|
fn immutable_slice_whitelist() -> BTreeSet<&'static str> {
|
Migrate `wasm-bindgen` to using `walrus`
This commit moves `wasm-bindgen` the CLI tool from internally using
`parity-wasm` for wasm parsing/serialization to instead use `walrus`.
The `walrus` crate is something we've been working on recently with an
aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the
current CLI tool more maintainable as well as more future-proof.
The `walrus` crate provides a much nicer AST to work with as well as a
structured `Module`, whereas `parity-wasm` provides a very raw interface
to the wasm module which isn't really appropriate for our use case. The
many transformations and tweaks that wasm-bindgen does have a huge
amount of ad-hoc index management to carefully craft a final wasm
binary, but this is all entirely taken care for us with the `walrus`
crate.
Additionally, `wasm-bindgen` will ingest and rewrite the wasm file,
often changing the binary offsets of functions. Eventually with DWARF
debug information we'll need to be sure to preserve the debug
information throughout the transformations that `wasm-bindgen` does
today. This is practically impossible to do with the `parity-wasm`
architecture, but `walrus` was designed from the get-go to solve this
problem transparently in the `walrus` crate itself. (it doesn't today,
but this is planned work)
It is the intention that this does not end up regressing any
`wasm-bindgen` use cases, neither in functionality or in speed. As a
large change and refactoring, however, it's likely that at least
something will arise! We'll want to continue to remain vigilant to any
issues that come up with this commit.
Note that the `gc` crate has been deleted as part of this change, as the
`gc` crate is no longer necessary since `walrus` does it automatically.
Additionally the `gc` crate was one of the main problems with preserving
debug information as it often deletes wasm items!
Finally, this also starts moving crates to the 2018 edition where
necessary since `walrus` requires the 2018 edition, and in general it's
more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
|
|
|
BTreeSet::from_iter(vec![
|
2019-03-08 15:12:41 -08:00
|
|
|
// WebGlRenderingContext, WebGl2RenderingContext
|
Migrate `wasm-bindgen` to using `walrus`
This commit moves `wasm-bindgen` the CLI tool from internally using
`parity-wasm` for wasm parsing/serialization to instead use `walrus`.
The `walrus` crate is something we've been working on recently with an
aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the
current CLI tool more maintainable as well as more future-proof.
The `walrus` crate provides a much nicer AST to work with as well as a
structured `Module`, whereas `parity-wasm` provides a very raw interface
to the wasm module which isn't really appropriate for our use case. The
many transformations and tweaks that wasm-bindgen does have a huge
amount of ad-hoc index management to carefully craft a final wasm
binary, but this is all entirely taken care for us with the `walrus`
crate.
Additionally, `wasm-bindgen` will ingest and rewrite the wasm file,
often changing the binary offsets of functions. Eventually with DWARF
debug information we'll need to be sure to preserve the debug
information throughout the transformations that `wasm-bindgen` does
today. This is practically impossible to do with the `parity-wasm`
architecture, but `walrus` was designed from the get-go to solve this
problem transparently in the `walrus` crate itself. (it doesn't today,
but this is planned work)
It is the intention that this does not end up regressing any
`wasm-bindgen` use cases, neither in functionality or in speed. As a
large change and refactoring, however, it's likely that at least
something will arise! We'll want to continue to remain vigilant to any
issues that come up with this commit.
Note that the `gc` crate has been deleted as part of this change, as the
`gc` crate is no longer necessary since `walrus` does it automatically.
Additionally the `gc` crate was one of the main problems with preserving
debug information as it often deletes wasm items!
Finally, this also starts moving crates to the 2018 edition where
necessary since `walrus` requires the 2018 edition, and in general it's
more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
|
|
|
"uniform1fv",
|
|
|
|
"uniform2fv",
|
|
|
|
"uniform3fv",
|
|
|
|
"uniform4fv",
|
|
|
|
"uniformMatrix2fv",
|
|
|
|
"uniformMatrix3fv",
|
|
|
|
"uniformMatrix4fv",
|
|
|
|
"vertexAttrib1fv",
|
|
|
|
"vertexAttrib2fv",
|
|
|
|
"vertexAttrib3fv",
|
|
|
|
"vertexAttrib4fv",
|
2019-03-08 15:12:41 -08:00
|
|
|
"bufferData",
|
|
|
|
"texImage2D",
|
|
|
|
"texSubImage2D",
|
|
|
|
"compressedTexImage2D",
|
|
|
|
// WebGl2RenderingContext
|
|
|
|
"texImage3D",
|
|
|
|
"texSubImage3D",
|
|
|
|
"compressedTexImage3D",
|
Migrate `wasm-bindgen` to using `walrus`
This commit moves `wasm-bindgen` the CLI tool from internally using
`parity-wasm` for wasm parsing/serialization to instead use `walrus`.
The `walrus` crate is something we've been working on recently with an
aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the
current CLI tool more maintainable as well as more future-proof.
The `walrus` crate provides a much nicer AST to work with as well as a
structured `Module`, whereas `parity-wasm` provides a very raw interface
to the wasm module which isn't really appropriate for our use case. The
many transformations and tweaks that wasm-bindgen does have a huge
amount of ad-hoc index management to carefully craft a final wasm
binary, but this is all entirely taken care for us with the `walrus`
crate.
Additionally, `wasm-bindgen` will ingest and rewrite the wasm file,
often changing the binary offsets of functions. Eventually with DWARF
debug information we'll need to be sure to preserve the debug
information throughout the transformations that `wasm-bindgen` does
today. This is practically impossible to do with the `parity-wasm`
architecture, but `walrus` was designed from the get-go to solve this
problem transparently in the `walrus` crate itself. (it doesn't today,
but this is planned work)
It is the intention that this does not end up regressing any
`wasm-bindgen` use cases, neither in functionality or in speed. As a
large change and refactoring, however, it's likely that at least
something will arise! We'll want to continue to remain vigilant to any
issues that come up with this commit.
Note that the `gc` crate has been deleted as part of this change, as the
`gc` crate is no longer necessary since `walrus` does it automatically.
Additionally the `gc` crate was one of the main problems with preserving
debug information as it often deletes wasm items!
Finally, this also starts moving crates to the 2018 edition where
necessary since `walrus` requires the 2018 edition, and in general it's
more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
|
|
|
// TODO: Add another type's functions here. Leave a comment header with the type name
|
|
|
|
])
|
2019-02-07 07:14:33 -05:00
|
|
|
}
|
|
|
|
|
2018-09-05 12:55:30 -07:00
|
|
|
/// Run codegen on the AST to generate rust code.
|
2018-09-17 13:46:18 -07:00
|
|
|
fn compile_ast(mut ast: Program) -> String {
|
2018-09-05 12:55:30 -07:00
|
|
|
// Iteratively prune all entries from the AST which reference undefined
|
|
|
|
// fields. Each pass may remove definitions of types and so we need to
|
|
|
|
// reexecute this pass to see if we need to keep removing types until we
|
|
|
|
// reach a steady state.
|
|
|
|
let builtin = builtin_idents();
|
|
|
|
let mut all_definitions = BTreeSet::new();
|
|
|
|
let track = env::var_os("__WASM_BINDGEN_DUMP_FEATURES");
|
2018-08-14 10:16:18 -07:00
|
|
|
loop {
|
|
|
|
let mut defined = builtin.clone();
|
2018-09-17 13:46:18 -07:00
|
|
|
{
|
|
|
|
let mut cb = |id: &Ident| {
|
|
|
|
defined.insert(id.clone());
|
|
|
|
if track.is_some() {
|
|
|
|
all_definitions.insert(id.clone());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
ast.main.imported_type_definitions(&mut cb);
|
2018-09-25 11:25:14 -07:00
|
|
|
for (name, m) in ast.submodules.iter() {
|
|
|
|
cb(&Ident::new(name, Span::call_site()));
|
2018-09-17 13:46:18 -07:00
|
|
|
m.imported_type_references(&mut cb);
|
2018-09-05 12:55:30 -07:00
|
|
|
}
|
2018-09-17 13:46:18 -07:00
|
|
|
}
|
2018-09-26 08:26:00 -07:00
|
|
|
let changed = ast
|
|
|
|
.main
|
|
|
|
.remove_undefined_imports(&|id| defined.contains(id))
|
|
|
|
|| ast
|
|
|
|
.submodules
|
|
|
|
.iter_mut()
|
|
|
|
.any(|(_, m)| m.remove_undefined_imports(&|id| defined.contains(id)));
|
2018-09-17 13:46:18 -07:00
|
|
|
if !changed {
|
2018-09-26 08:26:00 -07:00
|
|
|
break;
|
2018-08-14 10:16:18 -07:00
|
|
|
}
|
|
|
|
}
|
2018-09-05 12:55:30 -07:00
|
|
|
if let Some(path) = track {
|
2018-09-26 08:26:00 -07:00
|
|
|
let contents = all_definitions
|
|
|
|
.into_iter()
|
2018-09-25 11:25:14 -07:00
|
|
|
.filter(|def| !builtin.contains(def))
|
2018-09-05 12:55:30 -07:00
|
|
|
.map(|s| format!("{} = []", s))
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n");
|
|
|
|
fs::write(path, contents).unwrap();
|
|
|
|
}
|
2018-07-09 16:35:25 -07:00
|
|
|
|
2018-05-30 14:30:40 -07:00
|
|
|
let mut tokens = proc_macro2::TokenStream::new();
|
2018-09-17 13:46:18 -07:00
|
|
|
if let Err(e) = ast.main.try_to_tokens(&mut tokens) {
|
2018-08-01 17:15:27 -05:00
|
|
|
e.panic();
|
|
|
|
}
|
2018-09-17 13:46:18 -07:00
|
|
|
for (name, m) in ast.submodules.iter() {
|
|
|
|
let mut m_tokens = proc_macro2::TokenStream::new();
|
|
|
|
if let Err(e) = m.try_to_tokens(&mut m_tokens) {
|
|
|
|
e.panic();
|
|
|
|
}
|
|
|
|
|
|
|
|
let name = Ident::new(name, Span::call_site());
|
|
|
|
|
|
|
|
(quote! {
|
|
|
|
pub mod #name { #m_tokens }
|
2018-11-27 12:07:59 -08:00
|
|
|
})
|
|
|
|
.to_tokens(&mut tokens);
|
2018-09-17 13:46:18 -07:00
|
|
|
}
|
2018-05-30 14:30:40 -07:00
|
|
|
tokens.to_string()
|
|
|
|
}
|
|
|
|
|
2018-08-28 16:32:31 -07:00
|
|
|
impl<'src> FirstPassRecord<'src> {
|
2019-03-26 08:00:16 -07:00
|
|
|
fn append_enum(&self, program: &mut ast::Program, enum_: &'src weedle::EnumDefinition<'src>) {
|
2018-08-28 16:32:31 -07:00
|
|
|
let variants = &enum_.values.body.list;
|
2019-03-26 08:00:16 -07:00
|
|
|
program.imports.push(ast::Import {
|
|
|
|
module: ast::ImportModule::None,
|
2018-07-08 22:09:00 -04:00
|
|
|
js_namespace: None,
|
2019-03-26 08:00:16 -07:00
|
|
|
kind: ast::ImportKind::Enum(ast::ImportEnum {
|
2018-07-10 22:59:59 -07:00
|
|
|
vis: public(),
|
2018-08-28 16:32:31 -07:00
|
|
|
name: rust_ident(camel_case_ident(enum_.identifier.0).as_str()),
|
2018-08-03 14:39:33 -07:00
|
|
|
variants: variants
|
2018-07-08 22:09:00 -04:00
|
|
|
.iter()
|
2018-08-03 14:39:33 -07:00
|
|
|
.map(|v| {
|
2018-08-09 21:38:37 +01:00
|
|
|
if !v.0.is_empty() {
|
|
|
|
rust_ident(camel_case_ident(&v.0).as_str())
|
2018-08-04 00:19:06 +03:00
|
|
|
} else {
|
|
|
|
rust_ident("None")
|
|
|
|
}
|
2018-11-27 12:07:59 -08:00
|
|
|
})
|
|
|
|
.collect(),
|
2018-08-03 14:39:33 -07:00
|
|
|
variant_values: variants.iter().map(|v| v.0.to_string()).collect(),
|
2019-03-26 08:00:16 -07:00
|
|
|
rust_attrs: vec![syn::parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])],
|
2018-07-08 22:09:00 -04:00
|
|
|
}),
|
|
|
|
});
|
2018-07-13 06:04:40 +02:00
|
|
|
}
|
2018-08-09 21:38:37 +01:00
|
|
|
|
2018-08-28 16:32:31 -07:00
|
|
|
// tons more data for what's going on here at
|
|
|
|
// https://www.w3.org/TR/WebIDL-1/#idl-dictionaries
|
|
|
|
fn append_dictionary(
|
|
|
|
&self,
|
2019-03-26 08:00:16 -07:00
|
|
|
program: &mut ast::Program,
|
2018-08-29 15:00:58 -07:00
|
|
|
data: &first_pass::DictionaryData<'src>,
|
2018-08-28 16:32:31 -07:00
|
|
|
) {
|
|
|
|
let def = match data.definition {
|
|
|
|
Some(def) => def,
|
|
|
|
None => return,
|
2018-08-10 19:00:56 +01:00
|
|
|
};
|
2018-08-14 10:16:18 -07:00
|
|
|
let mut fields = Vec::new();
|
2018-08-29 10:40:17 -07:00
|
|
|
if !self.append_dictionary_members(def.identifier.0, &mut fields) {
|
2018-09-26 08:26:00 -07:00
|
|
|
return;
|
2018-08-14 10:16:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
program.dictionaries.push(ast::Dictionary {
|
2018-08-28 16:32:31 -07:00
|
|
|
name: rust_ident(&camel_case_ident(def.identifier.0)),
|
2018-08-14 10:16:18 -07:00
|
|
|
fields,
|
|
|
|
});
|
2018-08-29 10:40:17 -07:00
|
|
|
}
|
2018-08-14 10:16:18 -07:00
|
|
|
|
2018-08-29 10:40:17 -07:00
|
|
|
fn append_dictionary_members(
|
|
|
|
&self,
|
|
|
|
dict: &'src str,
|
|
|
|
dst: &mut Vec<ast::DictionaryField>,
|
|
|
|
) -> bool {
|
|
|
|
let dict_data = &self.dictionaries[&dict];
|
|
|
|
let definition = dict_data.definition.unwrap();
|
|
|
|
|
|
|
|
// > The order of the dictionary members on a given dictionary is
|
|
|
|
// > such that inherited dictionary members are ordered before
|
|
|
|
// > non-inherited members ...
|
|
|
|
if let Some(parent) = &definition.inheritance {
|
|
|
|
if !self.append_dictionary_members(parent.identifier.0, dst) {
|
2018-09-26 08:26:00 -07:00
|
|
|
return false;
|
2018-08-14 10:16:18 -07:00
|
|
|
}
|
2018-08-29 10:40:17 -07:00
|
|
|
}
|
2018-08-14 10:16:18 -07:00
|
|
|
|
2018-08-29 10:40:17 -07:00
|
|
|
// > ... and the dictionary members on the one dictionary
|
|
|
|
// > definition (including any partial dictionary definitions) are
|
|
|
|
// > ordered lexicographically by the Unicode codepoints that
|
|
|
|
// > comprise their identifiers.
|
|
|
|
let start = dst.len();
|
|
|
|
let members = definition.members.body.iter();
|
|
|
|
let partials = dict_data.partials.iter().flat_map(|d| &d.members.body);
|
|
|
|
for member in members.chain(partials) {
|
|
|
|
match self.dictionary_field(member) {
|
|
|
|
Some(f) => dst.push(f),
|
|
|
|
None => {
|
2019-03-26 08:00:16 -07:00
|
|
|
log::warn!(
|
2018-08-29 10:40:17 -07:00
|
|
|
"unsupported dictionary field {:?}",
|
|
|
|
(dict, member.identifier.0),
|
|
|
|
);
|
|
|
|
// If this is required then we can't support the
|
|
|
|
// dictionary at all, but if it's not required we can
|
|
|
|
// avoid generating bindings for the field and keep
|
|
|
|
// going otherwise.
|
|
|
|
if member.required.is_some() {
|
2018-09-26 08:26:00 -07:00
|
|
|
return false;
|
2018-08-14 10:16:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-07 14:15:00 +00:00
|
|
|
dst[start..].sort_by_key(|f| f.js_name.clone());
|
2018-08-14 10:16:18 -07:00
|
|
|
|
2018-09-26 08:26:00 -07:00
|
|
|
return true;
|
2018-08-29 10:40:17 -07:00
|
|
|
}
|
2018-08-14 10:16:18 -07:00
|
|
|
|
2018-08-29 10:40:17 -07:00
|
|
|
fn dictionary_field(
|
|
|
|
&self,
|
|
|
|
field: &'src DictionaryMember<'src>,
|
|
|
|
) -> Option<ast::DictionaryField> {
|
|
|
|
// use argument position now as we're just binding setters
|
2018-09-26 08:26:00 -07:00
|
|
|
let ty = field
|
|
|
|
.type_
|
2018-11-07 10:37:43 -08:00
|
|
|
.to_idl_type(self)
|
2018-09-26 08:26:00 -07:00
|
|
|
.to_syn_type(TypePosition::Argument)?;
|
2018-08-29 10:40:17 -07:00
|
|
|
|
|
|
|
// Slice types aren't supported because they don't implement
|
|
|
|
// `Into<JsValue>`
|
2018-08-30 12:15:37 +02:00
|
|
|
match ty {
|
2018-09-26 08:26:00 -07:00
|
|
|
syn::Type::Reference(ref i) => match &*i.elem {
|
|
|
|
syn::Type::Slice(_) => return None,
|
|
|
|
_ => (),
|
|
|
|
},
|
2018-08-30 12:15:37 +02:00
|
|
|
syn::Type::Path(ref path, ..) =>
|
2018-09-26 08:26:00 -07:00
|
|
|
// check that our inner don't contains slices either
|
|
|
|
{
|
2018-08-30 12:15:37 +02:00
|
|
|
for seg in path.path.segments.iter() {
|
|
|
|
if let syn::PathArguments::AngleBracketed(ref arg) = seg.arguments {
|
|
|
|
for elem in &arg.args {
|
|
|
|
if let syn::GenericArgument::Type(syn::Type::Reference(ref i)) = elem {
|
|
|
|
match &*i.elem {
|
|
|
|
syn::Type::Slice(_) => return None,
|
2018-09-26 08:26:00 -07:00
|
|
|
_ => (),
|
2018-08-30 12:15:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-26 08:26:00 -07:00
|
|
|
}
|
|
|
|
_ => (),
|
2018-08-30 12:15:37 +02:00
|
|
|
};
|
2018-08-14 10:16:18 -07:00
|
|
|
|
2018-08-29 10:40:17 -07:00
|
|
|
// Similarly i64/u64 aren't supported because they don't
|
|
|
|
// implement `Into<JsValue>`
|
|
|
|
let mut any_64bit = false;
|
|
|
|
ty.imported_type_references(&mut |i| {
|
|
|
|
any_64bit = any_64bit || i == "u64" || i == "i64";
|
|
|
|
});
|
|
|
|
if any_64bit {
|
2018-09-26 08:26:00 -07:00
|
|
|
return None;
|
2018-08-14 10:16:18 -07:00
|
|
|
}
|
2018-08-29 10:40:17 -07:00
|
|
|
|
|
|
|
Some(ast::DictionaryField {
|
|
|
|
required: field.required.is_some(),
|
2019-01-07 14:15:00 +00:00
|
|
|
rust_name: rust_ident(&snake_case_ident(field.identifier.0)),
|
|
|
|
js_name: field.identifier.0.to_string(),
|
2018-08-29 10:40:17 -07:00
|
|
|
ty,
|
|
|
|
})
|
2018-08-14 10:16:18 -07:00
|
|
|
}
|
2018-08-28 16:32:31 -07:00
|
|
|
|
|
|
|
fn append_ns(
|
|
|
|
&'src self,
|
|
|
|
name: &'src str,
|
|
|
|
ns: &'src first_pass::NamespaceData<'src>,
|
2019-03-26 08:00:16 -07:00
|
|
|
) -> ast::Program {
|
2018-09-17 13:46:18 -07:00
|
|
|
let mut ret = Default::default();
|
2018-08-28 16:32:31 -07:00
|
|
|
|
2018-08-29 18:32:47 -07:00
|
|
|
for (id, data) in ns.operations.iter() {
|
2018-09-17 13:46:18 -07:00
|
|
|
self.append_ns_member(&mut ret, name, id, data);
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
|
|
|
|
2018-09-26 08:26:00 -07:00
|
|
|
return ret;
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn append_ns_member(
|
|
|
|
&self,
|
2019-03-26 08:00:16 -07:00
|
|
|
module: &mut ast::Program,
|
2018-08-28 16:32:31 -07:00
|
|
|
self_name: &'src str,
|
2018-08-29 15:00:58 -07:00
|
|
|
id: &OperationId<'src>,
|
2018-08-29 18:32:47 -07:00
|
|
|
data: &OperationData<'src>,
|
2018-08-28 16:32:31 -07:00
|
|
|
) {
|
2018-08-29 15:00:58 -07:00
|
|
|
let name = match id {
|
|
|
|
OperationId::Operation(Some(name)) => name,
|
2018-09-26 08:26:00 -07:00
|
|
|
OperationId::Constructor(_)
|
|
|
|
| OperationId::Operation(None)
|
|
|
|
| OperationId::IndexingGetter
|
|
|
|
| OperationId::IndexingSetter
|
|
|
|
| OperationId::IndexingDeleter => {
|
2019-03-26 08:00:16 -07:00
|
|
|
log::warn!("Unsupported unnamed operation: on {:?}", self_name);
|
2018-09-26 08:26:00 -07:00
|
|
|
return;
|
2018-08-29 15:00:58 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let doc_comment = format!(
|
|
|
|
"The `{}.{}()` function\n\n{}",
|
2018-08-28 16:32:31 -07:00
|
|
|
self_name,
|
2018-08-29 15:00:58 -07:00
|
|
|
name,
|
|
|
|
mdn_doc(self_name, Some(&name))
|
|
|
|
);
|
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
let kind = ast::ImportFunctionKind::Normal;
|
2018-09-25 11:25:14 -07:00
|
|
|
let extra = snake_case_ident(self_name);
|
|
|
|
let extra = &[&extra[..]];
|
2018-08-31 17:38:34 -07:00
|
|
|
for mut import_function in self.create_imports(None, kind, id, data) {
|
2018-09-25 11:25:14 -07:00
|
|
|
let mut doc = Some(doc_comment.clone());
|
|
|
|
self.append_required_features_doc(&import_function, &mut doc, extra);
|
|
|
|
import_function.doc_comment = doc;
|
2019-03-26 08:00:16 -07:00
|
|
|
module.imports.push(ast::Import {
|
|
|
|
module: ast::ImportModule::None,
|
2018-09-26 08:26:00 -07:00
|
|
|
js_namespace: Some(raw_ident(self_name)),
|
2019-03-26 08:00:16 -07:00
|
|
|
kind: ast::ImportKind::Function(import_function),
|
2018-09-26 08:26:00 -07:00
|
|
|
});
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn append_const(
|
|
|
|
&self,
|
2019-03-26 08:00:16 -07:00
|
|
|
program: &mut ast::Program,
|
2018-08-28 16:32:31 -07:00
|
|
|
self_name: &'src str,
|
|
|
|
member: &'src weedle::interface::ConstMember<'src>,
|
|
|
|
) {
|
2018-11-07 10:37:43 -08:00
|
|
|
let idl_type = member.const_type.to_idl_type(self);
|
2018-08-28 16:32:31 -07:00
|
|
|
let ty = match idl_type.to_syn_type(TypePosition::Return) {
|
|
|
|
Some(ty) => ty,
|
|
|
|
None => {
|
2019-03-26 08:00:16 -07:00
|
|
|
log::warn!(
|
2018-08-28 16:32:31 -07:00
|
|
|
"Cannot convert const type to syn type: {:?} in {:?} on {:?}",
|
2019-03-26 08:00:16 -07:00
|
|
|
idl_type,
|
|
|
|
member,
|
|
|
|
self_name
|
2018-08-28 16:32:31 -07:00
|
|
|
);
|
2018-09-26 08:26:00 -07:00
|
|
|
return;
|
|
|
|
}
|
2018-08-28 16:32:31 -07:00
|
|
|
};
|
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
program.consts.push(ast::Const {
|
2018-08-28 16:32:31 -07:00
|
|
|
vis: public(),
|
2018-09-02 15:09:51 +03:00
|
|
|
name: rust_ident(shouty_snake_case_ident(member.identifier.0).as_str()),
|
2018-08-28 16:32:31 -07:00
|
|
|
class: Some(rust_ident(camel_case_ident(&self_name).as_str())),
|
|
|
|
ty,
|
|
|
|
value: webidl_const_v_to_backend_const_v(&member.const_value),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn append_interface(
|
|
|
|
&self,
|
2019-03-26 08:00:16 -07:00
|
|
|
program: &mut ast::Program,
|
2018-08-28 16:32:31 -07:00
|
|
|
name: &'src str,
|
2018-08-29 17:33:35 -07:00
|
|
|
data: &InterfaceData<'src>,
|
2018-08-28 16:32:31 -07:00
|
|
|
) {
|
2018-09-26 08:26:00 -07:00
|
|
|
let mut doc_comment = Some(format!("The `{}` object\n\n{}", name, mdn_doc(name, None),));
|
2018-09-28 14:16:17 -07:00
|
|
|
|
|
|
|
let mut attrs = Vec::new();
|
2019-03-26 08:00:16 -07:00
|
|
|
attrs.push(syn::parse_quote!( #[derive(Debug, Clone)] ));
|
2018-09-28 14:16:17 -07:00
|
|
|
self.add_deprecated(data, &mut attrs);
|
2019-03-26 08:00:16 -07:00
|
|
|
let mut import_type = ast::ImportType {
|
2018-09-05 12:55:30 -07:00
|
|
|
vis: public(),
|
|
|
|
rust_name: rust_ident(camel_case_ident(name).as_str()),
|
|
|
|
js_name: name.to_string(),
|
2018-09-28 14:16:17 -07:00
|
|
|
attrs,
|
2018-09-05 12:55:30 -07:00
|
|
|
doc_comment: None,
|
|
|
|
instanceof_shim: format!("__widl_instanceof_{}", name),
|
2019-04-12 11:08:05 -07:00
|
|
|
is_type_of: if data.has_interface {
|
|
|
|
None
|
|
|
|
} else {
|
2019-04-16 10:52:27 -07:00
|
|
|
Some(syn::parse_quote! { |_| false })
|
2019-04-12 11:08:05 -07:00
|
|
|
},
|
2018-09-25 11:25:14 -07:00
|
|
|
extends: Vec::new(),
|
2018-10-01 12:33:33 -07:00
|
|
|
vendor_prefixes: Vec::new(),
|
2018-09-25 11:25:14 -07:00
|
|
|
};
|
2018-09-28 13:17:37 -07:00
|
|
|
|
|
|
|
// whitelist a few names that have known polyfills
|
|
|
|
match name {
|
|
|
|
"AudioContext" => {
|
2018-11-27 12:07:59 -08:00
|
|
|
import_type
|
|
|
|
.vendor_prefixes
|
|
|
|
.push(Ident::new("webkit", Span::call_site()));
|
2018-09-28 13:17:37 -07:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2018-09-25 11:25:14 -07:00
|
|
|
let extra = camel_case_ident(name);
|
|
|
|
let extra = &[&extra[..]];
|
|
|
|
self.append_required_features_doc(&import_type, &mut doc_comment, extra);
|
2018-09-26 08:26:00 -07:00
|
|
|
import_type.extends = self
|
|
|
|
.all_superclasses(name)
|
2018-10-03 00:04:43 -07:00
|
|
|
.map(|name| Ident::new(&name, Span::call_site()).into())
|
|
|
|
.chain(Some(Ident::new("Object", Span::call_site()).into()))
|
2018-09-26 08:26:00 -07:00
|
|
|
.collect();
|
2018-09-05 12:55:30 -07:00
|
|
|
import_type.doc_comment = doc_comment;
|
2018-08-28 16:32:31 -07:00
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
program.imports.push(ast::Import {
|
|
|
|
module: ast::ImportModule::None,
|
2018-08-28 16:32:31 -07:00
|
|
|
js_namespace: None,
|
2019-03-26 08:00:16 -07:00
|
|
|
kind: ast::ImportKind::Type(import_type),
|
2018-08-28 16:32:31 -07:00
|
|
|
});
|
|
|
|
|
2018-08-29 18:32:47 -07:00
|
|
|
for (id, op_data) in data.operations.iter() {
|
|
|
|
self.member_operation(program, name, data, id, op_data);
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
|
|
|
for member in data.consts.iter() {
|
|
|
|
self.append_const(program, name, member);
|
|
|
|
}
|
|
|
|
for member in data.attributes.iter() {
|
|
|
|
self.member_attribute(
|
|
|
|
program,
|
|
|
|
name,
|
2018-09-28 14:16:17 -07:00
|
|
|
data,
|
2018-08-28 16:32:31 -07:00
|
|
|
member.modifier,
|
|
|
|
member.readonly.is_some(),
|
|
|
|
&member.type_,
|
|
|
|
member.identifier.0,
|
2018-08-31 17:38:34 -07:00
|
|
|
&member.attributes,
|
|
|
|
data.definition_attributes,
|
2018-08-28 16:32:31 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-08-29 17:33:35 -07:00
|
|
|
for mixin_data in self.all_mixins(name) {
|
2018-08-29 18:32:47 -07:00
|
|
|
for (id, op_data) in mixin_data.operations.iter() {
|
|
|
|
self.member_operation(program, name, data, id, op_data);
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
2018-08-29 17:33:35 -07:00
|
|
|
for member in &mixin_data.consts {
|
2018-08-29 10:27:44 -07:00
|
|
|
self.append_const(program, name, member);
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
2018-08-29 17:33:35 -07:00
|
|
|
for member in &mixin_data.attributes {
|
2018-08-28 16:32:31 -07:00
|
|
|
self.member_attribute(
|
|
|
|
program,
|
2018-08-29 10:27:44 -07:00
|
|
|
name,
|
2018-09-28 14:16:17 -07:00
|
|
|
data,
|
2018-08-28 16:32:31 -07:00
|
|
|
if let Some(s) = member.stringifier {
|
|
|
|
Some(weedle::interface::StringifierOrInheritOrStatic::Stringifier(s))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
|
|
|
member.readonly.is_some(),
|
|
|
|
&member.type_,
|
|
|
|
member.identifier.0,
|
2018-08-31 17:38:34 -07:00
|
|
|
&member.attributes,
|
2018-09-28 21:39:58 -07:00
|
|
|
data.definition_attributes,
|
2018-08-28 16:32:31 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn member_attribute(
|
|
|
|
&self,
|
2019-03-26 08:00:16 -07:00
|
|
|
program: &mut ast::Program,
|
2018-08-28 16:32:31 -07:00
|
|
|
self_name: &'src str,
|
2018-09-28 14:16:17 -07:00
|
|
|
data: &InterfaceData<'src>,
|
2018-08-28 16:32:31 -07:00
|
|
|
modifier: Option<weedle::interface::StringifierOrInheritOrStatic>,
|
|
|
|
readonly: bool,
|
|
|
|
type_: &'src weedle::types::AttributedType<'src>,
|
|
|
|
identifier: &'src str,
|
2018-08-31 17:38:34 -07:00
|
|
|
attrs: &'src Option<ExtendedAttributeList<'src>>,
|
|
|
|
container_attrs: Option<&'src ExtendedAttributeList<'src>>,
|
2018-08-28 16:32:31 -07:00
|
|
|
) {
|
|
|
|
use weedle::interface::StringifierOrInheritOrStatic::*;
|
|
|
|
|
|
|
|
let is_static = match modifier {
|
2018-08-30 16:29:51 -07:00
|
|
|
Some(Stringifier(_)) => unreachable!(), // filtered out earlier
|
2018-08-28 16:32:31 -07:00
|
|
|
Some(Inherit(_)) => false,
|
|
|
|
Some(Static(_)) => true,
|
|
|
|
None => false,
|
|
|
|
};
|
|
|
|
|
2018-09-05 12:55:30 -07:00
|
|
|
for mut import_function in self.create_getter(
|
2018-08-28 16:32:31 -07:00
|
|
|
identifier,
|
|
|
|
&type_.type_,
|
|
|
|
self_name,
|
|
|
|
is_static,
|
2018-08-31 17:38:34 -07:00
|
|
|
attrs,
|
|
|
|
container_attrs,
|
2018-08-28 16:32:31 -07:00
|
|
|
) {
|
2018-09-05 12:55:30 -07:00
|
|
|
let mut doc = import_function.doc_comment.take();
|
2018-09-25 11:25:14 -07:00
|
|
|
self.append_required_features_doc(&import_function, &mut doc, &[]);
|
2018-09-05 12:55:30 -07:00
|
|
|
import_function.doc_comment = doc;
|
2018-08-28 16:32:31 -07:00
|
|
|
program.imports.push(wrap_import_function(import_function));
|
|
|
|
}
|
|
|
|
|
|
|
|
if !readonly {
|
2018-09-05 12:55:30 -07:00
|
|
|
for mut import_function in self.create_setter(
|
2018-08-28 16:32:31 -07:00
|
|
|
identifier,
|
2018-08-31 17:38:34 -07:00
|
|
|
&type_.type_,
|
2018-08-28 16:32:31 -07:00
|
|
|
self_name,
|
|
|
|
is_static,
|
2018-08-31 17:38:34 -07:00
|
|
|
attrs,
|
|
|
|
container_attrs,
|
2018-08-28 16:32:31 -07:00
|
|
|
) {
|
2018-09-05 12:55:30 -07:00
|
|
|
let mut doc = import_function.doc_comment.take();
|
2018-09-25 11:25:14 -07:00
|
|
|
self.append_required_features_doc(&import_function, &mut doc, &[]);
|
2018-09-05 12:55:30 -07:00
|
|
|
import_function.doc_comment = doc;
|
2018-09-28 14:16:17 -07:00
|
|
|
self.add_deprecated(data, &mut import_function.function.rust_attrs);
|
2018-08-28 16:32:31 -07:00
|
|
|
program.imports.push(wrap_import_function(import_function));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 18:32:47 -07:00
|
|
|
fn member_operation(
|
2018-08-28 16:32:31 -07:00
|
|
|
&self,
|
2019-03-26 08:00:16 -07:00
|
|
|
program: &mut ast::Program,
|
2018-08-29 17:33:35 -07:00
|
|
|
self_name: &str,
|
|
|
|
data: &InterfaceData<'src>,
|
|
|
|
id: &OperationId<'src>,
|
2018-08-29 18:32:47 -07:00
|
|
|
op_data: &OperationData<'src>,
|
2018-08-28 16:32:31 -07:00
|
|
|
) {
|
2018-09-26 08:26:00 -07:00
|
|
|
let import_function_kind =
|
|
|
|
|opkind| self.import_function_kind(self_name, op_data.is_static, opkind);
|
2018-08-29 18:27:49 -07:00
|
|
|
let kind = match id {
|
|
|
|
OperationId::Constructor(ctor_name) => {
|
|
|
|
let self_ty = ident_ty(rust_ident(&camel_case_ident(self_name)));
|
2019-03-26 08:00:16 -07:00
|
|
|
ast::ImportFunctionKind::Method {
|
2018-08-29 18:27:49 -07:00
|
|
|
class: ctor_name.0.to_string(),
|
|
|
|
ty: self_ty.clone(),
|
2019-03-26 08:00:16 -07:00
|
|
|
kind: ast::MethodKind::Constructor,
|
2018-08-29 18:27:49 -07:00
|
|
|
}
|
|
|
|
}
|
2019-03-26 08:00:16 -07:00
|
|
|
OperationId::Operation(_) => import_function_kind(ast::OperationKind::Regular),
|
|
|
|
OperationId::IndexingGetter => import_function_kind(ast::OperationKind::IndexingGetter),
|
|
|
|
OperationId::IndexingSetter => import_function_kind(ast::OperationKind::IndexingSetter),
|
2018-08-29 18:27:49 -07:00
|
|
|
OperationId::IndexingDeleter => {
|
2019-03-26 08:00:16 -07:00
|
|
|
import_function_kind(ast::OperationKind::IndexingDeleter)
|
2018-08-29 17:33:35 -07:00
|
|
|
}
|
|
|
|
};
|
2018-09-04 14:52:56 -07:00
|
|
|
let doc = match id {
|
2018-09-27 12:35:46 -07:00
|
|
|
OperationId::Operation(None) => Some(String::new()),
|
2018-11-27 12:07:59 -08:00
|
|
|
OperationId::Constructor(_) => Some(format!(
|
|
|
|
"The `new {}(..)` constructor, creating a new \
|
|
|
|
instance of `{0}`\n\n{}",
|
|
|
|
self_name,
|
|
|
|
mdn_doc(self_name, Some(self_name))
|
|
|
|
)),
|
2018-09-26 08:26:00 -07:00
|
|
|
OperationId::Operation(Some(name)) => Some(format!(
|
|
|
|
"The `{}()` method\n\n{}",
|
|
|
|
name,
|
|
|
|
mdn_doc(self_name, Some(name))
|
|
|
|
)),
|
|
|
|
OperationId::IndexingGetter => Some(format!("The indexing getter\n\n")),
|
|
|
|
OperationId::IndexingSetter => Some(format!("The indexing setter\n\n")),
|
|
|
|
OperationId::IndexingDeleter => Some(format!("The indexing deleter\n\n")),
|
2018-09-04 14:52:56 -07:00
|
|
|
};
|
2018-08-31 17:38:34 -07:00
|
|
|
let attrs = data.definition_attributes;
|
2018-09-04 14:52:56 -07:00
|
|
|
for mut method in self.create_imports(attrs, kind, id, op_data) {
|
2018-09-05 12:55:30 -07:00
|
|
|
let mut doc = doc.clone();
|
2018-09-25 11:25:14 -07:00
|
|
|
self.append_required_features_doc(&method, &mut doc, &[]);
|
2018-09-05 12:55:30 -07:00
|
|
|
method.doc_comment = doc;
|
2018-09-28 14:16:17 -07:00
|
|
|
self.add_deprecated(data, &mut method.function.rust_attrs);
|
2018-08-29 17:33:35 -07:00
|
|
|
program.imports.push(wrap_import_function(method));
|
2018-08-28 16:32:31 -07:00
|
|
|
}
|
|
|
|
}
|
2018-09-05 12:55:30 -07:00
|
|
|
|
2018-09-28 14:16:17 -07:00
|
|
|
fn add_deprecated(&self, data: &InterfaceData<'src>, dst: &mut Vec<syn::Attribute>) {
|
|
|
|
let msg = match &data.deprecated {
|
|
|
|
Some(s) => s,
|
|
|
|
None => return,
|
|
|
|
};
|
2019-03-26 08:00:16 -07:00
|
|
|
dst.push(syn::parse_quote!( #[deprecated(note = #msg)] ));
|
2018-09-28 14:16:17 -07:00
|
|
|
}
|
|
|
|
|
2018-09-05 12:55:30 -07:00
|
|
|
fn append_required_features_doc(
|
|
|
|
&self,
|
|
|
|
item: impl ImportedTypeReferences,
|
|
|
|
doc: &mut Option<String>,
|
2018-09-25 11:25:14 -07:00
|
|
|
extra: &[&str],
|
2018-09-05 12:55:30 -07:00
|
|
|
) {
|
|
|
|
let doc = match doc {
|
|
|
|
Some(doc) => doc,
|
|
|
|
None => return,
|
|
|
|
};
|
2018-09-26 08:26:00 -07:00
|
|
|
let mut required = extra
|
|
|
|
.iter()
|
2018-09-25 11:25:14 -07:00
|
|
|
.map(|s| Ident::new(s, Span::call_site()))
|
|
|
|
.collect::<BTreeSet<_>>();
|
2018-09-05 12:55:30 -07:00
|
|
|
item.imported_type_references(&mut |f| {
|
|
|
|
if !self.builtin_idents.contains(f) {
|
|
|
|
required.insert(f.clone());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if required.len() == 0 {
|
2018-09-26 08:26:00 -07:00
|
|
|
return;
|
2018-09-05 12:55:30 -07:00
|
|
|
}
|
2018-09-26 08:26:00 -07:00
|
|
|
let list = required
|
|
|
|
.iter()
|
2018-09-05 12:55:30 -07:00
|
|
|
.map(|ident| format!("`{}`", ident))
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ");
|
|
|
|
doc.push_str(&format!(
|
2018-09-25 11:25:14 -07:00
|
|
|
"\n\n*This API requires the following crate features \
|
2018-09-05 12:55:30 -07:00
|
|
|
to be activated: {}*",
|
|
|
|
list,
|
|
|
|
));
|
|
|
|
}
|
2018-09-10 11:16:55 -07:00
|
|
|
|
|
|
|
fn append_callback_interface(
|
|
|
|
&self,
|
2019-03-26 08:00:16 -07:00
|
|
|
program: &mut ast::Program,
|
2018-09-10 11:16:55 -07:00
|
|
|
item: &CallbackInterfaceData<'src>,
|
|
|
|
) {
|
|
|
|
let mut fields = Vec::new();
|
|
|
|
for member in item.definition.members.body.iter() {
|
|
|
|
match member {
|
|
|
|
InterfaceMember::Operation(op) => {
|
|
|
|
let identifier = match op.identifier {
|
|
|
|
Some(i) => i.0,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
let pos = TypePosition::Argument;
|
|
|
|
fields.push(ast::DictionaryField {
|
|
|
|
required: false,
|
2019-01-07 14:15:00 +00:00
|
|
|
rust_name: rust_ident(&snake_case_ident(identifier)),
|
|
|
|
js_name: identifier.to_string(),
|
2018-09-26 08:26:00 -07:00
|
|
|
ty: idl_type::IdlType::Callback.to_syn_type(pos).unwrap(),
|
2018-09-10 11:16:55 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
_ => {
|
2019-03-26 08:00:16 -07:00
|
|
|
log::warn!(
|
2018-09-26 08:26:00 -07:00
|
|
|
"skipping callback interface member on {}",
|
|
|
|
item.definition.identifier.0
|
|
|
|
);
|
2018-09-10 11:16:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
program.dictionaries.push(ast::Dictionary {
|
|
|
|
name: rust_ident(&camel_case_ident(item.definition.identifier.0)),
|
|
|
|
fields,
|
|
|
|
});
|
|
|
|
}
|
2018-08-14 10:16:18 -07:00
|
|
|
}
|