2018-08-29 15:00:58 -07:00
|
|
|
use std::iter::FromIterator;
|
|
|
|
use std::ptr;
|
2018-06-14 02:03:52 -07:00
|
|
|
|
2018-09-02 15:09:51 +03:00
|
|
|
use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
|
2018-09-21 17:34:41 -07:00
|
|
|
use proc_macro2::{Ident, Span};
|
2018-06-14 02:03:52 -07:00
|
|
|
use syn;
|
2019-03-26 08:00:16 -07:00
|
|
|
use wasm_bindgen_backend::ast;
|
|
|
|
use wasm_bindgen_backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
|
2018-08-03 14:39:33 -07:00
|
|
|
use weedle;
|
2018-09-28 14:16:17 -07:00
|
|
|
use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList, IdentifierOrString};
|
2018-08-03 14:39:33 -07:00
|
|
|
use weedle::literal::{ConstValue, FloatLit, IntegerLit};
|
2018-06-14 02:03:52 -07:00
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
use crate::first_pass::{FirstPassRecord, OperationData, OperationId, Signature};
|
|
|
|
use crate::idl_type::{IdlType, ToIdlType};
|
2019-01-26 12:10:08 -05:00
|
|
|
|
2018-09-11 23:10:03 +03:00
|
|
|
/// For variadic operations an overload with a `js_sys::Array` argument is generated alongside with
|
|
|
|
/// `operation_name_0`, `operation_name_1`, `operation_name_2`, ..., `operation_name_n` overloads
|
|
|
|
/// which have the count of arguments for passing values to the variadic argument
|
|
|
|
/// in their names, where `n` is this constant.
|
|
|
|
const MAX_VARIADIC_ARGUMENTS_COUNT: usize = 7;
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Take a type and create an immutable shared reference to that type.
|
2018-09-03 13:27:24 +02:00
|
|
|
pub(crate) fn shared_ref(ty: syn::Type, mutable: bool) -> syn::Type {
|
2018-06-14 02:03:52 -07:00
|
|
|
syn::TypeReference {
|
|
|
|
and_token: Default::default(),
|
|
|
|
lifetime: None,
|
2018-09-26 08:26:00 -07:00
|
|
|
mutability: if mutable {
|
|
|
|
Some(syn::token::Mut::default())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2018-06-14 02:03:52 -07:00
|
|
|
elem: Box::new(ty),
|
2018-11-27 12:07:59 -08:00
|
|
|
}
|
|
|
|
.into()
|
2018-06-14 02:03:52 -07:00
|
|
|
}
|
|
|
|
|
2018-09-02 15:09:51 +03:00
|
|
|
/// Fix case of identifiers like `HTMLBRElement` or `texImage2D`
|
|
|
|
fn fix_ident(identifier: &str) -> String {
|
|
|
|
identifier
|
|
|
|
.replace("HTML", "HTML_")
|
|
|
|
.replace("1D", "_1d")
|
|
|
|
.replace("2D", "_2d")
|
|
|
|
.replace("3D", "_3d")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert an identifier to camel case
|
2018-07-27 17:57:24 +01:00
|
|
|
pub fn camel_case_ident(identifier: &str) -> String {
|
2018-09-02 15:09:51 +03:00
|
|
|
fix_ident(identifier).to_camel_case()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert an identifier to shouty snake case
|
|
|
|
pub fn shouty_snake_case_ident(identifier: &str) -> String {
|
|
|
|
fix_ident(identifier).to_shouty_snake_case()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert an identifier to snake case
|
|
|
|
pub fn snake_case_ident(identifier: &str) -> String {
|
|
|
|
fix_ident(identifier).to_snake_case()
|
2018-07-27 17:57:24 +01:00
|
|
|
}
|
|
|
|
|
2018-07-29 17:12:36 +01:00
|
|
|
// Returns a link to MDN
|
|
|
|
pub fn mdn_doc(class: &str, method: Option<&str>) -> String {
|
|
|
|
let mut link = format!("https://developer.mozilla.org/en-US/docs/Web/API/{}", class);
|
|
|
|
if let Some(method) = method {
|
|
|
|
link.push_str(&format!("/{}", method));
|
|
|
|
}
|
2018-09-05 12:55:30 -07:00
|
|
|
format!("[MDN Documentation]({})", link).into()
|
2018-07-29 17:12:36 +01:00
|
|
|
}
|
2018-07-27 17:57:24 +01:00
|
|
|
|
2019-01-21 19:18:35 -05:00
|
|
|
// Array type is borrowed for arguments (`&mut [T]` or `&[T]`) and owned for return value (`Vec<T>`).
|
|
|
|
pub(crate) fn array(base_ty: &str, pos: TypePosition, immutable: bool) -> syn::Type {
|
2018-08-03 14:39:33 -07:00
|
|
|
match pos {
|
|
|
|
TypePosition::Argument => {
|
2018-09-26 08:26:00 -07:00
|
|
|
shared_ref(
|
|
|
|
slice_ty(ident_ty(raw_ident(base_ty))),
|
2019-01-21 19:18:35 -05:00
|
|
|
/*mutable =*/ !immutable,
|
2018-09-26 08:26:00 -07:00
|
|
|
)
|
2018-08-03 14:39:33 -07:00
|
|
|
}
|
2018-09-26 08:26:00 -07:00
|
|
|
TypePosition::Return => vec_ty(ident_ty(raw_ident(base_ty))),
|
2018-08-03 14:39:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Map a webidl const value to the correct wasm-bindgen const value
|
2019-03-26 08:00:16 -07:00
|
|
|
pub fn webidl_const_v_to_backend_const_v(v: &ConstValue) -> ast::ConstValue {
|
2018-09-26 08:26:00 -07:00
|
|
|
use std::f64::{INFINITY, NAN, NEG_INFINITY};
|
2018-08-03 14:39:33 -07:00
|
|
|
|
2018-07-13 06:04:40 +02:00
|
|
|
match *v {
|
2018-08-03 14:39:33 -07:00
|
|
|
ConstValue::Boolean(b) => ast::ConstValue::BooleanLiteral(b.0),
|
2018-09-26 08:26:00 -07:00
|
|
|
ConstValue::Float(FloatLit::NegInfinity(_)) => ast::ConstValue::FloatLiteral(NEG_INFINITY),
|
|
|
|
ConstValue::Float(FloatLit::Infinity(_)) => ast::ConstValue::FloatLiteral(INFINITY),
|
|
|
|
ConstValue::Float(FloatLit::NaN(_)) => ast::ConstValue::FloatLiteral(NAN),
|
2018-08-03 14:39:33 -07:00
|
|
|
ConstValue::Float(FloatLit::Value(s)) => {
|
|
|
|
ast::ConstValue::FloatLiteral(s.0.parse().unwrap())
|
|
|
|
}
|
|
|
|
ConstValue::Integer(lit) => {
|
|
|
|
let mklit = |orig_text: &str, base: u32, offset: usize| {
|
|
|
|
let (negative, text) = if orig_text.starts_with("-") {
|
|
|
|
(true, &orig_text[1..])
|
|
|
|
} else {
|
|
|
|
(false, orig_text)
|
|
|
|
};
|
|
|
|
if text == "0" {
|
2018-09-26 08:26:00 -07:00
|
|
|
return ast::ConstValue::SignedIntegerLiteral(0);
|
2018-08-03 14:39:33 -07:00
|
|
|
}
|
|
|
|
let text = &text[offset..];
|
|
|
|
let n = u64::from_str_radix(text, base)
|
|
|
|
.unwrap_or_else(|_| panic!("literal too big: {}", orig_text));
|
|
|
|
if negative {
|
|
|
|
let n = if n > (i64::min_value() as u64).wrapping_neg() {
|
|
|
|
panic!("literal too big: {}", orig_text)
|
|
|
|
} else {
|
|
|
|
n.wrapping_neg() as i64
|
|
|
|
};
|
|
|
|
ast::ConstValue::SignedIntegerLiteral(n)
|
|
|
|
} else {
|
|
|
|
ast::ConstValue::UnsignedIntegerLiteral(n)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
match lit {
|
|
|
|
IntegerLit::Hex(h) => mklit(h.0, 16, 2), // leading 0x
|
2018-09-26 08:26:00 -07:00
|
|
|
IntegerLit::Oct(h) => mklit(h.0, 8, 1), // leading 0
|
2018-08-03 14:39:33 -07:00
|
|
|
IntegerLit::Dec(h) => mklit(h.0, 10, 0),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ConstValue::Null(_) => ast::ConstValue::Null,
|
2018-07-13 06:04:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// From `ident` and `Ty`, create `ident: Ty` for use in e.g. `fn(ident: Ty)`.
|
2018-06-14 02:03:52 -07:00
|
|
|
fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured {
|
|
|
|
syn::ArgCaptured {
|
|
|
|
pat: syn::Pat::Ident(syn::PatIdent {
|
|
|
|
by_ref: None,
|
|
|
|
mutability: None,
|
|
|
|
ident,
|
|
|
|
subpat: None,
|
|
|
|
}),
|
|
|
|
colon_token: Default::default(),
|
|
|
|
ty,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create `()`.
|
2018-07-11 11:07:03 -07:00
|
|
|
fn unit_ty() -> syn::Type {
|
|
|
|
syn::Type::Tuple(syn::TypeTuple {
|
|
|
|
paren_token: Default::default(),
|
|
|
|
elems: syn::punctuated::Punctuated::new(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-03-18 10:43:48 +01:00
|
|
|
/// From `T` create `Result<T, wasm_bindgen::JsValue>`.
|
2018-07-11 11:07:03 -07:00
|
|
|
fn result_ty(t: syn::Type) -> syn::Type {
|
|
|
|
let js_value = leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]);
|
|
|
|
|
|
|
|
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
|
|
|
colon2_token: None,
|
|
|
|
lt_token: Default::default(),
|
|
|
|
args: FromIterator::from_iter(vec![
|
|
|
|
syn::GenericArgument::Type(t),
|
|
|
|
syn::GenericArgument::Type(js_value),
|
|
|
|
]),
|
|
|
|
gt_token: Default::default(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let ident = raw_ident("Result");
|
|
|
|
let seg = syn::PathSegment { ident, arguments };
|
|
|
|
let path: syn::Path = seg.into();
|
|
|
|
let ty = syn::TypePath { qself: None, path };
|
|
|
|
ty.into()
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// From `T` create `[T]`.
|
2018-08-11 23:46:33 +03:00
|
|
|
pub(crate) fn slice_ty(t: syn::Type) -> syn::Type {
|
2018-07-18 17:59:24 -05:00
|
|
|
syn::TypeSlice {
|
|
|
|
bracket_token: Default::default(),
|
|
|
|
elem: Box::new(t),
|
2018-11-27 12:07:59 -08:00
|
|
|
}
|
|
|
|
.into()
|
2018-07-18 17:59:24 -05:00
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// From `T` create `Vec<T>`.
|
2018-08-11 23:46:33 +03:00
|
|
|
pub(crate) fn vec_ty(t: syn::Type) -> syn::Type {
|
2018-07-18 17:59:24 -05:00
|
|
|
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
|
|
|
colon2_token: None,
|
|
|
|
lt_token: Default::default(),
|
2018-09-26 08:26:00 -07:00
|
|
|
args: FromIterator::from_iter(vec![syn::GenericArgument::Type(t)]),
|
2018-07-18 17:59:24 -05:00
|
|
|
gt_token: Default::default(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let ident = raw_ident("Vec");
|
|
|
|
let seg = syn::PathSegment { ident, arguments };
|
|
|
|
let path: syn::Path = seg.into();
|
|
|
|
let ty = syn::TypePath { qself: None, path };
|
|
|
|
ty.into()
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
/// From `T` create `Option<T>`
|
2018-08-11 23:46:33 +03:00
|
|
|
pub(crate) fn option_ty(t: syn::Type) -> syn::Type {
|
2018-08-03 14:39:33 -07:00
|
|
|
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
|
|
|
colon2_token: None,
|
|
|
|
lt_token: Default::default(),
|
|
|
|
args: FromIterator::from_iter(vec![syn::GenericArgument::Type(t)]),
|
|
|
|
gt_token: Default::default(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let ident = raw_ident("Option");
|
|
|
|
let seg = syn::PathSegment { ident, arguments };
|
|
|
|
let path: syn::Path = seg.into();
|
|
|
|
let ty = syn::TypePath { qself: None, path };
|
|
|
|
ty.into()
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Possible positions for a type in a function signature.
|
2018-07-10 22:59:59 -07:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub enum TypePosition {
|
|
|
|
Argument,
|
|
|
|
Return,
|
|
|
|
}
|
2018-06-14 02:03:52 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> FirstPassRecord<'src> {
|
2018-08-29 10:28:04 -07:00
|
|
|
pub fn create_one_function<'a>(
|
|
|
|
&self,
|
|
|
|
js_name: &str,
|
|
|
|
rust_name: &str,
|
|
|
|
idl_arguments: impl Iterator<Item = (&'a str, &'a IdlType<'src>)>,
|
|
|
|
ret: &IdlType<'src>,
|
2019-03-26 08:00:16 -07:00
|
|
|
kind: ast::ImportFunctionKind,
|
2018-08-29 10:28:04 -07:00
|
|
|
structural: bool,
|
|
|
|
catch: bool,
|
2018-09-06 20:00:38 +03:00
|
|
|
variadic: bool,
|
2018-08-29 10:28:04 -07:00
|
|
|
doc_comment: Option<String>,
|
2019-03-26 08:00:16 -07:00
|
|
|
) -> Option<ast::ImportFunction>
|
2018-09-26 08:26:00 -07:00
|
|
|
where
|
|
|
|
'src: 'a,
|
|
|
|
{
|
2018-08-29 10:28:04 -07:00
|
|
|
// Convert all of the arguments from their IDL type to a `syn` type,
|
|
|
|
// ready to pass to the backend.
|
|
|
|
//
|
|
|
|
// Note that for non-static methods we add a `&self` type placeholder,
|
|
|
|
// but this type isn't actually used so it's just here for show mostly.
|
2019-03-26 08:00:16 -07:00
|
|
|
let mut arguments = if let &ast::ImportFunctionKind::Method {
|
2018-08-29 10:28:04 -07:00
|
|
|
ref ty,
|
2018-09-26 08:26:00 -07:00
|
|
|
kind:
|
2019-03-26 08:00:16 -07:00
|
|
|
ast::MethodKind::Operation(ast::Operation {
|
2018-08-29 10:28:04 -07:00
|
|
|
is_static: false, ..
|
2018-09-26 08:26:00 -07:00
|
|
|
}),
|
2018-08-29 10:28:04 -07:00
|
|
|
..
|
2018-09-26 08:26:00 -07:00
|
|
|
} = &kind
|
|
|
|
{
|
2018-08-29 10:28:04 -07:00
|
|
|
let mut res = Vec::with_capacity(idl_arguments.size_hint().0 + 1);
|
2018-09-26 08:26:00 -07:00
|
|
|
res.push(simple_fn_arg(
|
|
|
|
raw_ident("self_"),
|
|
|
|
shared_ref(ty.clone(), false),
|
|
|
|
));
|
2018-08-29 10:28:04 -07:00
|
|
|
res
|
|
|
|
} else {
|
|
|
|
Vec::with_capacity(idl_arguments.size_hint().0)
|
|
|
|
};
|
2018-09-06 20:00:38 +03:00
|
|
|
let idl_arguments: Vec<_> = idl_arguments.collect();
|
|
|
|
let arguments_count = idl_arguments.len();
|
|
|
|
for (i, (argument_name, idl_type)) in idl_arguments.into_iter().enumerate() {
|
2018-08-29 10:28:04 -07:00
|
|
|
let syn_type = match idl_type.to_syn_type(TypePosition::Argument) {
|
|
|
|
Some(t) => t,
|
|
|
|
None => {
|
2019-03-26 08:00:16 -07:00
|
|
|
log::warn!(
|
2018-08-15 14:24:09 -07:00
|
|
|
"Unsupported argument type: {:?} on {:?}",
|
2019-03-26 08:00:16 -07:00
|
|
|
idl_type,
|
|
|
|
rust_name
|
2018-08-15 11:45:45 -07:00
|
|
|
);
|
2018-09-26 08:26:00 -07:00
|
|
|
return None;
|
2018-08-29 10:28:04 -07:00
|
|
|
}
|
|
|
|
};
|
2018-09-06 20:00:38 +03:00
|
|
|
let syn_type = if variadic && i == arguments_count - 1 {
|
2018-09-11 00:37:59 +03:00
|
|
|
let path = vec![rust_ident("js_sys"), rust_ident("Array")];
|
|
|
|
shared_ref(leading_colon_path_ty(path), false)
|
2018-09-06 20:00:38 +03:00
|
|
|
} else {
|
|
|
|
syn_type
|
|
|
|
};
|
2018-08-29 10:28:04 -07:00
|
|
|
let argument_name = rust_ident(&argument_name.to_snake_case());
|
|
|
|
arguments.push(simple_fn_arg(argument_name, syn_type));
|
2018-08-09 19:24:33 +03:00
|
|
|
}
|
2018-08-29 10:28:04 -07:00
|
|
|
|
|
|
|
// Convert the return type to a `syn` type, handling the `catch`
|
|
|
|
// attribute here to use a `Result` in Rust.
|
|
|
|
let ret = match ret {
|
|
|
|
IdlType::Void => None,
|
2018-09-26 08:26:00 -07:00
|
|
|
ret @ _ => match ret.to_syn_type(TypePosition::Return) {
|
|
|
|
Some(ret) => Some(ret),
|
|
|
|
None => {
|
2019-03-26 08:00:16 -07:00
|
|
|
log::warn!("Unsupported return type: {:?} on {:?}", ret, rust_name);
|
2018-09-26 08:26:00 -07:00
|
|
|
return None;
|
2018-08-29 10:28:04 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
let js_ret = ret.clone();
|
|
|
|
let ret = if catch {
|
|
|
|
Some(ret.map_or_else(|| result_ty(unit_ty()), result_ty))
|
|
|
|
} else {
|
|
|
|
ret
|
|
|
|
};
|
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
Some(ast::ImportFunction {
|
|
|
|
function: ast::Function {
|
2018-08-29 10:28:04 -07:00
|
|
|
name: js_name.to_string(),
|
2018-09-21 17:34:41 -07:00
|
|
|
name_span: Span::call_site(),
|
|
|
|
renamed_via_js_name: false,
|
2018-08-29 10:28:04 -07:00
|
|
|
arguments,
|
|
|
|
ret: ret.clone(),
|
|
|
|
rust_attrs: vec![],
|
|
|
|
rust_vis: public(),
|
|
|
|
},
|
|
|
|
rust_name: rust_ident(rust_name),
|
|
|
|
js_ret: js_ret.clone(),
|
2018-09-06 20:00:38 +03:00
|
|
|
variadic,
|
2018-08-29 10:28:04 -07:00
|
|
|
catch,
|
|
|
|
structural,
|
2018-09-06 20:00:38 +03:00
|
|
|
shim: {
|
2018-08-29 10:28:04 -07:00
|
|
|
let ns = match kind {
|
2019-03-26 08:00:16 -07:00
|
|
|
ast::ImportFunctionKind::Normal => "",
|
|
|
|
ast::ImportFunctionKind::Method { ref class, .. } => class,
|
2018-08-29 10:28:04 -07:00
|
|
|
};
|
|
|
|
raw_ident(&format!("__widl_f_{}_{}", rust_name, ns))
|
|
|
|
},
|
|
|
|
kind,
|
|
|
|
doc_comment,
|
|
|
|
})
|
2018-08-11 23:46:33 +03:00
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a wasm-bindgen getter method, if possible.
|
2018-07-10 22:59:59 -07:00
|
|
|
pub fn create_getter(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
2018-08-29 15:00:58 -07:00
|
|
|
ty: &weedle::types::Type<'src>,
|
2018-07-10 22:59:59 -07:00
|
|
|
self_name: &str,
|
|
|
|
is_static: bool,
|
2018-08-31 17:38:34 -07:00
|
|
|
attrs: &Option<ExtendedAttributeList>,
|
|
|
|
container_attrs: Option<&ExtendedAttributeList>,
|
2019-03-26 08:00:16 -07:00
|
|
|
) -> Option<ast::ImportFunction> {
|
|
|
|
let kind = ast::OperationKind::Getter(Some(raw_ident(name)));
|
2018-09-17 14:01:53 -07:00
|
|
|
let kind = self.import_function_kind(self_name, is_static, kind);
|
2018-11-07 10:37:43 -08:00
|
|
|
let ret = ty.to_idl_type(self);
|
2018-08-29 10:28:04 -07:00
|
|
|
self.create_one_function(
|
|
|
|
&name,
|
2018-09-02 15:09:51 +03:00
|
|
|
&snake_case_ident(name),
|
2018-08-29 10:28:04 -07:00
|
|
|
None.into_iter(),
|
|
|
|
&ret,
|
|
|
|
kind,
|
2018-08-31 17:38:34 -07:00
|
|
|
is_structural(attrs.as_ref(), container_attrs),
|
|
|
|
throws(attrs),
|
2018-09-06 20:00:38 +03:00
|
|
|
false,
|
2018-09-26 08:26:00 -07:00
|
|
|
Some(format!(
|
|
|
|
"The `{}` getter\n\n{}",
|
|
|
|
name,
|
|
|
|
mdn_doc(self_name, Some(name))
|
|
|
|
)),
|
2018-08-29 10:28:04 -07:00
|
|
|
)
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
2018-06-14 22:48:32 -07:00
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a wasm-bindgen setter method, if possible.
|
2018-07-10 22:59:59 -07:00
|
|
|
pub fn create_setter(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
2018-08-31 17:38:34 -07:00
|
|
|
field_ty: &weedle::types::Type<'src>,
|
2018-07-10 22:59:59 -07:00
|
|
|
self_name: &str,
|
|
|
|
is_static: bool,
|
2018-08-31 17:38:34 -07:00
|
|
|
attrs: &Option<ExtendedAttributeList>,
|
|
|
|
container_attrs: Option<&ExtendedAttributeList>,
|
2019-03-26 08:00:16 -07:00
|
|
|
) -> Option<ast::ImportFunction> {
|
|
|
|
let kind = ast::OperationKind::Setter(Some(raw_ident(name)));
|
2018-09-17 14:01:53 -07:00
|
|
|
let kind = self.import_function_kind(self_name, is_static, kind);
|
2018-11-07 10:37:43 -08:00
|
|
|
let field_ty = field_ty.to_idl_type(self);
|
2018-08-29 10:28:04 -07:00
|
|
|
self.create_one_function(
|
|
|
|
&name,
|
|
|
|
&format!("set_{}", name).to_snake_case(),
|
|
|
|
Some((name, &field_ty)).into_iter(),
|
|
|
|
&IdlType::Void,
|
|
|
|
kind,
|
2018-08-31 17:38:34 -07:00
|
|
|
is_structural(attrs.as_ref(), container_attrs),
|
|
|
|
throws(attrs),
|
2018-09-06 20:00:38 +03:00
|
|
|
false,
|
2018-09-26 08:26:00 -07:00
|
|
|
Some(format!(
|
|
|
|
"The `{}` setter\n\n{}",
|
|
|
|
name,
|
|
|
|
mdn_doc(self_name, Some(name))
|
|
|
|
)),
|
2018-08-29 10:28:04 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-08-29 18:27:49 -07:00
|
|
|
pub fn import_function_kind(
|
2018-08-29 10:28:04 -07:00
|
|
|
&self,
|
|
|
|
self_name: &str,
|
|
|
|
is_static: bool,
|
2019-03-26 08:00:16 -07:00
|
|
|
operation_kind: ast::OperationKind,
|
|
|
|
) -> ast::ImportFunctionKind {
|
|
|
|
let operation = ast::Operation {
|
2018-08-28 15:19:31 -07:00
|
|
|
is_static,
|
2018-08-29 10:28:04 -07:00
|
|
|
kind: operation_kind,
|
2018-08-28 15:19:31 -07:00
|
|
|
};
|
|
|
|
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
2019-03-26 08:00:16 -07:00
|
|
|
ast::ImportFunctionKind::Method {
|
2018-09-17 14:01:53 -07:00
|
|
|
class: self_name.to_string(),
|
|
|
|
ty,
|
2019-03-26 08:00:16 -07:00
|
|
|
kind: ast::MethodKind::Operation(operation),
|
2018-08-29 10:28:04 -07:00
|
|
|
}
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
2018-08-29 15:00:58 -07:00
|
|
|
|
|
|
|
pub fn create_imports(
|
|
|
|
&self,
|
2018-08-31 17:38:34 -07:00
|
|
|
container_attrs: Option<&ExtendedAttributeList<'src>>,
|
2019-03-26 08:00:16 -07:00
|
|
|
kind: ast::ImportFunctionKind,
|
2018-08-29 15:00:58 -07:00
|
|
|
id: &OperationId<'src>,
|
2018-08-29 18:32:47 -07:00
|
|
|
data: &OperationData<'src>,
|
2019-03-26 08:00:16 -07:00
|
|
|
) -> Vec<ast::ImportFunction> {
|
2018-08-30 16:29:51 -07:00
|
|
|
// First up, prune all signatures that reference unsupported arguments.
|
|
|
|
// We won't consider these until said arguments are implemented.
|
2018-09-05 12:55:30 -07:00
|
|
|
//
|
|
|
|
// Note that we handle optional arguments as well. Optional arguments
|
|
|
|
// should only appear at the end of argument lists and when we see one
|
|
|
|
// we can simply push our signature so far onto the list for the
|
|
|
|
// signature where that and all remaining optional arguments are
|
|
|
|
// undefined.
|
2018-08-30 16:29:51 -07:00
|
|
|
let mut signatures = Vec::new();
|
2018-09-26 08:26:00 -07:00
|
|
|
'outer: for signature in data.signatures.iter() {
|
2018-08-30 16:29:51 -07:00
|
|
|
let mut idl_args = Vec::with_capacity(signature.args.len());
|
2018-09-05 12:55:30 -07:00
|
|
|
for (i, arg) in signature.args.iter().enumerate() {
|
|
|
|
if arg.optional {
|
2018-09-06 20:00:38 +03:00
|
|
|
assert!(
|
2018-09-26 08:26:00 -07:00
|
|
|
signature.args[i..]
|
2018-09-06 20:00:38 +03:00
|
|
|
.iter()
|
|
|
|
.all(|arg| arg.optional || arg.variadic),
|
|
|
|
"Not optional or variadic argument after optional argument: {:?}",
|
|
|
|
signature.args,
|
|
|
|
);
|
2018-09-05 12:55:30 -07:00
|
|
|
signatures.push((signature, idl_args.clone()));
|
|
|
|
}
|
2019-01-14 17:45:43 -05:00
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
let idl_type = arg.ty.to_idl_type(self);
|
2019-02-05 13:47:46 -05:00
|
|
|
let idl_type = self.maybe_adjust(idl_type, id);
|
2019-01-14 17:45:43 -05:00
|
|
|
idl_args.push(idl_type);
|
2018-08-30 16:29:51 -07:00
|
|
|
}
|
|
|
|
signatures.push((signature, idl_args));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next expand all the signatures in `data` into all signatures that
|
2018-08-29 15:00:58 -07:00
|
|
|
// we're going to generate. These signatures will be used to determine
|
|
|
|
// the names for all the various functions.
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct ExpandedSig<'a> {
|
|
|
|
orig: &'a Signature<'a>,
|
|
|
|
args: Vec<IdlType<'a>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut actual_signatures = Vec::new();
|
2018-08-30 16:29:51 -07:00
|
|
|
for (signature, idl_args) in signatures.iter() {
|
2019-03-26 08:00:16 -07:00
|
|
|
let start = actual_signatures.len();
|
2018-08-29 15:00:58 -07:00
|
|
|
|
|
|
|
// Start off with an empty signature, this'll handle zero-argument
|
|
|
|
// cases and otherwise the loop below will continue to add on to this.
|
|
|
|
actual_signatures.push(ExpandedSig {
|
|
|
|
orig: signature,
|
|
|
|
args: Vec::with_capacity(signature.args.len()),
|
|
|
|
});
|
|
|
|
|
2018-09-05 12:55:30 -07:00
|
|
|
for (i, idl_type) in idl_args.iter().enumerate() {
|
2018-08-30 16:29:51 -07:00
|
|
|
// small sanity check
|
2018-08-29 17:33:35 -07:00
|
|
|
assert!(start < actual_signatures.len());
|
|
|
|
for sig in actual_signatures[start..].iter() {
|
|
|
|
assert_eq!(sig.args.len(), i);
|
|
|
|
}
|
|
|
|
|
2018-08-30 16:29:51 -07:00
|
|
|
// The first element of the flattened type gets pushed directly
|
|
|
|
// in-place, but all other flattened types will cause new
|
|
|
|
// signatures to be created.
|
2018-08-29 17:33:35 -07:00
|
|
|
let cur = actual_signatures.len();
|
2018-08-30 22:31:03 -07:00
|
|
|
for (j, idl_type) in idl_type.flatten().into_iter().enumerate() {
|
|
|
|
for k in start..cur {
|
|
|
|
if j == 0 {
|
|
|
|
actual_signatures[k].args.push(idl_type.clone());
|
2018-08-29 15:00:58 -07:00
|
|
|
} else {
|
2018-08-30 22:31:03 -07:00
|
|
|
let mut sig = actual_signatures[k].clone();
|
2018-08-29 17:33:35 -07:00
|
|
|
assert_eq!(sig.args.len(), i + 1);
|
2018-08-29 15:00:58 -07:00
|
|
|
sig.args.truncate(i);
|
|
|
|
sig.args.push(idl_type.clone());
|
|
|
|
actual_signatures.push(sig);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 18:27:49 -07:00
|
|
|
let (name, force_structural, force_throws) = match id {
|
|
|
|
// Constructors aren't annotated with `[Throws]` extended attributes
|
|
|
|
// (how could they be, since they themselves are extended
|
|
|
|
// attributes?) so we must conservatively assume that they can
|
|
|
|
// always throw.
|
|
|
|
//
|
|
|
|
// From https://heycam.github.io/webidl/#Constructor (emphasis
|
|
|
|
// mine):
|
|
|
|
//
|
|
|
|
// > The prose definition of a constructor must either return an IDL
|
|
|
|
// > value of a type corresponding to the interface the
|
|
|
|
// > `[Constructor]` extended attribute appears on, **or throw an
|
|
|
|
// > exception**.
|
|
|
|
OperationId::Constructor(_) => ("new", false, true),
|
|
|
|
OperationId::Operation(Some(s)) => (*s, false, false),
|
2018-08-29 15:00:58 -07:00
|
|
|
OperationId::Operation(None) => {
|
2019-03-26 08:00:16 -07:00
|
|
|
log::warn!("unsupported unnamed operation");
|
2018-09-26 08:26:00 -07:00
|
|
|
return Vec::new();
|
2018-08-29 15:00:58 -07:00
|
|
|
}
|
2018-08-29 18:27:49 -07:00
|
|
|
OperationId::IndexingGetter => ("get", true, false),
|
|
|
|
OperationId::IndexingSetter => ("set", true, false),
|
|
|
|
OperationId::IndexingDeleter => ("delete", true, false),
|
2018-08-29 15:00:58 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
for signature in actual_signatures.iter() {
|
|
|
|
// Ignore signatures with invalid return types
|
2018-08-30 16:29:51 -07:00
|
|
|
//
|
|
|
|
// TODO: overloads probably never change return types, so we should
|
|
|
|
// do this much earlier to avoid all the above work if
|
|
|
|
// possible.
|
2018-11-07 10:37:43 -08:00
|
|
|
let ret_ty = signature.orig.ret.to_idl_type(self);
|
2018-08-29 15:00:58 -07:00
|
|
|
|
2018-09-02 15:09:51 +03:00
|
|
|
let mut rust_name = snake_case_ident(name);
|
2018-08-29 15:00:58 -07:00
|
|
|
let mut first = true;
|
|
|
|
for (i, arg) in signature.args.iter().enumerate() {
|
|
|
|
// Find out if any other known signature either has the same
|
|
|
|
// name for this argument or a different type for this argument.
|
|
|
|
let mut any_same_name = false;
|
|
|
|
let mut any_different_type = false;
|
2018-08-29 17:33:35 -07:00
|
|
|
let mut any_different = false;
|
2018-08-29 15:00:58 -07:00
|
|
|
let arg_name = signature.orig.args[i].name;
|
|
|
|
for other in actual_signatures.iter() {
|
|
|
|
if other.orig.args.get(i).map(|s| s.name) == Some(arg_name) {
|
|
|
|
if !ptr::eq(signature, other) {
|
|
|
|
any_same_name = true;
|
|
|
|
}
|
|
|
|
}
|
2018-08-29 17:33:35 -07:00
|
|
|
if let Some(other) = other.args.get(i) {
|
|
|
|
if other != arg {
|
|
|
|
any_different_type = true;
|
|
|
|
any_different = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
any_different = true;
|
2018-08-29 15:00:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If all signatures have the exact same type for this argument,
|
|
|
|
// then there's nothing to disambiguate so we don't modify the
|
|
|
|
// name.
|
2018-08-29 17:33:35 -07:00
|
|
|
if !any_different {
|
2018-09-26 08:26:00 -07:00
|
|
|
continue;
|
2018-08-29 15:00:58 -07:00
|
|
|
}
|
|
|
|
if first {
|
|
|
|
rust_name.push_str("_with_");
|
|
|
|
first = false;
|
|
|
|
} else {
|
|
|
|
rust_name.push_str("_and_");
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this name of the argument for this signature is unique
|
|
|
|
// then that's a bit more human readable so we include it in the
|
|
|
|
// method name. Otherwise the type name should disambiguate
|
|
|
|
// correctly.
|
2018-08-30 16:29:51 -07:00
|
|
|
//
|
|
|
|
// If any signature's argument has the same name as our argument
|
|
|
|
// then we can't use that if the types are also the same because
|
|
|
|
// otherwise it could be ambiguous.
|
|
|
|
if any_same_name && any_different_type {
|
2018-09-02 15:09:51 +03:00
|
|
|
arg.push_snake_case_name(&mut rust_name);
|
2018-08-30 16:29:51 -07:00
|
|
|
} else {
|
2018-09-02 15:09:51 +03:00
|
|
|
rust_name.push_str(&snake_case_ident(arg_name));
|
2018-08-29 15:00:58 -07:00
|
|
|
}
|
|
|
|
}
|
2018-09-26 08:26:00 -07:00
|
|
|
let structural =
|
|
|
|
force_structural || is_structural(signature.orig.attrs.as_ref(), container_attrs);
|
2018-09-11 00:37:59 +03:00
|
|
|
let catch = force_throws || throws(&signature.orig.attrs);
|
2018-11-27 12:07:59 -08:00
|
|
|
let variadic = signature.args.len() == signature.orig.args.len()
|
|
|
|
&& signature
|
|
|
|
.orig
|
|
|
|
.args
|
|
|
|
.last()
|
|
|
|
.map(|arg| arg.variadic)
|
|
|
|
.unwrap_or(false);
|
2018-09-26 08:26:00 -07:00
|
|
|
ret.extend(
|
|
|
|
self.create_one_function(
|
2018-09-11 23:10:03 +03:00
|
|
|
name,
|
2018-09-26 08:26:00 -07:00
|
|
|
&rust_name,
|
|
|
|
signature
|
|
|
|
.args
|
2018-09-11 23:10:03 +03:00
|
|
|
.iter()
|
2018-09-26 08:26:00 -07:00
|
|
|
.zip(&signature.orig.args)
|
|
|
|
.map(|(idl_type, orig_arg)| (orig_arg.name, idl_type)),
|
2018-09-11 23:10:03 +03:00
|
|
|
&ret_ty,
|
|
|
|
kind.clone(),
|
|
|
|
structural,
|
|
|
|
catch,
|
2018-09-26 08:26:00 -07:00
|
|
|
variadic,
|
2018-09-11 23:10:03 +03:00
|
|
|
None,
|
2018-09-26 08:26:00 -07:00
|
|
|
),
|
|
|
|
);
|
|
|
|
if !variadic {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let last_idl_type = &signature.args[signature.args.len() - 1];
|
|
|
|
let last_name = signature.orig.args[signature.args.len() - 1].name;
|
|
|
|
for i in 0..=MAX_VARIADIC_ARGUMENTS_COUNT {
|
|
|
|
ret.extend(
|
|
|
|
self.create_one_function(
|
|
|
|
name,
|
|
|
|
&format!("{}_{}", rust_name, i),
|
|
|
|
signature.args[..signature.args.len() - 1]
|
|
|
|
.iter()
|
|
|
|
.zip(&signature.orig.args)
|
|
|
|
.map(|(idl_type, orig_arg)| (orig_arg.name.to_string(), idl_type))
|
|
|
|
.chain((1..=i).map(|j| (format!("{}_{}", last_name, j), last_idl_type)))
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.iter()
|
|
|
|
.map(|(name, idl_type)| (&name[..], idl_type.clone())),
|
|
|
|
&ret_ty,
|
|
|
|
kind.clone(),
|
|
|
|
structural,
|
|
|
|
catch,
|
|
|
|
false,
|
|
|
|
None,
|
|
|
|
),
|
|
|
|
);
|
2018-09-11 23:10:03 +03:00
|
|
|
}
|
2018-08-29 15:00:58 -07:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2019-02-05 13:47:46 -05:00
|
|
|
|
|
|
|
/// When generating our web_sys APIs we default to setting slice references that
|
|
|
|
/// get passed to JS as mutable in case they get mutated in JS.
|
|
|
|
///
|
|
|
|
/// In certain cases we know for sure that the slice will not get mutated - for
|
|
|
|
/// example when working with the WebGlRenderingContext APIs.
|
|
|
|
///
|
|
|
|
/// Here we implement a whitelist for those cases. This whitelist is currently
|
|
|
|
/// maintained by hand.
|
|
|
|
///
|
|
|
|
/// When adding to this whitelist add tests to crates/web-sys/tests/wasm/whitelisted_immutable_slices.rs
|
|
|
|
fn maybe_adjust<'a>(&self, mut idl_type: IdlType<'a>, id: &'a OperationId) -> IdlType<'a> {
|
|
|
|
let op = match id {
|
|
|
|
OperationId::Operation(Some(op)) => op,
|
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
|
|
|
_ => return idl_type,
|
2019-02-05 13:47:46 -05:00
|
|
|
};
|
|
|
|
|
2019-03-08 15:12:41 -08:00
|
|
|
if self.immutable_slice_whitelist.contains(op) {
|
2019-02-05 13:47:46 -05:00
|
|
|
flag_slices_immutable(&mut idl_type)
|
|
|
|
}
|
|
|
|
|
|
|
|
idl_type
|
|
|
|
}
|
2018-06-14 22:48:32 -07:00
|
|
|
}
|
2018-07-02 20:35:05 -07:00
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Search for an attribute by name in some webidl object's attributes.
|
2018-08-31 17:38:34 -07:00
|
|
|
fn has_named_attribute(list: Option<&ExtendedAttributeList>, attribute: &str) -> bool {
|
2018-08-03 14:39:33 -07:00
|
|
|
let list = match list {
|
|
|
|
Some(list) => list,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
list.body.list.iter().any(|attr| match attr {
|
|
|
|
ExtendedAttribute::NoArgs(name) => (name.0).0 == attribute,
|
2018-07-10 22:59:59 -07:00
|
|
|
_ => false,
|
2018-07-02 20:35:05 -07:00
|
|
|
})
|
2018-07-07 10:20:31 -07:00
|
|
|
}
|
2018-07-09 16:35:25 -07:00
|
|
|
|
2018-09-17 14:10:23 -07:00
|
|
|
fn has_ident_attribute(list: Option<&ExtendedAttributeList>, ident: &str) -> bool {
|
|
|
|
let list = match list {
|
|
|
|
Some(list) => list,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
list.body.list.iter().any(|attr| match attr {
|
|
|
|
ExtendedAttribute::Ident(id) => id.lhs_identifier.0 == ident,
|
|
|
|
ExtendedAttribute::IdentList(id) => id.identifier.0 == ident,
|
|
|
|
_ => false,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-07-17 22:23:17 -07:00
|
|
|
/// ChromeOnly is for things that are only exposed to privileged code in Firefox.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn is_chrome_only(ext_attrs: &Option<ExtendedAttributeList>) -> bool {
|
2018-08-31 17:38:34 -07:00
|
|
|
has_named_attribute(ext_attrs.as_ref(), "ChromeOnly")
|
2018-07-17 22:23:17 -07:00
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Whether a webidl object is marked as a no interface object.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn is_no_interface_object(ext_attrs: &Option<ExtendedAttributeList>) -> bool {
|
2018-08-31 17:38:34 -07:00
|
|
|
has_named_attribute(ext_attrs.as_ref(), "NoInterfaceObject")
|
2018-07-17 22:23:17 -07:00
|
|
|
}
|
|
|
|
|
2018-11-27 12:07:59 -08:00
|
|
|
pub fn get_rust_deprecated<'a>(ext_attrs: &Option<ExtendedAttributeList<'a>>) -> Option<&'a str> {
|
|
|
|
ext_attrs
|
|
|
|
.as_ref()?
|
2018-09-28 14:16:17 -07:00
|
|
|
.body
|
|
|
|
.list
|
|
|
|
.iter()
|
2018-11-27 12:07:59 -08:00
|
|
|
.filter_map(|attr| match attr {
|
|
|
|
ExtendedAttribute::Ident(id) => Some(id),
|
|
|
|
_ => None,
|
2018-09-28 14:16:17 -07:00
|
|
|
})
|
2018-10-03 15:44:58 -07:00
|
|
|
.filter(|attr| attr.lhs_identifier.0 == "RustDeprecated")
|
2018-11-27 12:07:59 -08:00
|
|
|
.filter_map(|ident| match ident.rhs {
|
|
|
|
IdentifierOrString::String(s) => Some(s),
|
|
|
|
IdentifierOrString::Identifier(_) => None,
|
2018-09-28 14:16:17 -07:00
|
|
|
})
|
|
|
|
.next()
|
|
|
|
.map(|s| s.0)
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Whether a webidl object is marked as structural.
|
2018-08-31 17:38:34 -07:00
|
|
|
pub fn is_structural(
|
|
|
|
item_attrs: Option<&ExtendedAttributeList>,
|
|
|
|
container_attrs: Option<&ExtendedAttributeList>,
|
|
|
|
) -> bool {
|
2018-12-17 10:43:48 -08:00
|
|
|
// Note that once host bindings is implemented we'll want to switch this
|
|
|
|
// from `true` to `false`, and then we'll want to largely read information
|
|
|
|
// from the WebIDL about whether to use structural bindings or not.
|
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
|
|
|
true || has_named_attribute(item_attrs, "Unforgeable")
|
2018-09-26 08:26:00 -07:00
|
|
|
|| has_named_attribute(container_attrs, "Unforgeable")
|
|
|
|
|| has_ident_attribute(container_attrs, "Global")
|
2018-07-09 16:35:25 -07:00
|
|
|
}
|
2018-07-11 11:07:03 -07:00
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Whether a webidl object is marked as throwing.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn throws(attrs: &Option<ExtendedAttributeList>) -> bool {
|
2018-08-31 17:38:34 -07:00
|
|
|
has_named_attribute(attrs.as_ref(), "Throws")
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a syn `pub` token
|
2018-07-10 22:59:59 -07:00
|
|
|
pub fn public() -> syn::Visibility {
|
|
|
|
syn::Visibility::Public(syn::VisPublic {
|
|
|
|
pub_token: Default::default(),
|
2018-07-11 11:07:03 -07:00
|
|
|
})
|
|
|
|
}
|
2019-01-14 17:45:43 -05:00
|
|
|
|
2019-01-31 07:32:12 -05:00
|
|
|
fn flag_slices_immutable(ty: &mut IdlType) {
|
|
|
|
match ty {
|
2019-03-08 15:12:41 -08:00
|
|
|
IdlType::Uint8Array { immutable } => *immutable = true,
|
2019-01-31 07:32:12 -05:00
|
|
|
IdlType::Float32Array { immutable } => *immutable = true,
|
2019-03-08 15:12:41 -08:00
|
|
|
IdlType::ArrayBufferView { immutable } => *immutable = true,
|
|
|
|
IdlType::BufferSource { immutable } => *immutable = true,
|
2019-02-05 13:47:46 -05:00
|
|
|
IdlType::Nullable(item) => flag_slices_immutable(item),
|
|
|
|
IdlType::FrozenArray(item) => flag_slices_immutable(item),
|
|
|
|
IdlType::Sequence(item) => flag_slices_immutable(item),
|
|
|
|
IdlType::Promise(item) => flag_slices_immutable(item),
|
|
|
|
IdlType::Record(item1, item2) => {
|
|
|
|
flag_slices_immutable(item1);
|
|
|
|
flag_slices_immutable(item2);
|
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
|
|
|
}
|
2019-01-31 07:32:12 -05:00
|
|
|
IdlType::Union(list) => {
|
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
|
|
|
for item in list {
|
|
|
|
flag_slices_immutable(item);
|
|
|
|
}
|
2019-01-14 17:45:43 -05:00
|
|
|
}
|
2019-01-31 07:32:12 -05:00
|
|
|
// catch-all for everything else like Object
|
|
|
|
_ => {}
|
2019-01-14 17:45:43 -05:00
|
|
|
}
|
2019-01-31 07:32:12 -05:00
|
|
|
}
|