Implement static imports

This allows importing static objects like `document`, `window`, or an arbitrary
JS object from a module
This commit is contained in:
Alex Crichton
2018-03-21 08:09:59 -07:00
parent eebe23649a
commit 8e894fcfc5
7 changed files with 189 additions and 3 deletions

View File

@ -1044,9 +1044,12 @@ impl<'a, 'b> SubContext<'a, 'b> {
for f in self.program.exports.iter() {
self.generate_export(f);
}
for f in self.program.imports.iter() {
for f in self.program.imported_functions.iter() {
self.generate_import(f);
}
for f in self.program.imported_fields.iter() {
self.generate_import_field(f);
}
for e in self.program.enums.iter() {
self.generate_enum(e);
}
@ -1319,6 +1322,24 @@ impl<'a, 'b> SubContext<'a, 'b> {
(format!("{} {}", prefix, dst), format!("{} {}", prefix, dst_ts))
}
pub fn generate_import_field(&mut self, import: &shared::ImportField) {
let name = import.shim_name();
self.cx.imports_to_rewrite.insert(name.clone());
if let Some(ref module) = import.module {
self.cx.imports.push_str(&format!("
import {{ {} }} from '{}';
", import.name, module));
}
self.cx.expose_add_heap_object();
self.cx.globals.push_str(&format!("
export function {}() {{
return addHeapObject({});
}}
", name, import.name));
}
pub fn generate_import(&mut self, import: &shared::Import) {
if let Some(ref module) = import.module {
let name_to_import = import.class.as_ref().unwrap_or(&import.function.name);

View File

@ -11,6 +11,7 @@ pub struct Program {
pub enums: Vec<Enum>,
pub imported_types: Vec<ImportedType>,
pub structs: Vec<Struct>,
pub imported_fields: Vec<ImportField>,
}
pub struct Export {
@ -62,6 +63,13 @@ pub struct ImportedType {
pub name: syn::Ident,
}
pub struct ImportField {
pub vis: syn::Visibility,
pub ty: syn::Type,
pub module: Option<String>,
pub name: syn::Ident,
}
pub enum Type {
// special
Vector(VectorType, bool),
@ -208,6 +216,7 @@ impl Program {
match item {
syn::ForeignItem::Fn(f) => self.push_foreign_fn(f, &opts),
syn::ForeignItem::Type(t) => self.push_foreign_ty(t, &opts),
syn::ForeignItem::Static(s) => self.push_foreign_static(s, &opts),
_ => panic!("only foreign functions/types allowed for now"),
}
}
@ -341,6 +350,20 @@ impl Program {
});
}
pub fn push_foreign_static(&mut self,
f: syn::ForeignItemStatic,
module_opts: &BindgenAttrs) {
if f.mutability.is_some() {
panic!("cannot import mutable globals yet")
}
self.imported_fields.push(ImportField {
module: module_opts.module().map(|s| s.to_string()),
ty: *f.ty,
vis: f.vis,
name: f.ident
});
}
pub fn literal(&self, dst: &mut Tokens) -> usize {
let mut tmp = Tokens::new();
let cnt = {
@ -792,3 +815,12 @@ impl ToTokens for VectorType {
me.to_tokens(tokens);
}
}
impl ImportField {
pub fn shared(&self) -> shared::ImportField {
shared::ImportField {
module: self.module.clone(),
name: self.name.to_string(),
}
}
}

View File

@ -78,6 +78,9 @@ impl ToTokens for ast::Program {
for it in self.imported_types.iter() {
it.to_tokens(tokens);
}
for it in self.imported_fields.iter() {
it.to_tokens(tokens);
}
// Generate a static which will eventually be what lives in a custom section
// of the wasm executable. For now it's just a plain old static, but we'll
@ -591,3 +594,28 @@ impl ToTokens for ast::Enum {
}).to_tokens(into);
}
}
impl ToTokens for ast::ImportField {
fn to_tokens(&self, into: &mut Tokens) {
let name = self.name;
let ty = &self.ty;
let shim_name = syn::Ident::from(self.shared().shim_name());
let vis = &self.vis;
(my_quote! {
#vis static #name: ::wasm_bindgen::JsStatic<#ty> = {
fn init() -> #ty {
extern {
fn #shim_name() -> u32;
}
unsafe {
::wasm_bindgen::convert::WasmBoundary::from_js(#shim_name())
}
}
::wasm_bindgen::JsStatic {
__inner: ::std::cell::UnsafeCell::new(None),
__init: init,
}
};
}).to_tokens(into);
}
}

View File

@ -107,7 +107,8 @@ impl Literal for ast::Program {
fn literal(&self, a: &mut LiteralBuilder) {
a.fields(&[
("exports", &|a| a.list_of(&self.exports)),
("imports", &|a| a.list_of(&self.imports)),
("imported_functions", &|a| a.list_of(&self.imports)),
("imported_fields", &|a| a.list_of(&self.imported_fields)),
("enums", &|a| a.list_of(&self.enums)),
("custom_type_names", &|a| {
let names = self.exports
@ -271,3 +272,15 @@ impl Literal for ast::Variant {
])
}
}
impl Literal for ast::ImportField {
fn literal(&self, a: &mut LiteralBuilder) {
a.fields(&[
("name", &|a| a.str(self.name.as_ref())),
("module", &|a| match self.module {
Some(ref s) => a.str(s),
None => a.append("null"),
}),
])
}
}

View File

@ -11,7 +11,8 @@ pub const SCHEMA_VERSION: &str = "0";
pub struct Program {
pub exports: Vec<Export>,
pub enums: Vec<Enum>,
pub imports: Vec<Import>,
pub imported_functions: Vec<Import>,
pub imported_fields: Vec<ImportField>,
pub custom_type_names: Vec<CustomTypeName>,
pub version: String,
pub schema_version: String,
@ -30,6 +31,12 @@ pub struct Import {
pub function: Function,
}
#[derive(Deserialize)]
pub struct ImportField {
pub module: Option<String>,
pub name: String,
}
#[derive(Deserialize)]
pub struct Export {
pub class: Option<String>,
@ -148,3 +155,9 @@ pub fn version() -> String {
}
return v
}
impl ImportField {
pub fn shim_name(&self) -> String {
format!("__wbg_field_import_shim_{}", self.name)
}
}