Skip to content

Commit 7a688d6

Browse files
authored
Merge branch 'master' into string-substr
2 parents b81dc46 + d28d81f commit 7a688d6

File tree

8 files changed

+193
-90
lines changed

8 files changed

+193
-90
lines changed

crates/backend/src/ast.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use proc_macro2::{Ident, Span, TokenStream, TokenTree};
22
use quote::ToTokens;
33
use shared;
44
use syn;
5+
use util;
56

67
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
78
#[derive(Default)]
@@ -412,6 +413,11 @@ impl Program {
412413
ty: class.clone(),
413414
kind: MethodKind::Normal,
414415
}
416+
} else if let Some(cls) = wasm.opts.static_method_of() {
417+
let class = cls.to_string();
418+
let kind = MethodKind::Static;
419+
let ty = util::ident_ty(cls.clone());
420+
ImportFunctionKind::Method { class, ty, kind }
415421
} else if wasm.opts.constructor() {
416422
let class = match wasm.ret {
417423
Some(ref ty) => ty,
@@ -794,7 +800,7 @@ impl Struct {
794800
ty: field.ty.clone(),
795801
getter: Ident::new(&getter, Span::call_site()),
796802
setter: Ident::new(&setter, Span::call_site()),
797-
comments
803+
comments,
798804
});
799805
}
800806
}
@@ -888,6 +894,16 @@ impl BindgenAttrs {
888894
})
889895
}
890896

