"wasm-bindgen",
]
-[[package]]
-name = "console_log"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f"
-dependencies = [
- "log",
- "web-sys",
-]
-
[[package]]
name = "core-foundation"
version = "0.9.3"
"bytes",
"chrono",
"console_error_panic_hook",
- "console_log",
"cpu-time",
"criterion",
"crossterm",
"hostname",
"iai-callgrind",
"indexmap",
+ "js-sys",
"lazy_static",
"lexical",
"libc",
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
console_error_panic_hook = "0.1"
-console_log = "1.0"
wasm-bindgen = "0.2.87"
wasm-bindgen-futures = "0.4"
serde-wasm-bindgen = "0.5"
web-sys = { version = "0.3", features = ["Document", "Window", "Element"] }
+js-sys = "0.3"
[target.'cfg(target_os = "wasi")'.dependencies]
ring-wasi = { version = "0.16.25" }
ForeignCall,
#[strum_discriminants(strum(props(Arity = "2", Name = "$define_foreign_struct")))]
DefineForeignStruct,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$js_eval")))]
+ JsEval,
#[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
PredicateDefined,
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
&Instruction::CallLoadForeignLib |
&Instruction::CallForeignCall |
&Instruction::CallDefineForeignStruct |
+ &Instruction::CallJsEval |
&Instruction::CallPredicateDefined |
&Instruction::CallStripModule |
&Instruction::CallCurrentTime |
&Instruction::ExecuteLoadForeignLib |
&Instruction::ExecuteForeignCall |
&Instruction::ExecuteDefineForeignStruct |
+ &Instruction::ExecuteJsEval |
&Instruction::ExecutePredicateDefined |
&Instruction::ExecuteStripModule |
&Instruction::ExecuteCurrentTime |
Number::Float(f) => Number::Float(OrderedFloat(f.signum())),
_ => {
if self.is_positive() {
- if self.is_zero() {
- Number::Fixnum(Fixnum::build_with(0))
- } else {
- Number::Fixnum(Fixnum::build_with(1))
- }
+ if self.is_zero() {
+ Number::Fixnum(Fixnum::build_with(0))
+ } else {
+ Number::Fixnum(Fixnum::build_with(1))
+ }
} else if self.is_negative() {
Number::Fixnum(Fixnum::build_with(-1))
} else {
#[wasm_bindgen]
pub fn eval_code(s: &str) -> String {
use machine::mock_wam::*;
- use web_sys::console;
+
+ console_error_panic_hook::set_once();
let mut wam = Machine::with_test_streams();
let bytes = wam.test_load_string(s);
--- /dev/null
+/** Predicates for the WebAssembly platform
+
+This module contains predicates that are only available in
+the WASM (WebAssembly) version of Scryer Prolog.
+*/
+
+:- module(wasm, [js_eval/2]).
+
+:- use_module(library(error)).
+
+%% js_eval(+JsCode, -Result).
+%
+% Executes a JavaScript snippet `JsCode` using the platform
+% `eval` function. `Result` takes the return value of that code.
+% Strings, booleans, numbers, null and undefined are directly mapped to Prolog.
+% Arrays, objects, bigints, symbols and functions are not mapped.
+% Instead, a `js_{type}` atom will be returned.
+%
+% Example (on a browser):
+%
+% ```
+% ?- js_eval("prompt('What is your name?')", Name).
+% % A prompt is showed, with a textbox.
+% Name = "Whatever was written on the textbox".
+% ```
+js_eval(JsCode, Result) :-
+ must_be(chars, JsCode),
+ can_be(chars, Result),
+ '$js_eval'(JsCode, Result).
try_or_throw!(self.machine_st, self.define_foreign_struct());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
+ &Instruction::CallJsEval => {
+ try_or_throw!(self.machine_st, self.js_eval());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteJsEval => {
+ try_or_throw!(self.machine_st, self.js_eval());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
&Instruction::CallCurrentTime => {
self.current_time();
step_or_fail!(self, self.machine_st.p += 1);
Ok(())
}
+ #[cfg(not(target_arch = "wasm32"))]
+ #[inline(always)]
+ pub(crate) fn js_eval(&mut self) -> CallResult {
+ unimplemented!()
+ }
+
+ #[cfg(target_arch = "wasm32")]
+ #[inline(always)]
+ pub(crate) fn js_eval(&mut self) -> CallResult {
+ let code = self.deref_register(1);
+ let result_reg = self.deref_register(2);
+ if let Some(code) = self.machine_st.value_to_str_like(code) {
+ let result = match js_sys::eval(&code.as_str()) {
+ Ok(result) => self.unify_js_value(result, result_reg),
+ Err(result) => self.unify_js_value(result, result_reg),
+ };
+ return Ok(());
+ }
+ self.machine_st.fail = true;
+ Ok(())
+ }
+
+ #[cfg(target_arch = "wasm32")]
+ fn unify_js_value(&mut self, result: wasm_bindgen::JsValue, result_reg: HeapCellValue) {
+ match result.as_bool() {
+ Some(result) => match result {
+ true => self.machine_st.unify_atom(atom!("true"), result_reg),
+ false => self.machine_st.unify_atom(atom!("false"), result_reg),
+ },
+ None => match result.as_f64() {
+ Some(result) => {
+ let n = float_alloc!(result, self.machine_st.arena);
+ self.machine_st.unify_f64(n, result_reg);
+ }
+ None => match result.as_string() {
+ Some(result) => {
+ let result = AtomTable::build_with(&self.machine_st.atom_tbl, &result);
+ self.machine_st.unify_complete_string(result, result_reg);
+ }
+ None => {
+ if result.is_null() {
+ self.machine_st.unify_atom(atom!("null"), result_reg);
+ } else if result.is_undefined() {
+ self.machine_st.unify_atom(atom!("undefined"), result_reg);
+ } else if result.is_symbol() {
+ self.machine_st.unify_atom(atom!("js_symbol"), result_reg);
+ } else if result.is_object() {
+ self.machine_st.unify_atom(atom!("js_object"), result_reg);
+ } else if result.is_array() {
+ self.machine_st.unify_atom(atom!("js_array"), result_reg);
+ } else if result.is_function() {
+ self.machine_st.unify_atom(atom!("js_function"), result_reg);
+ } else if result.is_bigint() {
+ self.machine_st.unify_atom(atom!("js_bigint"), result_reg);
+ } else {
+ self.machine_st
+ .unify_atom(atom!("js_unknown_type"), result_reg);
+ }
+ }
+ },
+ },
+ }
+ }
+
#[inline(always)]
pub(crate) fn current_time(&mut self) {
let timestamp = self.systemtime_to_timestamp(SystemTime::now());