mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-02 02:11:06 +00:00
Merge branch 'master' into string-substr
This commit is contained in:
commit
7a688d6967
@ -2,6 +2,7 @@ use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
|||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use shared;
|
use shared;
|
||||||
use syn;
|
use syn;
|
||||||
|
use util;
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -412,6 +413,11 @@ impl Program {
|
|||||||
ty: class.clone(),
|
ty: class.clone(),
|
||||||
kind: MethodKind::Normal,
|
kind: MethodKind::Normal,
|
||||||
}
|
}
|
||||||
|
} else if let Some(cls) = wasm.opts.static_method_of() {
|
||||||
|
let class = cls.to_string();
|
||||||
|
let kind = MethodKind::Static;
|
||||||
|
let ty = util::ident_ty(cls.clone());
|
||||||
|
ImportFunctionKind::Method { class, ty, kind }
|
||||||
} else if wasm.opts.constructor() {
|
} else if wasm.opts.constructor() {
|
||||||
let class = match wasm.ret {
|
let class = match wasm.ret {
|
||||||
Some(ref ty) => ty,
|
Some(ref ty) => ty,
|
||||||
@ -794,7 +800,7 @@ impl Struct {
|
|||||||
ty: field.ty.clone(),
|
ty: field.ty.clone(),
|
||||||
getter: Ident::new(&getter, Span::call_site()),
|
getter: Ident::new(&getter, Span::call_site()),
|
||||||
setter: Ident::new(&setter, Span::call_site()),
|
setter: Ident::new(&setter, Span::call_site()),
|
||||||
comments
|
comments,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -888,6 +894,16 @@ impl BindgenAttrs {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn static_method_of(&self) -> Option<&Ident> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::StaticMethodOf(c) => Some(c),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
fn method(&self) -> bool {
|
fn method(&self) -> bool {
|
||||||
self.attrs.iter().any(|a| match a {
|
self.attrs.iter().any(|a| match a {
|
||||||
BindgenAttr::Method => true,
|
BindgenAttr::Method => true,
|
||||||
@ -980,6 +996,7 @@ pub enum BindgenAttr {
|
|||||||
Catch,
|
Catch,
|
||||||
Constructor,
|
Constructor,
|
||||||
Method,
|
Method,
|
||||||
|
StaticMethodOf(Ident),
|
||||||
JsNamespace(Ident),
|
JsNamespace(Ident),
|
||||||
Module(String),
|
Module(String),
|
||||||
Version(String),
|
Version(String),
|
||||||
@ -999,6 +1016,13 @@ impl syn::synom::Synom for BindgenAttr {
|
|||||||
|
|
|
|
||||||
call!(term, "method") => { |_| BindgenAttr::Method }
|
call!(term, "method") => { |_| BindgenAttr::Method }
|
||||||
|
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "static_method_of") >>
|
||||||
|
punct!(=) >>
|
||||||
|
cls: call!(term2ident) >>
|
||||||
|
(cls)
|
||||||
|
)=> { BindgenAttr::StaticMethodOf }
|
||||||
|
|
|
||||||
do_parse!(
|
do_parse!(
|
||||||
call!(term, "getter") >>
|
call!(term, "getter") >>
|
||||||
val: option!(do_parse!(
|
val: option!(do_parse!(
|
||||||
|
@ -12,3 +12,4 @@ extern crate wasm_bindgen_shared as shared;
|
|||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
pub mod util;
|
||||||
|
69
crates/backend/src/util.rs
Normal file
69
crates/backend/src/util.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
use ast;
|
||||||
|
use proc_macro2::{self, Ident};
|
||||||
|
use syn;
|
||||||
|
|
||||||
|
fn is_rust_keyword(name: &str) -> bool {
|
||||||
|
match name {
|
||||||
|
"abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue"
|
||||||
|
| "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if"
|
||||||
|
| "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut"
|
||||||
|
| "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return"
|
||||||
|
| "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true"
|
||||||
|
| "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while"
|
||||||
|
| "yield" | "bool" | "_" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword.
|
||||||
|
pub fn rust_ident(name: &str) -> Ident {
|
||||||
|
if is_rust_keyword(name) {
|
||||||
|
Ident::new(&format!("{}_", name), proc_macro2::Span::call_site())
|
||||||
|
} else {
|
||||||
|
raw_ident(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an `Ident` without checking to see if it conflicts with a Rust
|
||||||
|
// keyword.
|
||||||
|
pub fn raw_ident(name: &str) -> Ident {
|
||||||
|
Ident::new(name, proc_macro2::Span::call_site())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a path type from the given segments. For example an iterator yielding
|
||||||
|
/// the idents `[foo, bar, baz]` will result in the path type `foo::bar::baz`.
|
||||||
|
pub fn simple_path_ty<I>(segments: I) -> syn::Type
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Ident>,
|
||||||
|
{
|
||||||
|
let segments: Vec<_> = segments
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| syn::PathSegment {
|
||||||
|
ident: i,
|
||||||
|
arguments: syn::PathArguments::None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
path: syn::Path {
|
||||||
|
leading_colon: None,
|
||||||
|
segments: syn::punctuated::Punctuated::from_iter(segments),
|
||||||
|
},
|
||||||
|
}.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ident_ty(ident: Ident) -> syn::Type {
|
||||||
|
simple_path_ty(Some(ident))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap_import_function(function: ast::ImportFunction) -> ast::Import {
|
||||||
|
ast::Import {
|
||||||
|
module: None,
|
||||||
|
version: None,
|
||||||
|
js_namespace: None,
|
||||||
|
kind: ast::ImportKind::Function(function),
|
||||||
|
}
|
||||||
|
}
|
@ -18,19 +18,19 @@ extern crate syn;
|
|||||||
extern crate wasm_bindgen_backend as backend;
|
extern crate wasm_bindgen_backend as backend;
|
||||||
extern crate webidl;
|
extern crate webidl;
|
||||||
|
|
||||||
|
mod util;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::iter;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use backend::util::{ident_ty, rust_ident, wrap_import_function};
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
|
||||||
mod util;
|
|
||||||
|
|
||||||
use util::{
|
use util::{
|
||||||
create_basic_method, create_function, create_getter, create_setter, ident_ty, rust_ident,
|
create_basic_method, create_function, create_getter, create_setter, webidl_ty_to_syn_ty,
|
||||||
webidl_ty_to_syn_ty, wrap_import_function, TypePosition,
|
TypePosition,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Either `Ok(t)` or `Err(failure::Error)`.
|
/// Either `Ok(t)` or `Err(failure::Error)`.
|
||||||
|
@ -1,64 +1,12 @@
|
|||||||
use std::iter::{self, FromIterator};
|
use std::iter;
|
||||||
|
|
||||||
use backend;
|
use backend;
|
||||||
|
use backend::util::{ident_ty, raw_ident, rust_ident, simple_path_ty};
|
||||||
use heck::SnakeCase;
|
use heck::SnakeCase;
|
||||||
use proc_macro2::{self, Ident};
|
use proc_macro2::Ident;
|
||||||
use syn;
|
use syn;
|
||||||
use webidl;
|
use webidl;
|
||||||
|
|
||||||
fn is_rust_keyword(name: &str) -> bool {
|
|
||||||
match name {
|
|
||||||
"abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue"
|
|
||||||
| "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if"
|
|
||||||
| "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut"
|
|
||||||
| "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return"
|
|
||||||
| "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true"
|
|
||||||
| "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while"
|
|
||||||
| "yield" | "bool" | "_" => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword.
|
|
||||||
pub fn rust_ident(name: &str) -> Ident {
|
|
||||||
if is_rust_keyword(name) {
|
|
||||||
Ident::new(&format!("{}_", name), proc_macro2::Span::call_site())
|
|
||||||
} else {
|
|
||||||
raw_ident(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an `Ident` without checking to see if it conflicts with a Rust
|
|
||||||
// keyword.
|
|
||||||
fn raw_ident(name: &str) -> Ident {
|
|
||||||
Ident::new(name, proc_macro2::Span::call_site())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simple_path_ty<I>(segments: I) -> syn::Type
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = Ident>,
|
|
||||||
{
|
|
||||||
let segments: Vec<_> = segments
|
|
||||||
.into_iter()
|
|
||||||
.map(|i| syn::PathSegment {
|
|
||||||
ident: i,
|
|
||||||
arguments: syn::PathArguments::None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
syn::TypePath {
|
|
||||||
qself: None,
|
|
||||||
path: syn::Path {
|
|
||||||
leading_colon: None,
|
|
||||||
segments: syn::punctuated::Punctuated::from_iter(segments),
|
|
||||||
},
|
|
||||||
}.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ident_ty(ident: Ident) -> syn::Type {
|
|
||||||
simple_path_ty(Some(ident))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shared_ref(ty: syn::Type) -> syn::Type {
|
fn shared_ref(ty: syn::Type) -> syn::Type {
|
||||||
syn::TypeReference {
|
syn::TypeReference {
|
||||||
and_token: Default::default(),
|
and_token: Default::default(),
|
||||||
@ -337,12 +285,3 @@ pub fn create_setter(
|
|||||||
vec![backend::ast::BindgenAttr::Setter(Some(raw_ident(name)))],
|
vec![backend::ast::BindgenAttr::Setter(Some(raw_ident(name)))],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wrap_import_function(function: backend::ast::ImportFunction) -> backend::ast::Import {
|
|
||||||
backend::ast::Import {
|
|
||||||
module: None,
|
|
||||||
version: None,
|
|
||||||
js_namespace: None,
|
|
||||||
kind: backend::ast::ImportKind::Function(function),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
54
src/js.rs
54
src/js.rs
@ -278,12 +278,6 @@ extern {
|
|||||||
extern {
|
extern {
|
||||||
pub type Object;
|
pub type Object;
|
||||||
|
|
||||||
/// The Object constructor creates an object wrapper.
|
|
||||||
///
|
|
||||||
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
pub fn new() -> Object;
|
|
||||||
|
|
||||||
/// The `hasOwnProperty()` method returns a boolean indicating whether the
|
/// The `hasOwnProperty()` method returns a boolean indicating whether the
|
||||||
/// object has the specified property as its own property (as opposed to
|
/// object has the specified property as its own property (as opposed to
|
||||||
/// inheriting it).
|
/// inheriting it).
|
||||||
@ -292,6 +286,33 @@ extern {
|
|||||||
#[wasm_bindgen(method, js_name = hasOwnProperty)]
|
#[wasm_bindgen(method, js_name = hasOwnProperty)]
|
||||||
pub fn has_own_property(this: &Object, property: &JsValue) -> bool;
|
pub fn has_own_property(this: &Object, property: &JsValue) -> bool;
|
||||||
|
|
||||||
|
/// The isPrototypeOf() method checks if an object exists in another
|
||||||
|
/// object's prototype chain.
|
||||||
|
///
|
||||||
|
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf
|
||||||
|
#[wasm_bindgen(method, js_name = isPrototypeOf)]
|
||||||
|
pub fn is_prototype_of(this: &Object, value: &JsValue) -> bool;
|
||||||
|
|
||||||
|
/// The Object.keys() method returns an array of a given object's property
|
||||||
|
/// names, in the same order as we get with a normal loop.
|
||||||
|
///
|
||||||
|
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
|
||||||
|
#[wasm_bindgen(static_method_of = Object)]
|
||||||
|
pub fn keys(object: &Object) -> Array;
|
||||||
|
|
||||||
|
/// The Object constructor creates an object wrapper.
|
||||||
|
///
|
||||||
|
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new() -> Object;
|
||||||
|
|
||||||
|
/// The propertyIsEnumerable() method returns a Boolean indicating
|
||||||
|
/// whether the specified property is enumerable.
|
||||||
|
///
|
||||||
|
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable
|
||||||
|
#[wasm_bindgen(method, js_name = propertyIsEnumerable)]
|
||||||
|
pub fn property_is_enumerable(this: &Object, property: &JsValue) -> bool;
|
||||||
|
|
||||||
/// The toLocaleString() method returns a string representing the object.
|
/// The toLocaleString() method returns a string representing the object.
|
||||||
/// This method is meant to be overridden by derived objects for locale-specific
|
/// This method is meant to be overridden by derived objects for locale-specific
|
||||||
/// purposes.
|
/// purposes.
|
||||||
@ -306,20 +327,6 @@ extern {
|
|||||||
#[wasm_bindgen(method, js_name = toString)]
|
#[wasm_bindgen(method, js_name = toString)]
|
||||||
pub fn to_string(this: &Object) -> JsString;
|
pub fn to_string(this: &Object) -> JsString;
|
||||||
|
|
||||||
/// The isPrototypeOf() method checks if an object exists in another
|
|
||||||
/// object's prototype chain.
|
|
||||||
///
|
|
||||||
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf
|
|
||||||
#[wasm_bindgen(method, js_name = isPrototypeOf)]
|
|
||||||
pub fn is_prototype_of(this: &Object, value: &JsValue) -> bool;
|
|
||||||
|
|
||||||
/// The propertyIsEnumerable() method returns a Boolean indicating
|
|
||||||
/// whether the specified property is enumerable.
|
|
||||||
///
|
|
||||||
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable
|
|
||||||
#[wasm_bindgen(method, js_name = propertyIsEnumerable)]
|
|
||||||
pub fn property_is_enumerable(this: &Object, property: &JsValue) -> bool;
|
|
||||||
|
|
||||||
/// The valueOf() method returns the primitive value of the
|
/// The valueOf() method returns the primitive value of the
|
||||||
/// specified object.
|
/// specified object.
|
||||||
///
|
///
|
||||||
@ -334,6 +341,13 @@ extern {
|
|||||||
#[wasm_bindgen(js_name = JsString)]
|
#[wasm_bindgen(js_name = JsString)]
|
||||||
pub type JsString;
|
pub type JsString;
|
||||||
|
|
||||||
|
/// The String object's charAt() method returns a new string consisting of the single
|
||||||
|
/// UTF-16 code unit located at the specified offset into the string.
|
||||||
|
///
|
||||||
|
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt
|
||||||
|
#[wasm_bindgen(method, js_class = "String", js_name = charAt)]
|
||||||
|
pub fn char_at(this: &JsString, index: u32) -> JsString;
|
||||||
|
|
||||||
/// The slice() method extracts a section of a string and returns it as a
|
/// The slice() method extracts a section of a string and returns it as a
|
||||||
/// new string, without modifying the original string.
|
/// new string, without modifying the original string.
|
||||||
///
|
///
|
||||||
|
@ -2,6 +2,35 @@
|
|||||||
|
|
||||||
use project;
|
use project;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn char_at() {
|
||||||
|
project()
|
||||||
|
.file("src/lib.rs", r#"
|
||||||
|
#![feature(proc_macro, wasm_custom_section)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen::js;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn string_char_at(this: &js::JsString, index: u32) -> js::JsString {
|
||||||
|
this.char_at(index)
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.file("test.ts", r#"
|
||||||
|
import * as assert from "assert";
|
||||||
|
import * as wasm from "./out";
|
||||||
|
|
||||||
|
var anyString = 'Brave new world';
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
assert.equal(wasm.string_char_at(anyString, 0), "B");
|
||||||
|
assert.equal(wasm.string_char_at(anyString, 999), "");
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.test()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn slice() {
|
fn slice() {
|
||||||
project()
|
project()
|
||||||
|
@ -123,6 +123,33 @@ fn is_prototype_of() {
|
|||||||
.test()
|
.test()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keys() {
|
||||||
|
project()
|
||||||
|
.file("src/lib.rs", r#"
|
||||||
|
#![feature(proc_macro, wasm_custom_section)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen::js;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn keys(obj: &js::Object) -> js::Array {
|
||||||
|
js::Object::keys(obj)
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.file("test.ts", r#"
|
||||||
|
import * as assert from "assert";
|
||||||
|
import * as wasm from "./out";
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
const obj = { a: 1, b: 2, c: 3 };
|
||||||
|
assert.deepStrictEqual(wasm.keys(obj), ["a", "b", "c"]);
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.test()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn property_is_enumerable() {
|
fn property_is_enumerable() {
|
||||||
project()
|
project()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user