897+
fn static_method_of(&self) -> Option<&Ident> {
898+
self.attrs
899+
.iter()
900+
.filter_map(|a| match a {
901+
BindgenAttr::StaticMethodOf(c) => Some(c),
902+
_ => None,
903+
})
904+
.next()
905+
}
906+
891907
fn method(&self) -> bool {
892908
self.attrs.iter().any(|a| match a {
893909
BindgenAttr::Method => true,
@@ -980,6 +996,7 @@ pub enum BindgenAttr {
980996
Catch,
981997
Constructor,
982998
Method,
999+
StaticMethodOf(Ident),
9831000
JsNamespace(Ident),
9841001
Module(String),
9851002
Version(String),
@@ -999,6 +1016,13 @@ impl syn::synom::Synom for BindgenAttr {
9991016
|
10001017
call!(term, "method") => { |_| BindgenAttr::Method }
10011018
|
1019+
do_parse!(
1020+
call!(term, "static_method_of") >>
1021+
punct!(=) >>
1022+
cls: call!(term2ident) >>
1023+
(cls)
1024+
)=> { BindgenAttr::StaticMethodOf }
1025+
|
10021026
do_parse!(
10031027
call!(term, "getter") >>
10041028
val: option!(do_parse!(

crates/backend/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ extern crate wasm_bindgen_shared as shared;
1212

1313
pub mod ast;
1414
mod codegen;
15+
pub mod util;

crates/backend/src/util.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use std::iter::FromIterator;
2+
3+
use ast;
4+
use proc_macro2::{self, Ident};
5+
use syn;
6+
7+
fn is_rust_keyword(name: &str) -> bool {
8+
match name {
9+
"abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue"
10+
| "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if"
11+
| "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut"
12+
| "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return"
13+
| "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true"
14+
| "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while"
15+
| "yield" | "bool" | "_" => true,
16+
_ => false,
17+
}
18+
}
19+
20+
// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword.
21+
pub fn rust_ident(name: &str) -> Ident {
22+
if is_rust_keyword(name) {
23+
Ident::new(&format!("{}_", name), proc_macro2::Span::call_site())
24+
} else {
25+
raw_ident(name)
26+
}
27+
}
28+
29+
// Create an `Ident` without checking to see if it conflicts with a Rust
30+
// keyword.
31+
pub fn raw_ident(name: &str) -> Ident {
32+
Ident::new(name, proc_macro2::Span::call_site())
33+
}
34+
35+
/// Create a path type from the given segments. For example an iterator yielding
36+
/// the idents `[foo, bar, baz]` will result in the path type `foo::bar::baz`.
37+
pub fn simple_path_ty<I>(segments: I) -> syn::Type
38+
where
39+
I: IntoIterator<Item = Ident>,
40+
{
41+
let segments: Vec<_> = segments
42+
.into_iter()
43+
.map(|i| syn::PathSegment {
44+
ident: i,
45+
arguments: syn::PathArguments::None,
46+
})
47+
.collect();
48+
49+
syn::TypePath {
50+
qself: None,
51+
path: syn::Path {
52+
leading_colon: None,
53+
segments: syn::punctuated::Punctuated::from_iter(segments),
54+
},
55+
}.into()
56+
}
57+
58+
pub fn ident_ty(ident: Ident) -> syn::Type {
59+
simple_path_ty(Some(ident))
60+
}
61+
62+
pub fn wrap_import_function(function: ast::ImportFunction) -> ast::Import {
63+
ast::Import {
64+
module: None,
65+
version: None,
66+
js_namespace: None,
67+
kind: ast::ImportKind::Function(function),
68+
}
69+
}

crates/webidl/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ extern crate syn;
1818
extern crate wasm_bindgen_backend as backend;
1919
extern crate webidl;
2020

21+
mod util;
22+
2123
use std::fs;
2224
use std::io::{self, Read};
23-
use std::iter;
2425
use std::path::Path;
2526

27+
use backend::util::{ident_ty, rust_ident, wrap_import_function};
2628
use failure::ResultExt;
2729
use quote::ToTokens;
2830

29-
mod util;
30-
3131
use util::{
32-
create_basic_method, create_function, create_getter, create_setter, ident_ty, rust_ident,
33-
webidl_ty_to_syn_ty, wrap_import_function, TypePosition,
32+
create_basic_method, create_function, create_getter, create_setter, webidl_ty_to_syn_ty,
33+
TypePosition,
3434
};
3535

3636
/// Either `Ok(t)` or `Err(failure::Error)`.

crates/webidl/src/util.rs

Lines changed: 3 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,12 @@
1-
use std::iter::{self, FromIterator};
1+
use std::iter;
22

33
use backend;
4+
use backend::util::{ident_ty, raw_ident, rust_ident, simple_path_ty};
45
use heck::SnakeCase;
5-
use proc_macro2::{self, Ident};
6+
use proc_macro2::Ident;
67
use syn;
78
use webidl;
89

9-
fn is_rust_keyword(name: &str) -> bool {
10-
match name {
11-
"abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue"
12-
| "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if"
13-
| "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut"
14-
| "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return"
15-
| "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true"
16-
| "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while"
17-
| "yield" | "bool" | "_" => true,
18-
_ => false,
19-
}
20-
}
21-
22-
// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword.
23-
pub fn rust_ident(name: &str) -> Ident {
24-
if is_rust_keyword(name) {
25-
Ident::new(&format!("{}_", name), proc_macro2::Span::call_site())
26-
} else {
27-
raw_ident(name)
28-
}
29-
}
30-
31-
// Create an `Ident` without checking to see if it conflicts with a Rust
32-
// keyword.
33-
fn raw_ident(name: &str) -> Ident {
34-
Ident::new(name, proc_macro2::Span::call_site())
35-
}
36-
37-
fn simple_path_ty<I>(segments: I) -> syn::Type
38-
where
39-
I: IntoIterator<Item = Ident>,
40-
{
41-
let segments: Vec<_> = segments
42-
.into_iter()
43-
.map(|i| syn::PathSegment {
44-
ident: i,
45-
arguments: syn::PathArguments::None,
46-
})
47-
.collect();
48-
49-
syn::TypePath {
50-
qself: None,
51-
path: syn::Path {
52-
leading_colon: None,
53-
segments: syn::punctuated::Punctuated::from_iter(segments),
54-
},
55-
}.into()
56-
}
57-
58-
pub fn ident_ty(ident: Ident) -> syn::Type {
59-
simple_path_ty(Some(ident))
60-
}
61-
6210
fn shared_ref(ty: syn::Type) -> syn::Type {
6311
syn::TypeReference {
6412
and_token: Default::default(),
@@ -337,12 +285,3 @@ pub fn create_setter(
337285
vec![backend::ast::BindgenAttr::Setter(Some(raw_ident(name)))],
338286
)
339287
}
340-
341-
pub fn wrap_import_function(function: backend::ast::ImportFunction) -> backend::ast::Import {
342-
backend::ast::Import {
343-
module: None,
344-
version: None,
345-
js_namespace: None,
346-
kind: backend::ast::ImportKind::Function(function),
347-
}
348-
}

src/js.rs

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -278,12 +278,6 @@ extern {
278278
extern {
279279
pub type Object;
280280

281-
/// The Object constructor creates an object wrapper.
282-
///
283-
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
284-
#[wasm_bindgen(constructor)]
285-
pub fn new() -> Object;
286-
287281
/// The `hasOwnProperty()` method returns a boolean indicating whether the
288282
/// object has the specified property as its own property (as opposed to
289283
/// inheriting it).
@@ -292,34 +286,47 @@ extern {
292286
#[wasm_bindgen(method, js_name = hasOwnProperty)]
293287
pub fn has_own_property(this: &Object, property: &JsValue) -> bool;
294288

295-
/// The toLocaleString() method returns a string representing the object.
296-
/// This method is meant to be overridden by derived objects for locale-specific
297-
/// purposes.
298-
///
299-
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toLocaleString
300-
#[wasm_bindgen(method, js_name = toLocaleString)]
301-
pub fn to_locale_string(this: &Object) -> JsString;
302-
303-
/// The toString() method returns a string representing the object.
304-
///
305-
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
306-
#[wasm_bindgen(method, js_name = toString)]
307-
pub fn to_string(this: &Object) -> JsString;
308-
309289
/// The isPrototypeOf() method checks if an object exists in another
310290
/// object's prototype chain.
311291
///
312292
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf
313293
#[wasm_bindgen(method, js_name = isPrototypeOf)]
314294
pub fn is_prototype_of(this: &Object, value: &JsValue) -> bool;
315295

296+
/// The Object.keys() method returns an array of a given object's property
297+
/// names, in the same order as we get with a normal loop.
298+
///
299+
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
300+
#[wasm_bindgen(static_method_of = Object)]
301+
pub fn keys(object: &Object) -> Array;
302+
303+
/// The Object constructor creates an object wrapper.
304+
///
305+
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
306+
#[wasm_bindgen(constructor)]
307+
pub fn new() -> Object;
308+
316309
/// The propertyIsEnumerable() method returns a Boolean indicating
317310
/// whether the specified property is enumerable.
318311
///
319312
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable
320313
#[wasm_bindgen(method, js_name = propertyIsEnumerable)]
321314
pub fn property_is_enumerable(this: &Object, property: &JsValue) -> bool;
322315

316+
/// The toLocaleString() method returns a string representing the object.
317+
/// This method is meant to be overridden by derived objects for locale-specific
318+
/// purposes.
319+
///
320+
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toLocaleString
321+
#[wasm_bindgen(method, js_name = toLocaleString)]
322+
pub fn to_locale_string(this: &Object) -> JsString;
323+
324+
/// The toString() method returns a string representing the object.
325+
///
326+
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
327+
#[wasm_bindgen(method, js_name = toString)]
328+
pub fn to_string(this: &Object) -> JsString;
329+
323330
/// The valueOf() method returns the primitive value of the
324331
/// specified object.
325332
///
@@ -334,6 +341,13 @@ extern {
334341
#[wasm_bindgen(js_name = JsString)]
335342
pub type JsString;
336343

344+
/// The String object's charAt() method returns a new string consisting of the single
345+
/// UTF-16 code unit located at the specified offset into the string.
346+
///
347+
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt
348+
#[wasm_bindgen(method, js_class = "String", js_name = charAt)]
349+
pub fn char_at(this: &JsString, index: u32) -> JsString;
350+
337351
/// The slice() method extracts a section of a string and returns it as a
338352
/// new string, without modifying the original string.
339353
///

tests/all/js_globals/JsString.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,35 @@
22

33
use project;
44

5+
#[test]
6+
fn char_at() {
7+
project()
8+
.file("src/lib.rs", r#"
9+
#![feature(proc_macro, wasm_custom_section)]
10+
11+
extern crate wasm_bindgen;
12+
use wasm_bindgen::prelude::*;
13+
use wasm_bindgen::js;
14+
15+
#[wasm_bindgen]
16+
pub fn string_char_at(this: &js::JsString, index: u32) -> js::JsString {
17+
this.char_at(index)
18+
}
19+
"#)
20+
.file("test.ts", r#"
21+
import * as assert from "assert";
22+
import * as wasm from "./out";
23+
24+
var anyString = 'Brave new world';
25+
26+
export function test() {
27+
assert.equal(wasm.string_char_at(anyString, 0), "B");
28+
assert.equal(wasm.string_char_at(anyString, 999), "");
29+
}
30+
"#)
31+
.test()
32+
}
33+
534
#[test]
635
fn slice() {
736
project()

0 commit comments

Comments
 (0)