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",
|
||||
]
|
||||
|
||||
[[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"
|
||||
@@ -2326,7 +2316,6 @@ dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"cpu-time",
|
||||
"criterion",
|
||||
"crossterm",
|
||||
@@ -2343,6 +2332,7 @@ dependencies = [
|
||||
"hostname",
|
||||
"iai-callgrind",
|
||||
"indexmap",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"lexical",
|
||||
"libc",
|
||||
|
||||
@@ -95,11 +95,11 @@ tokio = { version = "1.28.2", features = [
|
||||
|
||||
[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" }
|
||||
|
||||
@@ -573,6 +573,8 @@ enum SystemClauseType {
|
||||
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")))]
|
||||
@@ -1774,6 +1776,7 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallLoadForeignLib |
|
||||
&Instruction::CallForeignCall |
|
||||
&Instruction::CallDefineForeignStruct |
|
||||
&Instruction::CallJsEval |
|
||||
&Instruction::CallPredicateDefined |
|
||||
&Instruction::CallStripModule |
|
||||
&Instruction::CallCurrentTime |
|
||||
@@ -2008,6 +2011,7 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteLoadForeignLib |
|
||||
&Instruction::ExecuteForeignCall |
|
||||
&Instruction::ExecuteDefineForeignStruct |
|
||||
&Instruction::ExecuteJsEval |
|
||||
&Instruction::ExecutePredicateDefined |
|
||||
&Instruction::ExecuteStripModule |
|
||||
&Instruction::ExecuteCurrentTime |
|
||||
|
||||
10
src/forms.rs
10
src/forms.rs
@@ -744,11 +744,11 @@ impl Number {
|
||||
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 {
|
||||
|
||||
@@ -51,7 +51,8 @@ use wasm_bindgen::prelude::*;
|
||||
#[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);
|
||||
|
||||
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());
|
||||
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);
|
||||
|
||||
@@ -4879,6 +4879,70 @@ impl Machine {
|
||||
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());
|
||||
|
||||
Reference in New Issue
Block a user