Skip to content

Commit

Permalink
Automatically bind float math functions
Browse files Browse the repository at this point in the history
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 rustwasm#28
  • Loading branch information
alexcrichton committed Feb 18, 2018
1 parent 9e7a4e7 commit d66bc25
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 22 deletions.
104 changes: 82 additions & 22 deletions crates/wasm-bindgen-cli-support/src/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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())
Expand Down Expand Up @@ -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());

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
}
// 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();
}
}

Expand Down
64 changes: 64 additions & 0 deletions tests/math.rs
Original file line number Diff line number Diff line change
@@ -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();
}

0 comments on commit d66bc25

Please sign in to comment.