From b9ea8ddcc9123f0e360ba8ff72090d49d4351ae4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 Aug 2018 08:14:58 +0000 Subject: [PATCH 01/24] Bump @types/node from 10.5.5 to 10.5.6 Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped) from 10.5.5 to 10.5.6. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits) Signed-off-by: dependabot[bot] --- package-lock.json | 47 +++++++++++++++++++++++++++++++++-------------- package.json | 2 +- yarn.lock | 20 ++++++++++---------- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index efa45e0a..9e7fb0e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -106,9 +106,9 @@ } }, "@types/node": { - "version": "10.5.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.5.tgz", - "integrity": "sha512-6Qnb1gXbp3g1JX9QVJj3A6ORzc9XCyhokxUKaoonHgNXcQhmk8adhotxfkeK8El9TnFeUuH72yI6jQ5nDJKS6w==", + "version": "10.5.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.6.tgz", + "integrity": "sha512-c5Z1j1ysgo4878ptz6gxLcgMfJ6Wf908R3l5KAGabr0XJ72ZFmOCgsaodPpNYTfp4iOrSwgTDvR/BxbFfB4zPQ==", "dev": true }, "@webassemblyjs/ast": { @@ -2379,7 +2379,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2400,12 +2401,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2420,17 +2423,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2547,7 +2553,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2559,6 +2566,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2573,6 +2581,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2580,12 +2589,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -2604,6 +2615,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -2684,7 +2696,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -2696,6 +2709,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -2781,7 +2795,8 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -2817,6 +2832,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2836,6 +2852,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2879,12 +2896,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/package.json b/package.json index 45f457e3..74a77a51 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "run-lint-generated-tests": "eslint ./target/generated-tests/*/out*js" }, "devDependencies": { - "@types/node": "^10.5.5", + "@types/node": "^10.5.6", "babel-eslint": "^8.2.6", "eslint": "^5.2.0", "geckodriver": "^1.12.1", diff --git a/yarn.lock b/yarn.lock index 13baf34b..d240502d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -78,9 +78,9 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@types/node@^10.5.5": - version "10.5.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.5.tgz#8e84d24e896cd77b0d4f73df274027e3149ec2ba" +"@types/node@^10.5.6": + version "10.5.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.6.tgz#1640f021dd0eaf12e731e54198c12ad2e020dc8e" "@webassemblyjs/ast@1.5.13": version "1.5.13" @@ -245,9 +245,9 @@ acorn@^5.0.0, acorn@^5.0.3, acorn@^5.6.0, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" -adm-zip@0.4.7: - version "0.4.7" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" +adm-zip@0.4.11: + version "0.4.11" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.11.tgz#2aa54c84c4b01a9d0fb89bb11982a51f13e3d62a" ajv-keywords@^3.0.0, ajv-keywords@^3.1.0: version "3.2.0" @@ -1651,11 +1651,11 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -geckodriver@^1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.12.0.tgz#997a1efeca90543192fbcf1eae70d7cb2196330e" +geckodriver@^1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.12.1.tgz#f3b2ecd5224f383462f07841f4fdcf5007d1b42d" dependencies: - adm-zip "0.4.7" + adm-zip "0.4.11" bluebird "3.4.6" got "5.6.0" tar "4.0.2" From 281bbfa60c8173efebe700c892c04dd71b6d3a8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 Aug 2018 08:16:15 +0000 Subject: [PATCH 02/24] Bump webpack from 4.16.4 to 4.16.5 Bumps [webpack](https://github.com/webpack/webpack) from 4.16.4 to 4.16.5. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v4.16.4...v4.16.5) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- package.json | 2 +- yarn.lock | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e7fb0e5..38bfb62f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6398,9 +6398,9 @@ } }, "webpack": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.16.4.tgz", - "integrity": "sha512-RqUfwp4qMqv3oFwBQQOoK69C2tdu2FHJEqPABPqgjGDvOIOLqkTOhmmdJjpiRabzNAAH1ahmkA3z4xowlHN+VA==", + "version": "4.16.5", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.16.5.tgz", + "integrity": "sha512-i5cHYHonzSc1zBuwB5MSzW4v9cScZFbprkHK8ZgzPDCRkQXGGpYzPmJhbus5bOrZ0tXTcQp+xyImRSvKb0b+Kw==", "dev": true, "requires": { "@webassemblyjs/ast": "1.5.13", diff --git a/package.json b/package.json index 74a77a51..c236c2ee 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "selenium-webdriver": "^4.0.0-alpha.1", "ts-loader": "^4.4.2", "typescript": "^3.0.1", - "webpack": "^4.16.4", + "webpack": "^4.16.5", "webpack-cli": "^3.1.0", "webpack-dev-server": "^3.1.5" } diff --git a/yarn.lock b/yarn.lock index d240502d..fba285f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4185,9 +4185,9 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.16.4: - version "4.16.4" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.4.tgz#6b020f76483bc66339164c296d89978aa100d37a" +webpack@^4.16.5: + version "4.16.5" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.5.tgz#29fb39462823d7eb8aefcab8b45f7f241db0d092" dependencies: "@webassemblyjs/ast" "1.5.13" "@webassemblyjs/helper-module-context" "1.5.13" From 63ee9a024d8421f9c8166f1432cbc61981a23fa9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 6 Aug 2018 10:02:24 +0000 Subject: [PATCH 03/24] Bump eslint from 5.2.0 to 5.3.0 Bumps [eslint](https://github.com/eslint/eslint) from 5.2.0 to 5.3.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v5.2.0...v5.3.0) Signed-off-by: dependabot[bot] --- package-lock.json | 20 ++++++++++---------- package.json | 2 +- yarn.lock | 14 +++++++------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 38bfb62f..dff028e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1759,9 +1759,9 @@ "dev": true }, "eslint": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.2.0.tgz", - "integrity": "sha512-zlggW1qp7/TBjwLfouRoY7eWXrXwJZFqCdIxxh0/LVB/QuuKuIMkzyUZEcDo6LBadsry5JcEMxIqd3H/66CXVg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.3.0.tgz", + "integrity": "sha512-N/tCqlMKkyNvAvLu+zI9AqDasnSLt00K+Hu8kdsERliC9jYEc8ck12XtjvOXrBKu8fK6RrBcN9bat6Xk++9jAg==", "dev": true, "requires": { "ajv": "^6.5.0", @@ -1795,7 +1795,7 @@ "path-is-inside": "^1.0.2", "pluralize": "^7.0.0", "progress": "^2.0.0", - "regexpp": "^1.1.0", + "regexpp": "^2.0.0", "require-uncached": "^1.0.3", "semver": "^5.5.0", "string.prototype.matchall": "^2.0.0", @@ -3244,9 +3244,9 @@ "dev": true }, "ignore": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.2.tgz", - "integrity": "sha512-uoxnT7PYpyEnsja+yX+7v49B7LXxmzDJ2JALqHH3oEGzpM2U1IGcbfnOr8Dt57z3B/UWs7/iAgPFbmye8m4I0g==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.3.tgz", + "integrity": "sha512-Z/vAH2GGIEATQnBVXMclE2IGV6i0GyVngKThcGZ5kHgHMxLo9Ow2+XHRq1aEKEej5vOF1TPJNbvX6J/anT0M7A==", "dev": true }, "immediate": { @@ -5039,9 +5039,9 @@ } }, "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.0.tgz", + "integrity": "sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA==", "dev": true }, "remove-trailing-separator": { diff --git a/package.json b/package.json index c236c2ee..ef89d68b 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "devDependencies": { "@types/node": "^10.5.6", "babel-eslint": "^8.2.6", - "eslint": "^5.2.0", + "eslint": "^5.3.0", "geckodriver": "^1.12.1", "selenium-webdriver": "^4.0.0-alpha.1", "ts-loader": "^4.4.2", diff --git a/yarn.lock b/yarn.lock index fba285f7..1f62c5b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1267,9 +1267,9 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.2.0.tgz#3901ae249195d473e633c4acbc370068b1c964dc" +eslint@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.3.0.tgz#53695aca5213968aacdf970ccb231e42a2b285f8" dependencies: ajv "^6.5.0" babel-code-frame "^6.26.0" @@ -1302,7 +1302,7 @@ eslint@^5.2.0: path-is-inside "^1.0.2" pluralize "^7.0.0" progress "^2.0.0" - regexpp "^1.1.0" + regexpp "^2.0.0" require-uncached "^1.0.3" semver "^5.5.0" string.prototype.matchall "^2.0.0" @@ -3271,9 +3271,9 @@ regexp.prototype.flags@^1.2.0: dependencies: define-properties "^1.1.2" -regexpp@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" +regexpp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365" remove-trailing-separator@^1.0.1: version "1.1.0" From 21c36d39029dcbd7c6e7236e497e67657d0b9a41 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Sun, 5 Aug 2018 00:17:30 +0200 Subject: [PATCH 04/24] Allow js_name attribute to accept a string --- crates/backend/src/ast.rs | 4 +- crates/macro-support/src/parser.rs | 41 ++++++++------ crates/webidl/src/util.rs | 2 +- tests/all/imports.rs | 85 ++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 18 deletions(-) diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 265f4ac6..375af0a2 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -116,7 +116,7 @@ pub struct ImportStatic { pub ty: syn::Type, pub shim: Ident, pub rust_name: Ident, - pub js_name: Ident, + pub js_name: String, } #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] @@ -143,7 +143,7 @@ pub struct ImportEnum { #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] pub struct Function { - pub name: Ident, + pub name: String, pub arguments: Vec, pub ret: Option, pub rust_attrs: Vec, diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 2e935843..3752251d 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -149,11 +149,11 @@ impl BindgenAttrs { } /// Get the first js_name attribute - fn js_name(&self) -> Option<&Ident> { + fn js_name(&self) -> Option<&str> { self.attrs .iter() .filter_map(|a| match a { - BindgenAttr::JsName(s) => Some(s), + BindgenAttr::JsName(s) => Some(&s[..]), _ => None, }) .next() @@ -200,7 +200,7 @@ pub enum BindgenAttr { Setter(Option), Structural, Readonly, - JsName(Ident), + JsName(String), JsClass(String), } @@ -267,8 +267,12 @@ impl syn::synom::Synom for BindgenAttr { do_parse!( call!(term, "js_name") >> punct!(=) >> - ns: call!(term2ident) >> - (ns) + name: alt!( + syn!(syn::LitStr) => { |s| s.value() } + | + call!(term2ident) => { |s| s.to_string() } + ) >> + (name) )=> { BindgenAttr::JsName } | do_parse!( @@ -365,9 +369,10 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option)> for syn::ForeignItemFn fn convert(self, (opts, module): (BindgenAttrs, &'a Option)) -> Result { - let js_name = opts.js_name().unwrap_or(&self.ident).clone(); + let default_name = self.ident.to_string(); + let js_name = opts.js_name().unwrap_or(&default_name); let wasm = function_from_decl( - &js_name, + js_name, self.decl.clone(), self.attrs.clone(), self.vis.clone(), @@ -475,7 +480,9 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option)> for syn::ForeignItemFn ast::ImportFunctionKind::Method { ref class, .. } => (1, &class[..]), }; let data = (ns, &self.ident, module); - format!("__wbg_{}_{}", js_name, ShortHash(data)) + format!("__wbg_{}_{}", + js_name.chars().filter(|c| c.is_ascii_alphanumeric()).collect::(), + ShortHash(data)) }; Ok(ast::ImportKind::Function(ast::ImportFunction { function: wasm, @@ -510,13 +517,16 @@ impl ConvertToAst for syn::ForeignItemStatic { if self.mutability.is_some() { bail_span!(self.mutability, "cannot import mutable globals yet") } - let js_name = opts.js_name().unwrap_or(&self.ident); - let shim = format!("__wbg_static_accessor_{}_{}", js_name, self.ident); + let default_name = self.ident.to_string(); + let js_name = opts.js_name().unwrap_or(&default_name); + let shim = format!("__wbg_static_accessor_{}_{}", + js_name.chars().filter(|c| c.is_ascii_alphanumeric()).collect::(), + self.ident); Ok(ast::ImportKind::Static(ast::ImportStatic { ty: *self.ty, vis: self.vis, rust_name: self.ident.clone(), - js_name: js_name.clone(), + js_name: js_name.to_string(), shim: Ident::new(&shim, Span::call_site()), })) } @@ -537,14 +547,15 @@ impl ConvertToAst for syn::ItemFn { bail_span!(self.unsafety, "can only #[wasm_bindgen] safe functions"); } - let name = attrs.js_name().unwrap_or(&self.ident); + let default_name = self.ident.to_string(); + let name = attrs.js_name().unwrap_or(&default_name); Ok(function_from_decl(name, self.decl, self.attrs, self.vis, false, None)?.0) } } /// Construct a function (and gets the self type if appropriate) for our AST from a syn function. fn function_from_decl( - name: &Ident, + name: &str, decl: Box, attrs: Vec, vis: syn::Visibility, @@ -619,7 +630,7 @@ fn function_from_decl( Ok(( ast::Function { - name: name.clone(), + name: name.to_string(), arguments, ret, rust_vis: vis, @@ -782,7 +793,7 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) { }; let (function, method_self) = function_from_decl( - opts.js_name().unwrap_or(&method.sig.ident), + opts.js_name().unwrap_or(&method.sig.ident.to_string()), Box::new(method.sig.decl.clone()), method.attrs.clone(), method.vis.clone(), diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 507a32b9..26c1e5fc 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -563,7 +563,7 @@ impl<'a> FirstPassRecord<'a> { name.to_snake_case() } ); - let name = raw_ident(name); + let name = name.to_string(); let arguments = self.webidl_arguments_to_syn_arg_captured(arguments.into_iter(), &kind)?; diff --git a/tests/all/imports.rs b/tests/all/imports.rs index 0a7add00..4b6c6201 100644 --- a/tests/all/imports.rs +++ b/tests/all/imports.rs @@ -36,6 +36,91 @@ fn unused_imports_not_generated() { assert!(!contents.contains("foo"), "found `foo` in {}", contents); } +#[test] +fn rename_with_string() { + project() + .file( + "src/lib.rs", + r#" + #![feature(use_extern_macros)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen(module = "./test")] + extern { + #[wasm_bindgen(js_name = "baz$")] + fn foo(); + } + + #[wasm_bindgen] + pub fn run() { + foo(); + } + "#, + ) + .file( + "test.js", + r#" + import * as wasm from "./out"; + import * as assert from "assert"; + + let called = false; + + export function baz$() { + called = true; + } + + export function test() { + wasm.run(); + assert.strictEqual(called, true); + } + "#, + ) + .test(); +} + +#[test] +fn rename_static_with_string() { + project() + .debug(false) + .file( + "src/lib.rs", + r#" + #![feature(use_extern_macros)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen(module = "./test")] + extern { + #[wasm_bindgen(js_name = "$foo")] + static FOO: JsValue; + } + + #[wasm_bindgen] + pub fn run() { + assert_eq!(FOO.as_f64(), Some(1.0)); + } + "#, + ) + .file( + "test.js", + r#" + import { run } from "./out"; + + export const $foo = 1.0; + + export function test() { + run(); + } + "#, + ) + .test(); +} + #[test] fn versions() { project() From e35295d37635afa084878ab259a3b6f5be0ea1c2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 3 Aug 2018 14:39:33 -0700 Subject: [PATCH 05/24] Migrate from the `webidl` crate to `weedle` This commit migrates the `wasm-bindgen-webidl` crate from the `webidl` parser to `weedle`. The main rationale for doing this is that `webidl` depends on `lalrpop`, which is quite a large dependency and takes a good deal of time to compile. The `weedle` crate, however, depends on `nom` and is much faster to compile. Almost all translations were pretty straightforward. Some abstractions changed and/or were introduced in this commit when moving to `weedle` like the `ToSynType` trait, but otherwise the generated bindings should be the same. It's been verified that the `weedle`-generated bindings are exactly the same as the `webidl`-generated bindings, with the one exception of `weedle` generates one more method, `WebGpuCommandEncoder::transition_buffer`. It's not clear currently why `webidl` didn't generate this method, as its [idl] is pretty straightforward! This commit is using a [fork] of `weedle` currently which has a number of fixes for parsing our WebIDL, although all the fixes are quite minor! Closes #620 [idl]: https://github.com/rustwasm/wasm-bindgen/blob/d66b834afd9b45daefc4dcd35a74f3274fc0ab12/crates/web-sys/webidls/enabled/WebGPU.webidl#L499 [fork]: https://github.com/alexcrichton/weedle/tree/fix-for-web-sys --- crates/web-sys/build.rs | 34 +- crates/webidl/Cargo.toml | 2 +- crates/webidl/src/first_pass.rs | 375 ++++------ crates/webidl/src/lib.rs | 685 +++++++++--------- crates/webidl/src/util.rs | 1153 +++++++++++++++++++------------ 5 files changed, 1225 insertions(+), 1024 deletions(-) diff --git a/crates/web-sys/build.rs b/crates/web-sys/build.rs index 0496a979..8dbb232c 100644 --- a/crates/web-sys/build.rs +++ b/crates/web-sys/build.rs @@ -1,4 +1,5 @@ extern crate env_logger; +#[macro_use] extern crate failure; extern crate wasm_bindgen_webidl; extern crate sourcefile; @@ -8,9 +9,8 @@ use sourcefile::SourceFile; use std::env; use std::ffi::OsStr; use std::fs; -use std::io::Write; use std::path; -use std::process; +use std::process::{self, Command}; fn main() { if let Err(e) = try_main() { @@ -32,12 +32,14 @@ fn try_main() -> Result<(), failure::Error> { let mut source = SourceFile::default(); for entry in entries { let entry = entry.context("getting webidls/enabled/*.webidl entry")?; - if entry.path().extension() == Some(OsStr::new("webidl")) { - println!("cargo:rerun-if-changed={}", entry.path().display()); - source = source.add_file(entry.path()) - .with_context(|_| format!("reading contents of file \"{}\"", - entry.path().display()))?; + let path = entry.path(); + if path.extension() != Some(OsStr::new("webidl")) { + continue } + println!("cargo:rerun-if-changed={}", path.display()); + source = source.add_file(&path) + .with_context(|_| format!("reading contents of file \"{}\"", + path.display()))?; } let bindings = match wasm_bindgen_webidl::compile(&source.contents) { @@ -60,17 +62,19 @@ fn try_main() -> Result<(), failure::Error> { let out_dir = env::var("OUT_DIR").context("reading OUT_DIR environment variable")?; let out_file_path = path::Path::new(&out_dir).join("bindings.rs"); - let mut out_file = fs::File::create(&out_file_path) - .context("creating output bindings file")?; - out_file - .write_all(bindings.as_bytes()) + fs::write(&out_file_path, bindings) .context("writing bindings to output file")?; // run rustfmt on the generated file - really handy for debugging - //if ! process::Command::new("rustfmt").arg(&out_file_path).status() - // .context("running rustfmt")?.success() { - // return Err(format_err!("rustfmt failed to format {}", out_file_path.display())); - //} + if env::var("WEBIDL_RUSTFMT_BINDINGS").is_ok() { + let status = Command::new("rustfmt") + .arg(&out_file_path) + .status() + .context("running rustfmt")?; + if !status.success() { + bail!("rustfmt failed: {}", status) + } + } Ok(()) } diff --git a/crates/webidl/Cargo.toml b/crates/webidl/Cargo.toml index e953891e..471b4c73 100644 --- a/crates/webidl/Cargo.toml +++ b/crates/webidl/Cargo.toml @@ -20,4 +20,4 @@ proc-macro2 = "0.4.8" quote = '0.6' syn = { version = '0.14', features = ['full'] } wasm-bindgen-backend = { version = "=0.2.15", path = "../backend" } -webidl = "0.7.0" +weedle = "0.6" diff --git a/crates/webidl/src/first_pass.rs b/crates/webidl/src/first_pass.rs index 6242ed09..5b9a39be 100644 --- a/crates/webidl/src/first_pass.rs +++ b/crates/webidl/src/first_pass.rs @@ -7,66 +7,58 @@ //! Only `interface`s, `dictionary`s, `enum`s and `mixin`s can //! be partial. -use std::{ - collections::{BTreeMap, BTreeSet}, mem, -}; +use std::collections::{BTreeMap, BTreeSet}; -use webidl; +use weedle::argument::Argument; +use weedle::attribute::ExtendedAttribute; +use weedle::interface::StringifierOrStatic; +use weedle::mixin::MixinMembers; +use weedle; use super::Result; +use util; /// Collection of constructs that may use partial. #[derive(Default)] -pub(crate) struct FirstPassRecord<'a> { - pub(crate) interfaces: BTreeMap, - pub(crate) dictionaries: BTreeSet, - pub(crate) enums: BTreeSet, +pub(crate) struct FirstPassRecord<'src> { + pub(crate) interfaces: BTreeMap<&'src str, InterfaceData<'src>>, + pub(crate) dictionaries: BTreeSet<&'src str>, + pub(crate) enums: BTreeSet<&'src str>, /// The mixins, mapping their name to the webidl ast node for the mixin. - pub(crate) mixins: BTreeMap>, - pub(crate) typedefs: BTreeMap, + pub(crate) mixins: BTreeMap<&'src str, Vec<&'src MixinMembers<'src>>>, + pub(crate) typedefs: BTreeMap<&'src str, &'src weedle::types::Type<'src>>, } /// We need to collect interface data during the first pass, to be used later. #[derive(Default)] -pub(crate) struct InterfaceData { +pub(crate) struct InterfaceData<'src> { /// Whether only partial interfaces were encountered pub(crate) partial: bool, - pub(crate) operations: BTreeMap, pub(crate) global: bool, + pub(crate) operations: BTreeMap, OperationData<'src>>, } #[derive(PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum OperationId { +pub(crate) enum OperationId<'src> { Constructor, - Operation(Option) + Operation(Option<&'src str>) } #[derive(Default)] -pub(crate) struct OperationData { +pub(crate) struct OperationData<'src> { pub(crate) overloaded: bool, /// Map from argument names to whether they are the same for multiple overloads - pub(crate) argument_names_same: BTreeMap, bool>, -} - -/// We need to collect mixin data during the first pass, to be used later. -#[derive(Default)] -pub(crate) struct MixinData<'a> { - /// The non partial mixin, if present. If there is more than one, we are - /// parsing is a malformed WebIDL file, but the parser will recover by - /// using the last parsed mixin. - pub(crate) non_partial: Option<&'a webidl::ast::NonPartialMixin>, - /// 0 or more partial mixins. - pub(crate) partials: Vec<&'a webidl::ast::PartialMixin>, + pub(crate) argument_names_same: BTreeMap, bool>, } /// Implemented on an AST node to populate the `FirstPassRecord` struct. -pub(crate) trait FirstPass { +pub(crate) trait FirstPass<'src, Ctx> { /// Populate `record` with any constructs in `self`. - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, ctx: Ctx) -> Result<()>; + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, ctx: Ctx) -> Result<()>; } -impl FirstPass<()> for [webidl::ast::Definition] { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { +impl<'src> FirstPass<'src, ()> for [weedle::Definition<'src>] { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { for def in self { def.first_pass(record, ())?; } @@ -75,15 +67,17 @@ impl FirstPass<()> for [webidl::ast::Definition] { } } -impl FirstPass<()> for webidl::ast::Definition { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - use webidl::ast::Definition::*; +impl<'src> FirstPass<'src, ()> for weedle::Definition<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { + use weedle::Definition::*; match self { Dictionary(dictionary) => dictionary.first_pass(record, ()), Enum(enum_) => enum_.first_pass(record, ()), Interface(interface) => interface.first_pass(record, ()), - Mixin(mixin) => mixin.first_pass(record, ()), + PartialInterface(interface) => interface.first_pass(record, ()), + InterfaceMixin(mixin) => mixin.first_pass(record, ()), + PartialInterfaceMixin(mixin) => mixin.first_pass(record, ()), Typedef(typedef) => typedef.first_pass(record, ()), _ => { // Other definitions aren't currently used in the first pass @@ -93,46 +87,38 @@ impl FirstPass<()> for webidl::ast::Definition { } } -impl FirstPass<()> for webidl::ast::Dictionary { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - use webidl::ast::Dictionary::*; - - match self { - NonPartial(dictionary) => dictionary.first_pass(record, ()), - _ => { - // Other dictionaries aren't currently used in the first pass - Ok(()) - } +impl<'src> FirstPass<'src, ()> for weedle::DictionaryDefinition<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { + if !record.dictionaries.insert(self.identifier.0) { + warn!("encountered multiple dictionary declarations of {}", self.identifier.0); } + Ok(()) } } -impl FirstPass<()> for webidl::ast::NonPartialDictionary { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - if record.dictionaries.insert(self.name.clone()) { - warn!("Encountered multiple declarations of {}", self.name); +impl<'src> FirstPass<'src, ()> for weedle::EnumDefinition<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { + if !record.enums.insert(self.identifier.0) { + warn!("Encountered multiple enum declarations of {}", self.identifier.0); } Ok(()) } } -impl FirstPass<()> for webidl::ast::Enum { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - if record.enums.insert(self.name.clone()) { - warn!("Encountered multiple declarations of {}", self.name); - } - - Ok(()) - } -} - -fn first_pass_operation<'a>( - record: &mut FirstPassRecord<'a>, - self_name: &str, - id: OperationId, - arguments: &[webidl::ast::Argument], +fn first_pass_operation<'src>( + record: &mut FirstPassRecord<'src>, + self_name: &'src str, + id: OperationId<'src>, + arguments: &[Argument<'src>], ) -> Result<()> { + let mut names = Vec::with_capacity(arguments.len()); + for argument in arguments { + match argument { + Argument::Single(arg) => names.push(arg.identifier.0), + Argument::Variadic(_) => return Ok(()), + } + } record .interfaces .get_mut(self_name) @@ -140,77 +126,48 @@ fn first_pass_operation<'a>( .operations .entry(id) .and_modify(|operation_data| operation_data.overloaded = true) - .or_insert_with(|| - OperationData { - overloaded: false, - argument_names_same: Default::default(), - } - ) + .or_insert_with(Default::default) .argument_names_same - .entry(arguments.iter().map(|argument| argument.name.clone()).collect()) + .entry(names) .and_modify(|same_argument_names| *same_argument_names = true) .or_insert(false); Ok(()) } -impl FirstPass<()> for webidl::ast::Interface { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - use webidl::ast::Interface::*; - - match self { - Partial(interface) => interface.first_pass(record, ()), - NonPartial(interface) => interface.first_pass(record, ()), - // TODO - Callback(..) => { - warn!("Unsupported WebIDL interface: {:?}", self); - Ok(()) - } +impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { + { + let interface = record + .interfaces + .entry(self.identifier.0) + .or_insert_with(Default::default); + interface.partial = false; } - } -} -impl FirstPass<()> for webidl::ast::NonPartialInterface { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - record - .interfaces - .entry(self.name.clone()) - .and_modify(|interface_data| { - if interface_data.partial { - interface_data.partial = false; - } else { - warn!("Encountered multiple declarations of {}", self.name); - } - }) - .or_insert_with(|| - InterfaceData { - partial: false, - operations: Default::default(), - global: false, - }, - ); - - if ::util::is_chrome_only(&self.extended_attributes) { + if util::is_chrome_only(&self.attributes) { return Ok(()) } - for extended_attribute in &self.extended_attributes { - extended_attribute.first_pass(record, &self.name)?; + if let Some(attrs) = &self.attributes { + for attr in &attrs.body.list { + attr.first_pass(record, self.identifier.0)?; + } } - for member in &self.members { - member.first_pass(record, &self.name)?; + for member in &self.members.body { + member.first_pass(record, self.identifier.0)?; } Ok(()) } } -impl FirstPass<()> for webidl::ast::PartialInterface { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { +impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceDefinition<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { record .interfaces - .entry(self.name.clone()) + .entry(self.identifier.0) .or_insert_with(|| InterfaceData { partial: true, @@ -219,168 +176,120 @@ impl FirstPass<()> for webidl::ast::PartialInterface { }, ); - if ::util::is_chrome_only(&self.extended_attributes) { + if util::is_chrome_only(&self.attributes) { return Ok(()) } - for member in &self.members { - member.first_pass(record, &self.name)?; + for member in &self.members.body { + member.first_pass(record, self.identifier.0)?; } Ok(()) } } -impl<'b> FirstPass<&'b str> for webidl::ast::ExtendedAttribute { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { +impl<'src> FirstPass<'src, &'src str> for ExtendedAttribute<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> { match self { - webidl::ast::ExtendedAttribute::ArgumentList( - webidl::ast::ArgumentListExtendedAttribute { arguments, name }, - ) - if name == "Constructor" => - { - first_pass_operation( - record, - self_name, - OperationId::Constructor, - &arguments, - ) - } - webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) - if name == "Constructor" => - { - first_pass_operation( - record, - self_name, - OperationId::Constructor, - &[], - ) - } - webidl::ast::ExtendedAttribute::NamedArgumentList( - webidl::ast::NamedArgumentListExtendedAttribute { - lhs_name, - rhs_arguments, - .. - }, - ) - if lhs_name == "NamedConstructor" => - { - first_pass_operation( - record, - self_name, - OperationId::Constructor, - &rhs_arguments, - ) - }, - webidl::ast::ExtendedAttribute::Identifier( - webidl::ast::IdentifierExtendedAttribute { lhs, .. } - ) - | webidl::ast::ExtendedAttribute::IdentifierList( - webidl::ast::IdentifierListExtendedAttribute { lhs, .. } - ) - if lhs == "Global" => - { - record.interfaces.get_mut(self_name).unwrap().global = true; - Ok(()) - } + ExtendedAttribute::ArgList(list) if list.identifier.0 == "Constructor" => { + first_pass_operation( + record, + self_name, + OperationId::Constructor, + &list.args.body.list, + ) + } + ExtendedAttribute::NoArgs(name) if (name.0).0 == "Constructor" => { + first_pass_operation( + record, + self_name, + OperationId::Constructor, + &[], + ) + } + ExtendedAttribute::NamedArgList(list) + if list.lhs_identifier.0 == "NamedConstructor" => + { + first_pass_operation( + record, + self_name, + OperationId::Constructor, + &list.args.body.list, + ) + } + ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "Global" => { + record.interfaces.get_mut(self_name).unwrap().global = true; + Ok(()) + } + ExtendedAttribute::IdentList(id) if id.identifier.0 == "Global" => { + record.interfaces.get_mut(self_name).unwrap().global = true; + Ok(()) + } _ => Ok(()) } } } -impl<'b> FirstPass<&'b str> for webidl::ast::InterfaceMember { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { +impl<'src> FirstPass<'src, &'src str> for weedle::interface::InterfaceMember<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> { match self { - webidl::ast::InterfaceMember::Operation(op) => op.first_pass(record, self_name), + weedle::interface::InterfaceMember::Operation(op) => { + op.first_pass(record, self_name) + } _ => Ok(()), } } } -impl<'b> FirstPass<&'b str> for webidl::ast::Operation { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { - match self { - webidl::ast::Operation::Regular(op) => op.first_pass(record, self_name), - webidl::ast::Operation::Static(op) => op.first_pass(record, self_name), - // TODO - webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => { - warn!("Unsupported WebIDL operation: {:?}", self); - Ok(()) - } +impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceMember<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> { + if self.specials.len() > 0 { + warn!("Unsupported webidl operation {:?}", self); + return Ok(()) + } + if let Some(StringifierOrStatic::Stringifier(_)) = self.modifier { + warn!("Unsupported webidl operation {:?}", self); + return Ok(()) } - } -} - -impl<'b> FirstPass<&'b str> for webidl::ast::RegularOperation { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { first_pass_operation( record, self_name, - OperationId::Operation(self.name.clone()), - &self.arguments, + OperationId::Operation(self.identifier.map(|s| s.0)), + &self.args.body.list, ) } } -impl<'b> FirstPass<&'b str> for webidl::ast::StaticOperation { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { - first_pass_operation( - record, - self_name, - OperationId::Operation(self.name.clone()), - &self.arguments, - ) - } -} - -impl FirstPass<()> for webidl::ast::Mixin { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - use webidl::ast::Mixin::*; - - match self { - NonPartial(mixin) => mixin.first_pass(record, ()), - Partial(mixin) => mixin.first_pass(record, ()), - } - } -} - -impl FirstPass<()> for webidl::ast::NonPartialMixin { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - let entry = record +impl<'src> FirstPass<'src, ()> for weedle::InterfaceMixinDefinition<'src>{ + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { + record .mixins - .entry(self.name.clone()) - .or_insert_with(Default::default); - if mem::replace(&mut entry.non_partial, Some(self)).is_some() { - warn!( - "Encounterd multiple declarations of {}, using last encountered", - self.name - ); - } - + .entry(self.identifier.0) + .or_insert_with(Default::default) + .push(&self.members.body); Ok(()) } } -impl FirstPass<()> for webidl::ast::PartialMixin { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - let entry = record +impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceMixinDefinition<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { + record .mixins - .entry(self.name.clone()) - .or_insert_with(Default::default); - entry.partials.push(self); - + .entry(self.identifier.0) + .or_insert_with(Default::default) + .push(&self.members.body); Ok(()) } } -impl FirstPass<()> for webidl::ast::Typedef { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { - if ::util::is_chrome_only(&self.extended_attributes) { +impl<'src> FirstPass<'src, ()> for weedle::TypedefDefinition<'src> { + fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { + if util::is_chrome_only(&self.attributes) { return Ok(()); } - if record.typedefs.insert(self.name.clone(), *self.type_.clone()).is_some() { - warn!("Encountered multiple declarations of {}", self.name); + if record.typedefs.insert(self.identifier.0, &self.type_.type_).is_some() { + warn!("Encountered multiple declarations of {}", self.identifier.0); } Ok(()) diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index ec41686d..6c3fb030 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -9,6 +9,7 @@ emitted for the types and methods described in the WebIDL. #![deny(missing_debug_implementations)] #![doc(html_root_url = "https://docs.rs/wasm-bindgen-webidl/0.2")] +#[macro_use] extern crate failure; #[macro_use] extern crate failure_derive; @@ -21,7 +22,7 @@ extern crate quote; #[macro_use] extern crate syn; extern crate wasm_bindgen_backend as backend; -extern crate webidl; +extern crate weedle; mod first_pass; mod util; @@ -36,11 +37,14 @@ use std::path::Path; use backend::TryToTokens; use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports}; use backend::util::{ident_ty, rust_ident, wrap_import_function}; -use failure::{ResultExt, Fail}; +use failure::ResultExt; use heck::{ShoutySnakeCase}; +use weedle::argument::Argument; +use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList}; use first_pass::{FirstPass, FirstPassRecord}; -use util::{ApplyTypedefs, public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, camel_case_ident, mdn_doc}; +use util::{public, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, mdn_doc}; +use util::ToSynType; pub use error::{Error, ErrorKind, Result}; @@ -55,22 +59,31 @@ fn parse_file(webidl_path: &Path) -> Result { /// Parse a string of WebIDL source text into a wasm-bindgen AST. fn parse(webidl_source: &str) -> Result { - let definitions = match webidl::parse_string(webidl_source) { + let definitions = match weedle::parse(webidl_source) { Ok(def) => def, Err(e) => { - let kind = match &e { - webidl::ParseError::InvalidToken { location } => { - ErrorKind::ParsingWebIDLSourcePos(*location) + return Err(match &e { + weedle::Err::Incomplete(needed) => { + format_err!("needed {:?} more bytes", needed) + .context(ErrorKind::ParsingWebIDLSource).into() } - webidl::ParseError::UnrecognizedToken { token: Some((start, ..)), .. } => { - ErrorKind::ParsingWebIDLSourcePos(*start) + weedle::Err::Error(cx) | + weedle::Err::Failure(cx) => { + let remaining = match cx { + weedle::Context::Code(remaining, _) => remaining, + }; + let pos = webidl_source.len() - remaining.len(); + format_err!("failed to parse WebIDL") + .context(ErrorKind::ParsingWebIDLSourcePos(pos)).into() } - webidl::ParseError::ExtraToken { token: (start, ..) } => { - ErrorKind::ParsingWebIDLSourcePos(*start) - }, - _ => ErrorKind::ParsingWebIDLSource - }; - return Err(e.context(kind).into()); + // webidl::ParseError::UnrecognizedToken { token: Some((start, ..)), .. } => { + // ErrorKind::ParsingWebIDLSourcePos(*start) + // } + // webidl::ParseError::ExtraToken { token: (start, ..) } => { + // ErrorKind::ParsingWebIDLSourcePos(*start) + // }, + // _ => ErrorKind::ParsingWebIDLSource + }); } }; @@ -119,21 +132,21 @@ fn compile_ast(mut ast: backend::ast::Program) -> String { } /// The main trait for parsing WebIDL AST into wasm-bindgen AST. -trait WebidlParse { +trait WebidlParse<'src, Ctx> { /// Parse `self` into wasm-bindgen AST, and insert it into `program`. fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, + first_pass: &FirstPassRecord<'src>, context: Ctx, ) -> Result<()>; } -impl WebidlParse<()> for [webidl::ast::Definition] { +impl<'src> WebidlParse<'src, ()> for [weedle::Definition<'src>] { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, + first_pass: &FirstPassRecord<'src>, (): (), ) -> Result<()> { for def in self { @@ -143,104 +156,85 @@ impl WebidlParse<()> for [webidl::ast::Definition] { } } -impl WebidlParse<()> for webidl::ast::Definition { +impl<'src> WebidlParse<'src, ()> for weedle::Definition<'src> { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, + first_pass: &FirstPassRecord<'src>, (): (), ) -> Result<()> { match self { - webidl::ast::Definition::Enum(enumeration) => { + weedle::Definition::Enum(enumeration) => { enumeration.webidl_parse(program, first_pass, ())? } - webidl::ast::Definition::Includes(includes) => { + weedle::Definition::IncludesStatement(includes) => { includes.webidl_parse(program, first_pass, ())? } - webidl::ast::Definition::Interface(interface) => { + weedle::Definition::Interface(interface) => { interface.webidl_parse(program, first_pass, ())? } - // TODO - webidl::ast::Definition::Callback(..) - | webidl::ast::Definition::Dictionary(..) - | webidl::ast::Definition::Implements(..) - | webidl::ast::Definition::Namespace(..) => { - warn!("Unsupported WebIDL definition: {:?}", self) + weedle::Definition::PartialInterface(interface) => { + interface.webidl_parse(program, first_pass, ())? } - webidl::ast::Definition::Mixin(_) - | webidl::ast::Definition::Typedef(_) => { + weedle::Definition::Typedef(_) | + weedle::Definition::InterfaceMixin(_) | + weedle::Definition::PartialInterfaceMixin(_) => { // handled in the first pass } - } - Ok(()) - } -} - -impl WebidlParse<()> for webidl::ast::Includes { - fn webidl_parse( - &self, - program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - (): (), - ) -> Result<()> { - match first_pass.mixins.get(&self.includee) { - Some(mixin) => { - if let Some(non_partial) = mixin.non_partial { - for member in &non_partial.members { - member.webidl_parse(program, first_pass, &self.includer)?; - } - } - for partial in &mixin.partials { - for member in &partial.members { - member.webidl_parse(program, first_pass, &self.includer)?; - } - } - } - None => warn!("Tried to include missing mixin {}", self.includee), - } - Ok(()) - } -} - -impl WebidlParse<()> for webidl::ast::Interface { - fn webidl_parse( - &self, - program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - (): (), - ) -> Result<()> { - match self { - webidl::ast::Interface::NonPartial(interface) => { - interface.webidl_parse(program, first_pass, ()) - } - webidl::ast::Interface::Partial(interface) => { - interface.webidl_parse(program, first_pass, ()) - } // TODO - webidl::ast::Interface::Callback(..) => { - warn!("Unsupported WebIDL interface: {:?}", self); - Ok(()) + weedle::Definition::Callback(..) + | weedle::Definition::CallbackInterface(..) + | weedle::Definition::Dictionary(..) + | weedle::Definition::PartialDictionary(..) + | weedle::Definition::Implements(..) + | weedle::Definition::Namespace(..) + | weedle::Definition::PartialNamespace(..) => { + warn!("Unsupported WebIDL definition: {:?}", self) } } + Ok(()) } } -impl WebidlParse<()> for webidl::ast::NonPartialInterface { +impl<'src> WebidlParse<'src, ()> for weedle::IncludesStatementDefinition<'src> { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, + first_pass: &FirstPassRecord<'src>, (): (), ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { + match first_pass.mixins.get(self.rhs_identifier.0) { + Some(member_lists) => { + for member in member_lists.iter().flat_map(|list| list.iter()) { + member.webidl_parse(program, first_pass, self.lhs_identifier.0)?; + } + } + None => warn!("Tried to include missing mixin {}", self.rhs_identifier.0), + } + Ok(()) + } +} + +impl<'src> WebidlParse<'src, ()> for weedle::InterfaceDefinition<'src> { + fn webidl_parse( + &'src self, + program: &mut backend::ast::Program, + first_pass: &FirstPassRecord<'src>, + (): (), + ) -> Result<()> { + if util::is_chrome_only(&self.attributes) { return Ok(()); } - if util::is_no_interface_object(&self.extended_attributes) { + if util::is_no_interface_object(&self.attributes) { return Ok(()); } - let doc_comment = Some(format!("The `{}` object\n\n{}", &self.name, mdn_doc(&self.name, None))); + let doc_comment = Some(format!( + "The `{}` object\n\n{}", + self.identifier.0, + mdn_doc(self.identifier.0, None), + )); program.imports.push(backend::ast::Import { module: None, @@ -248,70 +242,67 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface { js_namespace: None, kind: backend::ast::ImportKind::Type(backend::ast::ImportType { vis: public(), - name: rust_ident(camel_case_ident(&self.name).as_str()), + name: rust_ident(camel_case_ident(self.identifier.0).as_str()), attrs: Vec::new(), doc_comment, }), }); - for extended_attribute in &self.extended_attributes { - extended_attribute.webidl_parse(program, first_pass, self)?; + if let Some(attrs) = &self.attributes { + for attr in &attrs.body.list { + attr.webidl_parse(program, first_pass, self)?; + } } - for member in &self.members { - member.webidl_parse(program, first_pass, &self.name)?; + for member in &self.members.body { + member.webidl_parse(program, first_pass, self.identifier.0)?; } Ok(()) } } -impl WebidlParse<()> for webidl::ast::PartialInterface { +impl<'src> WebidlParse<'src, ()> for weedle::PartialInterfaceDefinition<'src> { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, + first_pass: &FirstPassRecord<'src>, (): (), ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { + if util::is_chrome_only(&self.attributes) { return Ok(()); } - if !first_pass.interfaces.contains_key(&self.name) { + if !first_pass.interfaces.contains_key(self.identifier.0) { warn!( "Partial interface {} missing non-partial interface", - self.name + self.identifier.0 ); } - for member in &self.members { - member.webidl_parse(program, first_pass, &self.name)?; + for member in &self.members.body { + member.webidl_parse(program, first_pass, self.identifier.0)?; } Ok(()) } } -impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::ExtendedAttribute { +impl<'src> WebidlParse<'src, &'src weedle::InterfaceDefinition<'src>> for ExtendedAttribute<'src> { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - interface: &'a webidl::ast::NonPartialInterface, + first_pass: &FirstPassRecord<'src>, + interface: &'src weedle::InterfaceDefinition<'src>, ) -> Result<()> { - let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| { - let arguments = &arguments - .iter() - .map(|argument| argument.apply_typedefs(first_pass)) - .collect::>(); - + let mut add_constructor = |arguments: &[Argument], class: &str| { let (overloaded, same_argument_names) = first_pass.get_operation_overloading( arguments, ::first_pass::OperationId::Constructor, - &interface.name, + interface.identifier.0, ); - let self_ty = ident_ty(rust_ident(camel_case_ident(&interface.name).as_str())); + let self_ty = ident_ty(rust_ident(camel_case_ident(interface.identifier.0).as_str())); let kind = backend::ast::ImportFunctionKind::Method { class: class.to_string(), @@ -340,9 +331,7 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte "new", overloaded, same_argument_names, - arguments - .iter() - .map(|arg| (&*arg.name, &*arg.type_, arg.variadic)), + arguments, Some(self_ty), kind, structural, @@ -354,34 +343,24 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte }; match self { - webidl::ast::ExtendedAttribute::ArgumentList( - webidl::ast::ArgumentListExtendedAttribute { arguments, name }, - ) - if name == "Constructor" => + ExtendedAttribute::ArgList(list) + if list.identifier.0 == "Constructor" => { - add_constructor(arguments, &interface.name) + add_constructor(&list.args.body.list, interface.identifier.0) } - webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) - if name == "Constructor" => + ExtendedAttribute::NoArgs(other) if (other.0).0 == "Constructor" => { + add_constructor(&[], interface.identifier.0) + } + ExtendedAttribute::NamedArgList(list) + if list.lhs_identifier.0 == "NamedConstructor" => { - add_constructor(&[], &interface.name) + add_constructor(&list.args.body.list, list.rhs_identifier.0) } - webidl::ast::ExtendedAttribute::NamedArgumentList( - webidl::ast::NamedArgumentListExtendedAttribute { - lhs_name, - rhs_arguments, - rhs_name, - }, - ) - if lhs_name == "NamedConstructor" => - { - add_constructor(rhs_arguments, rhs_name) - } - webidl::ast::ExtendedAttribute::ArgumentList(_) - | webidl::ast::ExtendedAttribute::Identifier(_) - | webidl::ast::ExtendedAttribute::IdentifierList(_) - | webidl::ast::ExtendedAttribute::NamedArgumentList(_) - | webidl::ast::ExtendedAttribute::NoArguments(_) => { + ExtendedAttribute::ArgList(_) + | ExtendedAttribute::Ident(_) + | ExtendedAttribute::IdentList(_) + | ExtendedAttribute::NamedArgList(_) + | ExtendedAttribute::NoArgs(_) => { warn!("Unsupported WebIDL extended attribute: {:?}", self); } } @@ -390,29 +369,32 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte } } -impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember { +impl<'src> WebidlParse<'src, &'src str> for weedle::interface::InterfaceMember<'src> { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, + first_pass: &FirstPassRecord<'src>, + self_name: &'src str, ) -> Result<()> { + use weedle::interface::InterfaceMember::*; + match self { - webidl::ast::InterfaceMember::Attribute(attr) => { + Attribute(attr) => { attr.webidl_parse(program, first_pass, self_name) } - webidl::ast::InterfaceMember::Operation(op) => { + Operation(op) => { op.webidl_parse(program, first_pass, self_name) } - webidl::ast::InterfaceMember::Const(cnst) => { + Const(cnst) => { cnst.webidl_parse(program, first_pass, self_name) } - webidl::ast::InterfaceMember::Iterable(iterable) => { + Iterable(iterable) => { iterable.webidl_parse(program, first_pass, self_name) } // TODO - | webidl::ast::InterfaceMember::Maplike(_) - | webidl::ast::InterfaceMember::Setlike(_) => { + | Maplike(_) + | Stringifier(_) + | Setlike(_) => { warn!("Unsupported WebIDL interface member: {:?}", self); Ok(()) } @@ -420,128 +402,236 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember { } } -impl<'a> WebidlParse<&'a str> for webidl::ast::MixinMember { +impl<'a, 'src> WebidlParse<'src, &'a str> for weedle::mixin::MixinMember<'src> { fn webidl_parse( &self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, + first_pass: &FirstPassRecord<'src>, self_name: &'a str, ) -> Result<()> { match self { - webidl::ast::MixinMember::Attribute(attr) => { + weedle::mixin::MixinMember::Attribute(attr) => { attr.webidl_parse(program, first_pass, self_name) } - webidl::ast::MixinMember::Operation(op) => { + weedle::mixin::MixinMember::Operation(op) => { op.webidl_parse(program, first_pass, self_name) } // TODO - webidl::ast::MixinMember::Const(_) => { - warn!("Unsupported WebIDL interface member: {:?}", self); - Ok(()) - } - } - } -} -impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute { - fn webidl_parse( - &self, - program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, - ) -> Result<()> { - match self { - webidl::ast::Attribute::Regular(attr) => { - attr.webidl_parse(program, first_pass, self_name) - } - webidl::ast::Attribute::Static(attr) => { - attr.webidl_parse(program, first_pass, self_name) - } - // TODO - webidl::ast::Attribute::Stringifier(_) => { - warn!("Unsupported WebIDL attribute: {:?}", self); + weedle::mixin::MixinMember::Stringifier(_) | + weedle::mixin::MixinMember::Const(_) => { + warn!("Unsupported WebIDL mixin member: {:?}", self); Ok(()) } } } } -impl<'a> WebidlParse<&'a str> for webidl::ast::Operation { +impl<'src> WebidlParse<'src, &'src str> for weedle::interface::AttributeInterfaceMember<'src> { fn webidl_parse( &self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, + first_pass: &FirstPassRecord<'src>, + self_name: &'src str, ) -> Result<()> { - match self { - webidl::ast::Operation::Regular(op) => op.webidl_parse(program, first_pass, self_name), - webidl::ast::Operation::Static(op) => op.webidl_parse(program, first_pass, self_name), - // TODO - webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => { - warn!("Unsupported WebIDL operation: {:?}", self); - Ok(()) - } - } + member_attribute( + program, + first_pass, + self_name, + &self.attributes, + self.modifier, + self.readonly.is_some(), + &self.type_, + self.identifier.0, + ) } } -impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute { +impl<'src> WebidlParse<'src, &'src str> for weedle::mixin::AttributeMixinMember<'src> { fn webidl_parse( &self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, + first_pass: &FirstPassRecord<'src>, + self_name: &'src str, ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { - return Ok(()); + member_attribute( + program, + first_pass, + self_name, + &self.attributes, + if let Some(s) = self.stringifier { + Some(weedle::interface::StringifierOrInheritOrStatic::Stringifier(s)) + } else { + None + }, + self.readonly.is_some(), + &self.type_, + self.identifier.0, + ) + } +} + +fn member_attribute<'src>( + program: &mut backend::ast::Program, + first_pass: &FirstPassRecord<'src>, + self_name: &'src str, + attrs: &'src Option, + modifier: Option, + readonly: bool, + type_: &'src weedle::types::AttributedType<'src>, + identifier: &'src str, +) -> Result<()> { + use weedle::interface::StringifierOrInheritOrStatic::*; + + if util::is_chrome_only(attrs) { + return Ok(()); + } + + let statik = match modifier { + Some(Stringifier(_)) => { + warn!("Unsupported stringifier on type {:?}", (self_name, identifier)); + return Ok(()) } + Some(Inherit(_)) => false, + Some(Static(_)) => true, + None => false, + }; - let is_structural = util::is_structural(&self.extended_attributes); - let throws = util::throws(&self.extended_attributes); + if type_.attributes.is_some() { + warn!("Unsupported attributes on type {:?}", (self_name, identifier)); + return Ok(()) + } + let is_structural = util::is_structural(attrs); + let throws = util::throws(attrs); + + first_pass + .create_getter( + identifier, + &type_.type_, + self_name, + statik, + is_structural, + throws, + ) + .map(wrap_import_function) + .map(|import| program.imports.push(import)); + + if !readonly { first_pass - .create_getter( - &self.name, - &self.type_.apply_typedefs(first_pass), + .create_setter( + identifier, + type_.type_.clone(), self_name, - false, + statik, is_structural, throws, ) .map(wrap_import_function) .map(|import| program.imports.push(import)); + } - if !self.read_only { - first_pass - .create_setter( - &self.name, - &self.type_.apply_typedefs(first_pass), - self_name, - false, - is_structural, - throws, - ) - .map(wrap_import_function) - .map(|import| program.imports.push(import)); - } + Ok(()) +} - Ok(()) +impl<'src> WebidlParse<'src, &'src str> for weedle::interface::OperationInterfaceMember<'src> { + fn webidl_parse( + &self, + program: &mut backend::ast::Program, + first_pass: &FirstPassRecord<'src>, + self_name: &'src str, + ) -> Result<()> { + member_operation( + program, + first_pass, + self_name, + &self.attributes, + self.modifier, + &self.specials, + &self.return_type, + &self.args.body.list, + &self.identifier, + ) } } -impl<'a> WebidlParse<&'a str> for webidl::ast::Iterable { +impl<'src> WebidlParse<'src, &'src str> for weedle::mixin::OperationMixinMember<'src> { + fn webidl_parse( + &self, + program: &mut backend::ast::Program, + first_pass: &FirstPassRecord<'src>, + self_name: &'src str, + ) -> Result<()> { + member_operation( + program, + first_pass, + self_name, + &self.attributes, + None, + &[], + &self.return_type, + &self.args.body.list, + &self.identifier, + ) + } +} + +fn member_operation<'src>( + program: &mut backend::ast::Program, + first_pass: &FirstPassRecord<'src>, + self_name: &'src str, + attrs: &'src Option, + modifier: Option, + specials: &[weedle::interface::Special], + return_type: &'src weedle::types::ReturnType<'src>, + args: &'src [Argument], + identifier: &Option>, +) -> Result<()> { + use weedle::interface::StringifierOrStatic::*; + + if util::is_chrome_only(attrs) { + return Ok(()); + } + let statik = match modifier { + Some(Stringifier(_)) => { + warn!("Unsupported stringifier on type {:?}", (self_name, identifier)); + return Ok(()) + } + Some(Static(_)) => true, + None => false, + }; + if specials.len() > 0 { + warn!("Unsupported specials on type {:?}", (self_name, identifier)); + return Ok(()) + } + + first_pass + .create_basic_method( + args, + identifier.map(|s| s.0), + return_type, + self_name, + statik, + util::throws(attrs), + ) + .map(wrap_import_function) + .map(|import| program.imports.push(import)); + Ok(()) +} + +impl<'src> WebidlParse<'src, &'src str> for weedle::interface::IterableInterfaceMember<'src> { fn webidl_parse( &self, _program: &mut backend::ast::Program, - _first_pass: &FirstPassRecord<'_>, - _self_name: &'a str, + _first_pass: &FirstPassRecord<'src>, + _self_name: &'src str, ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { - return Ok(()); - } + // if util::is_chrome_only(&self.attributes) { + // return Ok(()); + // } /* TODO let throws = util::throws(&self.extended_attributes); - let return_value = webidl::ast::ReturnType::NonVoid(self.value_type.clone()); + let return_value = weedle::ReturnType::NonVoid(self.value_type.clone()); let args = []; first_pass .create_basic_method( @@ -572,142 +662,32 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Iterable { } } -impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute { +impl<'src> WebidlParse<'src, ()> for weedle::EnumDefinition<'src> { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, - ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { - return Ok(()); - } - - let is_structural = util::is_structural(&self.extended_attributes); - let throws = util::throws(&self.extended_attributes); - - first_pass - .create_getter( - &self.name, - &self.type_.apply_typedefs(first_pass), - self_name, - true, - is_structural, - throws, - ) - .map(wrap_import_function) - .map(|import| program.imports.push(import)); - - if !self.read_only { - first_pass - .create_setter( - &self.name, - &self.type_.apply_typedefs(first_pass), - self_name, - true, - is_structural, - throws, - ) - .map(wrap_import_function) - .map(|import| program.imports.push(import)); - } - - Ok(()) - } -} - -impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation { - fn webidl_parse( - &self, - program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, - ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { - return Ok(()); - } - - let throws = util::throws(&self.extended_attributes); - - first_pass - .create_basic_method( - &self - .arguments - .iter() - .map(|argument| argument.apply_typedefs(first_pass)) - .collect::>(), - self.name.as_ref(), - &self.return_type.apply_typedefs(first_pass), - self_name, - false, - throws, - ) - .map(wrap_import_function) - .map(|import| program.imports.push(import)); - - Ok(()) - } -} - -impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation { - fn webidl_parse( - &self, - program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, - ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { - return Ok(()); - } - - let throws = util::throws(&self.extended_attributes); - - first_pass - .create_basic_method( - &self - .arguments - .iter() - .map(|argument| argument.apply_typedefs(first_pass)) - .collect::>(), - self.name.as_ref(), - &self.return_type.apply_typedefs(first_pass), - self_name, - true, - throws, - ) - .map(wrap_import_function) - .map(|import| program.imports.push(import)); - - Ok(()) - } -} - -impl<'a> WebidlParse<()> for webidl::ast::Enum { - fn webidl_parse( - &self, - program: &mut backend::ast::Program, - _: &FirstPassRecord<'_>, + _: &FirstPassRecord<'src>, (): (), ) -> Result<()> { + let variants = &self.values.body.list; program.imports.push(backend::ast::Import { module: None, version: None, js_namespace: None, kind: backend::ast::ImportKind::Enum(backend::ast::ImportEnum { vis: public(), - name: rust_ident(camel_case_ident(&self.name).as_str()), - variants: self - .variants + name: rust_ident(camel_case_ident(self.identifier.0).as_str()), + variants: variants .iter() - .map(|v| - if !v.is_empty() { - rust_ident(camel_case_ident(&v).as_str()) + .map(|v| { + if !v.0.is_empty() { + rust_ident(camel_case_ident(&v.0).as_str()) } else { rust_ident("None") } - ) + }) .collect(), - variant_values: self.variants.clone(), + variant_values: variants.iter().map(|v| v.0.to_string()).collect(), rust_attrs: vec![parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])], }), }); @@ -716,21 +696,24 @@ impl<'a> WebidlParse<()> for webidl::ast::Enum { } } -impl<'a> WebidlParse<&'a str> for webidl::ast::Const { +impl<'src> WebidlParse<'src, &'src str> for weedle::interface::ConstMember<'src> { fn webidl_parse( - &self, + &'src self, program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - self_name: &'a str, + record: &FirstPassRecord<'src>, + self_name: &'src str, ) -> Result<()> { - let ty = webidl_const_ty_to_syn_ty(&self.type_.apply_typedefs(first_pass)); + let ty = match self.const_type.to_syn_type(record, TypePosition::Return) { + Some(s) => s, + None => return Ok(()), + }; program.consts.push(backend::ast::Const { vis: public(), - name: rust_ident(self.name.to_shouty_snake_case().as_str()), + name: rust_ident(self.identifier.0.to_shouty_snake_case().as_str()), class: Some(rust_ident(camel_case_ident(&self_name).as_str())), ty, - value: webidl_const_v_to_backend_const_v(&self.value), + value: webidl_const_v_to_backend_const_v(&self.const_value), }); Ok(()) diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 26c1e5fc..50c05901 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -1,12 +1,16 @@ -use std::iter::{self, FromIterator}; +use std::iter::FromIterator; use backend; use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident}; use heck::{CamelCase, SnakeCase}; use proc_macro2::Ident; use syn; -use webidl; -use webidl::ast::ExtendedAttribute; +use weedle; +use weedle::attribute::{ExtendedAttributeList, ExtendedAttribute}; +use weedle::argument::{Argument, SingleArgument}; +use weedle::common::Identifier; +use weedle::types::*; +use weedle::literal::{ConstValue, FloatLit, IntegerLit}; use first_pass::FirstPassRecord; @@ -34,35 +38,392 @@ pub fn mdn_doc(class: &str, method: Option<&str>) -> String { format!("[Documentation]({})", link).into() } -/// For a webidl const type node, get the corresponding syn type node. -pub fn webidl_const_ty_to_syn_ty(ty: &webidl::ast::ConstType) -> syn::Type { - use webidl::ast::ConstType::*; +pub(crate) trait ToSynType<'src> { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option; +} - // similar to webidl_ty_to_syn_ty - match ty { - Boolean => ident_ty(raw_ident("bool")), - Byte => ident_ty(raw_ident("i8")), - Octet => ident_ty(raw_ident("u8")), - RestrictedDouble | UnrestrictedDouble => ident_ty(raw_ident("f64")), - RestrictedFloat | UnrestrictedFloat => ident_ty(raw_ident("f32")), - SignedLong => ident_ty(raw_ident("i32")), - SignedLongLong => ident_ty(raw_ident("i64")), - SignedShort => ident_ty(raw_ident("i16")), - UnsignedLong => ident_ty(raw_ident("u32")), - UnsignedLongLong => ident_ty(raw_ident("u64")), - UnsignedShort => ident_ty(raw_ident("u16")), - Identifier(ref id) => ident_ty(rust_ident(id)), +impl<'src, T: ToSynType<'src>> ToSynType<'src> for MayBeNull { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + let ty = self.type_.to_syn_type(record, pos)?; + if self.q_mark.is_some() { + Some(option_ty(ty)) + } else { + Some(ty) + } } } +impl<'src> ToSynType<'src> for ConstType<'src> { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + match self { + ConstType::Integer(l) => l.to_syn_type(record, pos), + ConstType::FloatingPoint(l) => l.to_syn_type(record, pos), + ConstType::Boolean(l) => l.to_syn_type(record, pos), + ConstType::Byte(l) => l.to_syn_type(record, pos), + ConstType::Octet(l) => l.to_syn_type(record, pos), + ConstType::Identifier(l) => l.to_syn_type(record, pos), + } + } +} + +impl<'src> ToSynType<'src> for IntegerType { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + match self { + IntegerType::LongLong(l) => l.to_syn_type(record, pos), + IntegerType::Long(l) => l.to_syn_type(record, pos), + IntegerType::Short(l) => l.to_syn_type(record, pos), + } + } +} + +impl<'src> ToSynType<'src> for ShortType { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + if self.unsigned.is_some() { + Some(ident_ty(raw_ident("u16"))) + } else { + Some(ident_ty(raw_ident("i16"))) + } + } +} + +impl<'src> ToSynType<'src> for LongType { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + if self.unsigned.is_some() { + Some(ident_ty(raw_ident("u32"))) + } else { + Some(ident_ty(raw_ident("i32"))) + } + } +} + +impl<'src> ToSynType<'src> for LongLongType { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + if self.unsigned.is_some() { + Some(ident_ty(raw_ident("u64"))) + } else { + Some(ident_ty(raw_ident("i64"))) + } + } +} + +impl<'src> ToSynType<'src> for FloatingPointType { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + match self { + FloatingPointType::Float(_) => Some(ident_ty(raw_ident("f32"))), + FloatingPointType::Double(_) => Some(ident_ty(raw_ident("f64"))), + } + } +} + +impl<'src> ToSynType<'src> for weedle::term::Boolean { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + Some(ident_ty(raw_ident("bool"))) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Byte { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + Some(ident_ty(raw_ident("i8"))) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Octet { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + Some(ident_ty(raw_ident("u8"))) + } +} + +impl<'src> ToSynType<'src> for weedle::common::Identifier<'src> { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + if let Some(other) = record.typedefs.get(&self.0) { + return other.to_syn_type(record, pos) + } + // A reference to a type by name becomes the same thing in the + // bindings. + let ty = ident_ty(rust_ident(camel_case_ident(self.0).as_str())); + Some(if record.interfaces.contains_key(self.0) { + if pos == TypePosition::Argument { + shared_ref(ty) + } else { + ty + } + } else if record.dictionaries.contains(self.0) { + ty + } else if record.enums.contains(self.0) { + ty + } else { + warn!("unrecognized type {}", self.0); + ty + }) + } +} + +impl<'src> ToSynType<'src> for weedle::term::DOMString { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + // strings -> `&str` for arguments and `String` for return + Some(match pos { + TypePosition::Argument => shared_ref(ident_ty(raw_ident("str"))), + TypePosition::Return => ident_ty(raw_ident("String")), + }) + } +} + +impl<'src> ToSynType<'src> for weedle::term::ByteString { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + // ByteString maps to String in JS - + // https://developer.mozilla.org/en-US/docs/Web/API/ByteString + weedle::term::DOMString.to_syn_type(record, pos) + } +} + +impl<'src> ToSynType<'src> for weedle::term::USVString { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + // USVString maps to String in JS - + // https://developer.mozilla.org/en-US/docs/Web/API/USVString + weedle::term::DOMString.to_syn_type(record, pos) + } +} + +// Array type is borrowed for arguments (`&[T]`) and owned for return value (`Vec`). +fn array(base_ty: &str, pos: TypePosition) -> syn::Type { + match pos { + TypePosition::Argument => { + shared_ref(slice_ty(ident_ty(raw_ident(base_ty)))) + } + TypePosition::Return => { + vec_ty(ident_ty(raw_ident(base_ty))) + } + } +} + +impl<'src> ToSynType<'src> for weedle::term::Float32Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("f32", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Float64Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("f64", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Int8Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("i8", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Int16Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("i16", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Int32Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("i32", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Uint8Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("u8", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Uint8ClampedArray { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("u8", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Uint16Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("u16", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Uint32Array { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + Some(array("u32", pos)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::ArrayBuffer { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + let path = vec![rust_ident("js_sys"), rust_ident("ArrayBuffer")]; + Some(leading_colon_path_ty(path)) + } +} + +impl<'src> ToSynType<'src> for weedle::term::Object { + fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition) + -> Option + { + let path = vec![rust_ident("js_sys"), rust_ident("Object")]; + Some(leading_colon_path_ty(path)) + } +} + +impl<'src> ToSynType<'src> for weedle::types::Type<'src> { + fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) + -> Option + { + use weedle::types::NonAnyType::*; + let single = match self { + Type::Single(s) => s, + Type::Union(_) => return None, + }; + + let ty = match single { + // `any` becomes `::wasm_bindgen::JsValue`. + SingleType::Any(_) => { + let path = vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]; + return Some(leading_colon_path_ty(path)) + } + SingleType::NonAny(other) => other, + }; + + match ty { + Boolean(s) => s.to_syn_type(record, pos), + Octet(s) => s.to_syn_type(record, pos), + Byte(s) => s.to_syn_type(record, pos), + Identifier(s) => s.to_syn_type(record, pos), + Integer(s) => s.to_syn_type(record, pos), + FloatingPoint(s) => s.to_syn_type(record, pos), + + Float32Array(s) => s.to_syn_type(record, pos), + Float64Array(s) => s.to_syn_type(record, pos), + Int8Array(s) => s.to_syn_type(record, pos), + Int16Array(s) => s.to_syn_type(record, pos), + Int32Array(s) => s.to_syn_type(record, pos), + Uint8Array(s) => s.to_syn_type(record, pos), + Uint8ClampedArray(s) => s.to_syn_type(record, pos), + Uint16Array(s) => s.to_syn_type(record, pos), + Uint32Array(s) => s.to_syn_type(record, pos), + + DOMString(s) => s.to_syn_type(record, pos), + ByteString(s) => s.to_syn_type(record, pos), + USVString(s) => s.to_syn_type(record, pos), + ArrayBuffer(b) => b.to_syn_type(record, pos), + Object(o) => o.to_syn_type(record, pos), + + // Support for these types is not yet implemented, so skip + // generating any bindings for this function. + | DataView(_) + | Error(_) + | FrozenArrayType(_) + | Promise(_) + | RecordType(..) + | Sequence(_) + | Symbol(_) => { + None + } + } + } +} + + /// Map a webidl const value to the correct wasm-bindgen const value -pub fn webidl_const_v_to_backend_const_v(v: &webidl::ast::ConstValue) -> backend::ast::ConstValue { +pub fn webidl_const_v_to_backend_const_v(v: &ConstValue) -> backend::ast::ConstValue { + use std::f64::{NEG_INFINITY, INFINITY, NAN}; + use backend::ast; + match *v { - webidl::ast::ConstValue::BooleanLiteral(b) => backend::ast::ConstValue::BooleanLiteral(b), - webidl::ast::ConstValue::FloatLiteral(f) => backend::ast::ConstValue::FloatLiteral(f), - webidl::ast::ConstValue::SignedIntegerLiteral(i) => backend::ast::ConstValue::SignedIntegerLiteral(i), - webidl::ast::ConstValue::UnsignedIntegerLiteral(u) => backend::ast::ConstValue::UnsignedIntegerLiteral(u), - webidl::ast::ConstValue::Null => backend::ast::ConstValue::Null, + ConstValue::Boolean(b) => ast::ConstValue::BooleanLiteral(b.0), + ConstValue::Float(FloatLit::NegInfinity(_)) => { + ast::ConstValue::FloatLiteral(NEG_INFINITY) + } + ConstValue::Float(FloatLit::Infinity(_)) => { + ast::ConstValue::FloatLiteral(INFINITY) + } + ConstValue::Float(FloatLit::NaN(_)) => { + ast::ConstValue::FloatLiteral(NAN) + } + ConstValue::Float(FloatLit::Value(s)) => { + ast::ConstValue::FloatLiteral(s.0.parse().unwrap()) + } + ConstValue::Integer(lit) => { + let mklit = |orig_text: &str, base: u32, offset: usize| { + let (negative, text) = if orig_text.starts_with("-") { + (true, &orig_text[1..]) + } else { + (false, orig_text) + }; + if text == "0" { + return ast::ConstValue::SignedIntegerLiteral(0) + } + let text = &text[offset..]; + let n = u64::from_str_radix(text, base) + .unwrap_or_else(|_| panic!("literal too big: {}", orig_text)); + if negative { + let n = if n > (i64::min_value() as u64).wrapping_neg() { + panic!("literal too big: {}", orig_text) + } else { + n.wrapping_neg() as i64 + }; + ast::ConstValue::SignedIntegerLiteral(n) + } else { + ast::ConstValue::UnsignedIntegerLiteral(n) + } + }; + match lit { + IntegerLit::Hex(h) => mklit(h.0, 16, 2), // leading 0x + IntegerLit::Oct(h) => mklit(h.0, 8, 1), // leading 0 + IntegerLit::Dec(h) => mklit(h.0, 10, 0), + } + } + ConstValue::Null(_) => ast::ConstValue::Null, } } @@ -135,6 +496,22 @@ fn vec_ty(t: syn::Type) -> syn::Type { ty.into() } +/// From `T` create `Option` +fn option_ty(t: syn::Type) -> syn::Type { + let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + colon2_token: None, + lt_token: Default::default(), + args: FromIterator::from_iter(vec![syn::GenericArgument::Type(t)]), + gt_token: Default::default(), + }); + + let ident = raw_ident("Option"); + let seg = syn::PathSegment { ident, arguments }; + let path: syn::Path = seg.into(); + let ty = syn::TypePath { qself: None, path }; + ty.into() +} + /// Possible positions for a type in a function signature. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum TypePosition { @@ -142,350 +519,280 @@ pub enum TypePosition { Return, } -fn type_kind_to_const_type(type_kind: &webidl::ast::TypeKind) -> webidl::ast::ConstType { - match type_kind { - webidl::ast::TypeKind::Boolean => webidl::ast::ConstType::Boolean, - webidl::ast::TypeKind::Byte => webidl::ast::ConstType::Byte, - webidl::ast::TypeKind::Identifier(identifier) => webidl::ast::ConstType::Identifier(identifier.clone()), - webidl::ast::TypeKind::Octet => webidl::ast::ConstType::Octet, - webidl::ast::TypeKind::RestrictedDouble => webidl::ast::ConstType::RestrictedDouble, - webidl::ast::TypeKind::RestrictedFloat => webidl::ast::ConstType::RestrictedFloat, - webidl::ast::TypeKind::SignedLong => webidl::ast::ConstType::SignedLong, - webidl::ast::TypeKind::SignedLongLong => webidl::ast::ConstType::SignedLongLong, - webidl::ast::TypeKind::SignedShort => webidl::ast::ConstType::SignedShort, - webidl::ast::TypeKind::UnrestrictedDouble => webidl::ast::ConstType::UnrestrictedDouble, - webidl::ast::TypeKind::UnrestrictedFloat => webidl::ast::ConstType::UnrestrictedFloat, - webidl::ast::TypeKind::UnsignedLong => webidl::ast::ConstType::UnsignedLong, - webidl::ast::TypeKind::UnsignedLongLong => webidl::ast::ConstType::UnsignedLongLong, - webidl::ast::TypeKind::UnsignedShort => webidl::ast::ConstType::UnsignedShort, - _ => panic!("can not convert TypeKind to ConstType: {:#?}", type_kind), - } -} - -/// Implemented on an AST type node to apply typedefs. -pub(crate) trait ApplyTypedefs { - fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self; -} - -impl ApplyTypedefs for webidl::ast::Type { - fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { - webidl::ast::Type { - extended_attributes: self.extended_attributes.clone(), - kind: self.kind.apply_typedefs(record), - nullable: self.nullable, - } - } -} - -impl ApplyTypedefs for webidl::ast::ReturnType { - fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { - match self { - webidl::ast::ReturnType::NonVoid(ty) => - webidl::ast::ReturnType::NonVoid(Box::new(ty.apply_typedefs(record))), - _ => self.clone(), - } - } -} - -impl ApplyTypedefs for webidl::ast::StringType { - fn apply_typedefs<'a>(&self, _: &FirstPassRecord<'a>) -> Self { - *self - } -} - -impl ApplyTypedefs for webidl::ast::ConstType { - fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { - match self { - webidl::ast::ConstType::Identifier(identifier) => - record - .typedefs - .get(identifier) - .map(|ty| type_kind_to_const_type(&ty.kind)) - .unwrap_or(self.clone()), - _ => self.clone(), - } - } -} - -impl ApplyTypedefs for webidl::ast::TypeKind { - fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { - match self { - webidl::ast::TypeKind::FrozenArray(ty) => - webidl::ast::TypeKind::FrozenArray(Box::new(ty.apply_typedefs(record))), - webidl::ast::TypeKind::Identifier(identifier) => record - .typedefs - .get(identifier) - .map(|ty| ty.kind.clone()) - .unwrap_or(self.clone()), - webidl::ast::TypeKind::Promise(ty) => - webidl::ast::TypeKind::Promise(ty.apply_typedefs(record)), - webidl::ast::TypeKind::Record(string_type, ty) => webidl::ast::TypeKind::Record( - string_type.apply_typedefs(record), - Box::new(ty.apply_typedefs(record)), - ), - webidl::ast::TypeKind::Union(types) => webidl::ast::TypeKind::Union( - types - .iter() - .map(|ty| Box::new(ty.apply_typedefs(record))) - .collect(), - ), - _ => self.clone(), - } - } -} - -impl ApplyTypedefs for webidl::ast::Argument { - fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { - webidl::ast::Argument { - extended_attributes: self.extended_attributes.clone(), - default: self.default.clone(), - name: self.name.clone(), - optional: self.optional, - type_: Box::new(self.type_.apply_typedefs(record)), - variadic: self.variadic, - } - } -} - /// Implemented on an AST type node to generate a snake case name. trait TypeToString { - fn type_to_string(&self) -> String; + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String); } -impl TypeToString for webidl::ast::Type { - fn type_to_string(&self) -> String { - if self.nullable { - "opt_".to_owned() + &self.kind.type_to_string() - } else { - self.kind.type_to_string() +impl TypeToString for MayBeNull { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { + if self.q_mark.is_some() { + dst.push_str("opt_"); } + self.type_.type_to_string(record, dst); } } -impl TypeToString for webidl::ast::ReturnType { - fn type_to_string(&self) -> String { +impl<'src> TypeToString for weedle::types::ReturnType<'src> { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { match self { - webidl::ast::ReturnType::NonVoid(ty) => (*ty).type_to_string(), - webidl::ast::ReturnType::Void => "void".to_owned(), + weedle::types::ReturnType::Type(ty) => (*ty).type_to_string(record, dst), + weedle::types::ReturnType::Void(_) => dst.push_str("void"), } } } -impl TypeToString for webidl::ast::StringType { - fn type_to_string(&self) -> String { +impl TypeToString for weedle::types::StringType { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { match self { - webidl::ast::StringType::ByteString => "byte_str".to_owned(), - webidl::ast::StringType::DOMString => "dom_str".to_owned(), - webidl::ast::StringType::USVString => "usv_str".to_owned(), + weedle::types::StringType::Byte(_) => dst.push_str("byte_str"), + weedle::types::StringType::DOM(_) => dst.push_str("dom_str"), + weedle::types::StringType::USV(_) => dst.push_str("usv_str"), } } } -impl TypeToString for webidl::ast::TypeKind { - fn type_to_string(&self) -> String { +impl TypeToString for weedle::term::Byte { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("i8"); + } +} + +impl TypeToString for weedle::term::Octet { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("u8"); + } +} + +impl TypeToString for weedle::term::Boolean { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("bool"); + } +} + +impl TypeToString for weedle::term::USVString { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("usv_str"); + } +} + +impl TypeToString for weedle::term::ByteString { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("byte_str"); + } +} + +impl TypeToString for weedle::term::DOMString { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("dom_str"); + } +} + +impl TypeToString for weedle::term::Float32Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("f32_array"); + } +} + +impl TypeToString for weedle::term::Float64Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("f64_array"); + } +} + +impl TypeToString for weedle::term::Int8Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("i8_array"); + } +} + +impl TypeToString for weedle::term::Int16Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("i16_array"); + } +} + +impl TypeToString for weedle::term::Int32Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("i32_array"); + } +} + +impl TypeToString for weedle::term::Uint8Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("u8_array"); + } +} + +impl TypeToString for weedle::term::Uint8ClampedArray { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("u8_clamped_array"); + } +} + +impl TypeToString for weedle::term::Uint16Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("u16_array"); + } +} + +impl TypeToString for weedle::term::Uint32Array { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("u32_array"); + } +} + +impl<'src> TypeToString for weedle::common::Identifier<'src> { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { + match record.typedefs.get(self.0) { + Some(other) => other.type_to_string(record, dst), + None => dst.push_str(&self.0.to_snake_case()), + } + } +} + +impl TypeToString for IntegerType { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { match self { - webidl::ast::TypeKind::Any => "any".to_owned(), - webidl::ast::TypeKind::ArrayBuffer => "array_buffer".to_owned(), - webidl::ast::TypeKind::Boolean => "bool".to_owned(), - webidl::ast::TypeKind::Byte => "i8".to_owned(), - webidl::ast::TypeKind::ByteString => "byte_str".to_owned(), - webidl::ast::TypeKind::DOMString => "dom_str".to_owned(), - webidl::ast::TypeKind::DataView => "data_view".to_owned(), - webidl::ast::TypeKind::Error => "error".to_owned(), - webidl::ast::TypeKind::Float32Array => "f32_array".to_owned(), - webidl::ast::TypeKind::Float64Array => "f64_array".to_owned(), - webidl::ast::TypeKind::FrozenArray(ty) => "frozen_array_of_".to_owned() + &ty.type_to_string(), - webidl::ast::TypeKind::Identifier(identifier) => identifier.to_snake_case(), - webidl::ast::TypeKind::Int16Array => "i16_array".to_owned(), - webidl::ast::TypeKind::Int32Array => "i32_array".to_owned(), - webidl::ast::TypeKind::Int8Array => "i8_array".to_owned(), - webidl::ast::TypeKind::Octet => "u8".to_owned(), - webidl::ast::TypeKind::Object => "object".to_owned(), - webidl::ast::TypeKind::Promise(ty) => "promise_of_".to_owned() + &(*ty).type_to_string(), - webidl::ast::TypeKind::Record(string_type, ty) => format!( - "record_from_{}_to_{}", - string_type.type_to_string(), - (*ty).type_to_string() - ), - webidl::ast::TypeKind::RestrictedDouble => "restricted_f64".to_owned(), - webidl::ast::TypeKind::RestrictedFloat => "restricted_f32".to_owned(), - webidl::ast::TypeKind::Sequence(ty) => "sequence_of_".to_owned() + &ty.type_to_string(), - webidl::ast::TypeKind::SignedLong => "i32".to_owned(), - webidl::ast::TypeKind::SignedLongLong => "i64".to_owned(), - webidl::ast::TypeKind::SignedShort => "i16".to_owned(), - webidl::ast::TypeKind::Symbol => "symbol".to_owned(), - webidl::ast::TypeKind::USVString => "usv_str".to_owned(), - webidl::ast::TypeKind::Uint16Array => "u16_array".to_owned(), - webidl::ast::TypeKind::Uint32Array => "u32_array".to_owned(), - webidl::ast::TypeKind::Uint8Array => "u8_array".to_owned(), - webidl::ast::TypeKind::Uint8ClampedArray => "u8_clamped_array".to_owned(), - webidl::ast::TypeKind::Union(types) => "union_of_".to_owned() + &types - .iter() - .map(|ty| (*ty).type_to_string()) - .collect::>() - .join("_and_"), - webidl::ast::TypeKind::UnrestrictedDouble => "unrestricted_f64".to_owned(), - webidl::ast::TypeKind::UnrestrictedFloat => "unrestricted_f32".to_owned(), - webidl::ast::TypeKind::UnsignedLong => "u32".to_owned(), - webidl::ast::TypeKind::UnsignedLongLong => "u64".to_owned(), - webidl::ast::TypeKind::UnsignedShort => "u16".to_owned(), + IntegerType::LongLong(l) if l.unsigned.is_some() => dst.push_str("u64"), + IntegerType::LongLong(_) => dst.push_str("i64"), + IntegerType::Long(l) if l.unsigned.is_some() => dst.push_str("u32"), + IntegerType::Long(_) => dst.push_str("i32"), + IntegerType::Short(l) if l.unsigned.is_some() => dst.push_str("u16"), + IntegerType::Short(_) => dst.push_str("i16"), } } } -impl<'a> FirstPassRecord<'a> { - /// Use information from the first pass to work out the correct Rust type to use for - /// a given WebIDL type. - pub fn webidl_ty_to_syn_ty( - &self, - ty: &webidl::ast::Type, - pos: TypePosition, - ) -> Option { - // Array type is borrowed for arguments (`&[T]`) and owned for return value (`Vec`). - let array = |base_ty: &str| { - match pos { - TypePosition::Argument => { - shared_ref(slice_ty(ident_ty(raw_ident(base_ty)))) - } - TypePosition::Return => { - vec_ty(ident_ty(raw_ident(base_ty))) - } - } +impl TypeToString for FloatingPointType { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + match self { + FloatingPointType::Float(_) => dst.push_str("f32"), + FloatingPointType::Double(_) => dst.push_str("f64"), + } + } +} + +impl TypeToString for weedle::term::ArrayBuffer { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("array_buffer"); + } +} + +impl TypeToString for weedle::term::Symbol { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("symbol"); + } +} + +impl TypeToString for weedle::term::Object { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("object"); + } +} + +impl TypeToString for weedle::term::DataView { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("data_view"); + } +} + +impl TypeToString for weedle::term::Error { + fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { + dst.push_str("error"); + } +} + +impl<'src> TypeToString for weedle::types::SequenceType<'src> { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { + dst.push_str("seq_"); + self.generics.body.type_to_string(record, dst); + } +} + +impl<'src> TypeToString for weedle::types::PromiseType<'src> { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { + dst.push_str("promise_"); + self.generics.body.type_to_string(record, dst); + } +} + +impl<'src> TypeToString for weedle::types::FrozenArrayType<'src> { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { + dst.push_str("frozen_array_"); + self.generics.body.type_to_string(record, dst); + } +} + +impl<'src> TypeToString for weedle::types::RecordType<'src> { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { + dst.push_str("record_from_"); + self.generics.body.0.type_to_string(record, dst); + dst.push_str("_to_"); + self.generics.body.2.type_to_string(record, dst); + } +} + +impl<'a> TypeToString for weedle::types::Type<'a> { + fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { + use weedle::types::NonAnyType::*; + + let single = match self { + Type::Single(s) => s, + Type::Union(_) => panic!("unions not supported"), }; - let base_ty = match ty.kind { - // `any` becomes `::wasm_bindgen::JsValue`. - webidl::ast::TypeKind::Any => { - leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]) - } - - // A reference to a type by name becomes the same thing in the - // bindings. - webidl::ast::TypeKind::Identifier(ref id) => { - let ty = ident_ty(rust_ident(camel_case_ident(&id).as_str())); - if self.interfaces.contains_key(id) { - if pos == TypePosition::Argument { - shared_ref(ty) - } else { - ty - } - } else if self.dictionaries.contains(id) { - ty - } else if self.enums.contains(id) { - ty - } else { - warn!("unrecognized type {}", id); - ty - } - } - - // Scalars. - webidl::ast::TypeKind::Boolean => ident_ty(raw_ident("bool")), - webidl::ast::TypeKind::Byte => ident_ty(raw_ident("i8")), - webidl::ast::TypeKind::Octet => ident_ty(raw_ident("u8")), - webidl::ast::TypeKind::RestrictedDouble | webidl::ast::TypeKind::UnrestrictedDouble => { - ident_ty(raw_ident("f64")) - } - webidl::ast::TypeKind::RestrictedFloat | webidl::ast::TypeKind::UnrestrictedFloat => { - ident_ty(raw_ident("f32")) - } - webidl::ast::TypeKind::SignedLong => ident_ty(raw_ident("i32")), - webidl::ast::TypeKind::SignedLongLong => ident_ty(raw_ident("i64")), - webidl::ast::TypeKind::SignedShort => ident_ty(raw_ident("i16")), - webidl::ast::TypeKind::UnsignedLong => ident_ty(raw_ident("u32")), - webidl::ast::TypeKind::UnsignedLongLong => ident_ty(raw_ident("u64")), - webidl::ast::TypeKind::UnsignedShort => ident_ty(raw_ident("u16")), - - webidl::ast::TypeKind::Float32Array => array("f32"), - webidl::ast::TypeKind::Float64Array => array("f64"), - webidl::ast::TypeKind::Int8Array => array("i8"), - webidl::ast::TypeKind::Int16Array => array("i16"), - webidl::ast::TypeKind::Int32Array => array("i32"), - webidl::ast::TypeKind::Uint8Array => array("u8"), - webidl::ast::TypeKind::Uint8ClampedArray => array("u8"), - webidl::ast::TypeKind::Uint16Array => array("u16"), - webidl::ast::TypeKind::Uint32Array => array("u32"), - - // strings -> `&str` for arguments and `String` for return - // - // Note that DOMString mostly makes sense here, ByteString maps to - // String in JS [1], along with USVString - // - // [1]: https://developer.mozilla.org/en-US/docs/Web/API/ByteString - // [2]: https://developer.mozilla.org/en-US/docs/Web/API/USVString - webidl::ast::TypeKind::DOMString - | webidl::ast::TypeKind::ByteString - | webidl::ast::TypeKind::USVString => { - match pos { - TypePosition::Argument => shared_ref(ident_ty(raw_ident("str"))), - TypePosition::Return => ident_ty(raw_ident("String")), - } - } - - // This seems like a "naively correct" mapping, but the online docs - // are a bit scary in this regard... - // - // https://heycam.github.io/webidl/#es-buffer-source-types - webidl::ast::TypeKind::ArrayBuffer => { - leading_colon_path_ty(vec![rust_ident("js_sys"), rust_ident("ArrayBuffer")]) - } - - // The WebIDL `object` maps to the ECMAScript `Object` - // - // https://heycam.github.io/webidl/#es-object - webidl::ast::TypeKind::Object => { - leading_colon_path_ty(vec![rust_ident("js_sys"), rust_ident("Object")]) - } - - // Support for these types is not yet implemented, so skip - // generating any bindings for this function. - | webidl::ast::TypeKind::DataView - | webidl::ast::TypeKind::Error - | webidl::ast::TypeKind::FrozenArray(_) - | webidl::ast::TypeKind::Promise(_) - | webidl::ast::TypeKind::Record(..) - | webidl::ast::TypeKind::Sequence(_) - | webidl::ast::TypeKind::Symbol - | webidl::ast::TypeKind::Union(_) => { - return None; - } + let ty = match single { + SingleType::Any(_) => return dst.push_str("any"), + SingleType::NonAny(other) => other, }; - // Map nullable to an option. - if ty.nullable { - let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { - colon2_token: None, - lt_token: Default::default(), - args: FromIterator::from_iter(vec![ - syn::GenericArgument::Type(base_ty), - ]), - gt_token: Default::default(), - }); + match ty { + Boolean(s) => s.type_to_string(record, dst), + Octet(s) => s.type_to_string(record, dst), + Byte(s) => s.type_to_string(record, dst), + Identifier(s) => s.type_to_string(record, dst), + Integer(s) => s.type_to_string(record, dst), + FloatingPoint(s) => s.type_to_string(record, dst), - let ident = raw_ident("Option"); - let seg = syn::PathSegment { ident, arguments }; - let path: syn::Path = seg.into(); - let ty = syn::TypePath { qself: None, path }; - Some(ty.into()) - } else { - Some(base_ty) + Float32Array(s) => s.type_to_string(record, dst), + Float64Array(s) => s.type_to_string(record, dst), + Int8Array(s) => s.type_to_string(record, dst), + Int16Array(s) => s.type_to_string(record, dst), + Int32Array(s) => s.type_to_string(record, dst), + Uint8Array(s) => s.type_to_string(record, dst), + Uint8ClampedArray(s) => s.type_to_string(record, dst), + Uint16Array(s) => s.type_to_string(record, dst), + Uint32Array(s) => s.type_to_string(record, dst), + + DOMString(s) => s.type_to_string(record, dst), + ByteString(s) => s.type_to_string(record, dst), + USVString(s) => s.type_to_string(record, dst), + ArrayBuffer(s) => s.type_to_string(record, dst), + + DataView(s) => s.type_to_string(record, dst), + Error(s) => s.type_to_string(record, dst), + FrozenArrayType(s) => s.type_to_string(record, dst), + Object(s) => s.type_to_string(record, dst), + Promise(s) => s.type_to_string(record, dst), + RecordType(s) => s.type_to_string(record, dst), + Sequence(s) => s.type_to_string(record, dst), + Symbol(s) => s.type_to_string(record, dst), } } +} +impl<'src> FirstPassRecord<'src> { /// Use the first pass to convert webidl function arguments to rust arguments. /// /// `kind` is whether the function is a method, in which case we would need a `self` /// parameter. - fn webidl_arguments_to_syn_arg_captured<'b, I>( + fn webidl_arguments_to_syn_arg_captured( &self, - arguments: I, + arguments: &[Argument], kind: &backend::ast::ImportFunctionKind, ) -> Option> - where - I: Iterator, { - let estimate = arguments.size_hint(); - let len = estimate.1.unwrap_or(estimate.0); let mut res = if let backend::ast::ImportFunctionKind::Method { ty, kind: @@ -495,25 +802,27 @@ impl<'a> FirstPassRecord<'a> { .. } = kind { - let mut res = Vec::with_capacity(len + 1); + let mut res = Vec::with_capacity(arguments.len() + 1); res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone()))); res } else { - Vec::with_capacity(len) + Vec::with_capacity(arguments.len()) }; - for (name, ty, variadic) in arguments { - if variadic { - warn!("Variadic arguments are not supported yet",); - return None; - } - - match self.webidl_ty_to_syn_ty(ty, TypePosition::Argument) { + for argument in arguments { + let argument = match argument { + Argument::Single(arg) => arg, + Argument::Variadic(_) => return None, + }; + match argument.type_.type_.to_syn_type(self, TypePosition::Argument) { None => { - warn!("Argument's type is not yet supported: {:?}", ty); + warn!("Argument's type is not yet supported: {:?}", argument); return None; } - Some(ty) => res.push(simple_fn_arg(rust_ident(&name.to_snake_case()), ty)), + Some(ty) => { + let name = argument.identifier.0.to_snake_case(); + res.push(simple_fn_arg(rust_ident(&name), ty)) + } } } @@ -521,39 +830,38 @@ impl<'a> FirstPassRecord<'a> { } /// Create a wasm-bindgen function, if possible. - pub fn create_function<'b, I>( + pub fn create_function( &self, name: &str, overloaded: bool, same_argument_names: bool, - arguments: I, + arguments: &[Argument], mut ret: Option, kind: backend::ast::ImportFunctionKind, structural: bool, catch: bool, doc_comment: Option, ) -> Option - where - I: Iterator, { - let arguments: Vec<_> = arguments.collect(); + let ast_arguments = self.webidl_arguments_to_syn_arg_captured(arguments, &kind)?; + let rust_name = rust_ident( &if overloaded && !arguments.is_empty() { - let argument_type_names = arguments - .iter() - .map(|&(name, ty, variadic)| { - if same_argument_names { - if variadic { - "variadic_".to_owned() + &ty.type_to_string() - } else { - ty.type_to_string() - } - } else { - name.to_snake_case() - } - }) - .collect::>() - .join("_and_"); + let mut argument_type_names = String::new(); + for arg in arguments { + let arg = match arg { + Argument::Single(single) => single, + Argument::Variadic(_) => return None, + }; + if argument_type_names.len() > 0 { + argument_type_names.push_str("_and_"); + } + if same_argument_names { + arg.type_.type_.type_to_string(self, &mut argument_type_names); + } else { + argument_type_names.push_str(&arg.identifier.0.to_snake_case()); + } + } if name == "new" { "with_".to_owned() + &argument_type_names } else { @@ -565,8 +873,6 @@ impl<'a> FirstPassRecord<'a> { ); let name = name.to_string(); - let arguments = self.webidl_arguments_to_syn_arg_captured(arguments.into_iter(), &kind)?; - let js_ret = ret.clone(); if catch { @@ -585,7 +891,7 @@ impl<'a> FirstPassRecord<'a> { Some(backend::ast::ImportFunction { function: backend::ast::Function { name, - arguments, + arguments: ast_arguments, ret, rust_attrs: vec![], rust_vis: public(), @@ -603,16 +909,16 @@ impl<'a> FirstPassRecord<'a> { /// Create a wasm-bindgen method, if possible. pub fn create_basic_method( &self, - arguments: &[webidl::ast::Argument], - name: Option<&String>, - return_type: &webidl::ast::ReturnType, + arguments: &[weedle::argument::Argument], + name: Option<&str>, + return_type: &weedle::types::ReturnType, self_name: &str, is_static: bool, catch: bool, ) -> Option { let (overloaded, same_argument_names) = self.get_operation_overloading( arguments, - ::first_pass::OperationId::Operation(name.cloned()), + ::first_pass::OperationId::Operation(name), self_name, ); @@ -634,9 +940,9 @@ impl<'a> FirstPassRecord<'a> { }; let ret = match return_type { - webidl::ast::ReturnType::Void => None, - webidl::ast::ReturnType::NonVoid(ty) => { - match self.webidl_ty_to_syn_ty(ty, TypePosition::Return) { + weedle::types::ReturnType::Void(_) => None, + weedle::types::ReturnType::Type(ty) => { + match ty.to_syn_type(self, TypePosition::Return) { None => { warn!("Operation's return type is not yet supported: {:?}", ty); return None; @@ -651,9 +957,7 @@ impl<'a> FirstPassRecord<'a> { &name, overloaded, same_argument_names, - arguments - .iter() - .map(|arg| (&*arg.name, &*arg.type_, arg.variadic)), + arguments, ret, kind, self @@ -670,47 +974,45 @@ impl<'a> FirstPassRecord<'a> { /// whether there overloads with same argument names for given argument types pub fn get_operation_overloading( &self, - arguments: &[webidl::ast::Argument], + arguments: &[weedle::argument::Argument], id: ::first_pass::OperationId, self_name: &str, ) -> (bool, bool) { - self - .interfaces - .get(self_name) - .map(|interface_data| { - interface_data - .operations - .get(&id) - .map(|operation_data| - ( - operation_data.overloaded, - *operation_data - .argument_names_same - .get( - &arguments - .iter() - .map(|argument| argument.name.clone()) - .collect::>() - ) - .unwrap_or(&false) - ) - ) - .unwrap_or((false, false)) - }) - .unwrap_or((false, false)) + let data = match self.interfaces.get(self_name) { + Some(data) => data, + None => return (false, false), + }; + let data = match data.operations.get(&id) { + Some(data) => data, + None => return (false, false), + }; + let mut names = Vec::with_capacity(arguments.len()); + for arg in arguments { + match arg { + Argument::Single(arg) => names.push(arg.identifier.0), + Argument::Variadic(_) => return (false, false), + } + } + ( + data.overloaded, + *data + .argument_names_same + .get(&names) + .unwrap_or(&false) + ) } /// Create a wasm-bindgen getter method, if possible. pub fn create_getter( &self, name: &str, - ty: &webidl::ast::Type, + ty: &weedle::types::Type, self_name: &str, is_static: bool, is_structural: bool, catch: bool, ) -> Option { - let ret = match self.webidl_ty_to_syn_ty(ty, TypePosition::Return) { + let ret = match ty.to_syn_type(self, TypePosition::Return) { None => { warn!("Attribute's type does not yet support reading: {:?}", ty); return None; @@ -728,14 +1030,14 @@ impl<'a> FirstPassRecord<'a> { }; let doc_comment = Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name)))); - self.create_function(name, false, false, iter::empty(), ret, kind, is_structural, catch, doc_comment) + self.create_function(name, false, false, &[], ret, kind, is_structural, catch, doc_comment) } /// Create a wasm-bindgen setter method, if possible. pub fn create_setter( &self, name: &str, - ty: &webidl::ast::Type, + ty: weedle::types::Type, self_name: &str, is_static: bool, is_structural: bool, @@ -755,7 +1057,16 @@ impl<'a> FirstPassRecord<'a> { &format!("set_{}", name), false, false, - iter::once((name, ty, false)), + &[Argument::Single(SingleArgument { + attributes: None, + optional: None, + type_: AttributedType { + attributes: None, + type_: ty, + }, + identifier: Identifier(name), + default: None, + })], None, kind, is_structural, @@ -766,41 +1077,35 @@ impl<'a> FirstPassRecord<'a> { } /// Search for an attribute by name in some webidl object's attributes. -fn has_named_attribute(ext_attrs: &[Box], attribute: &str) -> bool { - ext_attrs.iter().any(|attr| match &**attr { - ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => { - name == attribute - } +fn has_named_attribute(list: &Option, attribute: &str) -> bool { + let list = match list { + Some(list) => list, + None => return false, + }; + list.body.list.iter().any(|attr| match attr { + ExtendedAttribute::NoArgs(name) => (name.0).0 == attribute, _ => false, }) } /// ChromeOnly is for things that are only exposed to privileged code in Firefox. -pub fn is_chrome_only(ext_attrs: &[Box]) -> bool { +pub fn is_chrome_only(ext_attrs: &Option) -> bool { has_named_attribute(ext_attrs, "ChromeOnly") } /// Whether a webidl object is marked as a no interface object. -pub fn is_no_interface_object(ext_attrs: &[Box]) -> bool { +pub fn is_no_interface_object(ext_attrs: &Option) -> bool { has_named_attribute(ext_attrs, "NoInterfaceObject") } /// Whether a webidl object is marked as structural. -pub fn is_structural(attrs: &[Box]) -> bool { - attrs.iter().any(|attr| match &**attr { - ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => { - name == "Unforgeable" - } - _ => false, - }) +pub fn is_structural(attrs: &Option) -> bool { + has_named_attribute(attrs, "Unforgeable") } /// Whether a webidl object is marked as throwing. -pub fn throws(attrs: &[Box]) -> bool { - attrs.iter().any(|attr| match &**attr { - ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => name == "Throws", - _ => false, - }) +pub fn throws(attrs: &Option) -> bool { + has_named_attribute(attrs, "Throws") } /// Create a syn `pub` token From 73e89fc59b360d2db44ff55f8686156452a64cf1 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Mon, 6 Aug 2018 17:19:47 +0200 Subject: [PATCH 06/24] Add bindings for RegExp.$1-$9 --- crates/js-sys/src/lib.rs | 24 ++++++++++++++++++++++++ crates/js-sys/tests/wasm/RegExp.rs | 16 +++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index b4c4198b..908062d3 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2168,6 +2168,30 @@ extern { #[wasm_bindgen(method, getter)] pub fn multiline(this: &RegExp) -> bool; + /// The non-standard $1, $2, $3, $4, $5, $6, $7, $8, $9 properties + /// are static and read-only properties of regular expressions + /// that contain parenthesized substring matches. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/n + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$1")] + pub fn n1() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$2")] + pub fn n2() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$3")] + pub fn n3() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$4")] + pub fn n4() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$5")] + pub fn n5() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$6")] + pub fn n6() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$7")] + pub fn n7() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$8")] + pub fn n8() -> JsString; + #[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$9")] + pub fn n9() -> JsString; + /// The RegExp constructor creates a regular expression object for matching text with a pattern. /// /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp diff --git a/crates/js-sys/tests/wasm/RegExp.rs b/crates/js-sys/tests/wasm/RegExp.rs index a9b60c70..842a0049 100644 --- a/crates/js-sys/tests/wasm/RegExp.rs +++ b/crates/js-sys/tests/wasm/RegExp.rs @@ -3,7 +3,6 @@ use js_sys::*; #[wasm_bindgen_test] fn exec() { - let re = RegExp::new("quick\\s(brown).+?(jumps)", "ig"); let result = re.exec("The Quick Brown Fox Jumps Over The Lazy Dog"); @@ -76,6 +75,21 @@ fn multiline() { assert!(re.multiline()); } +#[wasm_bindgen_test] +fn n1_to_n9() { + let re = RegExp::new(r"(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)", ""); + re.test("The Quick Brown Fox Jumps Over The Lazy Dog"); + assert_eq!(RegExp::n1(), "The"); + assert_eq!(RegExp::n2(), "Quick"); + assert_eq!(RegExp::n3(), "Brown"); + assert_eq!(RegExp::n4(), "Fox"); + assert_eq!(RegExp::n5(), "Jumps"); + assert_eq!(RegExp::n6(), "Over"); + assert_eq!(RegExp::n7(), "The"); + assert_eq!(RegExp::n8(), "Lazy"); + assert_eq!(RegExp::n9(), "Dog"); +} + #[wasm_bindgen_test] fn new() { let re = RegExp::new("foo", ""); From 72fff9c43ef85e8ef02a9d971401459f54ed1fcf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 4 Aug 2018 14:16:37 -0700 Subject: [PATCH 07/24] Ignore `implements` items explicitly No need to warn about them because there's not much to handle with them anyway! --- crates/webidl/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 6c3fb030..6c212068 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -181,12 +181,14 @@ impl<'src> WebidlParse<'src, ()> for weedle::Definition<'src> { weedle::Definition::PartialInterfaceMixin(_) => { // handled in the first pass } + weedle::Definition::Implements(..) => { + // nothing to do for this, ignore it + } // TODO weedle::Definition::Callback(..) | weedle::Definition::CallbackInterface(..) | weedle::Definition::Dictionary(..) | weedle::Definition::PartialDictionary(..) - | weedle::Definition::Implements(..) | weedle::Definition::Namespace(..) | weedle::Definition::PartialNamespace(..) => { warn!("Unsupported WebIDL definition: {:?}", self) From f96fcf78a1100ea56e36994102d5f5d4d91906cb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 4 Aug 2018 14:17:37 -0700 Subject: [PATCH 08/24] Explicitly ignore some extended attributes Cut down on generated warnings by explicitly ignoring attributes which it looks like we don't need to handle at all. --- crates/webidl/src/lib.rs | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 6c212068..76e17669 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -358,6 +358,50 @@ impl<'src> WebidlParse<'src, &'src weedle::InterfaceDefinition<'src>> for Extend { add_constructor(&list.args.body.list, list.rhs_identifier.0) } + + // these appear to be mapping to gecko preferences, seems like we + // can safely ignore + ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "Pref" => {} + + // looks to be a gecko-specific attribute to tie WebIDL back to C++ + // functions perhaps + ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "Func" => {} + ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "JSImplementation" => {} + ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "HeaderFile" => {} + + // Not actually mentioned in the spec and presumably a hint to + // Gecko's JS engine? Unsure, but seems like it doesn't matter to us + ExtendedAttribute::NoArgs(id) + if (id.0).0 == "ProbablyShortLivingWrapper" => {} + + // Indicates something about enumerable properties, we're not too + // interested in it + // https://heycam.github.io/webidl/#LegacyUnenumerableNamedProperties + ExtendedAttribute::NoArgs(id) + if (id.0).0 == "LegacyUnenumerableNamedProperties" => {} + + // Indicates where objects are defined (web workers and such), we + // may later want to use this for cfgs but for now we ignore it. + // https://heycam.github.io/webidl/#Exposed + ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "Exposed" => {} + ExtendedAttribute::IdentList(id) if id.identifier.0 == "Exposed" => {} + + // We handle this with the "structural" attribute elsewhere + ExtendedAttribute::IdentList(id) if id.identifier.0 == "Global" => {} + + // Seems like it's safe to ignore for now, just telling us where a + // binding appears + // https://heycam.github.io/webidl/#SecureContext + ExtendedAttribute::NoArgs(id) if (id.0).0 == "SecureContext" => {} + + // We handle this elsewhere + ExtendedAttribute::NoArgs(id) if (id.0).0 == "Unforgeable" => {} + + // Looks like this attribute just says that we can't call the + // constructor + // https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor + ExtendedAttribute::NoArgs(id) if (id.0).0 == "HTMLConstructor" => {} + ExtendedAttribute::ArgList(_) | ExtendedAttribute::Ident(_) | ExtendedAttribute::IdentList(_) From 4661588171accad0886a6e801ed35c88a5f3915d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 09:20:19 -0700 Subject: [PATCH 09/24] Move most of the "simple" test to the `wasm` suite --- tests/all/main.rs | 2 +- tests/all/simple.rs | 422 ------------------------------------------- tests/wasm/main.rs | 1 + tests/wasm/simple.js | 85 +++++++++ tests/wasm/simple.rs | 180 ++++++++++++++++++ 5 files changed, 267 insertions(+), 423 deletions(-) create mode 100644 tests/wasm/simple.js create mode 100644 tests/wasm/simple.rs diff --git a/tests/all/main.rs b/tests/all/main.rs index a546d2c4..8c3164db 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -8,8 +8,8 @@ mod comments; mod dependencies; mod js_objects; mod imports; +mod simple; mod node; mod non_debug; mod non_wasm; -mod simple; mod typescript; diff --git a/tests/all/simple.rs b/tests/all/simple.rs index 2243d044..6b441c2b 100644 --- a/tests/all/simple.rs +++ b/tests/all/simple.rs @@ -1,64 +1,5 @@ use super::project; -#[test] -fn add() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn add(a: u32, b: u32) -> u32 { - a + b - } - - #[wasm_bindgen] - pub fn add3(a: u32) -> u32 { - a + 3 - } - - #[wasm_bindgen] - pub fn get2(_b: bool) -> u32 { - 2 - } - - #[wasm_bindgen] - pub fn return_and_take_bool(a: bool, b: bool) -> bool { - a && b - } - - #[wasm_bindgen] - pub fn raw_pointers_work(a: *mut u32, b: *const u8) -> *const u32 { - unsafe { - (*a) = (*b) as u32; - return a - } - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - assert.strictEqual(wasm.add(1, 2), 3); - assert.strictEqual(wasm.add(2, 3), 5); - assert.strictEqual(wasm.add3(2), 5); - assert.strictEqual(wasm.get2(true), 2); - assert.strictEqual(wasm.return_and_take_bool(true, false), false); - } - "#, - ) - .test(); -} - #[test] fn add_headless() { project() @@ -92,176 +33,6 @@ fn add_headless() { .test(); } -#[test] -fn string_arguments() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn assert_foo_and_bar(a: &str, b: &str) { - assert_eq!(a, "foo2"); - assert_eq!(b, "bar"); - } - - #[wasm_bindgen] - pub fn assert_foo(a: &str) { - assert_eq!(a, "foo"); - } - "#, - ) - .file( - "test.js", - r#" - import * as wasm from "./out"; - - export function test() { - wasm.assert_foo("foo"); - wasm.assert_foo_and_bar("foo2", "bar"); - } - "#, - ) - .test(); -} - -#[test] -fn return_a_string() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn clone(a: &str) -> String { - a.to_string() - } - - #[wasm_bindgen] - pub fn concat(a: &str, b: &str, c: i8) -> String { - format!("{} {} {}", a, b, c) - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - assert.strictEqual(wasm.clone("foo"), "foo"); - assert.strictEqual(wasm.clone("another"), "another"); - assert.strictEqual(wasm.concat("a", "b", 3), "a b 3"); - assert.strictEqual(wasm.concat("c", "d", -2), "c d -2"); - } - "#, - ) - .test(); -} - -#[test] -fn exceptions() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn foo(_a: u32) {} - - #[wasm_bindgen] - pub fn bar(_a: &str) {} - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - assert.throws(() => wasm.foo('a'), /expected a number argument/); - assert.throws(() => wasm.bar(3), /expected a string argument/); - } - "#, - ) - .test(); -} - -// #[test] -// fn other_imports() { -// project() -// .file("src/lib.rs", r#" -// #![feature(use_extern_macros)] -// -// extern crate wasm_bindgen; -// -// use wasm_bindgen::prelude::*; -// -// extern { -// fn another_import(a: u32); -// } -// -// wasm_bindgen! { -// pub fn foo(a: u32) { -// unsafe { another_import(a); } -// } -// } -// "#) -// .file("test.js", r#" -// import * as assert from "assert"; -// import * as wasm from "./out"; -// -// let ARG: number | null = null; -// -// export function test() { -// wasm.foo(2); -// assert.strictEqual(ARG, 2); -// } -// "#) -// .test(); -// } - -#[test] -fn other_exports() { - project() - .file( - "src/lib.rs", - r#" - #[no_mangle] - pub extern fn foo(_a: u32) { - } - "#, - ) - .file( - "test.js", - r#" - import * as wasm from "./out_bg"; - - export function test() { - wasm.foo(2); - } - "#, - ) - .test(); -} - #[test] fn no_std() { project() @@ -369,196 +140,3 @@ fn no_std_class() { .test(); } -#[test] -fn jsvalue_typeof() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn is_object(val: &JsValue) -> bool { - val.is_object() - } - - #[wasm_bindgen] - pub fn is_function(val: &JsValue) -> bool { - val.is_function() - } - - #[wasm_bindgen] - pub fn is_string(val: &JsValue) -> bool { - val.is_string() - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - assert.ok(wasm.is_object({})); - assert.ok(!wasm.is_object(42)); - assert.ok(wasm.is_function(function() {})); - assert.ok(!wasm.is_function(42)); - assert.ok(wasm.is_string("2b or !2b")); - assert.ok(!wasm.is_string(42)); - } - "#, - ) - .test(); -} - -#[test] -fn binding_to_unimplemented_apis_doesnt_break_everything() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - extern { - #[derive(Clone)] - type Array; - - #[wasm_bindgen(constructor)] - fn new() -> Array; - - #[wasm_bindgen(method, catch)] - fn standardized_method_this_js_runtime_doesnt_implement_yet(this: &Array) - -> Result<(), JsValue>; - } - - #[wasm_bindgen] - pub fn test() { - let array = Array::new(); - let res = array.standardized_method_this_js_runtime_doesnt_implement_yet(); - assert!(res.is_err()); - } - "#, - ) - .test(); -} - -#[test] -fn optional_slices() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros, wasm_custom_section)] - extern crate wasm_bindgen; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "./foo")] - extern { - fn optional_str_none(a: Option<&str>); - fn optional_str_some(a: Option<&str>); - fn optional_slice_none(a: Option<&[u8]>); - fn optional_slice_some(a: Option<&[u8]>); - - fn optional_string_none(a: Option); - fn optional_string_some(a: Option); - fn optional_string_some_empty(a: Option); - - fn return_string_none() -> Option; - fn return_string_some() -> Option; - - fn run_rust_tests(); - } - - #[wasm_bindgen] - pub fn test() { - optional_str_none(None); - optional_str_some(Some("x")); - optional_slice_none(None); - optional_slice_some(Some(&[1, 2, 3])); - optional_string_none(None); - optional_string_some_empty(Some(String::new())); - optional_string_some(Some("abcd".to_string())); - - assert_eq!(return_string_none(), None); - assert_eq!(return_string_some(), Some("foo".to_string())); - run_rust_tests(); - } - - #[wasm_bindgen] - pub fn take_optional_str_none(x: Option) { - assert!(x.is_none()) - } - #[wasm_bindgen] - pub fn take_optional_str_some(x: Option) { - assert_eq!(x, Some(String::from("hello"))); - } - #[wasm_bindgen] - pub fn return_optional_str_none() -> Option { - None - } - #[wasm_bindgen] - pub fn return_optional_str_some() -> Option { - Some("world".to_string()) - } - "#, - ) - .file( - "foo.js", - r#" - import { strictEqual } from "assert"; - import * as wasm from "./out"; - - export function optional_str_none(x) { - strictEqual(x, undefined); - } - - export function optional_str_some(x) { - strictEqual(x, 'x'); - } - - export function optional_slice_none(x) { - strictEqual(x, undefined); - } - - export function optional_slice_some(x) { - strictEqual(x.length, 3); - strictEqual(x[0], 1); - strictEqual(x[1], 2); - strictEqual(x[2], 3); - } - - export function optional_string_none(x) { - strictEqual(x, undefined); - } - - export function optional_string_some(x) { - strictEqual(x, 'abcd'); - } - - export function optional_string_some_empty(x) { - strictEqual(x, ''); - } - - export function return_string_none() {} - export function return_string_some() { - return 'foo'; - } - - export function run_rust_tests() { - wasm.take_optional_str_none(); - wasm.take_optional_str_none(null); - wasm.take_optional_str_none(undefined); - wasm.take_optional_str_some('hello'); - strictEqual(wasm.return_optional_str_none(), undefined); - strictEqual(wasm.return_optional_str_some(), 'world'); - } - "# - ) - .test(); -} diff --git a/tests/wasm/main.rs b/tests/wasm/main.rs index 3c42a70e..7ab95c55 100644 --- a/tests/wasm/main.rs +++ b/tests/wasm/main.rs @@ -16,6 +16,7 @@ pub mod js_objects; pub mod math; pub mod option; pub mod optional_primitives; +pub mod simple; pub mod slice; pub mod structural; pub mod u64; diff --git a/tests/wasm/simple.js b/tests/wasm/simple.js new file mode 100644 index 00000000..34d5fef0 --- /dev/null +++ b/tests/wasm/simple.js @@ -0,0 +1,85 @@ +const assert = require('assert'); +const wasm = require('wasm-bindgen-test'); + +exports.test_add = function() { + assert.strictEqual(wasm.simple_add(1, 2), 3); + assert.strictEqual(wasm.simple_add(2, 3), 5); + assert.strictEqual(wasm.simple_add3(2), 5); + assert.strictEqual(wasm.simple_get2(true), 2); + assert.strictEqual(wasm.simple_return_and_take_bool(true, false), false); +}; + +exports.test_string_arguments = function() { + wasm.simple_assert_foo("foo"); + wasm.simple_assert_foo_and_bar("foo2", "bar"); +}; + +exports.test_return_a_string = function() { + assert.strictEqual(wasm.simple_clone("foo"), "foo"); + assert.strictEqual(wasm.simple_clone("another"), "another"); + assert.strictEqual(wasm.simple_concat("a", "b", 3), "a b 3"); + assert.strictEqual(wasm.simple_concat("c", "d", -2), "c d -2"); +}; + +exports.test_wrong_types = function() { + assert.throws(() => wasm.simple_int('a'), /expected a number argument/); + assert.throws(() => wasm.simple_str(3), /expected a string argument/); +}; + +exports.test_other_exports_still_available = function() { + require('wasm-bindgen-test_bg').foo(3); +}; + +exports.test_jsvalue_typeof = function() { + assert.ok(wasm.is_object({})); + assert.ok(!wasm.is_object(42)); + assert.ok(wasm.is_function(function() {})); + assert.ok(!wasm.is_function(42)); + assert.ok(wasm.is_string("2b or !2b")); + assert.ok(!wasm.is_string(42)); +}; + +exports.optional_str_none = function(x) { + assert.strictEqual(x, undefined); +}; + +exports.optional_str_some = function(x) { + assert.strictEqual(x, 'x'); +}; + +exports.optional_slice_none = function(x) { + assert.strictEqual(x, undefined); +}; + +exports.optional_slice_some = function(x) { + assert.strictEqual(x.length, 3); + assert.strictEqual(x[0], 1); + assert.strictEqual(x[1], 2); + assert.strictEqual(x[2], 3); +} + +exports.optional_string_none = function(x) { + assert.strictEqual(x, undefined); +}; + +exports.optional_string_some = function(x) { + assert.strictEqual(x, 'abcd'); +}; + +exports.optional_string_some_empty = function(x) { + assert.strictEqual(x, ''); +}; + +exports.return_string_none = function() {}; +exports.return_string_some = function() { + return 'foo'; +}; + +exports.test_rust_optional = function() { + wasm.take_optional_str_none(); + wasm.take_optional_str_none(null); + wasm.take_optional_str_none(undefined); + wasm.take_optional_str_some('hello'); + assert.strictEqual(wasm.return_optional_str_none(), undefined); + assert.strictEqual(wasm.return_optional_str_some(), 'world'); +}; diff --git a/tests/wasm/simple.rs b/tests/wasm/simple.rs new file mode 100644 index 00000000..d58f7ee1 --- /dev/null +++ b/tests/wasm/simple.rs @@ -0,0 +1,180 @@ +use wasm_bindgen_test::*; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen(module = "tests/wasm/simple.js", version = "*")] +extern { + fn test_add(); + fn test_string_arguments(); + fn test_return_a_string(); + fn test_wrong_types(); + fn test_other_exports_still_available(); + fn test_jsvalue_typeof(); + + fn optional_str_none(a: Option<&str>); + fn optional_str_some(a: Option<&str>); + fn optional_slice_none(a: Option<&[u8]>); + fn optional_slice_some(a: Option<&[u8]>); + fn optional_string_none(a: Option); + fn optional_string_some(a: Option); + fn optional_string_some_empty(a: Option); + fn return_string_none() -> Option; + fn return_string_some() -> Option; + fn test_rust_optional(); +} + +#[wasm_bindgen_test] +fn add() { + test_add(); +} + +#[wasm_bindgen] +pub fn simple_add(a: u32, b: u32) -> u32 { + a + b +} + +#[wasm_bindgen] +pub fn simple_add3(a: u32) -> u32 { + a + 3 +} + +#[wasm_bindgen] +pub fn simple_get2(_b: bool) -> u32 { + 2 +} + +#[wasm_bindgen] +pub fn simple_return_and_take_bool(a: bool, b: bool) -> bool { + a && b +} + +#[wasm_bindgen] +pub fn simple_raw_pointers_work(a: *mut u32, b: *const u8) -> *const u32 { + unsafe { + (*a) = (*b) as u32; + return a + } +} + +#[wasm_bindgen_test] +fn string_arguments() { + test_string_arguments(); +} + +#[wasm_bindgen] +pub fn simple_assert_foo_and_bar(a: &str, b: &str) { + assert_eq!(a, "foo2"); + assert_eq!(b, "bar"); +} + +#[wasm_bindgen] +pub fn simple_assert_foo(a: &str) { + assert_eq!(a, "foo"); +} + +#[wasm_bindgen_test] +fn return_a_string() { + test_return_a_string(); +} + +#[wasm_bindgen] +pub fn simple_clone(a: &str) -> String { + a.to_string() +} + +#[wasm_bindgen] +pub fn simple_concat(a: &str, b: &str, c: i8) -> String { + format!("{} {} {}", a, b, c) +} + +#[wasm_bindgen_test] +fn wrong_types() { + test_wrong_types(); +} + +#[wasm_bindgen] +pub fn simple_int(_a: u32) {} + +#[wasm_bindgen] +pub fn simple_str(_a: &str) {} + +#[wasm_bindgen_test] +fn other_exports() { + test_other_exports_still_available(); +} + +#[no_mangle] +pub extern fn foo(_a: u32) { +} + +#[wasm_bindgen_test] +fn jsvalue_typeof() { + test_jsvalue_typeof(); +} + +#[wasm_bindgen] +pub fn is_object(val: &JsValue) -> bool { + val.is_object() +} + +#[wasm_bindgen] +pub fn is_function(val: &JsValue) -> bool { + val.is_function() +} + +#[wasm_bindgen] +pub fn is_string(val: &JsValue) -> bool { + val.is_string() +} + +#[wasm_bindgen] +extern { + #[derive(Clone)] + type Array; + #[wasm_bindgen(constructor)] + fn new() -> Array; + #[wasm_bindgen(method, catch)] + fn standardized_method_this_js_runtime_doesnt_implement_yet(this: &Array) + -> Result<(), JsValue>; +} + +#[wasm_bindgen_test] +fn binding_to_unimplemented_apis_doesnt_break_everything() { + let array = Array::new(); + let res = array.standardized_method_this_js_runtime_doesnt_implement_yet(); + assert!(res.is_err()); +} + +#[wasm_bindgen_test] +fn optional_slices() { + optional_str_none(None); + optional_str_some(Some("x")); + optional_slice_none(None); + optional_slice_some(Some(&[1, 2, 3])); + optional_string_none(None); + optional_string_some_empty(Some(String::new())); + optional_string_some(Some("abcd".to_string())); + + assert_eq!(return_string_none(), None); + assert_eq!(return_string_some(), Some("foo".to_string())); + test_rust_optional(); +} + +#[wasm_bindgen] +pub fn take_optional_str_none(x: Option) { + assert!(x.is_none()) + +} +#[wasm_bindgen] +pub fn take_optional_str_some(x: Option) { + assert_eq!(x, Some(String::from("hello"))); +} + +#[wasm_bindgen] +pub fn return_optional_str_none() -> Option { + None +} + +#[wasm_bindgen] +pub fn return_optional_str_some() -> Option { + Some("world".to_string()) +} From 0bdb31d41e75d128be3f2dad6c8dd19db96addb8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 09:43:55 -0700 Subject: [PATCH 10/24] Migrate the `serde-serialize` test to `wasm` --- .travis.yml | 1 + Cargo.toml | 1 + crates/test-macro/src/lib.rs | 15 ++++-- tests/all/js_objects.rs | 94 ------------------------------------ tests/wasm/js_objects.js | 16 ++++++ tests/wasm/js_objects.rs | 38 +++++++++++++++ tests/wasm/main.rs | 4 ++ 7 files changed, 71 insertions(+), 98 deletions(-) diff --git a/.travis.yml b/.travis.yml index ff05fdaf..e77ead9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,6 +52,7 @@ matrix: script: - cargo test --release - cargo test --target wasm32-unknown-unknown + - cargo test --target wasm32-unknown-unknown --features serde-serialize # Check JS output from all tests against eslint - npm run run-lint-generated-tests # Check Examples against eslint diff --git a/Cargo.toml b/Cargo.toml index a3c8b84f..869d8a02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ serde_json = { version = "1.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = { path = 'crates/test', version = '=0.2.15' } +serde_derive = "1.0" [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] wasm-bindgen-test-project-builder = { path = "crates/test-project-builder", version = '=0.2.15' } diff --git a/crates/test-macro/src/lib.rs b/crates/test-macro/src/lib.rs index 4d7aa083..19b77590 100644 --- a/crates/test-macro/src/lib.rs +++ b/crates/test-macro/src/lib.rs @@ -32,9 +32,16 @@ pub fn wasm_bindgen_test( let mut body = TokenStream::from(body).into_iter(); - // Assume the input item is of the form `fn #ident ...`, and extract - // `#ident` - let fn_tok = body.next(); + // Skip over other attributes to `fn #ident ...`, and extract `#ident` + let mut leading_tokens = Vec::new(); + while let Some(token) = body.next() { + leading_tokens.push(token.clone()); + if let TokenTree::Ident(token) = token { + if token == "fn" { + break + } + } + } let ident = match body.next() { Some(TokenTree::Ident(token)) => token, _ => panic!("expected a function name"), @@ -64,7 +71,7 @@ pub fn wasm_bindgen_test( } }).into_iter()); - tokens.extend(fn_tok); + tokens.extend(leading_tokens); tokens.push(ident.into()); tokens.extend(body); diff --git a/tests/all/js_objects.rs b/tests/all/js_objects.rs index 5bee2819..e69de29b 100644 --- a/tests/all/js_objects.rs +++ b/tests/all/js_objects.rs @@ -1,94 +0,0 @@ -use super::project; - -#[test] -fn serde() { - project() - .serde(true) - .depend("serde = '1.0'") - .depend("serde_derive = '1.0'") - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - #[macro_use] - extern crate serde_derive; - - use wasm_bindgen::prelude::*; - - #[derive(Deserialize, Serialize)] - pub struct Foo { - a: u32, - b: String, - c: Option, - d: Bar, - } - - #[derive(Deserialize, Serialize)] - pub struct Bar { - a: u32, - } - - #[wasm_bindgen(module = "./test")] - extern { - fn verify(a: JsValue) -> JsValue; - } - - #[wasm_bindgen] - pub fn run() { - let js = JsValue::from_serde("foo").unwrap(); - assert_eq!(js.as_string(), Some("foo".to_string())); - - let ret = verify(JsValue::from_serde(&Foo { - a: 0, - b: "foo".to_string(), - c: None, - d: Bar { a: 1 }, - }).unwrap()); - - let foo = ret.into_serde::().unwrap(); - assert_eq!(foo.a, 2); - assert_eq!(foo.b, "bar"); - assert!(foo.c.is_some()); - assert_eq!(foo.c.as_ref().unwrap().a, 3); - assert_eq!(foo.d.a, 4); - } - - #[wasm_bindgen] - pub fn parse(j: &JsValue) { - let s = j.into_serde::().unwrap(); - assert_eq!(s, "bar"); - } - "#, - ) - .file( - "test.js", - r#" - import { run, parse } from "./out"; - import * as assert from "assert"; - - export function verify(a) { - assert.deepStrictEqual(a, { - a: 0, - b: 'foo', - c: null, - d: { a: 1 } - }); - - return { - a: 2, - b: 'bar', - c: { a: 3 }, - d: { a: 4 }, - } - } - - export function test() { - run(); - parse('bar'); - } - "#, - ) - .test(); -} diff --git a/tests/wasm/js_objects.js b/tests/wasm/js_objects.js index f53b84d7..96aa7bcf 100644 --- a/tests/wasm/js_objects.js +++ b/tests/wasm/js_objects.js @@ -82,3 +82,19 @@ exports.js_returning_vector = () => { exports.js_another_vector_return = () => { assert.deepStrictEqual(wasm.another_vector_return_get_array(), [1, 2, 3, 4, 5, 6]); }; + +exports.verify_serde = function(a) { + assert.deepStrictEqual(a, { + a: 0, + b: 'foo', + c: null, + d: { a: 1 } + }); + + return { + a: 2, + b: 'bar', + c: { a: 3 }, + d: { a: 4 }, + } +}; diff --git a/tests/wasm/js_objects.rs b/tests/wasm/js_objects.rs index 6b162410..9c660492 100644 --- a/tests/wasm/js_objects.rs +++ b/tests/wasm/js_objects.rs @@ -26,6 +26,7 @@ extern { fn js_returning_vector(); fn js_another_vector_return(); + fn verify_serde(val: JsValue) -> JsValue; } #[wasm_bindgen] @@ -105,3 +106,40 @@ pub fn another_vector_return_get_array() -> Vec { fn another_vector_return() { js_another_vector_return(); } + +#[cfg(feature = "serde-serialize")] +#[wasm_bindgen_test] +fn serde() { + #[derive(Deserialize, Serialize)] + pub struct Foo { + a: u32, + b: String, + c: Option, + d: Bar, + } + + #[derive(Deserialize, Serialize)] + pub struct Bar { + a: u32, + } + + + let js = JsValue::from_serde("foo").unwrap(); + assert_eq!(js.as_string(), Some("foo".to_string())); + + let ret = verify_serde(JsValue::from_serde(&Foo { + a: 0, + b: "foo".to_string(), + c: None, + d: Bar { a: 1 }, + }).unwrap()); + + let foo = ret.into_serde::().unwrap(); + assert_eq!(foo.a, 2); + assert_eq!(foo.b, "bar"); + assert!(foo.c.is_some()); + assert_eq!(foo.c.as_ref().unwrap().a, 3); + assert_eq!(foo.d.a, 4); + + assert_eq!(JsValue::from("bar").into_serde::().unwrap(), "bar"); +} diff --git a/tests/wasm/main.rs b/tests/wasm/main.rs index 7ab95c55..3a1a373b 100644 --- a/tests/wasm/main.rs +++ b/tests/wasm/main.rs @@ -4,6 +4,10 @@ extern crate wasm_bindgen_test; extern crate wasm_bindgen; +#[cfg(feature = "serde-serialize")] +#[macro_use] +extern crate serde_derive; + pub mod api; pub mod char; pub mod classes; From aeca24c7ab7b85d8de8542e10c00a6034b5dc147 Mon Sep 17 00:00:00 2001 From: Camille TJHOA Date: Mon, 6 Aug 2018 15:27:47 +0000 Subject: [PATCH 11/24] Add `ArrayBuffer.prototype.byteLength` to js-sys --- crates/js-sys/src/lib.rs | 10 ++++++++++ crates/js-sys/tests/wasm/ArrayBuffer.rs | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 908062d3..c637eb41 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -361,6 +361,16 @@ extern "C" { #[wasm_bindgen(constructor)] pub fn new(length: u32) -> ArrayBuffer; + /// The byteLength property of an object which is an instance of type ArrayBuffer + /// it's an accessor property whose set accessor function is undefined, + /// meaning that you can only read this property. + /// The value is established when the array is constructed and cannot be changed. + /// This property returns 0 if this ArrayBuffer has been detached. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/byteLength + #[wasm_bindgen(method, getter, js_name = byteLength)] + pub fn byte_length(this: &ArrayBuffer) -> u32; + /// The `isView()` method returns true if arg is one of the `ArrayBuffer` /// views, such as typed array objects or a DataView; false otherwise. /// diff --git a/crates/js-sys/tests/wasm/ArrayBuffer.rs b/crates/js-sys/tests/wasm/ArrayBuffer.rs index 904221ff..ddfcdeef 100644 --- a/crates/js-sys/tests/wasm/ArrayBuffer.rs +++ b/crates/js-sys/tests/wasm/ArrayBuffer.rs @@ -9,6 +9,12 @@ fn new() { assert!(y.is_object()); } +#[wasm_bindgen_test] +fn byte_length() { + let buf = ArrayBuffer::new(42); + assert_eq!(buf.byte_length(), 42); +} + #[wasm_bindgen_test] fn is_view() { let x = Uint8Array::new(&JsValue::from(42)); From 851385897351e2366f8cd7dd6d15e66efd643e8e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 09:51:12 -0700 Subject: [PATCH 12/24] Move $-renaming tests to `wasm` --- tests/all/imports.rs | 85 ------------------------------------------- tests/wasm/imports.js | 3 ++ tests/wasm/imports.rs | 15 ++++++++ 3 files changed, 18 insertions(+), 85 deletions(-) diff --git a/tests/all/imports.rs b/tests/all/imports.rs index 4b6c6201..0a7add00 100644 --- a/tests/all/imports.rs +++ b/tests/all/imports.rs @@ -36,91 +36,6 @@ fn unused_imports_not_generated() { assert!(!contents.contains("foo"), "found `foo` in {}", contents); } -#[test] -fn rename_with_string() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "./test")] - extern { - #[wasm_bindgen(js_name = "baz$")] - fn foo(); - } - - #[wasm_bindgen] - pub fn run() { - foo(); - } - "#, - ) - .file( - "test.js", - r#" - import * as wasm from "./out"; - import * as assert from "assert"; - - let called = false; - - export function baz$() { - called = true; - } - - export function test() { - wasm.run(); - assert.strictEqual(called, true); - } - "#, - ) - .test(); -} - -#[test] -fn rename_static_with_string() { - project() - .debug(false) - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "./test")] - extern { - #[wasm_bindgen(js_name = "$foo")] - static FOO: JsValue; - } - - #[wasm_bindgen] - pub fn run() { - assert_eq!(FOO.as_f64(), Some(1.0)); - } - "#, - ) - .file( - "test.js", - r#" - import { run } from "./out"; - - export const $foo = 1.0; - - export function test() { - run(); - } - "#, - ) - .test(); -} - #[test] fn versions() { project() diff --git a/tests/wasm/imports.js b/tests/wasm/imports.js index 7351deff..57fd962c 100644 --- a/tests/wasm/imports.js +++ b/tests/wasm/imports.js @@ -90,3 +90,6 @@ exports.touch_custom_type = function() { exports.interpret_2_as_custom_type = function() { assert.throws(wasm.interpret_2_as_custom_type, /expected value of type CustomType/); }; + +exports.baz$ = function() {}; +exports.$foo = 1.0; diff --git a/tests/wasm/imports.rs b/tests/wasm/imports.rs index 2ba501fb..40f0f7ac 100644 --- a/tests/wasm/imports.rs +++ b/tests/wasm/imports.rs @@ -42,6 +42,11 @@ extern { fn custom_type_return_2() -> CustomType; #[wasm_bindgen(js_name = interpret_2_as_custom_type)] fn js_interpret_2_as_custom_type(); + + #[wasm_bindgen(js_name = "baz$")] + fn renamed_with_dollar_sign(); + #[wasm_bindgen(js_name = "$foo")] + static RENAMED: JsValue; } #[wasm_bindgen] @@ -153,3 +158,13 @@ impl CustomType { } } + +#[wasm_bindgen_test] +fn rename_with_string() { + renamed_with_dollar_sign(); +} + +#[wasm_bindgen_test] +fn rename_static_with_string() { + assert_eq!(RENAMED.as_f64(), Some(1.0)); +} From c83e498f52ce6989d2e5df730ec78c6570abd2ca Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 09:55:20 -0700 Subject: [PATCH 13/24] Move non-wasm test to an actual non-wasm test --- tests/all/main.rs | 1 - tests/all/non_wasm.rs | 101 ------------------------------------------ tests/non_wasm.rs | 53 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 102 deletions(-) delete mode 100644 tests/all/non_wasm.rs create mode 100644 tests/non_wasm.rs diff --git a/tests/all/main.rs b/tests/all/main.rs index 8c3164db..607b8f6d 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -11,5 +11,4 @@ mod imports; mod simple; mod node; mod non_debug; -mod non_wasm; mod typescript; diff --git a/tests/all/non_wasm.rs b/tests/all/non_wasm.rs deleted file mode 100644 index 63099863..00000000 --- a/tests/all/non_wasm.rs +++ /dev/null @@ -1,101 +0,0 @@ -use super::{project, run}; -use std::process::Command; - -#[test] -fn works() { - let mut p = project(); - let name = p.crate_name(); - p.rlib(true) - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub struct A { - x: u32, - } - - #[wasm_bindgen] - impl A { - pub fn new() -> A { - A { x: 3 } - } - - pub fn foo(&self) { - } - } - - #[wasm_bindgen] - pub fn foo(x: bool) { - A::new().foo(); - - if x { - bar("test"); - baz(JsValue::from(3)); - } - } - - #[wasm_bindgen] - extern { - fn some_import(); - static A: JsValue; - } - - #[wasm_bindgen] - pub fn bar(_: &str) -> JsValue { - some_import(); - A.clone() - } - - #[wasm_bindgen] - pub fn baz(_: JsValue) { - } - "#, - ) - .file( - "tests/foo.rs", - &format!( - " - extern crate {} as mytest; - - #[test] - fn foo() {{ - mytest::foo(false); - mytest::A::new().foo(); - }} - ", - name - ), - ) - .file( - "benches/foo.rs", - &format!( - " - #![feature(test)] - extern crate test; - extern crate {} as mytest; - - #[bench] - fn foo(b: &mut test::Bencher) {{ - b.iter(|| mytest::foo(false)); - }} - ", - name - ), - ); - let (root, target_dir) = p.build(); - let mut cmd = Command::new("cargo"); - cmd.arg("test") - .arg("--test") - .arg("foo") - .arg("--bench") - .arg("foo") - .current_dir(&root) - .env("CARGO_TARGET_DIR", &target_dir); - run(&mut cmd, "cargo"); -} diff --git a/tests/non_wasm.rs b/tests/non_wasm.rs new file mode 100644 index 00000000..7a8128f7 --- /dev/null +++ b/tests/non_wasm.rs @@ -0,0 +1,53 @@ +#![feature(use_extern_macros)] + +extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct A { + x: u32, +} + +#[wasm_bindgen] +impl A { + pub fn new() -> A { + A { x: 3 } + } + + pub fn foo(&self) { + drop(self.x); + } +} + +#[wasm_bindgen] +pub fn foo(x: bool) { + A::new().foo(); + + if x { + bar("test"); + baz(JsValue::from(3)); + } +} + +#[wasm_bindgen] +extern { + fn some_import(); + static A: JsValue; +} + +#[wasm_bindgen] +pub fn bar(_: &str) -> JsValue { + some_import(); + A.clone() +} + +#[wasm_bindgen] +pub fn baz(_: JsValue) { +} + +#[test] +fn test_foo() { + foo(false); + A::new().foo(); +} From 3c52a822138f356c1ef5a33afd33f935feee3f48 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 09:55:45 -0700 Subject: [PATCH 14/24] Remove unused import --- tests/all/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/all/main.rs b/tests/all/main.rs index 607b8f6d..8de76d9a 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -2,7 +2,7 @@ extern crate wasm_bindgen_test_project_builder as project_builder; -use project_builder::{project, run}; +use project_builder::project; mod comments; mod dependencies; From 6edf063c9471a872017b0c73dda29d012a4c9b99 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 09:57:41 -0700 Subject: [PATCH 15/24] Allow disabling `--debug` in `wasm-bindgen-test-runner` Afterwards remove the `non_debug` test as we're running the entire test suite in non-debug mode! --- .travis.yml | 1 + .../src/bin/wasm-bindgen-test-runner/main.rs | 3 +- tests/all/main.rs | 1 - tests/all/non_debug.rs | 48 ------------------- tests/wasm/classes.js | 4 ++ tests/wasm/simple.js | 4 ++ 6 files changed, 11 insertions(+), 50 deletions(-) delete mode 100644 tests/all/non_debug.rs diff --git a/.travis.yml b/.travis.yml index e77ead9f..7a71eb82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,6 +52,7 @@ matrix: script: - cargo test --release - cargo test --target wasm32-unknown-unknown + - WASM_BINDGEN_NO_DEBUG=1 cargo test --target wasm32-unknown-unknown - cargo test --target wasm32-unknown-unknown --features serde-serialize # Check JS output from all tests against eslint - npm run run-lint-generated-tests diff --git a/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs b/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs index 695359f0..e03dc8d7 100644 --- a/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs +++ b/crates/cli/src/bin/wasm-bindgen-test-runner/main.rs @@ -123,11 +123,12 @@ fn rmain() -> Result<(), Error> { node = !custom.payload().contains(&0x01); } let headless = env::var("NO_HEADLESS").is_err(); + let debug = env::var("WASM_BINDGEN_NO_DEBUG").is_err(); // Make the generated bindings available for the tests to execute against. shell.status("Executing bindgen..."); let mut b = Bindgen::new(); - b.debug(true) + b.debug(debug) .nodejs(node) .input_module(module, wasm, |w| parity_wasm::serialize(w).unwrap()) .keep_debug(false) diff --git a/tests/all/main.rs b/tests/all/main.rs index 8de76d9a..d05b4c1d 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -10,5 +10,4 @@ mod js_objects; mod imports; mod simple; mod node; -mod non_debug; mod typescript; diff --git a/tests/all/non_debug.rs b/tests/all/non_debug.rs deleted file mode 100644 index e43532da..00000000 --- a/tests/all/non_debug.rs +++ /dev/null @@ -1,48 +0,0 @@ -use super::project; - -#[test] -fn works() { - project() - .debug(false) - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub struct A {} - - #[wasm_bindgen] - impl A { - pub fn new() -> A { - A {} - } - } - - #[wasm_bindgen] - pub fn clone(a: &JsValue) -> JsValue { - drop(a.clone()); - a.clone() - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - let sym = Symbol('a'); - assert.strictEqual(wasm.clone(sym), sym); - let a = wasm.A.new(); - a.free(); - } - "#, - ) - .test(); -} diff --git a/tests/wasm/classes.js b/tests/wasm/classes.js index 6764a0a8..1ffd4a9b 100644 --- a/tests/wasm/classes.js +++ b/tests/wasm/classes.js @@ -31,6 +31,10 @@ exports.js_strings = () => { }; exports.js_exceptions = () => { + // this test only works when `--debug` is passed to `wasm-bindgen` (or the + // equivalent thereof) + if (require('process').env.WASM_BINDGEN_NO_DEBUG) + return; assert.throws(() => new wasm.ClassesExceptions1(), /cannot invoke `new` directly/); let a = wasm.ClassesExceptions1.new(); a.free(); diff --git a/tests/wasm/simple.js b/tests/wasm/simple.js index 34d5fef0..1ac7d041 100644 --- a/tests/wasm/simple.js +++ b/tests/wasm/simple.js @@ -22,6 +22,10 @@ exports.test_return_a_string = function() { }; exports.test_wrong_types = function() { + // this test only works when `--debug` is passed to `wasm-bindgen` (or the + // equivalent thereof) + if (require('process').env.WASM_BINDGEN_NO_DEBUG) + return; assert.throws(() => wasm.simple_int('a'), /expected a number argument/); assert.throws(() => wasm.simple_str(3), /expected a string argument/); }; From d978878d862d7c4fd6fde710c1c44f87bec196ca Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 09:59:05 -0700 Subject: [PATCH 16/24] Remove `add_headless` test We've got tons of other headless tests, no need for this particular one to stick around! --- tests/all/simple.rs | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/tests/all/simple.rs b/tests/all/simple.rs index 6b441c2b..8fbea188 100644 --- a/tests/all/simple.rs +++ b/tests/all/simple.rs @@ -1,38 +1,5 @@ use super::project; -#[test] -fn add_headless() { - project() - .headless(true) - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn add(a: u32, b: u32) -> u32 { - a + b - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - console.log("start `add_headless` test"); - assert.strictEqual(wasm.add(1, 2), 3); - console.log("end `add_headless` test"); - } - "#, - ) - .test(); -} - #[test] fn no_std() { project() From 59d4c5a06acabdcfa4fe5fd57874e084d7e71d7a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 10:00:01 -0700 Subject: [PATCH 17/24] Remove dependencies_work test The fact that `web-sys` works at all obviates the need for this test! --- tests/all/dependencies.rs | 91 --------------------------------------- 1 file changed, 91 deletions(-) diff --git a/tests/all/dependencies.rs b/tests/all/dependencies.rs index 624ca000..49577e23 100644 --- a/tests/all/dependencies.rs +++ b/tests/all/dependencies.rs @@ -1,96 +1,5 @@ use super::project; -#[test] -fn dependencies_work() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - extern crate dependency; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn return_dep_ty(x: f64) -> dependency::Foo { - dependency::Foo(x) - } - - #[wasm_bindgen] - pub fn takes_own_dep_ty(foo: dependency::Foo) -> f64 { - foo.0 - } - - #[wasm_bindgen] - pub fn takes_ref_dep_ty(foo: &dependency::Foo) -> f64 { - foo.0 - } - - #[wasm_bindgen] - pub fn takes_mut_dep_ty(foo: &mut dependency::Foo, x: f64) { - foo.0 = x; - } - "#, - ) - .add_local_dependency("dependency", "vendor/dependency") - .file( - "vendor/dependency/Cargo.toml", - &format!( - r#" - [package] - name = "dependency" - version = "0.0.1" - authors = [] - - [dependencies] - wasm-bindgen = {{ path = '{}' }} - "#, - env!("CARGO_MANIFEST_DIR") - ), - ) - .file( - "vendor/dependency/src/lib.rs", - r#" - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub struct Foo(pub f64); - - #[wasm_bindgen] - impl Foo { - pub fn new(x: f64) -> Foo { Foo(x) } - pub fn get(&self) -> f64 { self.0 } - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - const foo = wasm.return_dep_ty(42); - assert.strictEqual(foo.get(), 42); - - const x = wasm.takes_ref_dep_ty(foo); - assert.strictEqual(x, 42); - - const y = 1337; - wasm.takes_mut_dep_ty(foo, y); - assert.strictEqual(foo.get(), y); - - const z = wasm.takes_own_dep_ty(foo); - assert.strictEqual(z, y); - assert.strictEqual(foo.ptr, 0); - } - "#, - ) - .test(); -} - #[test] fn same_api_two_crates() { project() From 28036db2629b407eb1e814a517d53dc3c5d77a10 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 10:06:45 -0700 Subject: [PATCH 18/24] Move `node` test over to `wasm` --- tests/all/main.rs | 1 - tests/all/node.rs | 161 --------------------------------------------- tests/wasm/main.rs | 1 + tests/wasm/node.js | 34 ++++++++++ tests/wasm/node.rs | 105 +++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 162 deletions(-) delete mode 100644 tests/all/node.rs create mode 100644 tests/wasm/node.js create mode 100644 tests/wasm/node.rs diff --git a/tests/all/main.rs b/tests/all/main.rs index d05b4c1d..a58fedfa 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -9,5 +9,4 @@ mod dependencies; mod js_objects; mod imports; mod simple; -mod node; mod typescript; diff --git a/tests/all/node.rs b/tests/all/node.rs deleted file mode 100644 index 7928c70c..00000000 --- a/tests/all/node.rs +++ /dev/null @@ -1,161 +0,0 @@ -use super::project; - -#[test] -fn works() { - project() - .debug(false) - .nodejs_experimental_modules(false) - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "./test")] - extern { - static FOO: JsValue; - fn hit(); - } - - #[wasm_bindgen] - pub fn run() { - hit(); - assert_eq!(FOO.as_f64(), Some(1.0)); - } - - #[wasm_bindgen] - pub struct Foo { - contents: u32, - } - - #[wasm_bindgen] - impl Foo { - pub fn new() -> Foo { - Foo::with_contents(0) - } - pub fn with_contents(a: u32) -> Foo { - Foo { contents: a } - } - pub fn add(&mut self, amt: u32) -> u32 { - self.contents += amt; - self.contents - } - } - - #[wasm_bindgen] - pub enum Color { - Green, - Yellow, - Red, - } - #[wasm_bindgen] - pub fn cycle(color: Color) -> Color { - match color { - Color::Green => Color::Yellow, - Color::Yellow => Color::Red, - Color::Red => Color::Green, - } - } - - #[wasm_bindgen] - pub fn math(a: f32, b: f64) -> f64 { - b.acos() + - b.asin() + - b.atan() + - b.atan2(b) + - b.cbrt() + - b.cosh() + - b.exp_m1() + - b.ln_1p() + - b.sinh() + - b.tan() + - b.tanh() + - b.hypot(b) + - b.cos() + - b.exp() + - b.exp2() + - b.mul_add(b, b) + - b.ln() + - b.log(b) + - b.log10() + - b.log2() + - b.powi(8) + - b.powf(b) + - b.round() + - b.sin() + - b.abs() + - b.signum() + - b.floor() + - b.ceil() + - b.trunc() + - b.sqrt() + - (b % (a as f64)) + - ((a.cos() + - a.exp() + - a.exp2() + - a.mul_add(a, a) + - a.ln() + - a.log(a) + - a.log10() + - a.log2() + - a.powi(8) + - a.powf(a) + - a.round() + - a.sin() + - a.abs() + - a.signum() + - a.floor() + - a.ceil() + - a.trunc() + - a.sqrt() + - (a % (b as f32))) as f64) + - (b + 2.0f64.powf(a as f64)) - } - "#, - ) - .file( - "test.js", - r#" - const assert = require('assert'); - - var called = false; - - module.exports.hit = function() { - called = true; - }; - - module.exports.FOO = 1.0; - - const { math, run, Foo, Color, cycle } = require('./out'); - - module.exports.test = function() { - run(); - assert.strictEqual(called, true); - - var r = Foo.new(); - assert.strictEqual(r.add(0), 0); - assert.strictEqual(r.add(1), 1); - assert.strictEqual(r.add(2), 3); - r.free(); - - var r2 = Foo.with_contents(10); - assert.strictEqual(r2.add(0), 10); - assert.strictEqual(r2.add(1), 11); - assert.strictEqual(r2.add(2), 13); - r2.free(); - - assert.strictEqual(Color.Green, 0); - assert.strictEqual(Color.Yellow, 1); - assert.strictEqual(Color.Red, 2); - assert.strictEqual(Object.keys(Color).length, 3); - assert.strictEqual(cycle(Color.Green), Color.Yellow); - - math(1.0, 2.0); - }; - "#, - ) - .test(); -} diff --git a/tests/wasm/main.rs b/tests/wasm/main.rs index 3a1a373b..eccf57d0 100644 --- a/tests/wasm/main.rs +++ b/tests/wasm/main.rs @@ -18,6 +18,7 @@ pub mod imports; pub mod import_class; pub mod js_objects; pub mod math; +pub mod node; pub mod option; pub mod optional_primitives; pub mod simple; diff --git a/tests/wasm/node.js b/tests/wasm/node.js new file mode 100644 index 00000000..1887904f --- /dev/null +++ b/tests/wasm/node.js @@ -0,0 +1,34 @@ +const assert = require('assert'); +const wasm = require('wasm-bindgen-test'); + +var called = false; + +exports.hit = function() { + called = true; +}; + +exports.FOO = 1.0; + +exports.test_works = function() { + assert.strictEqual(called, true); + + var r = wasm.Foo.new(); + assert.strictEqual(r.add(0), 0); + assert.strictEqual(r.add(1), 1); + assert.strictEqual(r.add(2), 3); + r.free(); + + var r2 = wasm.Foo.with_contents(10); + assert.strictEqual(r2.add(0), 10); + assert.strictEqual(r2.add(1), 11); + assert.strictEqual(r2.add(2), 13); + r2.free(); + + assert.strictEqual(wasm.Color.Green, 0); + assert.strictEqual(wasm.Color.Yellow, 1); + assert.strictEqual(wasm.Color.Red, 2); + assert.strictEqual(Object.keys(wasm.Color).length, 3); + assert.strictEqual(wasm.cycle(wasm.Color.Green), wasm.Color.Yellow); + + wasm.node_math(1.0, 2.0); +}; diff --git a/tests/wasm/node.rs b/tests/wasm/node.rs new file mode 100644 index 00000000..cee7986e --- /dev/null +++ b/tests/wasm/node.rs @@ -0,0 +1,105 @@ +use wasm_bindgen_test::*; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen(module = "tests/wasm/node.js", version = "*")] +extern { + fn test_works(); + static FOO: JsValue; + fn hit(); +} + +#[wasm_bindgen_test] +fn works() { + hit(); + assert_eq!(FOO.as_f64(), Some(1.0)); + test_works(); +} + +#[wasm_bindgen] +pub struct Foo { + contents: u32, +} + +#[wasm_bindgen] +impl Foo { + pub fn new() -> Foo { + Foo::with_contents(0) + } + pub fn with_contents(a: u32) -> Foo { + Foo { contents: a } + } + pub fn add(&mut self, amt: u32) -> u32 { + self.contents += amt; + self.contents + } +} + +#[wasm_bindgen] +pub enum Color { + Green, + Yellow, + Red, +} +#[wasm_bindgen] +pub fn cycle(color: Color) -> Color { + match color { + Color::Green => Color::Yellow, + Color::Yellow => Color::Red, + Color::Red => Color::Green, + } +} + +#[wasm_bindgen] +pub fn node_math(a: f32, b: f64) -> f64 { + b.acos() + + b.asin() + + b.atan() + + b.atan2(b) + + b.cbrt() + + b.cosh() + + b.exp_m1() + + b.ln_1p() + + b.sinh() + + b.tan() + + b.tanh() + + b.hypot(b) + + b.cos() + + b.exp() + + b.exp2() + + b.mul_add(b, b) + + b.ln() + + b.log(b) + + b.log10() + + b.log2() + + b.powi(8) + + b.powf(b) + + b.round() + + b.sin() + + b.abs() + + b.signum() + + b.floor() + + b.ceil() + + b.trunc() + + b.sqrt() + + (b % (a as f64)) + + ((a.cos() + + a.exp() + + a.exp2() + + a.mul_add(a, a) + + a.ln() + + a.log(a) + + a.log10() + + a.log2() + + a.powi(8) + + a.powf(a) + + a.round() + + a.sin() + + a.abs() + + a.signum() + + a.floor() + + a.ceil() + + a.trunc() + + a.sqrt() + + (a % (b as f32))) as f64) + + (b + 2.0f64.powf(a as f64)) +} From 005f7eb9fad5da9426cd48dc0b2ec440759b9bc1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 10:42:08 -0700 Subject: [PATCH 19/24] Migrate rest of `dependencies` test to `wasm` --- Cargo.toml | 2 + tests/all/dependencies.rs | 118 ----------------------------------- tests/all/main.rs | 1 - tests/crates/a/Cargo.toml | 9 +++ tests/crates/a/src/lib.rs | 14 +++++ tests/crates/b/Cargo.toml | 9 +++ tests/crates/b/src/lib.rs | 14 +++++ tests/wasm/duplicate_deps.js | 17 +++++ tests/wasm/duplicate_deps.rs | 18 ++++++ tests/wasm/main.rs | 5 +- 10 files changed, 87 insertions(+), 120 deletions(-) delete mode 100644 tests/all/dependencies.rs create mode 100644 tests/crates/a/Cargo.toml create mode 100644 tests/crates/a/src/lib.rs create mode 100644 tests/crates/b/Cargo.toml create mode 100644 tests/crates/b/src/lib.rs create mode 100644 tests/wasm/duplicate_deps.js create mode 100644 tests/wasm/duplicate_deps.rs diff --git a/Cargo.toml b/Cargo.toml index 869d8a02..727270d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,8 @@ serde_json = { version = "1.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = { path = 'crates/test', version = '=0.2.15' } serde_derive = "1.0" +wasm-bindgen-test-crate-a = { path = 'tests/crates/a' } +wasm-bindgen-test-crate-b = { path = 'tests/crates/b' } [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] wasm-bindgen-test-project-builder = { path = "crates/test-project-builder", version = '=0.2.15' } diff --git a/tests/all/dependencies.rs b/tests/all/dependencies.rs deleted file mode 100644 index 49577e23..00000000 --- a/tests/all/dependencies.rs +++ /dev/null @@ -1,118 +0,0 @@ -use super::project; - -#[test] -fn same_api_two_crates() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - extern crate a; - extern crate b; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "./foo")] - extern { - fn assert_next_undefined(); - fn assert_next_ten(); - } - - #[wasm_bindgen] - pub fn test() { - assert_next_undefined(); - a::test(); - assert_next_ten(); - b::test(); - } - "#, - ) - .file( - "foo.js", - r#" - import { strictEqual } from "assert"; - - let next = null; - - export function assert_next_undefined() { - next = undefined; - } - - export function assert_next_ten() { - next = 10; - } - - export function foo(a) { - console.log(a, next); - strictEqual(a, next); - next = null; - } - "#, - ) - .add_local_dependency("a", "a") - .file( - "a/Cargo.toml", - &format!(r#" - [package] - name = 'a' - version = '0.0.0' - - [dependencies] - wasm-bindgen = {{ path = '{}' }} - "#, - env!("CARGO_MANIFEST_DIR") - ), - ) - .file( - "a/src/lib.rs", - " - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = \"./foo\")] - extern { - fn foo(); - } - - pub fn test() { - foo(); - } - ", - ) - .add_local_dependency("b", "b") - .file( - "b/Cargo.toml", - &format!(r#" - [package] - name = 'b' - version = '0.0.0' - - [dependencies] - wasm-bindgen = {{ path = '{}' }} - "#, - env!("CARGO_MANIFEST_DIR") - ), - ) - .file( - "b/src/lib.rs", - " - #![feature(use_extern_macros)] - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = \"./foo\")] - extern { - fn foo(x: u32); - } - - pub fn test() { - foo(10); - } - ", - ) - .test(); -} diff --git a/tests/all/main.rs b/tests/all/main.rs index a58fedfa..5f1822f5 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -5,7 +5,6 @@ extern crate wasm_bindgen_test_project_builder as project_builder; use project_builder::project; mod comments; -mod dependencies; mod js_objects; mod imports; mod simple; diff --git a/tests/crates/a/Cargo.toml b/tests/crates/a/Cargo.toml new file mode 100644 index 00000000..d8d93d0a --- /dev/null +++ b/tests/crates/a/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "wasm-bindgen-test-crate-a" +version = "0.1.0" +authors = ["The wasm-bindgen Authors"] +license = "MIT/Apache-2.0" +description = "internal test crate for wasm-bindgen" + +[dependencies] +wasm-bindgen = { path = '../../..', version = '0.2' } diff --git a/tests/crates/a/src/lib.rs b/tests/crates/a/src/lib.rs new file mode 100644 index 00000000..f3a4c04e --- /dev/null +++ b/tests/crates/a/src/lib.rs @@ -0,0 +1,14 @@ +#![feature(use_extern_macros)] + +extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js", version = "*")] +extern { + fn foo(); +} + +pub fn test() { + foo(); +} diff --git a/tests/crates/b/Cargo.toml b/tests/crates/b/Cargo.toml new file mode 100644 index 00000000..aee2848b --- /dev/null +++ b/tests/crates/b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "wasm-bindgen-test-crate-b" +version = "0.1.0" +authors = ["The wasm-bindgen Authors"] +license = "MIT/Apache-2.0" +description = "internal test crate for wasm-bindgen" + +[dependencies] +wasm-bindgen = { path = '../../..', version = '0.2' } diff --git a/tests/crates/b/src/lib.rs b/tests/crates/b/src/lib.rs new file mode 100644 index 00000000..6d57e404 --- /dev/null +++ b/tests/crates/b/src/lib.rs @@ -0,0 +1,14 @@ +#![feature(use_extern_macros)] + +extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js", version = "*")] +extern { + fn foo(x: u32); +} + +pub fn test() { + foo(10); +} diff --git a/tests/wasm/duplicate_deps.js b/tests/wasm/duplicate_deps.js new file mode 100644 index 00000000..b69139df --- /dev/null +++ b/tests/wasm/duplicate_deps.js @@ -0,0 +1,17 @@ +const assert = require('assert'); + +let next = null; + +exports.assert_next_undefined = function() { + next = undefined; +}; + +exports.assert_next_ten = function() { + next = 10; +}; + +exports.foo = function(a) { + console.log(a, next); + assert.strictEqual(a, next); + next = null; +}; diff --git a/tests/wasm/duplicate_deps.rs b/tests/wasm/duplicate_deps.rs new file mode 100644 index 00000000..d19e4134 --- /dev/null +++ b/tests/wasm/duplicate_deps.rs @@ -0,0 +1,18 @@ +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; +use wasm_bindgen_test_crate_a as a; +use wasm_bindgen_test_crate_b as b; + +#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js", version = "*")] +extern { + fn assert_next_undefined(); + fn assert_next_ten(); +} + +#[wasm_bindgen_test] +fn works() { + assert_next_undefined(); + a::test(); + assert_next_ten(); + b::test(); +} diff --git a/tests/wasm/main.rs b/tests/wasm/main.rs index eccf57d0..74be2707 100644 --- a/tests/wasm/main.rs +++ b/tests/wasm/main.rs @@ -3,6 +3,8 @@ extern crate wasm_bindgen_test; extern crate wasm_bindgen; +extern crate wasm_bindgen_test_crate_a; +extern crate wasm_bindgen_test_crate_b; #[cfg(feature = "serde-serialize")] #[macro_use] @@ -12,10 +14,11 @@ pub mod api; pub mod char; pub mod classes; pub mod closures; +pub mod duplicate_deps; pub mod duplicates; pub mod enums; -pub mod imports; pub mod import_class; +pub mod imports; pub mod js_objects; pub mod math; pub mod node; From 0a2399a7f1085a7f6171cc2388bb031f7b7405e5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 11:08:35 -0700 Subject: [PATCH 20/24] Migrate `#![no_std]` tests to `wasm` This required getting a little creative in a few places, but otherwise these tests shouldn't need the test builder any more. --- .travis.yml | 1 + Cargo.toml | 1 + tests/all/main.rs | 1 - tests/all/simple.rs | 109 ---------------------------------- tests/no-std/Cargo.toml | 10 ++++ tests/no-std/lib.rs | 0 tests/no-std/test.rs | 28 +++++++++ tests/std-crate-no-std-dep | 0 tests/std-crate-no-std-dep.rs | 30 ++++++++++ 9 files changed, 70 insertions(+), 110 deletions(-) delete mode 100644 tests/all/simple.rs create mode 100644 tests/no-std/Cargo.toml create mode 100644 tests/no-std/lib.rs create mode 100644 tests/no-std/test.rs create mode 100644 tests/std-crate-no-std-dep create mode 100644 tests/std-crate-no-std-dep.rs diff --git a/.travis.yml b/.travis.yml index 7a71eb82..0173cb89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,7 @@ matrix: - cargo test --target wasm32-unknown-unknown - WASM_BINDGEN_NO_DEBUG=1 cargo test --target wasm32-unknown-unknown - cargo test --target wasm32-unknown-unknown --features serde-serialize + - cargo test --target wasm32-unknown-unknown -p no-std # Check JS output from all tests against eslint - npm run run-lint-generated-tests # Check Examples against eslint diff --git a/Cargo.toml b/Cargo.toml index 727270d7..06eec5d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,7 @@ members = [ "examples/performance", "examples/smorgasboard", "examples/wasm-in-wasm", + "tests/no-std", ] [patch.crates-io] diff --git a/tests/all/main.rs b/tests/all/main.rs index 5f1822f5..4e68040e 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -7,5 +7,4 @@ use project_builder::project; mod comments; mod js_objects; mod imports; -mod simple; mod typescript; diff --git a/tests/all/simple.rs b/tests/all/simple.rs deleted file mode 100644 index 8fbea188..00000000 --- a/tests/all/simple.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::project; - -#[test] -fn no_std() { - project() - .no_std(true) - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - #![no_std] - #![allow(dead_code)] - - extern crate wasm_bindgen; - extern crate std as _some_other_name; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "./foo")] - extern { - fn test(a: &str); - - type Js; - #[wasm_bindgen(constructor)] - fn new() -> Js; - #[wasm_bindgen(method)] - fn init(this: &Js); - } - - #[wasm_bindgen] - pub fn foo(_a: u32) {} - "#, - ) - .file( - "test.js", - r#" - import * as wasm from "./out_bg"; - - export function test() { - // mostly just testing the project compiles here - wasm.foo(1); - } - "#, - ) - .file( - "foo.js", - r#" - export class Js { - init() { - } - } - "#, - ) - .test(); -} - -#[test] -fn no_std_class() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - #![no_std] - #![allow(dead_code)] - - extern crate wasm_bindgen; - extern crate std as _some_other_name; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - extern { - fn test(a: &str); - - type Js; - #[wasm_bindgen(constructor)] - fn new() -> Js; - #[wasm_bindgen(method, structural)] - fn init(this: &Js); - } - - #[wasm_bindgen] - pub fn foo(_a: u32) {} - - #[wasm_bindgen] - pub struct A {} - - #[wasm_bindgen] - impl A { - pub fn foo(&self) {} - pub fn bar(&mut self) {} - } - "#, - ) - .file( - "test.js", - r#" - import * as wasm from "./out_bg"; - - export function test() { - // mostly just testing the project compiles here - wasm.foo(1); - } - "#, - ) - .test(); -} - diff --git a/tests/no-std/Cargo.toml b/tests/no-std/Cargo.toml new file mode 100644 index 00000000..23f30400 --- /dev/null +++ b/tests/no-std/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "no-std" +version = "0.1.0" +authors = ["The wasm-bindgen Developers"] + +[lib] +path = "test.rs" + +[dependencies] +wasm-bindgen = { path = '../..', default-features = false } diff --git a/tests/no-std/lib.rs b/tests/no-std/lib.rs new file mode 100644 index 00000000..e69de29b diff --git a/tests/no-std/test.rs b/tests/no-std/test.rs new file mode 100644 index 00000000..4dc5c91e --- /dev/null +++ b/tests/no-std/test.rs @@ -0,0 +1,28 @@ +//! This is a test that we compile `wasm-bindgen` itself in `no_std` mode and we +//! can export/import various items. +//! +//! This doesn't actually run any tests, it's mostly a compile-time verification +//! that things work. + +#![feature(use_extern_macros)] +#![no_std] +#![allow(dead_code)] + +extern crate wasm_bindgen; +extern crate std as _some_other_name; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn foo(_a: u32) {} + +#[wasm_bindgen] +extern { + fn test(a: &str); + + type Js; + #[wasm_bindgen(constructor)] + fn new() -> Js; + #[wasm_bindgen(method, structural)] + fn init(this: &Js); +} diff --git a/tests/std-crate-no-std-dep b/tests/std-crate-no-std-dep new file mode 100644 index 00000000..e69de29b diff --git a/tests/std-crate-no-std-dep.rs b/tests/std-crate-no-std-dep.rs new file mode 100644 index 00000000..77a9a11e --- /dev/null +++ b/tests/std-crate-no-std-dep.rs @@ -0,0 +1,30 @@ +//! This is a test that we can define items in a `#![no_std]` crate when +//! `wasm-bindgen` is compiled itself with the `std` feature and everything +//! works out just fine. + +#![feature(use_extern_macros)] +#![no_std] + +extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern { + fn test(a: &str); + + type Js; + #[wasm_bindgen(constructor)] + fn new() -> Js; + #[wasm_bindgen(method, structural)] + fn init(this: &Js); +} + +#[wasm_bindgen] +pub struct A {} + +#[wasm_bindgen] +impl A { + pub fn foo(&self) {} + pub fn bar(&mut self) {} +} From 0fbdc7682c9b999b2beba490e0aac84e361325cb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 11:10:19 -0700 Subject: [PATCH 21/24] Remove stray file no longer needed --- tests/all/js_objects.rs | 0 tests/all/main.rs | 1 - 2 files changed, 1 deletion(-) delete mode 100644 tests/all/js_objects.rs diff --git a/tests/all/js_objects.rs b/tests/all/js_objects.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/all/main.rs b/tests/all/main.rs index 4e68040e..e31d286c 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -5,6 +5,5 @@ extern crate wasm_bindgen_test_project_builder as project_builder; use project_builder::project; mod comments; -mod js_objects; mod imports; mod typescript; From 7f8d510f3db535bff2429097b514cc55f64543f5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 11:28:08 -0700 Subject: [PATCH 22/24] Move `unused_imports_not_generated` test to wasm --- tests/all/imports.rs | 36 ------------------------------------ tests/wasm/imports.js | 7 +++++++ tests/wasm/imports.rs | 8 ++++++++ 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/tests/all/imports.rs b/tests/all/imports.rs index 0a7add00..c290c3ec 100644 --- a/tests/all/imports.rs +++ b/tests/all/imports.rs @@ -1,41 +1,5 @@ use super::project; -#[test] -fn unused_imports_not_generated() { - let mut project = project(); - - project - .debug(false) - .file("src/lib.rs", r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - extern { - pub fn foo(); - } - - #[wasm_bindgen] - pub fn run() { - } - "#) - .file("test.js", r#" - import { run } from "./out"; - - export function test() { - run(); - } - "#) - .test(); - - let contents = project.read_js(); - assert!(contents.contains("run"), "didn't find `run` in {}", contents); - assert!(!contents.contains("foo"), "found `foo` in {}", contents); -} - #[test] fn versions() { project() diff --git a/tests/wasm/imports.js b/tests/wasm/imports.js index 57fd962c..a12d7b67 100644 --- a/tests/wasm/imports.js +++ b/tests/wasm/imports.js @@ -1,5 +1,6 @@ const assert = require('assert'); const wasm = require('wasm-bindgen-test'); +const fs = require('fs'); let ARG = null; let ANOTHER_ARG = null; @@ -93,3 +94,9 @@ exports.interpret_2_as_custom_type = function() { exports.baz$ = function() {}; exports.$foo = 1.0; + +exports.assert_dead_import_not_generated = function() { + const filename = require.resolve("wasm-bindgen-test"); + const bindings = fs.readFileSync(filename); + assert.ok(!bindings.includes("unused_import")); +}; diff --git a/tests/wasm/imports.rs b/tests/wasm/imports.rs index 40f0f7ac..731d24f7 100644 --- a/tests/wasm/imports.rs +++ b/tests/wasm/imports.rs @@ -47,6 +47,9 @@ extern { fn renamed_with_dollar_sign(); #[wasm_bindgen(js_name = "$foo")] static RENAMED: JsValue; + + fn unused_import(); + fn assert_dead_import_not_generated(); } #[wasm_bindgen] @@ -168,3 +171,8 @@ fn rename_with_string() { fn rename_static_with_string() { assert_eq!(RENAMED.as_f64(), Some(1.0)); } + +#[wasm_bindgen_test] +fn dead_imports_not_generated() { + assert_dead_import_not_generated(); +} From d5b81595ec910b6a4ba7a935a55c1c80731c6bde Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 10:55:04 -0700 Subject: [PATCH 23/24] Remove support for the `version` attribute First added in #161 this never ended up panning out, so let's remove the experimental suport which isn't actually used by anything today and hold off on any other changes until an RFC happens. --- crates/backend/src/ast.rs | 26 ---------- crates/backend/src/util.rs | 1 - crates/cli-support/Cargo.toml | 1 - crates/cli-support/src/js/mod.rs | 61 ------------------------ crates/cli-support/src/lib.rs | 3 -- crates/js-sys/tests/wasm/Function.rs | 2 +- crates/js-sys/tests/wasm/Generator.rs | 2 +- crates/js-sys/tests/wasm/Object.rs | 2 +- crates/js-sys/tests/wasm/Proxy.rs | 2 +- crates/js-sys/tests/wasm/Reflect.rs | 2 +- crates/js-sys/tests/wasm/Symbol.rs | 2 +- crates/macro-support/src/parser.rs | 24 ---------- crates/shared/src/lib.rs | 1 - crates/webidl-tests/build.rs | 2 +- crates/webidl/src/lib.rs | 2 - guide/src/design/import-customization.md | 31 ------------ tests/all/imports.rs | 52 -------------------- tests/all/main.rs | 1 - tests/crates/a/src/lib.rs | 2 +- tests/crates/b/src/lib.rs | 2 +- tests/wasm/api.rs | 2 +- tests/wasm/char.rs | 2 +- tests/wasm/classes.rs | 2 +- tests/wasm/closures.rs | 2 +- tests/wasm/duplicate_deps.rs | 2 +- tests/wasm/duplicates.rs | 8 ++-- tests/wasm/enums.rs | 2 +- tests/wasm/import_class.rs | 2 +- tests/wasm/imports.rs | 2 +- tests/wasm/js_objects.rs | 2 +- tests/wasm/math.rs | 4 +- tests/wasm/node.rs | 2 +- tests/wasm/option.rs | 2 +- tests/wasm/optional_primitives.rs | 2 +- tests/wasm/simple.rs | 2 +- tests/wasm/slice.rs | 6 +-- tests/wasm/structural.rs | 2 +- tests/wasm/u64.rs | 2 +- tests/wasm/validate_prt.rs | 2 +- 39 files changed, 34 insertions(+), 237 deletions(-) delete mode 100644 tests/all/imports.rs diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 375af0a2..852595c4 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -56,7 +56,6 @@ pub enum MethodSelf { #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] pub struct Import { pub module: Option, - pub version: Option, pub js_namespace: Option, pub kind: ImportKind, } @@ -301,33 +300,8 @@ impl Variant { impl Import { fn shared(&self) -> Result { - match (&self.module, &self.version) { - (&Some(ref m), None) if m.starts_with("./") => {} - (&Some(ref m), &Some(_)) if m.starts_with("./") => { - panic!( - "when a module path starts with `./` that indicates \ - that a local file is being imported so the `version` \ - key cannot also be specified" - ); - } - (&Some(_), &Some(_)) => {} - (&Some(_), &None) => panic!( - "when the `module` directive doesn't start with `./` \ - then it's interpreted as an NPM package which requires \ - a `version` to be specified as well, try using \ - #[wasm_bindgen(module = \"...\", version = \"...\")]" - ), - (&None, &Some(_)) => { - panic!( - "the #[wasm_bindgen(version = \"...\")] attribute can only \ - be used when `module = \"...\"` is also specified" - ); - } - (&None, &None) => {} - } Ok(shared::Import { module: self.module.clone(), - version: self.version.clone(), js_namespace: self.js_namespace.as_ref().map(|s| s.to_string()), kind: self.kind.shared(), }) diff --git a/crates/backend/src/util.rs b/crates/backend/src/util.rs index bab8cb5d..f0bf53e7 100644 --- a/crates/backend/src/util.rs +++ b/crates/backend/src/util.rs @@ -94,7 +94,6 @@ pub fn ident_ty(ident: Ident) -> syn::Type { pub fn wrap_import_function(function: ast::ImportFunction) -> ast::Import { ast::Import { module: None, - version: None, js_namespace: None, kind: ast::ImportKind::Function(function), } diff --git a/crates/cli-support/Cargo.toml b/crates/cli-support/Cargo.toml index 6dc5a91a..2c16e608 100644 --- a/crates/cli-support/Cargo.toml +++ b/crates/cli-support/Cargo.toml @@ -15,7 +15,6 @@ base64 = "0.9" failure = "0.1.2" parity-wasm = "0.31" serde = "1.0" -serde_derive = "1.0" serde_json = "1.0" tempfile = "3.0" wasm-bindgen-shared = { path = "../shared", version = '=0.2.15' } diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 9a63fc5d..e1ad5939 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -5,7 +5,6 @@ use std::mem; use failure::{Error, ResultExt}; use parity_wasm; use parity_wasm::elements::*; -use serde_json; use shared; use wasm_gc; @@ -43,7 +42,6 @@ pub struct Context<'a> { pub exported_classes: HashMap, pub function_table_needed: bool, pub run_descriptor: &'a Fn(&str) -> Option>, - pub module_versions: Vec<(String, String)>, } #[derive(Default)] @@ -458,7 +456,6 @@ impl<'a> Context<'a> { self.export_table(); self.gc()?; - self.add_wasm_pack_section(); while js.contains("\n\n\n") { js = js.replace("\n\n\n", "\n\n"); @@ -1629,28 +1626,6 @@ impl<'a> Context<'a> { self.globals.push_str("\n"); } - fn add_wasm_pack_section(&mut self) { - if self.module_versions.len() == 0 { - return; - } - - #[derive(Serialize)] - struct WasmPackSchema<'a> { - version: &'a str, - modules: &'a [(String, String)], - } - - let contents = serde_json::to_string(&WasmPackSchema { - version: "0.0.1", - modules: &self.module_versions, - }).unwrap(); - - let mut section = CustomSection::default(); - *section.name_mut() = "__wasm_pack_unstable".to_string(); - *section.payload_mut() = contents.into_bytes(); - self.module.sections_mut().push(Section::Custom(section)); - } - fn use_node_require(&self) -> bool { self.config.nodejs && !self.config.nodejs_experimental_modules } @@ -1766,7 +1741,6 @@ impl<'a, 'b> SubContext<'a, 'b> { } fn generate_import(&mut self, import: &shared::Import) -> Result<(), Error> { - self.validate_import_module(import)?; match import.kind { shared::ImportKind::Function(ref f) => { self.generate_import_function(import, f).with_context(|_| { @@ -1787,41 +1761,6 @@ impl<'a, 'b> SubContext<'a, 'b> { Ok(()) } - fn validate_import_module(&mut self, import: &shared::Import) -> Result<(), Error> { - let version = match import.version { - Some(ref s) => s, - None => return Ok(()), - }; - let module = match import.module { - Some(ref s) => s, - None => return Ok(()), - }; - if module.starts_with("./") { - return Ok(()); - } - let pkg = if module.starts_with("@") { - // Translate `@foo/bar/baz` to `@foo/bar` and `@foo/bar` to itself - let first_slash = match module.find('/') { - Some(i) => i, - None => bail!( - "packages starting with `@` must be of the form \ - `@foo/bar`, but found: `{}`", - module - ), - }; - match module[first_slash + 1..].find('/') { - Some(i) => &module[..i], - None => module, - } - } else { - module.split('/').next().unwrap() - }; - self.cx - .module_versions - .push((pkg.to_string(), version.clone())); - Ok(()) - } - fn generate_import_static( &mut self, info: &shared::Import, diff --git a/crates/cli-support/src/lib.rs b/crates/cli-support/src/lib.rs index d8cb8fdb..5933a691 100644 --- a/crates/cli-support/src/lib.rs +++ b/crates/cli-support/src/lib.rs @@ -2,8 +2,6 @@ extern crate parity_wasm; extern crate wasm_bindgen_shared as shared; -#[macro_use] -extern crate serde_derive; extern crate serde_json; extern crate wasm_gc; extern crate wasmi; @@ -203,7 +201,6 @@ impl Bindgen { config: &self, module: &mut module, function_table_needed: false, - module_versions: Default::default(), run_descriptor: &|name| { let mut v = MyExternals(Vec::new()); match instance.invoke_export(name, &[], &mut v) { diff --git a/crates/js-sys/tests/wasm/Function.rs b/crates/js-sys/tests/wasm/Function.rs index 02e9865f..f2339496 100644 --- a/crates/js-sys/tests/wasm/Function.rs +++ b/crates/js-sys/tests/wasm/Function.rs @@ -29,7 +29,7 @@ fn apply() { assert_eq!(Array::from(&arr).length(), 1); } -#[wasm_bindgen(module = "tests/wasm/Function.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/Function.js")] extern { fn get_function_to_bind() -> Function; fn get_value_to_bind_to() -> JsValue; diff --git a/crates/js-sys/tests/wasm/Generator.rs b/crates/js-sys/tests/wasm/Generator.rs index 6d114b9f..5fb738fc 100644 --- a/crates/js-sys/tests/wasm/Generator.rs +++ b/crates/js-sys/tests/wasm/Generator.rs @@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; use js_sys::*; -#[wasm_bindgen(module = "tests/wasm/Generator.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/Generator.js")] extern { fn one_two_generator() -> Generator; fn dummy_generator() -> Generator; diff --git a/crates/js-sys/tests/wasm/Object.rs b/crates/js-sys/tests/wasm/Object.rs index 80246535..da245a97 100644 --- a/crates/js-sys/tests/wasm/Object.rs +++ b/crates/js-sys/tests/wasm/Object.rs @@ -10,7 +10,7 @@ extern { fn set_foo(this: &Foo42, val: JsValue); } -#[wasm_bindgen(module = "tests/wasm/Object.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/Object.js")] extern { fn map_with_symbol_key() -> Object; fn symbol_key() -> JsValue; diff --git a/crates/js-sys/tests/wasm/Proxy.rs b/crates/js-sys/tests/wasm/Proxy.rs index b362b888..30b23418 100644 --- a/crates/js-sys/tests/wasm/Proxy.rs +++ b/crates/js-sys/tests/wasm/Proxy.rs @@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; use js_sys::*; -#[wasm_bindgen(module = "tests/wasm/Proxy.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/Proxy.js")] extern { fn proxy_target() -> JsValue; fn proxy_handler() -> Object; diff --git a/crates/js-sys/tests/wasm/Reflect.rs b/crates/js-sys/tests/wasm/Reflect.rs index a7c42748..5f6f47f1 100644 --- a/crates/js-sys/tests/wasm/Reflect.rs +++ b/crates/js-sys/tests/wasm/Reflect.rs @@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; use js_sys::*; -#[wasm_bindgen(module = "tests/wasm/Reflect.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/Reflect.js")] extern { fn get_char_at() -> Function; diff --git a/crates/js-sys/tests/wasm/Symbol.rs b/crates/js-sys/tests/wasm/Symbol.rs index cf455c44..a34a1ca2 100644 --- a/crates/js-sys/tests/wasm/Symbol.rs +++ b/crates/js-sys/tests/wasm/Symbol.rs @@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; use js_sys::*; -#[wasm_bindgen(module = "tests/wasm/Symbol.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/Symbol.js")] extern { fn test_has_instance(sym: &Symbol); fn test_is_concat_spreadable(sym: &Symbol); diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 3752251d..9c5bc23c 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -53,17 +53,6 @@ impl BindgenAttrs { .next() } - /// Get the first version attribute - fn version(&self) -> Option<&str> { - self.attrs - .iter() - .filter_map(|a| match a { - BindgenAttr::Version(s) => Some(&s[..]), - _ => None, - }) - .next() - } - /// Whether the catch attribute is present fn catch(&self) -> bool { self.attrs.iter().any(|a| match a { @@ -195,7 +184,6 @@ pub enum BindgenAttr { StaticMethodOf(Ident), JsNamespace(Ident), Module(String), - Version(String), Getter(Option), Setter(Option), Structural, @@ -257,13 +245,6 @@ impl syn::synom::Synom for BindgenAttr { (s.value()) )=> { BindgenAttr::Module } | - do_parse!( - call!(term, "version") >> - punct!(=) >> - s: syn!(syn::LitStr) >> - (s.value()) - )=> { BindgenAttr::Version } - | do_parse!( call!(term, "js_name") >> punct!(=) >> @@ -909,10 +890,6 @@ impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem { BindgenAttrs::find(attrs)? }; let module = item_opts.module().or(opts.module()).map(|s| s.to_string()); - let version = item_opts - .version() - .or(opts.version()) - .map(|s| s.to_string()); let js_namespace = item_opts.js_namespace().or(opts.js_namespace()).cloned(); let kind = match self { syn::ForeignItem::Fn(f) => f.convert((item_opts, &module))?, @@ -923,7 +900,6 @@ impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem { program.imports.push(ast::Import { module, - version, js_namespace, kind, }); diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index c7b7a69f..bfdf34dc 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -24,7 +24,6 @@ pub struct Program { #[derive(Deserialize, Serialize)] pub struct Import { pub module: Option, - pub version: Option, pub js_namespace: Option, pub kind: ImportKind, } diff --git a/crates/webidl-tests/build.rs b/crates/webidl-tests/build.rs index 2f8294b3..536ccf07 100644 --- a/crates/webidl-tests/build.rs +++ b/crates/webidl-tests/build.rs @@ -28,7 +28,7 @@ fn main() { use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; - #[wasm_bindgen(module = "{}", version = "*")] + #[wasm_bindgen(module = "{}")] extern {{ fn not_actually_a_function{1}(); }} diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 76e17669..4cdb457f 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -240,7 +240,6 @@ impl<'src> WebidlParse<'src, ()> for weedle::InterfaceDefinition<'src> { program.imports.push(backend::ast::Import { module: None, - version: None, js_namespace: None, kind: backend::ast::ImportKind::Type(backend::ast::ImportType { vis: public(), @@ -718,7 +717,6 @@ impl<'src> WebidlParse<'src, ()> for weedle::EnumDefinition<'src> { let variants = &self.values.body.list; program.imports.push(backend::ast::Import { module: None, - version: None, js_namespace: None, kind: backend::ast::ImportKind::Enum(backend::ast::ImportEnum { vis: public(), diff --git a/guide/src/design/import-customization.md b/guide/src/design/import-customization.md index 3db5a505..4f1b6d9a 100644 --- a/guide/src/design/import-customization.md +++ b/guide/src/design/import-customization.md @@ -5,37 +5,6 @@ controlling precisely how imports are imported and what they map to in JS. This section is intended to hopefully be an exhaustive reference of the possibilities! -* `module` and `version` - we've seen `module` so far indicating where we can - import items from but `version` is also allowed: - - ```rust - #[wasm_bindgen(module = "moment", version = "^2.0.0")] - extern { - type Moment; - fn moment() -> Moment; - #[wasm_bindgen(method)] - fn format(this: &Moment) -> String; - } - ``` - - The `module` key is used to configure the module that each item is imported - from. The `version` key does not affect the generated wasm itself but rather - it's an informative directive for tools like [wasm-pack]. Tools like wasm-pack - will generate a `package.json` for you and the `version` listed here, when - `module` is also an NPM package, will correspond to what to write down in - `package.json`. - - In other words the usage of `module` as the name of an NPM package and - `version` as the version requirement allows you to, inline in Rust, depend on - the NPM ecosystem and import functionality from those packages. When bundled - with a tool like [wasm-pack] everything will automatically get wired up with - bundlers and you should be good to go! - - Note that the `version` is *required* if `module` doesn't start with `./`. If - `module` starts with `./` then it is an error to provide a version. - -[wasm-pack]: https://github.com/rustwasm/wasm-pack - * `catch` - this attribute allows catching a JS exception. This can be attached to any imported function and the function must return a `Result` where the `Err` payload is a `JsValue`, like so: diff --git a/tests/all/imports.rs b/tests/all/imports.rs deleted file mode 100644 index c290c3ec..00000000 --- a/tests/all/imports.rs +++ /dev/null @@ -1,52 +0,0 @@ -use super::project; - -#[test] -fn versions() { - project() - .debug(false) - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "webpack", version = "^0.2.0")] - extern { - fn foo(); - } - - #[wasm_bindgen] - pub fn run() { - foo(); - } - "#, - ) - .file( - "test.js", - r#" - import * as fs from 'fs'; - import * as assert from 'assert'; - - export function test() { - const bytes = fs.readFileSync('out_bg.wasm'); - const m = new WebAssembly.Module(bytes); - const name = '__wasm_pack_unstable'; - const sections = WebAssembly.Module.customSections(m, name); - assert.strictEqual(sections.length, 1); - const b = new Uint8Array(sections[0]); - const buf = new Buffer(b); - const map = JSON.parse(buf.toString()); - assert.deepStrictEqual(map, { - version: '0.0.1', - modules: [ - ['webpack', '^0.2.0'] - ] - }); - }; - "#, - ) - .test(); -} diff --git a/tests/all/main.rs b/tests/all/main.rs index e31d286c..fecf2e1f 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -5,5 +5,4 @@ extern crate wasm_bindgen_test_project_builder as project_builder; use project_builder::project; mod comments; -mod imports; mod typescript; diff --git a/tests/crates/a/src/lib.rs b/tests/crates/a/src/lib.rs index f3a4c04e..04dde653 100644 --- a/tests/crates/a/src/lib.rs +++ b/tests/crates/a/src/lib.rs @@ -4,7 +4,7 @@ extern crate wasm_bindgen; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js")] extern { fn foo(); } diff --git a/tests/crates/b/src/lib.rs b/tests/crates/b/src/lib.rs index 6d57e404..87f781da 100644 --- a/tests/crates/b/src/lib.rs +++ b/tests/crates/b/src/lib.rs @@ -4,7 +4,7 @@ extern crate wasm_bindgen; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js")] extern { fn foo(x: u32); } diff --git a/tests/wasm/api.rs b/tests/wasm/api.rs index f7be28ea..1953929b 100644 --- a/tests/wasm/api.rs +++ b/tests/wasm/api.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/api.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/api.js")] extern { fn js_works(); fn js_eq_works(); diff --git a/tests/wasm/char.rs b/tests/wasm/char.rs index 328151a8..6d2ef325 100644 --- a/tests/wasm/char.rs +++ b/tests/wasm/char.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/char.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/char.js")] extern { fn js_identity(c: char) -> char; fn js_works(); diff --git a/tests/wasm/classes.rs b/tests/wasm/classes.rs index ae4bd2e2..2c58c609 100644 --- a/tests/wasm/classes.rs +++ b/tests/wasm/classes.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/classes.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/classes.js")] extern { fn js_simple(); fn js_strings(); diff --git a/tests/wasm/closures.rs b/tests/wasm/closures.rs index 2c926866..84794725 100644 --- a/tests/wasm/closures.rs +++ b/tests/wasm/closures.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; use std::cell::Cell; use std::rc::Rc; -#[wasm_bindgen(module = "tests/wasm/closures.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/closures.js")] extern { fn works_call(a: &Fn()); fn works_thread(a: &Fn(u32) -> u32) -> u32; diff --git a/tests/wasm/duplicate_deps.rs b/tests/wasm/duplicate_deps.rs index d19e4134..0a451301 100644 --- a/tests/wasm/duplicate_deps.rs +++ b/tests/wasm/duplicate_deps.rs @@ -3,7 +3,7 @@ use wasm_bindgen_test::*; use wasm_bindgen_test_crate_a as a; use wasm_bindgen_test_crate_b as b; -#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js")] extern { fn assert_next_undefined(); fn assert_next_ten(); diff --git a/tests/wasm/duplicates.rs b/tests/wasm/duplicates.rs index c0beadad..f35e6d37 100644 --- a/tests/wasm/duplicates.rs +++ b/tests/wasm/duplicates.rs @@ -3,7 +3,7 @@ use wasm_bindgen_test::*; pub mod same_function_different_locations_a { use wasm_bindgen::prelude::*; - #[wasm_bindgen(module = "tests/wasm/duplicates_a.js", version = "*")] + #[wasm_bindgen(module = "tests/wasm/duplicates_a.js")] extern { pub fn foo(); } @@ -12,7 +12,7 @@ pub mod same_function_different_locations_a { pub mod same_function_different_locations_b { use wasm_bindgen::prelude::*; - #[wasm_bindgen(module = "tests/wasm/duplicates_a.js", version = "*")] + #[wasm_bindgen(module = "tests/wasm/duplicates_a.js")] extern { pub fn foo(); } @@ -27,7 +27,7 @@ fn same_function_different_locations() { pub mod same_function_different_modules_a { use wasm_bindgen::prelude::*; - #[wasm_bindgen(module = "tests/wasm/duplicates_b.js", version = "*")] + #[wasm_bindgen(module = "tests/wasm/duplicates_b.js")] extern { pub fn foo() -> bool; } @@ -36,7 +36,7 @@ pub mod same_function_different_modules_a { pub mod same_function_different_modules_b { use wasm_bindgen::prelude::*; - #[wasm_bindgen(module = "tests/wasm/duplicates_c.js", version = "*")] + #[wasm_bindgen(module = "tests/wasm/duplicates_c.js")] extern { pub fn foo() -> bool; } diff --git a/tests/wasm/enums.rs b/tests/wasm/enums.rs index f49a18b9..4c1ad2dc 100644 --- a/tests/wasm/enums.rs +++ b/tests/wasm/enums.rs @@ -2,7 +2,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; use self::inner::ColorWithCustomValues; -#[wasm_bindgen(module = "tests/wasm/enums.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/enums.js")] extern { fn js_c_style_enum(); fn js_c_style_enum_with_custom_values(); diff --git a/tests/wasm/import_class.rs b/tests/wasm/import_class.rs index 329e9e48..06083ea2 100644 --- a/tests/wasm/import_class.rs +++ b/tests/wasm/import_class.rs @@ -5,7 +5,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/import_class.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/import_class.js")] extern { fn math_log(f: f64) -> f64; diff --git a/tests/wasm/imports.rs b/tests/wasm/imports.rs index 731d24f7..1ad9208e 100644 --- a/tests/wasm/imports.rs +++ b/tests/wasm/imports.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/imports.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/imports.js")] extern { fn test_simple(); diff --git a/tests/wasm/js_objects.rs b/tests/wasm/js_objects.rs index 9c660492..70b3518e 100644 --- a/tests/wasm/js_objects.rs +++ b/tests/wasm/js_objects.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/js_objects.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/js_objects.js")] extern { fn simple_foo(s: &JsValue); fn js_simple(); diff --git a/tests/wasm/math.rs b/tests/wasm/math.rs index 47ea5ce2..413e8f2f 100644 --- a/tests/wasm/math.rs +++ b/tests/wasm/math.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/math.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/math.js")] extern { fn js_auto_bind_math(); } @@ -64,4 +64,4 @@ pub fn math(a: f32, b: f64) -> f64 { #[wasm_bindgen_test] fn auto_bind_math() { js_auto_bind_math(); -} \ No newline at end of file +} diff --git a/tests/wasm/node.rs b/tests/wasm/node.rs index cee7986e..741febfc 100644 --- a/tests/wasm/node.rs +++ b/tests/wasm/node.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/node.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/node.js")] extern { fn test_works(); static FOO: JsValue; diff --git a/tests/wasm/option.rs b/tests/wasm/option.rs index 98c7ece1..8da01e3b 100644 --- a/tests/wasm/option.rs +++ b/tests/wasm/option.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/option.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/option.js")] extern { pub type MyType; #[wasm_bindgen(constructor)] diff --git a/tests/wasm/optional_primitives.rs b/tests/wasm/optional_primitives.rs index 57a4bd1e..3543a4e2 100644 --- a/tests/wasm/optional_primitives.rs +++ b/tests/wasm/optional_primitives.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/optional_primitives.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/optional_primitives.js")] extern { fn optional_i32_js_identity(a: Option) -> Option; fn optional_u32_js_identity(a: Option) -> Option; diff --git a/tests/wasm/simple.rs b/tests/wasm/simple.rs index d58f7ee1..5182a366 100644 --- a/tests/wasm/simple.rs +++ b/tests/wasm/simple.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/simple.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/simple.js")] extern { fn test_add(); fn test_string_arguments(); diff --git a/tests/wasm/slice.rs b/tests/wasm/slice.rs index 653ec01c..6347a601 100644 --- a/tests/wasm/slice.rs +++ b/tests/wasm/slice.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/slice.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/slice.js")] extern { fn js_export(); @@ -44,7 +44,7 @@ fn export() { macro_rules! import_macro { ($(($rust:ident, $js:ident, $i:ident))*) => ($( - #[wasm_bindgen(module = "tests/wasm/slice.js", version = "*")] + #[wasm_bindgen(module = "tests/wasm/slice.js")] extern { fn $js(a: &[$i]) -> Vec<$i>; } @@ -105,7 +105,7 @@ fn pass_array() { macro_rules! import_mut_macro { ($(($rust:ident, $js:ident, $i:ident))*) => ( $( - #[wasm_bindgen(module = "tests/wasm/slice.js", version = "*")] + #[wasm_bindgen(module = "tests/wasm/slice.js")] extern { fn $js(a: &mut [$i]); } diff --git a/tests/wasm/structural.rs b/tests/wasm/structural.rs index 92a13fe2..4729620c 100644 --- a/tests/wasm/structural.rs +++ b/tests/wasm/structural.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/structural.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/structural.js")] extern { fn js_works(); } diff --git a/tests/wasm/u64.rs b/tests/wasm/u64.rs index d5d60760..1900d3cd 100644 --- a/tests/wasm/u64.rs +++ b/tests/wasm/u64.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/u64.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/u64.js")] extern { fn i64_js_identity(a: i64) -> i64; fn u64_js_identity(a: u64) -> u64; diff --git a/tests/wasm/validate_prt.rs b/tests/wasm/validate_prt.rs index f6446fde..c04f3353 100644 --- a/tests/wasm/validate_prt.rs +++ b/tests/wasm/validate_prt.rs @@ -1,7 +1,7 @@ use wasm_bindgen_test::*; use wasm_bindgen::prelude::*; -#[wasm_bindgen(module = "tests/wasm/validate_prt.js", version = "*")] +#[wasm_bindgen(module = "tests/wasm/validate_prt.js")] extern { fn js_works(); } From 2ee4ab362df466bb22ff5d826d406d5a1d2d26d4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Aug 2018 11:31:24 -0700 Subject: [PATCH 24/24] Remove a stray file --- tests/std-crate-no-std-dep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/std-crate-no-std-dep diff --git a/tests/std-crate-no-std-dep b/tests/std-crate-no-std-dep deleted file mode 100644 index e69de29b..00000000