Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Compiler/wasm: make the type of some Wasm primitives more precise (#2100)
* Compiler: reference unboxing (#1958)
* Runtime: improved handling of NaNs (#2110)
* Runtime/wasm: provide access to JavaScript eval function (#2108)

## Bug fixes
* Compiler: fix purity of comparison functions (again) (#2092)
Expand Down
16 changes: 12 additions & 4 deletions runtime/js/jslib.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ function caml_js_var(x) {
//console.error("Js.Unsafe.eval_string")
}
// biome-ignore lint/security/noGlobalEval:
return eval(x);
return eval?.(x);
}
//Provides: caml_js_call (const, mutable, shallow)
//Requires: caml_js_from_array
Expand Down Expand Up @@ -478,24 +478,32 @@ function caml_js_strict_equals(x, y) {
//Provides: caml_js_eval_string (const)
//Requires: caml_jsstring_of_string
function caml_js_eval_string(s) {
// Uses an indirect eval through the optional chaining operator.
// (see https://mdn.dev/docs/Web/JavaScript/Reference/Global_Objects/eval)
// This is faster and avoid variable captures.
// Also prepends `"use strict"` directive since this is not inherited
// from the enclosing function with an indirect eval.
// biome-ignore lint/security/noGlobalEval:
return eval(caml_jsstring_of_string(s));
return eval?.('"use strict";' + caml_jsstring_of_string(s));
}

//Provides: caml_js_expr (const)
//Requires: caml_jsstring_of_string
function caml_js_expr(s) {
console.error("caml_js_expr: fallback to runtime evaluation\n");
// We add parentheses to avoid the ambiguity between expressions
// and statements. This means that we accept invalid inputs like
// "a)(b", but this is unlikely to be an issue in practice.
// biome-ignore lint/security/noGlobalEval:
return eval(caml_jsstring_of_string(s));
return eval?.('"use strict";(' + caml_jsstring_of_string(s) + ")");
}

//Provides: caml_pure_js_expr const (const)
//Requires: caml_jsstring_of_string
function caml_pure_js_expr(s) {
console.error("caml_pure_js_expr: fallback to runtime evaluation\n");
// biome-ignore lint/security/noGlobalEval:
return eval(caml_jsstring_of_string(s));
return eval?.('"use strict";(' + caml_jsstring_of_string(s) + ")");
}

//Provides: caml_js_object (object_literal)
Expand Down
8 changes: 8 additions & 0 deletions runtime/wasm/jslib.wat
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
(import "bindings" "identity" (func $to_int32 (param anyref) (result i32)))
(import "bindings" "identity" (func $from_int32 (param i32) (result anyref)))
(import "bindings" "from_bool" (func $from_bool (param i32) (result anyref)))
(import "bindings" "eval" (func $eval (param anyref) (result anyref)))
(import "bindings" "get"
(func $get (param (ref extern)) (param anyref) (result anyref)))
(import "bindings" "set"
Expand Down Expand Up @@ -128,6 +129,13 @@
(ref.i31 (call $strict_equals
(call $unwrap (local.get 0)) (call $unwrap (local.get 1)))))

(func (export "caml_js_expr") (export "caml_pure_js_expr")
(export "caml_js_var") (export "caml_js_eval_string")
(param (ref eq)) (result (ref eq))
(local $s (ref $bytes))
(local.set $s (ref.cast (ref $bytes) (local.get 0)))
(return_call $wrap (call $eval (call $jsstring_of_bytes (local.get $s)))))

(func (export "caml_js_global") (param (ref eq)) (result (ref eq))
(call $wrap (global.get $global_this)))

Expand Down
2 changes: 2 additions & 0 deletions runtime/wasm/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@
typeof: (x) => typeof x,
// biome-ignore lint/suspicious/noDoubleEquals:
equals: (x, y) => x == y,
// biome-ignore lint/security/noGlobalEval:
eval: (x) => eval?.('"use strict";(' + x + ")"),
strict_equals: (x, y) => x === y,
fun_call: (f, o, args) => f.apply(o, args),
meth_call: (o, f, args) => o[f].apply(o, args),
Expand Down