mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-18 07:21:24 +00:00
Merge pull request #1690 from alexcrichton/webidl-polyfill
Add support as a vanilla polyfill of WebIDL bindings
This commit is contained in:
@ -259,6 +259,7 @@ impl Bindgen {
|
|||||||
.generate_dwarf(self.keep_debug)
|
.generate_dwarf(self.keep_debug)
|
||||||
.generate_name_section(!self.remove_name_section)
|
.generate_name_section(!self.remove_name_section)
|
||||||
.generate_producers_section(!self.remove_producers_section)
|
.generate_producers_section(!self.remove_producers_section)
|
||||||
|
.on_parse(wasm_webidl_bindings::binary::on_parse)
|
||||||
.parse(&contents)
|
.parse(&contents)
|
||||||
.context("failed to parse input file as wasm")?;
|
.context("failed to parse input file as wasm")?;
|
||||||
let stem = match &self.out_name {
|
let stem = match &self.out_name {
|
||||||
|
@ -27,7 +27,7 @@ use crate::decode;
|
|||||||
use crate::descriptor::{Descriptor, Function};
|
use crate::descriptor::{Descriptor, Function};
|
||||||
use crate::descriptors::WasmBindgenDescriptorsSection;
|
use crate::descriptors::WasmBindgenDescriptorsSection;
|
||||||
use crate::intrinsic::Intrinsic;
|
use crate::intrinsic::Intrinsic;
|
||||||
use failure::{bail, Error};
|
use failure::{bail, format_err, Error};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -504,6 +504,10 @@ pub fn process(
|
|||||||
cx.program(program)?;
|
cx.program(program)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(standard) = cx.module.customs.delete_typed::<ast::WebidlBindings>() {
|
||||||
|
cx.standard(&standard)?;
|
||||||
|
}
|
||||||
|
|
||||||
cx.verify()?;
|
cx.verify()?;
|
||||||
|
|
||||||
let bindings = cx.module.customs.add(cx.bindings);
|
let bindings = cx.module.customs.add(cx.bindings);
|
||||||
@ -1287,6 +1291,171 @@ impl<'a> Context<'a> {
|
|||||||
Ok(JsImport { name, fields })
|
Ok(JsImport { name, fields })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Processes bindings from a standard WebIDL bindings custom section.
|
||||||
|
///
|
||||||
|
/// No module coming out of the Rust compiler will have one of these, but
|
||||||
|
/// eventually there's going to be other producers of the WebIDL bindings
|
||||||
|
/// custom section as well. This functionality is intended to allow
|
||||||
|
/// `wasm-bindgen`-the-CLI-tool to act as a polyfill for those modules as
|
||||||
|
/// well as Rust modules.
|
||||||
|
///
|
||||||
|
/// Here a standard `WebidlBindings` custom section is taken and we process
|
||||||
|
/// that into our own internal data structures to ensure that we have a
|
||||||
|
/// binding listed for all the described bindings.
|
||||||
|
///
|
||||||
|
/// In other words, this is a glorified conversion from the "official"
|
||||||
|
/// WebIDL bindings custom section into the wasm-bindgen internal
|
||||||
|
/// representation.
|
||||||
|
fn standard(&mut self, std: &ast::WebidlBindings) -> Result<(), Error> {
|
||||||
|
for (_id, bind) in std.binds.iter() {
|
||||||
|
let binding = self.standard_binding(std, bind)?;
|
||||||
|
let func = self.module.funcs.get(bind.func);
|
||||||
|
match &func.kind {
|
||||||
|
walrus::FunctionKind::Import(i) => {
|
||||||
|
let id = i.import;
|
||||||
|
self.standard_import(binding, id)?;
|
||||||
|
}
|
||||||
|
walrus::FunctionKind::Local(_) => {
|
||||||
|
let export = self
|
||||||
|
.module
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.find(|e| match e.item {
|
||||||
|
walrus::ExportItem::Function(f) => f == bind.func,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
.ok_or_else(|| format_err!("missing export function for webidl binding"))?;
|
||||||
|
let id = export.id();
|
||||||
|
self.standard_export(binding, id)?;
|
||||||
|
}
|
||||||
|
walrus::FunctionKind::Uninitialized(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a wasm-bindgen-internal `Binding` from an official `Bind`
|
||||||
|
/// structure specified in the upstream binary format.
|
||||||
|
///
|
||||||
|
/// This will largely just copy some things into our own arenas but also
|
||||||
|
/// processes the list of binding expressions into our own representations.
|
||||||
|
fn standard_binding(
|
||||||
|
&mut self,
|
||||||
|
std: &ast::WebidlBindings,
|
||||||
|
bind: &ast::Bind,
|
||||||
|
) -> Result<Binding, Error> {
|
||||||
|
let binding: &ast::FunctionBinding = std
|
||||||
|
.bindings
|
||||||
|
.get(bind.binding)
|
||||||
|
.ok_or_else(|| format_err!("bad binding id"))?;
|
||||||
|
let (wasm_ty, webidl_ty, incoming, outgoing) = match binding {
|
||||||
|
ast::FunctionBinding::Export(e) => (
|
||||||
|
e.wasm_ty,
|
||||||
|
e.webidl_ty,
|
||||||
|
e.params.bindings.as_slice(),
|
||||||
|
e.result.bindings.as_slice(),
|
||||||
|
),
|
||||||
|
ast::FunctionBinding::Import(e) => (
|
||||||
|
e.wasm_ty,
|
||||||
|
e.webidl_ty,
|
||||||
|
e.result.bindings.as_slice(),
|
||||||
|
e.params.bindings.as_slice(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let webidl_ty = copy_ty(&mut self.bindings.types, webidl_ty, &std.types);
|
||||||
|
let webidl_ty = match webidl_ty {
|
||||||
|
ast::WebidlTypeRef::Id(id) => <ast::WebidlFunction as ast::WebidlTypeId>::wrap(id),
|
||||||
|
_ => bail!("invalid webidl type listed"),
|
||||||
|
};
|
||||||
|
return Ok(Binding {
|
||||||
|
wasm_ty,
|
||||||
|
webidl_ty,
|
||||||
|
incoming: incoming
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(NonstandardIncoming::Standard)
|
||||||
|
.collect(),
|
||||||
|
outgoing: outgoing
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(NonstandardOutgoing::Standard)
|
||||||
|
.collect(),
|
||||||
|
return_via_outptr: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Recursively clones `ty` into` dst` where it originally indexes
|
||||||
|
/// values in `src`, returning a new type ref which indexes inside of
|
||||||
|
/// `dst`.
|
||||||
|
fn copy_ty(
|
||||||
|
dst: &mut ast::WebidlTypes,
|
||||||
|
ty: ast::WebidlTypeRef,
|
||||||
|
src: &ast::WebidlTypes,
|
||||||
|
) -> ast::WebidlTypeRef {
|
||||||
|
let id = match ty {
|
||||||
|
ast::WebidlTypeRef::Id(id) => id,
|
||||||
|
ast::WebidlTypeRef::Scalar(_) => return ty,
|
||||||
|
};
|
||||||
|
let ty: &ast::WebidlCompoundType = src.get(id).unwrap();
|
||||||
|
match ty {
|
||||||
|
ast::WebidlCompoundType::Function(f) => {
|
||||||
|
let params = f
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.map(|param| copy_ty(dst, *param, src))
|
||||||
|
.collect();
|
||||||
|
let result = f.result.map(|ty| copy_ty(dst, ty, src));
|
||||||
|
dst.insert(ast::WebidlFunction {
|
||||||
|
kind: f.kind.clone(),
|
||||||
|
params,
|
||||||
|
result,
|
||||||
|
})
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers that `id` has a `binding` which was read from a standard
|
||||||
|
/// webidl bindings section, so the source of `id` is its actual module/name
|
||||||
|
/// listed in the wasm module.
|
||||||
|
fn standard_import(&mut self, binding: Binding, id: walrus::ImportId) -> Result<(), Error> {
|
||||||
|
let import = self.module.imports.get(id);
|
||||||
|
let js = JsImport {
|
||||||
|
name: JsImportName::Module {
|
||||||
|
module: import.module.clone(),
|
||||||
|
name: import.name.clone(),
|
||||||
|
},
|
||||||
|
fields: Vec::new(),
|
||||||
|
};
|
||||||
|
let value = AuxValue::Bare(js);
|
||||||
|
assert!(self
|
||||||
|
.aux
|
||||||
|
.import_map
|
||||||
|
.insert(id, AuxImport::Value(value))
|
||||||
|
.is_none());
|
||||||
|
assert!(self.bindings.imports.insert(id, binding).is_none());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers that `id` has a `binding` and comes from a standard webidl
|
||||||
|
/// bindings section so it doesn't have any documentation or debug names we
|
||||||
|
/// can work with.
|
||||||
|
fn standard_export(&mut self, binding: Binding, id: walrus::ExportId) -> Result<(), Error> {
|
||||||
|
let export = self.module.exports.get(id);
|
||||||
|
let kind = AuxExportKind::Function(export.name.clone());
|
||||||
|
let export = AuxExport {
|
||||||
|
debug_name: format!("standard export {:?}", id),
|
||||||
|
comments: String::new(),
|
||||||
|
arg_names: None,
|
||||||
|
kind,
|
||||||
|
};
|
||||||
|
assert!(self.aux.export_map.insert(id, export).is_none());
|
||||||
|
assert!(self.bindings.exports.insert(id, binding).is_none());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform a small verification pass over the module to perform some
|
/// Perform a small verification pass over the module to perform some
|
||||||
/// internal sanity checks.
|
/// internal sanity checks.
|
||||||
fn verify(&self) -> Result<(), Error> {
|
fn verify(&self) -> Result<(), Error> {
|
||||||
|
Reference in New Issue
Block a user