Add js_eval/2 for wasm32
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -354,16 +354,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"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]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
@@ -2326,7 +2316,6 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"console_log",
|
|
||||||
"cpu-time",
|
"cpu-time",
|
||||||
"criterion",
|
"criterion",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
@@ -2343,6 +2332,7 @@ dependencies = [
|
|||||||
"hostname",
|
"hostname",
|
||||||
"iai-callgrind",
|
"iai-callgrind",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"js-sys",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lexical",
|
"lexical",
|
||||||
"libc",
|
"libc",
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ tokio = { version = "1.28.2", features = [
|
|||||||
|
|
||||||
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
|
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
console_log = "1.0"
|
|
||||||
wasm-bindgen = "0.2.87"
|
wasm-bindgen = "0.2.87"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
serde-wasm-bindgen = "0.5"
|
serde-wasm-bindgen = "0.5"
|
||||||
web-sys = { version = "0.3", features = ["Document", "Window", "Element"] }
|
web-sys = { version = "0.3", features = ["Document", "Window", "Element"] }
|
||||||
|
js-sys = "0.3"
|
||||||
|
|
||||||
[target.'cfg(target_os = "wasi")'.dependencies]
|
[target.'cfg(target_os = "wasi")'.dependencies]
|
||||||
ring-wasi = { version = "0.16.25" }
|
ring-wasi = { version = "0.16.25" }
|
||||||
|
|||||||
@@ -573,6 +573,8 @@ enum SystemClauseType {
|
|||||||
ForeignCall,
|
ForeignCall,
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$define_foreign_struct")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$define_foreign_struct")))]
|
||||||
DefineForeignStruct,
|
DefineForeignStruct,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$js_eval")))]
|
||||||
|
JsEval,
|
||||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
|
||||||
PredicateDefined,
|
PredicateDefined,
|
||||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
|
||||||
@@ -1774,6 +1776,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallLoadForeignLib |
|
&Instruction::CallLoadForeignLib |
|
||||||
&Instruction::CallForeignCall |
|
&Instruction::CallForeignCall |
|
||||||
&Instruction::CallDefineForeignStruct |
|
&Instruction::CallDefineForeignStruct |
|
||||||
|
&Instruction::CallJsEval |
|
||||||
&Instruction::CallPredicateDefined |
|
&Instruction::CallPredicateDefined |
|
||||||
&Instruction::CallStripModule |
|
&Instruction::CallStripModule |
|
||||||
&Instruction::CallCurrentTime |
|
&Instruction::CallCurrentTime |
|
||||||
@@ -2008,6 +2011,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteLoadForeignLib |
|
&Instruction::ExecuteLoadForeignLib |
|
||||||
&Instruction::ExecuteForeignCall |
|
&Instruction::ExecuteForeignCall |
|
||||||
&Instruction::ExecuteDefineForeignStruct |
|
&Instruction::ExecuteDefineForeignStruct |
|
||||||
|
&Instruction::ExecuteJsEval |
|
||||||
&Instruction::ExecutePredicateDefined |
|
&Instruction::ExecutePredicateDefined |
|
||||||
&Instruction::ExecuteStripModule |
|
&Instruction::ExecuteStripModule |
|
||||||
&Instruction::ExecuteCurrentTime |
|
&Instruction::ExecuteCurrentTime |
|
||||||
|
|||||||
10
src/forms.rs
10
src/forms.rs
@@ -744,11 +744,11 @@ impl Number {
|
|||||||
Number::Float(f) => Number::Float(OrderedFloat(f.signum())),
|
Number::Float(f) => Number::Float(OrderedFloat(f.signum())),
|
||||||
_ => {
|
_ => {
|
||||||
if self.is_positive() {
|
if self.is_positive() {
|
||||||
if self.is_zero() {
|
if self.is_zero() {
|
||||||
Number::Fixnum(Fixnum::build_with(0))
|
Number::Fixnum(Fixnum::build_with(0))
|
||||||
} else {
|
} else {
|
||||||
Number::Fixnum(Fixnum::build_with(1))
|
Number::Fixnum(Fixnum::build_with(1))
|
||||||
}
|
}
|
||||||
} else if self.is_negative() {
|
} else if self.is_negative() {
|
||||||
Number::Fixnum(Fixnum::build_with(-1))
|
Number::Fixnum(Fixnum::build_with(-1))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ use wasm_bindgen::prelude::*;
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn eval_code(s: &str) -> String {
|
pub fn eval_code(s: &str) -> String {
|
||||||
use machine::mock_wam::*;
|
use machine::mock_wam::*;
|
||||||
use web_sys::console;
|
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
let mut wam = Machine::with_test_streams();
|
let mut wam = Machine::with_test_streams();
|
||||||
let bytes = wam.test_load_string(s);
|
let bytes = wam.test_load_string(s);
|
||||||
|
|||||||
29
src/lib/wasm.pl
Normal file
29
src/lib/wasm.pl
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/** 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).
|
||||||
@@ -4128,6 +4128,14 @@ impl Machine {
|
|||||||
try_or_throw!(self.machine_st, self.define_foreign_struct());
|
try_or_throw!(self.machine_st, self.define_foreign_struct());
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
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 => {
|
&Instruction::CallCurrentTime => {
|
||||||
self.current_time();
|
self.current_time();
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
|||||||
@@ -4879,6 +4879,70 @@ impl Machine {
|
|||||||
Ok(())
|
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)]
|
#[inline(always)]
|
||||||
pub(crate) fn current_time(&mut self) {
|
pub(crate) fn current_time(&mut self) {
|
||||||
let timestamp = self.systemtime_to_timestamp(SystemTime::now());
|
let timestamp = self.systemtime_to_timestamp(SystemTime::now());
|
||||||
|
|||||||
Reference in New Issue
Block a user