58
Cargo.lock
generated
58
Cargo.lock
generated
@@ -39,6 +39,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aliasable"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android-tzdata"
|
name = "android-tzdata"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -1129,6 +1135,12 @@ dependencies = [
|
|||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -1844,6 +1856,30 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ouroboros"
|
||||||
|
version = "0.18.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
|
||||||
|
dependencies = [
|
||||||
|
"aliasable",
|
||||||
|
"ouroboros_macro",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ouroboros_macro"
|
||||||
|
version = "0.18.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.4.1",
|
||||||
|
"proc-macro2",
|
||||||
|
"proc-macro2-diagnostics",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.72",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@@ -2132,6 +2168,19 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2-diagnostics"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.72",
|
||||||
|
"version_check",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
@@ -2580,6 +2629,7 @@ dependencies = [
|
|||||||
"native-tls",
|
"native-tls",
|
||||||
"num-order",
|
"num-order",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
|
"ouroboros",
|
||||||
"phf 0.11.2",
|
"phf 0.11.2",
|
||||||
"pprof",
|
"pprof",
|
||||||
"predicates-core",
|
"predicates-core",
|
||||||
@@ -2966,7 +3016,7 @@ version = "0.26.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
@@ -3780,6 +3830,12 @@ dependencies = [
|
|||||||
"tap",
|
"tap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.35"
|
version = "0.7.35"
|
||||||
|
|||||||
12
Cargo.toml
12
Cargo.toml
@@ -116,6 +116,7 @@ web-sys = { version = "0.3", features = [
|
|||||||
"Performance",
|
"Performance",
|
||||||
] }
|
] }
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
|
ouroboros = "0.18"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
@@ -139,6 +140,17 @@ opt-level = 3
|
|||||||
lto = true
|
lto = true
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
|
[profile.wasm-dev]
|
||||||
|
inherits = "dev"
|
||||||
|
opt-level = 1
|
||||||
|
lto = "off"
|
||||||
|
|
||||||
|
[profile.wasm-release]
|
||||||
|
inherits = "release"
|
||||||
|
lto = "off"
|
||||||
|
panic = "abort"
|
||||||
|
codegen-units = 256
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "run_criterion"
|
name = "run_criterion"
|
||||||
harness = false
|
harness = false
|
||||||
|
|||||||
15
flake.nix
15
flake.nix
@@ -20,6 +20,10 @@
|
|||||||
rustToolchainDev = super.rust-bin.stable.latest.default.override {
|
rustToolchainDev = super.rust-bin.stable.latest.default.override {
|
||||||
extensions = [ "rust-src" "rust-analyzer" ];
|
extensions = [ "rust-src" "rust-analyzer" ];
|
||||||
};
|
};
|
||||||
|
rustToolchainDevWasm = super.rust-bin.stable.latest.default.override {
|
||||||
|
extensions = [ "rust-src" "rust-analyzer" ];
|
||||||
|
targets = [ "wasm32-unknown-unknown" ];
|
||||||
|
};
|
||||||
rustToolchainNightly = super.rust-bin.selectLatestNightlyWith (toolchain:
|
rustToolchainNightly = super.rust-bin.selectLatestNightlyWith (toolchain:
|
||||||
toolchain.default.override {
|
toolchain.default.override {
|
||||||
extensions = [ "rust-src" "rust-analyzer" "miri" ];
|
extensions = [ "rust-src" "rust-analyzer" "miri" ];
|
||||||
@@ -38,12 +42,21 @@
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells = {
|
devShells = {
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell.override { stdenv = pkgs.clangMultiStdenv; } {
|
||||||
nativeBuildInputs = nativeBuildInputs;
|
nativeBuildInputs = nativeBuildInputs;
|
||||||
buildInputs = buildInputs ++ (with pkgs; [
|
buildInputs = buildInputs ++ (with pkgs; [
|
||||||
rustToolchainDev
|
rustToolchainDev
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
wasm-js = pkgs.mkShell.override { stdenv = pkgs.clangMultiStdenv; } {
|
||||||
|
nativeBuildInputs = nativeBuildInputs;
|
||||||
|
buildInputs = buildInputs ++ (with pkgs; [
|
||||||
|
wasm-pack
|
||||||
|
rustToolchainDevWasm
|
||||||
|
]);
|
||||||
|
TARGET_CC = "${pkgs.clangMultiStdenv.cc}/bin/clang";
|
||||||
|
hardeningDisable = [ "all" ];
|
||||||
|
};
|
||||||
# For use with Miri and stuff like it
|
# For use with Miri and stuff like it
|
||||||
nightly = pkgs.mkShell {
|
nightly = pkgs.mkShell {
|
||||||
nativeBuildInputs = nativeBuildInputs;
|
nativeBuildInputs = nativeBuildInputs;
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
fn main() -> std::process::ExitCode {
|
fn main() -> std::process::ExitCode {
|
||||||
scryer_prolog::run_binary()
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
return std::process::ExitCode::SUCCESS;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
return scryer_prolog::run_binary();
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/lib.rs
16
src/lib.rs
@@ -39,27 +39,15 @@ mod repl_helper;
|
|||||||
mod targets;
|
mod targets;
|
||||||
pub(crate) mod types;
|
pub(crate) mod types;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
|
|
||||||
// Re-exports
|
// Re-exports
|
||||||
pub use machine::config::*;
|
pub use machine::config::*;
|
||||||
pub use machine::lib_machine::*;
|
pub use machine::lib_machine::*;
|
||||||
pub use machine::Machine;
|
pub use machine::Machine;
|
||||||
|
|
||||||
/// Eval a source file in Wasm.
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
#[wasm_bindgen]
|
pub mod wasm;
|
||||||
pub fn eval_code(s: &str) -> String {
|
|
||||||
use machine::mock_wam::*;
|
|
||||||
|
|
||||||
console_error_panic_hook::set_once();
|
|
||||||
|
|
||||||
let mut wam = MachineBuilder::default().build();
|
|
||||||
let bytes = wam.test_load_string(s);
|
|
||||||
String::from_utf8_lossy(&bytes).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
/// The entry point for the Scryer Prolog CLI.
|
/// The entry point for the Scryer Prolog CLI.
|
||||||
pub fn run_binary() -> std::process::ExitCode {
|
pub fn run_binary() -> std::process::ExitCode {
|
||||||
use crate::atom_table::Atom;
|
use crate::atom_table::Atom;
|
||||||
|
|||||||
289
src/wasm.rs
Normal file
289
src/wasm.rs
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
//! Wasm interface
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
|
|
||||||
|
use ouroboros::self_referencing;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// A builder for a `Machine`.
|
||||||
|
#[wasm_bindgen(js_name = MachineBuilder)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WasmMachineBuilder {
|
||||||
|
inner: MachineBuilder,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_class = MachineBuilder)]
|
||||||
|
impl WasmMachineBuilder {
|
||||||
|
/// Creates a new `MachineBuilder` with the default configuration.
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `Machine`.
|
||||||
|
pub fn build(&mut self) -> WasmMachine {
|
||||||
|
WasmMachine {
|
||||||
|
inner: Ok(std::mem::take(&mut self.inner).build()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Scryer Prolog `Machine`.
|
||||||
|
#[wasm_bindgen(js_name = Machine)]
|
||||||
|
pub struct WasmMachine {
|
||||||
|
inner: Result<Machine, Receiver<Machine>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_class = Machine)]
|
||||||
|
impl WasmMachine {
|
||||||
|
fn ensure_machine_ownership(&mut self) -> Result<(), JsValue> {
|
||||||
|
if self.inner.is_err() {
|
||||||
|
// We have a receiver, try to get the Machine
|
||||||
|
let machine = self
|
||||||
|
.inner
|
||||||
|
.as_mut()
|
||||||
|
.unwrap_err()
|
||||||
|
.try_recv()
|
||||||
|
.map_err(|_| js_sys::Error::new("Another query is still active"))?;
|
||||||
|
let _ = mem::replace(&mut self.inner, Ok(machine));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs a query.
|
||||||
|
///
|
||||||
|
/// You can only have one query at a time. If you try to do anything with this machine while
|
||||||
|
/// doing a query an error will be thrown.
|
||||||
|
#[wasm_bindgen(js_name = runQuery)]
|
||||||
|
pub fn run_query(&mut self, query: String) -> Result<JsValue, JsValue> {
|
||||||
|
self.ensure_machine_ownership()?;
|
||||||
|
assert!(self.inner.is_ok());
|
||||||
|
|
||||||
|
// Installs a receiver and gets the machine
|
||||||
|
let (sender, receiver) = mpsc::channel();
|
||||||
|
let machine = mem::replace(&mut self.inner, Err(receiver)).unwrap();
|
||||||
|
|
||||||
|
let query_state: JsValue = WasmQueryState {
|
||||||
|
inner: Some(
|
||||||
|
WasmQueryStateInnerBuilder {
|
||||||
|
machine,
|
||||||
|
drop_channel: sender,
|
||||||
|
query_state_builder: move |m: &mut Machine| m.run_query(query),
|
||||||
|
}
|
||||||
|
.build(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
|
||||||
|
Ok(query_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consults a module.
|
||||||
|
#[wasm_bindgen(js_name = consultModuleString)]
|
||||||
|
pub fn consult_module_string(
|
||||||
|
&mut self,
|
||||||
|
module: String,
|
||||||
|
program: String,
|
||||||
|
) -> Result<(), JsValue> {
|
||||||
|
self.ensure_machine_ownership()?;
|
||||||
|
assert!(self.inner.is_ok());
|
||||||
|
|
||||||
|
let inner = self.inner.as_mut().unwrap();
|
||||||
|
inner.consult_module_string(&module, program);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[self_referencing]
|
||||||
|
struct WasmQueryStateInner {
|
||||||
|
machine: Machine,
|
||||||
|
drop_channel: Sender<Machine>,
|
||||||
|
#[covariant]
|
||||||
|
#[borrows(mut machine)]
|
||||||
|
query_state: QueryState<'this>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The state of a running query.
|
||||||
|
#[wasm_bindgen(js_name = QueryState)]
|
||||||
|
pub struct WasmQueryState {
|
||||||
|
inner: Option<WasmQueryStateInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_class = QueryState)]
|
||||||
|
impl WasmQueryState {
|
||||||
|
/// Gets the next leaf answer.
|
||||||
|
///
|
||||||
|
/// This follows the Javascript iterator protocol, so it returns an object that
|
||||||
|
/// contains a `done` field and a `value` field. If `done` is `false`, then the query ended
|
||||||
|
/// and control of the `Machine` will be given back to the `Machine` that created this query.
|
||||||
|
/// Any call after that will result in an error.
|
||||||
|
#[wasm_bindgen(js_name = next)]
|
||||||
|
pub fn next_answer(&mut self) -> Result<JsValue, JsValue> {
|
||||||
|
let ret = js_sys::Object::new();
|
||||||
|
let mut error = None;
|
||||||
|
let mut to_drop = false;
|
||||||
|
match &mut self.inner {
|
||||||
|
Some(ref mut inner) => {
|
||||||
|
inner.with_query_state_mut(|query_state| match query_state.next() {
|
||||||
|
Some(Ok(leaf_answer)) => {
|
||||||
|
js_sys::Reflect::set(&ret, &"value".into(), &leaf_answer.into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&ret, &"done".into(), &false.into()).unwrap();
|
||||||
|
}
|
||||||
|
Some(Err(error_term)) => {
|
||||||
|
let js_error = js_sys::Error::new("Prolog error");
|
||||||
|
js_error.set_cause(&error_term.into());
|
||||||
|
error = Some(js_error);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
js_sys::Reflect::set(&ret, &"done".into(), &true.into()).unwrap();
|
||||||
|
to_drop = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => return Err(js_sys::Error::new("This query was already dropped").into()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(e) = error {
|
||||||
|
self.drop_inner();
|
||||||
|
return Err(JsValue::from(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if to_drop {
|
||||||
|
self.drop_inner();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ret.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drops the query.
|
||||||
|
///
|
||||||
|
/// This is useful to end a query early. Like finishing a query, control will be given back
|
||||||
|
/// to the `Machine` and any call to `next` after that will result in an error.
|
||||||
|
#[wasm_bindgen(js_name = drop)]
|
||||||
|
pub fn drop_inner(&mut self) {
|
||||||
|
let ouroboros_impl_wasm_query_state_inner::Heads {
|
||||||
|
machine,
|
||||||
|
drop_channel,
|
||||||
|
} = self.inner.take().unwrap().into_heads();
|
||||||
|
drop_channel.send(machine).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LeafAnswer> for JsValue {
|
||||||
|
fn from(leaf_answer: LeafAnswer) -> JsValue {
|
||||||
|
match leaf_answer {
|
||||||
|
LeafAnswer::True => true.into(),
|
||||||
|
LeafAnswer::False => false.into(),
|
||||||
|
LeafAnswer::Exception(e) => {
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"exception".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"exception".into(), &e.into()).unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
LeafAnswer::LeafAnswer { bindings } => {
|
||||||
|
let bindings_obj = js_sys::Object::new();
|
||||||
|
for (var, term) in bindings.into_iter() {
|
||||||
|
js_sys::Reflect::set(&bindings_obj, &var.into(), &term.into()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let leaf_answer_obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&leaf_answer_obj, &"type".into(), &"leafAnswer".into())
|
||||||
|
.unwrap();
|
||||||
|
js_sys::Reflect::set(&leaf_answer_obj, &"bindings".into(), &bindings_obj.into())
|
||||||
|
.unwrap();
|
||||||
|
leaf_answer_obj.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Term> for JsValue {
|
||||||
|
fn from(term: Term) -> JsValue {
|
||||||
|
match term {
|
||||||
|
Term::Integer(i) => {
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"integer".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&obj,
|
||||||
|
&"integer".into(),
|
||||||
|
&js_sys::BigInt::new(&i.to_string().into()).unwrap().into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
Term::Rational(r) => {
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"rational".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&obj,
|
||||||
|
&"numerator".into(),
|
||||||
|
&js_sys::BigInt::new(&r.numerator().to_string().into())
|
||||||
|
.unwrap()
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&obj,
|
||||||
|
&"denominator".into(),
|
||||||
|
&js_sys::BigInt::new(&r.denominator().to_string().into())
|
||||||
|
.unwrap()
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
Term::Float(f) => {
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"float".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"float".into(), &f.into()).unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
Term::Atom(a) => {
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"atom".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"atom".into(), &a.into()).unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
Term::String(s) => {
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"string".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"string".into(), &s.into()).unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
Term::List(l) => {
|
||||||
|
let list = js_sys::Array::new();
|
||||||
|
for term in l {
|
||||||
|
list.push(&term.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"list".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"list".into(), &list.into()).unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
Term::Compound(functor, args) => {
|
||||||
|
let args_list = js_sys::Array::new();
|
||||||
|
for term in args {
|
||||||
|
args_list.push(&term.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"compound".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"functor".into(), &functor.into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"args".into(), &args_list.into()).unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
Term::Var(v) => {
|
||||||
|
let obj = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(&obj, &"type".into(), &"variable".into()).unwrap();
|
||||||
|
js_sys::Reflect::set(&obj, &"variable".into(), &v.into()).unwrap();
|
||||||
|
obj.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user