From d66bc257499f4996920eb3fd42db139e92ff0c0e Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Sat, 17 Feb 2018 16:43:58 -0800 Subject: [PATCH] Automatically bind float math functions These tend to have one "pretty obvious" definition in JS anyway, so let's paper over this deficiency in rustc for now by automatically resolving any imports for these functions. Closes #28 --- crates/wasm-bindgen-cli-support/src/js.rs | 104 +++++++++++++++++----- tests/math.rs | 64 +++++++++++++ 2 files changed, 146 insertions(+), 22 deletions(-) create mode 100644 tests/math.rs diff --git a/crates/wasm-bindgen-cli-support/src/js.rs b/crates/wasm-bindgen-cli-support/src/js.rs index faba08eb..b06986a9 100644 --- a/crates/wasm-bindgen-cli-support/src/js.rs +++ b/crates/wasm-bindgen-cli-support/src/js.rs @@ -192,6 +192,8 @@ impl<'a> Context<'a> { }); } + self.rewrite_imports(module_name); + let js = format!(" /* tslint:disable */ import * as wasm from './{module_name}_wasm'; // imports from wasm file @@ -204,7 +206,6 @@ impl<'a> Context<'a> { imports = self.imports, ); - self.rewrite_imports(module_name); self.unexport_unused_internal_exports(); (js, self.typescript.clone()) @@ -257,30 +258,89 @@ impl<'a> Context<'a> { } fn rewrite_imports(&mut self, module_name: &str) { - for section in self.module.sections_mut() { - let imports = match *section { - Section::Import(ref mut s) => s, - _ => continue, - }; - for import in imports.entries_mut() { - if import.field().starts_with("__wbindgen") { - import.module_mut().truncate(0); - import.module_mut().push_str("./"); - import.module_mut().push_str(module_name); - continue + let imports = self.module.sections_mut() + .iter_mut() + .filter_map(|s| { + match *s { + Section::Import(ref mut s) => Some(s), + _ => None, } + }) + .flat_map(|s| s.entries_mut()); - // rustc doesn't have support for importing from anything other - // than the module `env` so let's use the metadata here to - // rewrite the imports if they import from `env` until it's - // fixed upstream. - if self.imports_to_rewrite.contains(import.field()) { - import.module_mut().truncate(0); - import.module_mut().push_str("./"); - import.module_mut().push_str(module_name); - continue - } + for import in imports { + if import.field().starts_with("__wbindgen") { + import.module_mut().truncate(0); + import.module_mut().push_str("./"); + import.module_mut().push_str(module_name); + continue } + + // rustc doesn't have support for importing from anything other + // than the module `env` so let's use the metadata here to + // rewrite the imports if they import from `env` until it's + // fixed upstream. + if self.imports_to_rewrite.contains(import.field()) { + import.module_mut().truncate(0); + import.module_mut().push_str("./"); + import.module_mut().push_str(module_name); + continue + } + + if import.module() != "env" { + continue + } + + let mut globals = &mut self.globals; + let renamed_import = format!("__wbindgen_{}", import.field()); + let mut bind_math = |expr: &str| { + globals.push_str(&format!(" + export const {} = {}; + ", renamed_import, expr)); + }; + + match import.field() { + "Math_acos" => bind_math("Math.acos"), + "Math_asin" => bind_math("Math.asin"), + "Math_atan" => bind_math("Math.atan"), + "Math_atan2" => bind_math("Math.atan2"), + "Math_cbrt" => bind_math("Math.cbrt"), + "Math_cosh" => bind_math("Math.cosh"), + "Math_expm1" => bind_math("Math.expm1"), + "Math_hypot" => bind_math("Math.hypot"), + "Math_log1p" => bind_math("Math.log1p"), + "Math_sinh" => bind_math("Math.sinh"), + "Math_tan" => bind_math("Math.tan"), + "Math_tanh" => bind_math("Math.tanh"), + "cos" => bind_math("Math.cos"), + "cosf" => bind_math("Math.cos"), + "exp" => bind_math("Math.exp"), + "expf" => bind_math("Math.exp"), + "log2" => bind_math("Math.log2"), + "log2f" => bind_math("Math.log2"), + "log10" => bind_math("Math.log10"), + "log10f" => bind_math("Math.log10"), + "log" => bind_math("Math.log"), + "logf" => bind_math("Math.log"), + "round" => bind_math("Math.round"), + "roundf" => bind_math("Math.round"), + "sin" => bind_math("Math.sin"), + "sinf" => bind_math("Math.sin"), + "pow" => bind_math("Math.pow"), + "powf" => bind_math("Math.pow"), + "exp2" => bind_math("(a) => Math.pow(2, a)"), + "exp2f" => bind_math("(a) => Math.pow(2, a)"), + "fmod" => bind_math("(a, b) => a % b"), + "fmodf" => bind_math("(a, b) => a % b"), + "fma" => bind_math("(a, b, c) => (a * b) + c"), + "fmaf" => bind_math("(a, b, c) => (a * b) + c"), + _ => continue, + } + + import.module_mut().truncate(0); + import.module_mut().push_str("./"); + import.module_mut().push_str(module_name); + *import.field_mut() = renamed_import.clone(); } } diff --git a/tests/math.rs b/tests/math.rs new file mode 100644 index 00000000..6183dbb6 --- /dev/null +++ b/tests/math.rs @@ -0,0 +1,64 @@ +extern crate test_support; + +#[test] +fn auto_bind_math() { + test_support::project() + .file("src/lib.rs", r#" + #![feature(proc_macro)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen] + #[no_mangle] + pub extern 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.log(b) + + b.log10() + + b.log2() + + b.powi(8) + + b.powf(b) + + b.round() + + b.sin() + + (b % (a as f64)) + + ((a.cos() + + a.exp() + + a.exp2() + + a.mul_add(a, a) + + a.log(a) + + a.log10() + + a.log2() + + a.powi(8) + + a.powf(a) + + a.round() + + a.sin() + + (a % (b as f32))) as f64) + + (b + 2.0f64.powf(a as f64)) + } + "#) + .file("test.ts", r#" + import { math } from "./out"; + + export function test() { + math(1.0, 2.0); + } + "#) + .test(); +} +