mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-21 08:41:35 +00:00
Rename static
to namespace
This commit renames the `static` attribute to `namespace` and simultaneously reduces and expands the scope. The `namespace` attribute can now be applied to all imports in addition to functions, and it no longer recognizes full typed paths but rather just a bare identifier. The `namespace` attribute will generate a Rust namespace to invoke the item through if one doesn't already exist (aka bindign a type).
This commit is contained in:
@ -9,9 +9,7 @@ pub struct Program {
|
||||
pub exports: Vec<Export>,
|
||||
pub imports: Vec<Import>,
|
||||
pub enums: Vec<Enum>,
|
||||
pub imported_types: Vec<ImportedType>,
|
||||
pub structs: Vec<Struct>,
|
||||
pub imported_fields: Vec<ImportField>,
|
||||
}
|
||||
|
||||
pub struct Export {
|
||||
@ -23,17 +21,44 @@ pub struct Export {
|
||||
|
||||
pub struct Import {
|
||||
pub module: Option<String>,
|
||||
pub namespace: Option<syn::Ident>,
|
||||
pub kind: ImportKind,
|
||||
pub function: Function,
|
||||
}
|
||||
|
||||
pub enum ImportKind {
|
||||
Method { class: String, ty: syn::Type },
|
||||
Static { class: String, ty: syn::Type },
|
||||
JsConstructor { class: String, ty: syn::Type },
|
||||
Function(ImportFunction),
|
||||
Static(ImportStatic),
|
||||
Type(ImportType),
|
||||
}
|
||||
|
||||
pub struct ImportFunction {
|
||||
pub function: Function,
|
||||
pub kind: ImportFunctionKind,
|
||||
}
|
||||
|
||||
pub enum ImportFunctionKind {
|
||||
Method {
|
||||
class: String,
|
||||
ty: syn::Type,
|
||||
},
|
||||
JsConstructor {
|
||||
class: String,
|
||||
ty: syn::Type,
|
||||
},
|
||||
Normal,
|
||||
}
|
||||
|
||||
pub struct ImportStatic {
|
||||
pub vis: syn::Visibility,
|
||||
pub ty: syn::Type,
|
||||
pub name: syn::Ident,
|
||||
}
|
||||
|
||||
pub struct ImportType {
|
||||
pub vis: syn::Visibility,
|
||||
pub name: syn::Ident,
|
||||
}
|
||||
|
||||
pub struct Function {
|
||||
pub name: syn::Ident,
|
||||
pub arguments: Vec<Type>,
|
||||
@ -58,18 +83,6 @@ pub struct Variant {
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
pub struct ImportedType {
|
||||
pub vis: syn::Visibility,
|
||||
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),
|
||||
@ -206,22 +219,6 @@ impl Program {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn push_foreign_mod(&mut self, f: syn::ItemForeignMod, opts: BindgenAttrs) {
|
||||
match f.abi.name {
|
||||
Some(ref l) if l.value() == "C" => {}
|
||||
None => {}
|
||||
_ => panic!("only foreign mods with the `C` ABI are allowed"),
|
||||
}
|
||||
for item in f.items.into_iter() {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_enum(&mut self, item: syn::ItemEnum, _opts: BindgenAttrs) {
|
||||
match item.vis {
|
||||
syn::Visibility::Public(_) => {}
|
||||
@ -255,11 +252,38 @@ impl Program {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn push_foreign_fn(&mut self,
|
||||
mut f: syn::ForeignItemFn,
|
||||
module_opts: &BindgenAttrs) {
|
||||
let opts = BindgenAttrs::find(&mut f.attrs);
|
||||
pub fn push_foreign_mod(&mut self, f: syn::ItemForeignMod, opts: BindgenAttrs) {
|
||||
match f.abi.name {
|
||||
Some(ref l) if l.value() == "C" => {}
|
||||
None => {}
|
||||
_ => panic!("only foreign mods with the `C` ABI are allowed"),
|
||||
}
|
||||
for mut item in f.items.into_iter() {
|
||||
let item_opts = {
|
||||
let attrs = match item {
|
||||
syn::ForeignItem::Fn(ref mut f) => &mut f.attrs,
|
||||
syn::ForeignItem::Type(ref mut t) => &mut t.attrs,
|
||||
syn::ForeignItem::Static(ref mut s) => &mut s.attrs,
|
||||
_ => panic!("only foreign functions/types allowed for now"),
|
||||
};
|
||||
BindgenAttrs::find(attrs)
|
||||
};
|
||||
let module = item_opts.module().or(opts.module()).map(|s| s.to_string());
|
||||
let namespace = item_opts.namespace().or(opts.namespace());
|
||||
let mut kind = match item {
|
||||
syn::ForeignItem::Fn(f) => self.push_foreign_fn(f, item_opts),
|
||||
syn::ForeignItem::Type(t) => self.push_foreign_ty(t),
|
||||
syn::ForeignItem::Static(s) => self.push_foreign_static(s),
|
||||
_ => panic!("only foreign functions/types allowed for now"),
|
||||
};
|
||||
|
||||
self.imports.push(Import { module, namespace, kind });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_foreign_fn(&mut self, f: syn::ForeignItemFn, opts: BindgenAttrs)
|
||||
-> ImportKind
|
||||
{
|
||||
let mut wasm = Function::from_decl(f.ident,
|
||||
f.decl,
|
||||
f.attrs,
|
||||
@ -298,7 +322,7 @@ impl Program {
|
||||
let class_name = extract_path_ident(class_name)
|
||||
.expect("first argument of method must be a bare type");
|
||||
|
||||
ImportKind::Method {
|
||||
ImportFunctionKind::Method {
|
||||
class: class_name.as_ref().to_string(),
|
||||
ty: class.clone(),
|
||||
}
|
||||
@ -314,54 +338,40 @@ impl Program {
|
||||
let class_name = extract_path_ident(class_name)
|
||||
.expect("first argument of method must be a bare type");
|
||||
|
||||
ImportKind::JsConstructor {
|
||||
ImportFunctionKind::JsConstructor {
|
||||
class: class_name.as_ref().to_string(),
|
||||
ty: class.clone(),
|
||||
}
|
||||
|
||||
} else if let Some(class) = wasm.opts.static_receiver() {
|
||||
let class_name = match *class {
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => path,
|
||||
_ => panic!("first argument of method must be a path"),
|
||||
};
|
||||
let class_name = extract_path_ident(class_name)
|
||||
.expect("first argument of method must be a bare type");
|
||||
ImportKind::Static {
|
||||
class: class_name.to_string(),
|
||||
ty: class.clone(),
|
||||
}
|
||||
} else {
|
||||
ImportKind::Normal
|
||||
ImportFunctionKind::Normal
|
||||
};
|
||||
|
||||
self.imports.push(Import {
|
||||
module: module_opts.module().map(|s| s.to_string()),
|
||||
kind,
|
||||
ImportKind::Function(ImportFunction {
|
||||
function: wasm,
|
||||
});
|
||||
kind,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push_foreign_ty(&mut self,
|
||||
f: syn::ForeignItemType,
|
||||
_module_opts: &BindgenAttrs) {
|
||||
self.imported_types.push(ImportedType {
|
||||
pub fn push_foreign_ty(&mut self, f: syn::ForeignItemType)
|
||||
-> ImportKind
|
||||
{
|
||||
ImportKind::Type(ImportType {
|
||||
vis: f.vis,
|
||||
name: f.ident
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push_foreign_static(&mut self,
|
||||
f: syn::ForeignItemStatic,
|
||||
module_opts: &BindgenAttrs) {
|
||||
pub fn push_foreign_static(&mut self, f: syn::ForeignItemStatic)
|
||||
-> ImportKind
|
||||
{
|
||||
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()),
|
||||
ImportKind::Static(ImportStatic {
|
||||
ty: *f.ty,
|
||||
vis: f.vis,
|
||||
name: f.ident
|
||||
});
|
||||
name: f.ident,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn literal(&self, dst: &mut Tokens) -> usize {
|
||||
@ -552,7 +562,7 @@ impl Export {
|
||||
}
|
||||
}
|
||||
|
||||
impl Import {
|
||||
impl ImportFunction {
|
||||
pub fn infer_getter_property(&self) -> String {
|
||||
self.function.name.as_ref().to_string()
|
||||
}
|
||||
@ -630,11 +640,11 @@ impl BindgenAttrs {
|
||||
})
|
||||
}
|
||||
|
||||
fn static_receiver(&self) -> Option<&syn::Type> {
|
||||
fn namespace(&self) -> Option<syn::Ident> {
|
||||
self.attrs.iter()
|
||||
.filter_map(|a| {
|
||||
match *a {
|
||||
BindgenAttr::Static(ref s) => Some(s),
|
||||
BindgenAttr::Namespace(s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
@ -681,7 +691,7 @@ enum BindgenAttr {
|
||||
Catch,
|
||||
Constructor,
|
||||
Method,
|
||||
Static(syn::Type),
|
||||
Namespace(syn::Ident),
|
||||
Module(String),
|
||||
Getter,
|
||||
Setter,
|
||||
@ -700,11 +710,11 @@ impl syn::synom::Synom for BindgenAttr {
|
||||
call!(term, "setter") => { |_| BindgenAttr::Setter }
|
||||
|
|
||||
do_parse!(
|
||||
call!(term, "static") >>
|
||||
call!(term, "namespace") >>
|
||||
punct!(=) >>
|
||||
s: syn!(syn::Type) >>
|
||||
(s)
|
||||
)=> { BindgenAttr::Static }
|
||||
ns: syn!(syn::Ident) >>
|
||||
(ns)
|
||||
)=> { BindgenAttr::Namespace }
|
||||
|
|
||||
do_parse!(
|
||||
call!(term, "module") >>
|
||||
@ -815,12 +825,3 @@ 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ extern crate wasm_bindgen_shared as shared;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::sync::atomic::*;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
@ -69,18 +70,44 @@ impl ToTokens for ast::Program {
|
||||
for s in self.structs.iter() {
|
||||
s.to_tokens(tokens);
|
||||
}
|
||||
let mut types = HashSet::new();
|
||||
let mut buckets = BTreeMap::new();
|
||||
for i in self.imports.iter() {
|
||||
i.to_tokens(tokens);
|
||||
buckets.entry(i.namespace)
|
||||
.or_insert(Vec::new())
|
||||
.push(i);
|
||||
if let ast::ImportKind::Type(ref t) = i.kind {
|
||||
types.insert(t.name);
|
||||
}
|
||||
}
|
||||
for (namespace, imports) in buckets {
|
||||
let mut sub_tokens = Tokens::new();
|
||||
for import in imports {
|
||||
import.kind.to_tokens(&mut sub_tokens);
|
||||
}
|
||||
match namespace {
|
||||
Some(ns) if types.contains(&ns) => {
|
||||
(quote! { impl #ns { #sub_tokens } }).to_tokens(tokens);
|
||||
}
|
||||
Some(ns) => {
|
||||
(quote! {
|
||||
// TODO: allow controlling `pub` here.
|
||||
//
|
||||
// TODO: we don't really want to generate a type here,
|
||||
// it'd be preferrable to generate a namespace indicator
|
||||
// or something like that (but modules interact weirdly
|
||||
// with imports and such)
|
||||
pub struct #ns { _priv: () }
|
||||
|
||||
impl #ns { #sub_tokens }
|
||||
}).to_tokens(tokens);
|
||||
}
|
||||
None => sub_tokens.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
for e in self.enums.iter() {
|
||||
e.to_tokens(tokens);
|
||||
}
|
||||
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
|
||||
@ -311,7 +338,7 @@ impl ToTokens for ast::Export {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ast::ImportedType {
|
||||
impl ToTokens for ast::ImportType {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let vis = &self.vis;
|
||||
let name = &self.name;
|
||||
@ -344,23 +371,32 @@ impl ToTokens for ast::ImportedType {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ast::Import {
|
||||
impl ToTokens for ast::ImportKind {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
match *self {
|
||||
ast::ImportKind::Function(ref f) => f.to_tokens(tokens),
|
||||
ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
|
||||
ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ast::ImportFunction {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let mut class_ty = None;
|
||||
let mut is_method = false;
|
||||
let mut class_name = None;
|
||||
match self.kind {
|
||||
ast::ImportKind::Method { ref ty, ref class } => {
|
||||
ast::ImportFunctionKind::Method { ref ty, ref class } => {
|
||||
is_method = true;
|
||||
class_ty = Some(ty);
|
||||
class_name = Some(class);
|
||||
}
|
||||
ast::ImportKind::Static { ref ty, ref class } |
|
||||
ast::ImportKind::JsConstructor { ref ty, ref class } => {
|
||||
ast::ImportFunctionKind::JsConstructor { ref ty, ref class } => {
|
||||
class_ty = Some(ty);
|
||||
class_name = Some(class);
|
||||
}
|
||||
ast::ImportKind::Normal => {}
|
||||
ast::ImportFunctionKind::Normal => {}
|
||||
}
|
||||
let import_name = shared::mangled_import_name(
|
||||
class_name.map(|s| &**s),
|
||||
@ -595,11 +631,12 @@ impl ToTokens for ast::Enum {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ast::ImportField {
|
||||
impl ToTokens for ast::ImportStatic {
|
||||
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 shim_name = shared::static_import_shim_name(name.as_ref());
|
||||
let shim_name = syn::Ident::from(shim_name);
|
||||
let vis = &self.vis;
|
||||
(my_quote! {
|
||||
#vis static #name: ::wasm_bindgen::JsStatic<#ty> = {
|
||||
|
@ -107,8 +107,7 @@ impl Literal for ast::Program {
|
||||
fn literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("exports", &|a| a.list_of(&self.exports)),
|
||||
("imported_functions", &|a| a.list_of(&self.imports)),
|
||||
("imported_fields", &|a| a.list_of(&self.imported_fields)),
|
||||
("imports", &|a| a.list_of(&self.imports)),
|
||||
("enums", &|a| a.list_of(&self.enums)),
|
||||
("custom_type_names", &|a| {
|
||||
let names = self.exports
|
||||
@ -199,25 +198,46 @@ impl Literal for ast::Export {
|
||||
}
|
||||
|
||||
impl Literal for ast::Import {
|
||||
fn literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("module", &|a| match self.module {
|
||||
Some(ref s) => a.str(s),
|
||||
None => a.append("null"),
|
||||
}),
|
||||
("namespace", &|a| match self.namespace {
|
||||
Some(ref s) => a.str(s.as_ref()),
|
||||
None => a.append("null"),
|
||||
}),
|
||||
("kind", &|a| self.kind.literal(a)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal for ast::ImportKind {
|
||||
fn literal(&self, a: &mut LiteralBuilder) {
|
||||
match *self {
|
||||
ast::ImportKind::Function(ref f) => f.literal(a),
|
||||
ast::ImportKind::Static(ref s) => s.literal(a),
|
||||
ast::ImportKind::Type(ref t) => t.literal(a),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal for ast::ImportFunction {
|
||||
fn literal(&self, a: &mut LiteralBuilder) {
|
||||
let mut method = false;
|
||||
let mut js_new = false;
|
||||
let mut statik = false;
|
||||
let mut class_name = None;
|
||||
match self.kind {
|
||||
ast::ImportKind::Method { ref class, .. } => {
|
||||
ast::ImportFunctionKind::Method { ref class, .. } => {
|
||||
method = true;
|
||||
class_name = Some(class);
|
||||
}
|
||||
ast::ImportKind::JsConstructor { ref class, .. } => {
|
||||
ast::ImportFunctionKind::JsConstructor { ref class, .. } => {
|
||||
js_new = true;
|
||||
class_name = Some(class);
|
||||
}
|
||||
ast::ImportKind::Static { ref class, .. } => {
|
||||
statik = true;
|
||||
class_name = Some(class);
|
||||
}
|
||||
ast::ImportKind::Normal => {}
|
||||
ast::ImportFunctionKind::Normal => {}
|
||||
}
|
||||
|
||||
let mut getter = None;
|
||||
@ -230,14 +250,10 @@ impl Literal for ast::Import {
|
||||
setter = Some(self.infer_setter_property());
|
||||
}
|
||||
a.fields(&[
|
||||
("module", &|a| match self.module {
|
||||
Some(ref s) => a.str(s),
|
||||
None => a.append("null"),
|
||||
}),
|
||||
("kind", &|a| a.str("function")),
|
||||
("catch", &|a| a.bool(self.function.opts.catch())),
|
||||
("method", &|a| a.bool(method)),
|
||||
("js_new", &|a| a.bool(js_new)),
|
||||
("statik", &|a| a.bool(statik)),
|
||||
("getter", &|a| match getter {
|
||||
Some(ref s) => a.str(s),
|
||||
None => a.append("null"),
|
||||
@ -273,14 +289,19 @@ impl Literal for ast::Variant {
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal for ast::ImportField {
|
||||
impl Literal for ast::ImportStatic {
|
||||
fn literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("kind", &|a| a.str("static")),
|
||||
("name", &|a| a.str(self.name.as_ref())),
|
||||
("module", &|a| match self.module {
|
||||
Some(ref s) => a.str(s),
|
||||
None => a.append("null"),
|
||||
}),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal for ast::ImportType {
|
||||
fn literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("kind", &|a| a.str("type")),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user