diff --git a/Cargo.lock b/Cargo.lock index e054b9db..f4a4952a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -189,7 +198,7 @@ checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -1164,6 +1173,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "markup5ever" version = "0.11.0" @@ -1787,12 +1802,41 @@ version = "0.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6" +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.3.3", + "regex-syntax", +] + [[package]] name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + [[package]] name = "reqwest" version = "0.11.20" @@ -2018,6 +2062,7 @@ dependencies = [ "libc", "libffi", "libloading", + "maplit", "modular-bitfield", "native-tls", "num-order", @@ -2028,6 +2073,7 @@ dependencies = [ "quote", "rand", "ref_thread_local", + "regex", "reqwest", "ring", "ring-wasi", diff --git a/Cargo.toml b/Cargo.toml index 5fb0db69..6366610a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,7 @@ smallvec = "1.8.0" static_assertions = "1.1.0" ryu = "1.0.9" futures = "0.3" +regex = "1.9.1" libloading = "0.7" derive_deref = "1.1.1" bytes = "1" @@ -84,7 +85,7 @@ tokio = { version = "1.28.2", features = ["full"] } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.10", features = ["js"] } -tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt"] } +tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt", "time"] } [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] console_error_panic_hook = "0.1" @@ -107,6 +108,7 @@ ring = { version = "0.16.13" } [dev-dependencies] assert_cmd = "1.0.3" predicates-core = "1.0.2" +maplit = "1.0.2" serial_test = "2.0.0" [patch.crates-io] diff --git a/src/arena.rs b/src/arena.rs index 20763b8c..77d82a36 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -10,7 +10,6 @@ use crate::read::*; use crate::parser::dashu::{Integer, Rational}; use ordered_float::OrderedFloat; -use tokio::sync::RwLock; use std::alloc; use std::cell::UnsafeCell; @@ -20,6 +19,7 @@ use std::mem; use std::net::TcpListener; use std::ops::{Deref, DerefMut}; use std::ptr; +use std::sync::RwLock; #[macro_export] macro_rules! arena_alloc { @@ -90,7 +90,8 @@ pub fn lookup_float( offset: F64Offset, ) -> RcuRef, UnsafeCell>> { let f64table = global_f64table() - .blocking_read() + .read() + .unwrap() .upgrade() .expect("We should only be looking up floats while there is a float table"); @@ -108,12 +109,12 @@ pub fn lookup_float( impl F64Table { #[inline] pub fn new() -> Arc { - let upgraded = global_f64table().blocking_read().upgrade(); + let upgraded = global_f64table().read().unwrap().upgrade(); // don't inline upgraded, otherwise temporary will be dropped too late in case of None if let Some(atom_table) = upgraded { atom_table } else { - let mut guard = global_f64table().blocking_write(); + let mut guard = global_f64table().write().unwrap(); // try to upgrade again in case we lost the race on the write lock if let Some(atom_table) = guard.upgrade() { atom_table diff --git a/src/atom_table.rs b/src/atom_table.rs index 80ba5411..db38f642 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -12,12 +12,12 @@ use std::slice; use std::str; use std::sync::Arc; use std::sync::Mutex; +use std::sync::RwLock; use std::sync::Weak; use indexmap::IndexSet; use modular_bitfield::prelude::*; -use tokio::sync::RwLock; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Atom { @@ -74,7 +74,7 @@ fn global_atom_table() -> &'static RwLock> { #[inline(always)] fn arc_atom_table() -> Option> { - global_atom_table().blocking_read().upgrade() + global_atom_table().read().unwrap().upgrade() } impl RawBlockTraits for AtomTable { @@ -310,12 +310,12 @@ impl InnerAtomTable { impl AtomTable { #[inline] pub fn new() -> Arc { - let upgraded = global_atom_table().blocking_read().upgrade(); + let upgraded = global_atom_table().read().unwrap().upgrade(); // don't inline upgraded, otherwise temporary will be dropped too late in case of None if let Some(atom_table) = upgraded { atom_table } else { - let mut guard = global_atom_table().blocking_write(); + let mut guard = global_atom_table().write().unwrap(); // try to upgrade again in case we lost the race on the write lock if let Some(atom_table) = guard.upgrade() { atom_table diff --git a/src/bin/scryer-prolog.rs b/src/bin/scryer-prolog.rs index 09465006..aa507cfd 100644 --- a/src/bin/scryer-prolog.rs +++ b/src/bin/scryer-prolog.rs @@ -1,5 +1,6 @@ fn main() -> std::process::ExitCode { use scryer_prolog::*; + use scryer_prolog::atom_table::Atom; use std::sync::atomic::Ordering; #[cfg(feature = "repl")] @@ -8,6 +9,20 @@ fn main() -> std::process::ExitCode { }) .unwrap(); - let mut wam = machine::Machine::new(); - wam.run_top_level() + #[cfg(target_arch = "wasm32")] + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + #[cfg(not(target_arch = "wasm32"))] + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + runtime.block_on(async move { + let mut wam = machine::Machine::new(Default::default()); + wam.run_top_level(atom!("$toplevel"), (atom!("$repl"), 1)) + }) } diff --git a/src/lib.rs b/src/lib.rs index 8817fa5f..3579fcf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ #[macro_use] extern crate static_assertions; +#[cfg(test)] +#[macro_use] extern crate maplit; #[macro_use] pub mod macros; @@ -47,7 +49,6 @@ use wasm_bindgen::prelude::*; #[cfg(target_arch = "wasm32")] #[wasm_bindgen] pub fn eval_code(s: &str) -> String { - use web_sys::console; use machine::mock_wam::*; let mut wam = Machine::with_test_streams(); diff --git a/src/loader.pl b/src/loader.pl index d0fb65a8..d1b718b0 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -621,6 +621,10 @@ use_module(Module, Exports, Evacuable) :- ) ). +consult_stream(Stream, PathFileName) :- + '$push_load_state_payload'(Evacuable), + file_load(Stream, PathFileName, Subevacuable), + '$use_module'(Evacuable, Subevacuable, _). :- non_counted_backtracking check_predicate_property/5. diff --git a/src/machine/config.rs b/src/machine/config.rs new file mode 100644 index 00000000..6268c8d8 --- /dev/null +++ b/src/machine/config.rs @@ -0,0 +1,32 @@ +pub struct MachineConfig { + pub streams: StreamConfig, + pub toplevel: &'static str, +} + +pub enum StreamConfig { + Stdio, + Memory, +} + +impl Default for MachineConfig { + fn default() -> Self { + MachineConfig { + streams: StreamConfig::Stdio, + toplevel: include_str!("../toplevel.pl"), + } + } +} + +impl MachineConfig { + pub fn in_memory() -> Self { + MachineConfig { + streams: StreamConfig::Memory, + ..Default::default() + } + } + + pub fn with_toplevel(mut self, toplevel: &'static str) -> Self { + self.toplevel = toplevel; + self + } +} diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 5722484f..191a023f 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -5221,16 +5221,22 @@ impl Machine { self.machine_st.throw_interrupt_exception(); self.machine_st.backtrack(); - #[cfg(not(target_arch = "wasm32"))] - let runtime = tokio::runtime::Runtime::new().unwrap(); - #[cfg(target_arch = "wasm32")] - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); + // We have extracted controll over the Tokio runtime to the calling context for enabling library use case + // (see https://github.com/mthom/scryer-prolog/pull/1880) + // So we only have access to a runtime handle in here and can't shut it down. + // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880 + // was not merged, I'm only deactivating it for now. + + //#[cfg(not(target_arch = "wasm32"))] + //let runtime = tokio::runtime::Runtime::new().unwrap(); + //#[cfg(target_arch = "wasm32")] + //let runtime = tokio::runtime::Builder::new_current_thread() + // .enable_all() + // .build() + // .unwrap(); - let old_runtime = std::mem::replace(&mut self.runtime, runtime); - old_runtime.shutdown_background(); + //let old_runtime = tokio::runtime::Handle::current(); + //old_runtime.shutdown_background(); } } Err(_) => unreachable!(), diff --git a/src/machine/lib_integration_test_commands.txt b/src/machine/lib_integration_test_commands.txt new file mode 100644 index 00000000..faf40938 --- /dev/null +++ b/src/machine/lib_integration_test_commands.txt @@ -0,0 +1,1018 @@ +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +:- discontiguous(languageName/2). +:- discontiguous(expressionAddress/2). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +=====query +subject_class(X, _). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +:- discontiguous(languageName/2). +:- discontiguous(expressionAddress/2). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class(X, _). +=====query +subject_class("Todo", C), constructor(C, Actions). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:construct%20test", "todo://state", "todo://ready"). +link("literal://string:construct%20test", "todo://state", "todo://ready", 1691084130581, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:construct%20test", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:construct%20test", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), instance(C, "literal://string:construct%20test"). +=====query +subject_class("Todo", C), instance(C, "literal://string:construct%20test"). +=====query +subject_class("Todo", C), property(C, Property). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "state"). +=====query +subject_class("Todo", C), property_resolve(C, "title"). +=====query +subject_class("Todo", C), property_setter(C, Property, Setter). +=====query +subject_class("Todo", C), property_resolve_language(C, "state", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), collection(C, Collection). +=====query +subject_class("Todo", C), collection_adder(C, Collection, Adder). +=====query +subject_class("Todo", C), collection_remover(C, Collection, Remover). +=====query +subject_class("Todo", C), collection_setter(C, Collection, Setter). +=====query +subject_class("Todo", C), instance(C, "literal://string:construct%20test"). +=====query +subject_class("Todo", C), constructor(C, Actions). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:construct%20test", "todo://state", "todo://ready"). +triple("literal://string:get%20proxy%20test", "todo://state", "todo://ready"). +link("literal://string:construct%20test", "todo://state", "todo://ready", 1691084130581, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:get%20proxy%20test", "todo://state", "todo://ready", 1691084130761, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:construct%20test", "literal"). +languageAddress("literal://string:get%20proxy%20test", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:construct%20test", "literal"). +languageName("literal://string:get%20proxy%20test", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +expressionAddress("literal://string:get%20proxy%20test", "string:get%20proxy%20test"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), instance(C, "literal://string:get%20proxy%20test"). +=====query +subject_class("Todo", C), instance(C, "literal://string:get%20proxy%20test"). +=====query +subject_class("Todo", C), property(C, Property). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "state"). +=====query +subject_class("Todo", C), property_resolve(C, "title"). +=====query +subject_class("Todo", C), property_setter(C, Property, Setter). +=====query +subject_class("Todo", C), property_resolve_language(C, "state", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), collection(C, Collection). +=====query +subject_class("Todo", C), collection_adder(C, Collection, Adder). +=====query +subject_class("Todo", C), collection_remover(C, Collection, Remover). +=====query +subject_class("Todo", C), collection_setter(C, Collection, Setter). +=====query +subject_class("Todo", C), instance(C, "literal://string:get%20proxy%20test"). +=====query +subject_class("Todo", C), instance(C, "literal://string:get%20proxy%20test"). +=====query +subject_class("Todo", C), property(C, Property). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "state"). +=====query +subject_class("Todo", C), property_resolve(C, "title"). +=====query +subject_class("Todo", C), property_setter(C, Property, Setter). +=====query +subject_class("Todo", C), property_resolve_language(C, "state", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), collection(C, Collection). +=====query +subject_class("Todo", C), collection_adder(C, Collection, Adder). +=====query +subject_class("Todo", C), collection_remover(C, Collection, Remover). +=====query +subject_class("Todo", C), collection_setter(C, Collection, Setter). +=====query +subject_class("Todo", C), property_getter(C, "literal://string:get%20proxy%20test", "state", Value). +=====query +subject_class("Todo", C), property_getter(C, "literal://string:get%20proxy%20test", "title", Value). +=====query +subject_class("Todo", C), constructor(C, Actions). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:construct%20test", "todo://state", "todo://ready"). +triple("literal://string:get%20proxy%20test", "todo://state", "todo://ready"). +triple("literal://string:construct%20test", "todo://state", "todo://ready"). +link("literal://string:construct%20test", "todo://state", "todo://ready", 1691084130581, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:get%20proxy%20test", "todo://state", "todo://ready", 1691084130761, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://state", "todo://ready", 1691084131145, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:construct%20test", "literal"). +languageAddress("literal://string:get%20proxy%20test", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:construct%20test", "literal"). +languageName("literal://string:get%20proxy%20test", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +expressionAddress("literal://string:get%20proxy%20test", "string:get%20proxy%20test"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), instance(C, "literal://string:construct%20test"). +=====query +subject_class("Todo", C), instance(C, "literal://string:construct%20test"). +=====query +subject_class("Todo", C), property(C, Property). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "state"). +=====query +subject_class("Todo", C), property_resolve(C, "title"). +=====query +subject_class("Todo", C), property_setter(C, Property, Setter). +=====query +subject_class("Todo", C), property_resolve_language(C, "state", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), collection(C, Collection). +=====query +subject_class("Todo", C), collection_adder(C, Collection, Adder). +=====query +subject_class("Todo", C), collection_remover(C, Collection, Remover). +=====query +subject_class("Todo", C), collection_setter(C, Collection, Setter). +=====query +subject_class("Todo", C), property_getter(C, "literal://string:construct%20test", "state", Value). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:get%20proxy%20test", "todo://state", "todo://ready"). +triple("literal://string:construct%20test", "todo://state", "todo://done"). +link("literal://string:get%20proxy%20test", "todo://state", "todo://ready", 1691084130761, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://state", "todo://done", 1691084131359, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:get%20proxy%20test", "literal"). +languageAddress("literal://string:construct%20test", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:get%20proxy%20test", "literal"). +languageName("literal://string:construct%20test", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:get%20proxy%20test", "string:get%20proxy%20test"). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), property_getter(C, "literal://string:construct%20test", "state", Value). +=====query +subject_class("Todo", C), property_getter(C, "literal://string:construct%20test", "title", Value). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:get%20proxy%20test", "todo://state", "todo://ready"). +triple("literal://string:construct%20test", "todo://state", "todo://done"). +triple("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +link("literal://string:get%20proxy%20test", "todo://state", "todo://ready", 1691084130761, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://state", "todo://done", 1691084131359, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", 1691084131416, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:get%20proxy%20test", "literal"). +languageAddress("literal://string:construct%20test", "literal"). +languageAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:get%20proxy%20test", "literal"). +languageName("literal://string:construct%20test", "literal"). +languageName("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:get%20proxy%20test", "string:get%20proxy%20test"). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +expressionAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), property_getter(C, "literal://string:construct%20test", "title", Value). +=====query +subject_class("Todo", C), collection_getter(C, "literal://string:construct%20test", "comments", Value). +=====query +subject_class("Todo", C), collection_getter(C, "literal://string:construct%20test", "comments", Value). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:get%20proxy%20test", "todo://state", "todo://ready"). +triple("literal://string:construct%20test", "todo://state", "todo://done"). +triple("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +triple("literal://string:construct%20test", "todo://comment", "literal://string:comment%201"). +link("literal://string:get%20proxy%20test", "todo://state", "todo://ready", 1691084130761, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://state", "todo://done", 1691084131359, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", 1691084131416, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://comment", "literal://string:comment%201", 1691084131473, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:get%20proxy%20test", "literal"). +languageAddress("literal://string:construct%20test", "literal"). +languageAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +languageAddress("literal://string:comment%201", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:get%20proxy%20test", "literal"). +languageName("literal://string:construct%20test", "literal"). +languageName("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +languageName("literal://string:comment%201", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:get%20proxy%20test", "string:get%20proxy%20test"). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +expressionAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +expressionAddress("literal://string:comment%201", "string:comment%201"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), collection_getter(C, "literal://string:construct%20test", "comments", Value). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:get%20proxy%20test", "todo://state", "todo://ready"). +triple("literal://string:construct%20test", "todo://state", "todo://done"). +triple("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +link("literal://string:get%20proxy%20test", "todo://state", "todo://ready", 1691084130761, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://state", "todo://done", 1691084131359, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", 1691084131416, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:get%20proxy%20test", "literal"). +languageAddress("literal://string:construct%20test", "literal"). +languageAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:get%20proxy%20test", "literal"). +languageName("literal://string:construct%20test", "literal"). +languageName("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:get%20proxy%20test", "string:get%20proxy%20test"). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +expressionAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), collection_getter(C, "literal://string:construct%20test", "comments", Value). +=====consult +:- discontiguous(triple/3). +:- discontiguous(link/5). +triple("literal://string:get%20proxy%20test", "todo://state", "todo://ready"). +triple("literal://string:construct%20test", "todo://state", "todo://done"). +triple("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +triple("literal://string:construct%20test", "todo://comment", "literal://string:new%20comment%201"). +link("literal://string:get%20proxy%20test", "todo://state", "todo://ready", 1691084130761, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://state", "todo://done", 1691084131359, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://has_title", "literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", 1691084131416, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +link("literal://string:construct%20test", "todo://comment", "literal://string:new%20comment%201", 1691084131557, "did:key:z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa"). +:- discontiguous(reachable/2). +reachable(A,B) :- triple(A,_,B). +reachable(A,B) :- triple(A,_,X), reachable(X,B). +:- discontiguous(hiddenExpression/1). +:- discontiguous(languageAddress/2). +languageAddress("literal://string:get%20proxy%20test", "literal"). +languageAddress("literal://string:construct%20test", "literal"). +languageAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +languageAddress("literal://string:new%20comment%201", "literal"). +:- discontiguous(languageName/2). +languageName("literal://string:get%20proxy%20test", "literal"). +languageName("literal://string:construct%20test", "literal"). +languageName("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "literal"). +languageName("literal://string:new%20comment%201", "literal"). +:- discontiguous(expressionAddress/2). +expressionAddress("literal://string:get%20proxy%20test", "string:get%20proxy%20test"). +expressionAddress("literal://string:construct%20test", "string:construct%20test"). +expressionAddress("literal://json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D", "json:%7B%22author%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22timestamp%22%3A%222023-08-03T17%3A35%3A31.405Z%22%2C%22data%22%3A%22test%20title%22%2C%22proof%22%3A%7B%22key%22%3A%22did%3Akey%3Az6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%23z6MkfMZgoaZc5CRUSMxrugjiJLufgkAmRZ72gctjRY4LfxRa%22%2C%22signature%22%3A%2253a6d498d7c19fed24000efe3339526b564d779f0906b71304c96b1016a09f0288b1f2c5718505f4e23933c95b7a7e68466330a824e01a80c6275d922030860c%22%2C%22valid%22%3Atrue%2C%22invalid%22%3Afalse%7D%7D"). +expressionAddress("literal://string:new%20comment%201", "string:new%20comment%201"). +:- discontiguous(register_sdna_flow/2). +:- discontiguous(flowable/2). +:- discontiguous(flow_state/3). +:- discontiguous(start_action/2). +:- discontiguous(action/4). +:- discontiguous(subject_class/2). +:- discontiguous(constructor/2). +:- discontiguous(destructor/2). +:- discontiguous(instance/2). +:- discontiguous(property/2). +:- discontiguous(property_getter/4). +:- discontiguous(property_setter/3). +:- discontiguous(property_resolve/2). +:- discontiguous(property_resolve_language/3). +:- discontiguous(property_named_option/4). +:- discontiguous(collection/2). +:- discontiguous(collection_getter/4). +:- discontiguous(collection_setter/3). +:- discontiguous(collection_remover/3). +:- discontiguous(collection_adder/3). +:- discontiguous(p3_class_icon/2). +:- discontiguous(p3_class_color/2). +:- discontiguous(p3_instance_color/3). +subject_class("Todo", c). +constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). +instance(c, Base) :- triple(Base, "todo://state", _). + +destructor(c, '[{action: "removeLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + +property(c, "state"). +property_getter(c, Base, "state", Value) :- triple(Base, "todo://state", Value). +property_setter(c, "state", '[{action: "setSingleTarget", source: "this", predicate: "todo://state", target: "value"}]'). + +property(c, "title"). +property_resolve(c, "title"). +property_resolve_language(c, "title", "literal"). +property_getter(c, Base, "title", Value) :- triple(Base, "todo://has_title", Value). +property_setter(c, "title", '[{action: "setSingleTarget", source: "this", predicate: "todo://has_title", target: "value"}]'). + +property(c, "isLiked"). +property_getter(c, Base, "isLiked", Value) :- triple(Base, "flux://has_reaction", "flux://thumbsup"), Value = true. + +collection(c, "comments"). +collection_getter(c, Base, "comments", List) :- findall(C, triple(Base, "todo://comment", C), List). +collection_adder(c, "commentss", '[{action: "addLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_remover(c, "commentss", '[{action: "removeLink", source: "this", predicate: "todo://comment", target: "value"}]'). +collection_setter(c, "commentss", '[{action: "collectionSetter", source: "this", predicate: "todo://comment", target: "value"}]'). + +collection(c, "entries"). +collection_getter(c, Base, "entries", List) :- findall(C, triple(Base, "flux://entry_type", C), List). +collection_adder(c, "entriess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "entriess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "entriess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "messages"). +collection_getter(c, Base, "messages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), instance(OtherClass, Target), subject_class("Message", OtherClass)), List). +collection_adder(c, "messagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "messagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "messagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +collection(c, "likedMessages"). +collection_getter(c, Base, "likedMessages", List) :- setof(Target, (triple(Base, "flux://entry_type", Target), triple(Target, "flux://has_reaction", "flux://thumbsup")), List). +collection_adder(c, "likedMessagess", '[{action: "addLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_remover(c, "likedMessagess", '[{action: "removeLink", source: "this", predicate: "flux://entry_type", target: "value"}]'). +collection_setter(c, "likedMessagess", '[{action: "collectionSetter", source: "this", predicate: "flux://entry_type", target: "value"}]'). + +=====query +subject_class("Todo", C), collection_getter(C, "literal://string:construct%20test", "comments", Value). +=====query +subject_class("Todo", C), instance(C, X). +=====query +subject_class("Todo", C), instance(C, "literal://string:construct%20test"). +=====query +subject_class("Todo", C), instance(C, "literal://string:get%20proxy%20test"). +=====query +subject_class("Todo", C), instance(C, "literal://string:construct%20test"). +=====query +subject_class("Todo", C), instance(C, "literal://string:get%20proxy%20test"). +=====query +subject_class("Todo", C), property(C, Property). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "isLiked"). +=====query +subject_class("Todo", C), property_resolve(C, "state"). +=====query +subject_class("Todo", C), property_resolve(C, "title"). +=====query +subject_class("Todo", C), property_setter(C, Property, Setter). +=====query +subject_class("Todo", C), property_resolve_language(C, "state", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), property_resolve_language(C, "title", Language). +=====query +subject_class("Todo", C), collection(C, Collection). +=====query +subject_class("Todo", C), collection_adder(C, Collection, Adder). +=====query +subject_class("Todo", C), collection_remover(C, Collection, Remover). +=====query +subject_class("Todo", C), collection_setter(C, Collection, Setter). +=====query +subject_class("Todo", C), property_getter(C, "literal://string:get%20proxy%20test", "state", Value). +=====query +subject_class(Class, C), property(C, "state"), property(C, "title"), collection(C, "comments"), property_setter(C, "state", _), property_setter(C, "title", _), collection_adder(C, "commentss", _), collection_setter(C, "commentss", _). diff --git a/src/machine/lib_machine.rs b/src/machine/lib_machine.rs new file mode 100644 index 00000000..78ff50c7 --- /dev/null +++ b/src/machine/lib_machine.rs @@ -0,0 +1,484 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + +use crate::atom_table; +use crate::heap_print::{HCPrinter, HCValueOutputter, PrinterOutputter}; +use crate::machine::{BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS}; +use crate::machine::mock_wam::CompositeOpDir; +use crate::parser::parser::{Parser, Tokens}; +use crate::read::write_term_to_heap; +use crate::machine::machine_indices::VarKey; +use crate::parser::ast::{Var, VarPtr}; +use indexmap::IndexMap; + +use super::{ + Machine, MachineConfig, QueryResult, QueryResolutionLine, + Atom, AtomCell, HeapCellValue, HeapCellValueTag, Value, QueryResolution, + streams::Stream +}; + +impl Machine { + pub fn new_lib() -> Self { + Machine::new(MachineConfig::in_memory()) + } + + pub fn load_module_string(&mut self, module_name: &str, program: String) { + let stream = Stream::from_owned_string(program, &mut self.machine_st.arena); + self.load_file(module_name, stream); + } + + pub fn consult_module_string(&mut self, module_name: &str, program: String) { + let stream = Stream::from_owned_string(program, &mut self.machine_st.arena); + self.machine_st.registers[1] = stream_as_cell!(stream); + self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with(&self.machine_st.atom_tbl, module_name)); + + self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2)); + } + + fn allocate_stub_choice_point(&mut self) { + // NOTE: create a choice point to terminate the dispatch_loop + // if an exception is thrown. since the and/or stack is presumed empty, + + let stub_b = self.machine_st.stack.allocate_or_frame(0); + let or_frame = self.machine_st.stack.index_or_frame_mut(0); + + or_frame.prelude.num_cells = 0; + or_frame.prelude.e = 0; + or_frame.prelude.cp = 0; + or_frame.prelude.b = 0; + or_frame.prelude.bp = BREAK_FROM_DISPATCH_LOOP_LOC; + or_frame.prelude.boip = 0; + or_frame.prelude.biip = 0; + or_frame.prelude.tr = 0; + or_frame.prelude.h = 0; + or_frame.prelude.b0 = 0; + or_frame.prelude.attr_var_queue_len = 0; + + self.machine_st.b = stub_b; + } + + pub fn run_query(&mut self, query: String) -> QueryResult { + println!("Query: {}", query); + // Parse the query so we can analyze and then call the term + let mut parser = Parser::new( + Stream::from_owned_string(query, &mut self.machine_st.arena), + &mut self.machine_st + ); + let op_dir = CompositeOpDir::new(&self.indices.op_dir, None); + let term = parser.read_term(&op_dir, Tokens::Default).expect("Failed to parse query"); + + // Write parsed term to heap + let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap, &mut self.machine_st.atom_tbl).expect("couldn't write term to heap"); + + // Write term to heap + self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc]; + + self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC; + self.machine_st.p = self.indices.code_dir.get(&(atom!("call"), 1)).expect("couldn't get code index").local().unwrap(); + + let var_names: IndexMap<_, _> = term_write_result.var_dict.iter() + .map(|(var_key, cell)| match var_key { + // NOTE: not the intention behind Var::InSitu here but + // we can hijack it to store anonymous variables + // without creating problems. + VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))), + VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()), + }) + .collect(); + + self.allocate_stub_choice_point(); + + let stub_b = self.machine_st.b; + + let mut matches: Vec = Vec::new(); + // Call the term + loop { + self.dispatch_loop(); + + //println!("b: {}", self.machine_st.b); + //println!("stub_b: {}", stub_b); + //println!("fail: {}", self.machine_st.fail); + + if self.machine_st.ball.stub.len() != 0 { + // NOTE: this means an exception was thrown, at which + // point we backtracked to the stub choice point. + // this should halt the search for solutions as it + // does in the Scryer top-level. the exception term is + // contained in self.machine_st.ball. + let error_string = self.machine_st.ball.stub + .iter() + .filter(|h| match h.get_tag() { + HeapCellValueTag::Atom => true, + HeapCellValueTag::Fixnum => true, + _ => false, + }) + .map(|h| match h.get_tag() { + HeapCellValueTag::Atom => { + let (name, _) = cell_as_atom_cell!(h).get_name_and_arity(); + name.as_str().to_string() + } + HeapCellValueTag::Fixnum => { + h.get_value().clone().to_string() + }, + _ => unreachable!(), + }) + .collect::>() + .join(" "); + + return Err(error_string); + } + + /* + if self.machine_st.fail { + // NOTE: only print results on success + self.machine_st.fail = false; + println!("fail!"); + matches.push(QueryResolutionLine::False); + break; + }; + */ + + if term_write_result.var_dict.is_empty() { + if self.machine_st.p == LIB_QUERY_SUCCESS { + matches.push(QueryResolutionLine::True); + break; + } else if self.machine_st.p == BREAK_FROM_DISPATCH_LOOP_LOC { + // NOTE: only print results on success + // self.machine_st.fail = false; + // println!("b == stub_b"); + matches.push(QueryResolutionLine::False); + break; + } + } + + let mut bindings: BTreeMap = BTreeMap::new(); + + for (var_key, term_to_be_printed) in &term_write_result.var_dict { + if var_key.to_string().starts_with("_") { + continue; + } + let mut printer = HCPrinter::new( + &mut self.machine_st.heap, + Arc::clone(&self.machine_st.atom_tbl), + &mut self.machine_st.stack, + &self.indices.op_dir, + PrinterOutputter::new(), + *term_to_be_printed, + ); + + printer.ignore_ops = false; + printer.numbervars = true; + printer.quoted = true; + printer.max_depth = 1000; // NOTE: set this to 0 for unbounded depth + printer.double_quotes = true; + printer.var_names = var_names.clone(); + + let outputter = printer.print(); + + let output: String = outputter.result(); + println!("Result: {} = {}", var_key.to_string(), output); + + bindings.insert(var_key.to_string(), Value::try_from(output).expect("asdfs")); + } + + matches.push(QueryResolutionLine::Match(bindings)); + + // NOTE: there are outstanding choicepoints, backtrack + // through them for further solutions. if + // self.machine_st.b == stub_b we've backtracked to the stub + // choice point, so we should break. + self.machine_st.backtrack(); + + if self.machine_st.b <= stub_b { + // NOTE: out of choicepoints to backtrack through, no + // more solutions to gather. + break; + } + } + + // NOTE: deallocate stub choice point + if self.machine_st.b == stub_b { + self.trust_me(); + } + + Ok(QueryResolution::from(matches)) + } +} + +#[cfg(test)] +mod tests { + use ordered_float::OrderedFloat; + + use super::*; + use crate::machine::{QueryMatch, Value, QueryResolution}; + + #[test] + fn programatic_query() { + let mut machine = Machine::new_lib(); + + machine.load_module_string( + "facts", + String::from( + r#" + triple("a", "p1", "b"). + triple("a", "p2", "b"). + "#, + ), + ); + + let query = String::from(r#"triple("a",P,"b")."#); + let output = machine.run_query(query); + assert_eq!( + output, + Ok(QueryResolution::Matches(vec![ + QueryMatch::from(btreemap! { + "P" => Value::from("p1"), + }), + QueryMatch::from(btreemap! { + "P" => Value::from("p2"), + }), + ])) + ); + + assert_eq!( + machine.run_query(String::from(r#"triple("a","p1","b")."#)), + Ok(QueryResolution::True) + ); + + assert_eq!( + machine.run_query(String::from(r#"triple("x","y","z")."#)), + Ok(QueryResolution::False) + ); + } + + #[test] + fn failing_query() { + let mut machine = Machine::new_lib(); + let query = String::from(r#"triple("a",P,"b")."#); + let output = machine.run_query(query); + assert_eq!( + output, + Err(String::from("error existence_error procedure / triple 3 / triple 3")) + ); + } + + #[test] + fn complex_results() { + let mut machine = Machine::new_lib(); + machine.load_module_string( + "facts", + r#" + :- discontiguous(subject_class/2). + :- discontiguous(constructor/2). + + subject_class("Todo", c). + constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]'). + + subject_class("Recipe", xyz). + constructor(xyz, '[{action: "addLink", source: "this", predicate: "recipe://title", target: "literal://string:Meta%20Muffins"}]'). + "#.to_string()); + + let result = machine.run_query(String::from("subject_class(\"Todo\", C), constructor(C, Actions).")); + assert_eq!( + result, + Ok(QueryResolution::Matches(vec![ + QueryMatch::from(btreemap! { + "C" => Value::from("c"), + "Actions" => Value::from("[{action: \"addLink\", source: \"this\", predicate: \"todo://state\", target: \"todo://ready\"}]"), + }), + ])) + ); + + let result = machine.run_query(String::from("subject_class(\"Recipe\", C), constructor(C, Actions).")); + assert_eq!( + result, + Ok(QueryResolution::Matches(vec![ + QueryMatch::from(btreemap! { + "C" => Value::from("xyz"), + "Actions" => Value::from("[{action: \"addLink\", source: \"this\", predicate: \"recipe://title\", target: \"literal://string:Meta%20Muffins\"}]"), + }), + ])) + ); + + let result = machine.run_query(String::from("subject_class(Class, _).")); + assert_eq!( + result, + Ok(QueryResolution::Matches(vec![ + QueryMatch::from(btreemap! { + "Class" => Value::from("Todo") + }), + QueryMatch::from(btreemap! { + "Class" => Value::from("Recipe") + }), + ])) + ); + } + + #[test] + fn list_results() { + let mut machine = Machine::new_lib(); + machine.load_module_string( + "facts", + r#" + list([1,2,3]). + "#.to_string()); + + let result = machine.run_query(String::from("list(X).")); + assert_eq!( + result, + Ok(QueryResolution::Matches(vec![ + QueryMatch::from(btreemap! { + "X" => Value::List( + Vec::from([ + Value::Float(OrderedFloat::from(1.0)), + Value::Float(OrderedFloat::from(2.0)), + Value::Float(OrderedFloat::from(3.0)) + ]) + ) + }), + ])) + ); + } + + + #[test] + fn consult() { + let mut machine = Machine::new_lib(); + + machine.consult_module_string( + "facts", + String::from( + r#" + triple("a", "p1", "b"). + triple("a", "p2", "b"). + "#, + ), + ); + + let query = String::from(r#"triple("a",P,"b")."#); + let output = machine.run_query(query); + assert_eq!( + output, + Ok(QueryResolution::Matches(vec![ + QueryMatch::from(btreemap! { + "P" => Value::from("p1"), + }), + QueryMatch::from(btreemap! { + "P" => Value::from("p2"), + }), + ])) + ); + + assert_eq!( + machine.run_query(String::from(r#"triple("a","p1","b")."#)), + Ok(QueryResolution::True) + ); + + assert_eq!( + machine.run_query(String::from(r#"triple("x","y","z")."#)), + Ok(QueryResolution::False) + ); + + machine.consult_module_string( + "facts", + String::from( + r#" + triple("a", "new", "b"). + "#, + ), + ); + + assert_eq!( + machine.run_query(String::from(r#"triple("a","p1","b")."#)), + Ok(QueryResolution::False) + ); + + assert_eq!( + machine.run_query(String::from(r#"triple("a","new","b")."#)), + Ok(QueryResolution::True) + ); + + } + + #[ignore = "fails on windows"] + #[test] + fn stress_integration_test() { + let mut machine = Machine::new_lib(); + + // File with test commands, i.e. program code to consult and queries to run + let code = include_str!("./lib_integration_test_commands.txt"); + + // Split the code into blocks + let blocks = code.split("====="); + + let mut i = 0; + // Iterate over the blocks + for block in blocks { + // Trim the block to remove any leading or trailing whitespace + let block = block.trim(); + + // Skip empty blocks + if block.is_empty() { + continue; + } + + // Check if the block is a query + if block.starts_with("query") { + // Extract the query from the block + let query = &block[5..]; + + i += 1; + println!("query #{}: {}", i, query); + // Parse and execute the query + let result = machine.run_query(query.to_string()); + + assert!(result.is_ok()); + + // Print the result + println!("{:?}", result); + } else if block.starts_with("consult") { + // Extract the code from the block + let code = &block[7..]; + + println!("load code: {}", code); + + // Load the code into the machine + machine.consult_module_string("facts", code.to_string()); + } + } + } + + #[test] + fn findall() { + let mut machine = Machine::new_lib(); + + machine.consult_module_string( + "facts", + String::from( + r#" + triple("a", "p1", "b"). + triple("a", "p2", "b"). + "#, + ), + ); + + let query = String::from(r#"findall([Predicate, Target], triple(_,Predicate,Target), Result)."#); + let output = machine.run_query(query); + assert_eq!( + output, + Ok(QueryResolution::Matches(vec![ + QueryMatch::from(btreemap! { + "Predicate" => Value::from("Predicate"), + "Result" => Value::List( + Vec::from([ + Value::List([Value::from("p1"), Value::from("b")].into()), + Value::List([Value::from("p2"), Value::from("b")].into()), + ]) + ), + "Target" => Value::from("Target"), + }), + ])) + ); + + } +} diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 033b3090..94e85af8 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -672,6 +672,14 @@ impl MachineState { } } + if let Stream::Byte(_) = stream { + return self.read_term( + stream, + indices, + MachineState::read_term_from_user_input_eof_handler + ) + } + unreachable!("Stream must be a Stream::Readline(_)") } diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 56119f60..4b3de5ed 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -221,109 +221,10 @@ pub(crate) fn parse_and_write_parsed_term_to_heap( impl Machine { pub fn with_test_streams() -> Self { - use ref_thread_local::RefThreadLocal; - - let mut machine_st = MachineState::new(); - - let user_input = Stream::Null(StreamOptions::default()); - let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena); - let user_error = Stream::stderr(&mut machine_st.arena); - - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - let mut wam = Machine { - machine_st, - indices: IndexStore::new(), - code: Code::new(), - user_input, - user_output, - user_error, - load_contexts: vec![], - runtime, - #[cfg(feature = "ffi")] - foreign_function_table: Default::default(), - rng: StdRng::from_entropy(), - }; - - let mut lib_path = current_dir(); - - lib_path.pop(); - lib_path.push("lib"); - - wam.add_impls_to_indices(); - - bootstrapping_compile( - Stream::from_static_string( - LIBRARIES.borrow()["ops_and_meta_predicates"], - &mut wam.machine_st.arena, - ), - &mut wam, - ListingSource::from_file_and_path( - atom!("ops_and_meta_predicates.pl"), - lib_path.clone(), - ), - ) - .unwrap(); - - bootstrapping_compile( - Stream::from_static_string(LIBRARIES.borrow()["builtins"], &mut wam.machine_st.arena), - &mut wam, - ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()), - ) - .unwrap(); - - if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) { - load_module( - &mut wam.machine_st, - &mut wam.indices.code_dir, - &mut wam.indices.op_dir, - &mut wam.indices.meta_predicates, - &CompilationTarget::User, - builtins, - ); - - import_builtin_impls(&wam.indices.code_dir, builtins); - } else { - unreachable!() - } - - lib_path.pop(); // remove the "lib" at the end - - bootstrapping_compile( - Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena), - &mut wam, - ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()), - ) - .unwrap(); - - wam.configure_modules(); - - if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { - load_module( - &mut wam.machine_st, - &mut wam.indices.code_dir, - &mut wam.indices.op_dir, - &mut wam.indices.meta_predicates, - &CompilationTarget::User, - loader, - ); - } else { - unreachable!() - } - - wam.load_special_forms(); - wam.load_top_level(); - wam.configure_streams(); - - wam + Machine::new(MachineConfig::in_memory()) } pub fn test_load_file(&mut self, file: &str) -> Vec { - use std::io::Read; - let stream = Stream::from_owned_string( std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), &mut self.machine_st.arena, @@ -334,8 +235,6 @@ impl Machine { } pub fn test_load_string(&mut self, code: &str) -> Vec { - use std::io::Read; - let stream = Stream::from_owned_string( code.to_owned(), &mut self.machine_st.arena, diff --git a/src/machine/mod.rs b/src/machine/mod.rs index c44df762..b4f1687e 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -5,18 +5,21 @@ pub mod code_walker; #[macro_use] pub mod loader; pub mod compile; +pub mod config; pub mod copier; pub mod cycle_detection; pub mod disjuncts; pub mod dispatch; pub mod gc; pub mod heap; +pub mod lib_machine; pub mod load_state; pub mod machine_errors; pub mod machine_indices; pub mod machine_state; pub mod machine_state_impl; pub mod mock_wam; +pub mod parsed_results; pub mod partial_string; pub mod preprocessor; pub mod stack; @@ -52,9 +55,12 @@ use ordered_float::OrderedFloat; use std::cmp::Ordering; use std::env; +use std::io::Read; use std::path::PathBuf; use std::sync::atomic::AtomicBool; -use tokio::runtime::Runtime; + +use self::config::MachineConfig; +use self::parsed_results::*; use rand::rngs::StdRng; use rand::SeedableRng; @@ -71,7 +77,6 @@ pub struct Machine { pub(super) user_output: Stream, pub(super) user_error: Stream, pub(super) load_contexts: Vec, - pub(super) runtime: Runtime, #[cfg(feature = "ffi")] pub(super) foreign_function_table: ForeignFunctionTable, pub(super) rng: StdRng, @@ -113,6 +118,7 @@ include!(concat!(env!("OUT_DIR"), "/libraries.rs")); pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0; pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1; pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 2; +pub static LIB_QUERY_SUCCESS: usize = 3; pub struct MachinePreludeView<'a> { pub indices: &'a mut IndexStore, @@ -240,14 +246,15 @@ impl Machine { self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2)); } - fn load_top_level(&mut self) { + fn load_top_level(&mut self, program: &'static str) { let mut path_buf = current_dir(); path_buf.push("src/toplevel.pl"); let path = path_buf.to_str().unwrap(); - let toplevel_stream = - Stream::from_static_string(include_str!("../toplevel.pl"), &mut self.machine_st.arena); + let toplevel_stream = + Stream::from_static_string(program, &mut self.machine_st.arena); + self.load_file(path, toplevel_stream); @@ -293,7 +300,7 @@ impl Machine { } } - pub fn run_top_level(&mut self) -> std::process::ExitCode { + pub fn run_top_level(&mut self, module_name: Atom, key: PredicateKey) -> std::process::ExitCode { let mut arg_pstrs = vec![]; for arg in env::args() { @@ -309,7 +316,16 @@ impl Machine { arg_pstrs.into_iter() )); - self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1)) + self.run_module_predicate(module_name, key) + } + + pub fn set_user_input(&mut self, input: String) { + self.user_input = Stream::from_owned_string(input, &mut self.machine_st.arena); + } + + pub fn get_user_output(&self) -> String { + let output_bytes: Vec<_> = self.user_output.bytes().map(|b| b.unwrap()).collect(); + String::from_utf8(output_bytes).unwrap() } pub(crate) fn configure_modules(&mut self) { @@ -382,13 +398,14 @@ impl Machine { } pub(crate) fn add_impls_to_indices(&mut self) { - let impls_offset = self.code.len() + 3; + let impls_offset = self.code.len() + 4; self.code.extend( vec![ Instruction::BreakFromDispatchLoop, Instruction::InstallVerifyAttr, Instruction::VerifyAttrInterrupt, + Instruction::BreakFromDispatchLoop, // the location of LIB_QUERY_SUCCESS Instruction::ExecuteTermGreaterThan, Instruction::ExecuteTermLessThan, Instruction::ExecuteTermGreaterThanOrEqual, @@ -447,23 +464,24 @@ impl Machine { } } - pub fn new() -> Self { + pub fn new(config: MachineConfig) -> Self { use ref_thread_local::RefThreadLocal; let args = MachineArgs::new(); let mut machine_st = MachineState::new(); - let user_input = Stream::stdin(&mut machine_st.arena, args.add_history); - let user_output = Stream::stdout(&mut machine_st.arena); - let user_error = Stream::stderr(&mut machine_st.arena); - - #[cfg(not(target_arch = "wasm32"))] - let runtime = tokio::runtime::Runtime::new().unwrap(); - #[cfg(target_arch = "wasm32")] - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); + let (user_input, user_output, user_error) = match config.streams { + config::StreamConfig::Stdio => ( + Stream::stdin(&mut machine_st.arena, args.add_history), + Stream::stdout(&mut machine_st.arena), + Stream::stderr(&mut machine_st.arena), + ), + config::StreamConfig::Memory => ( + Stream::Null(StreamOptions::default()), + Stream::from_owned_string("".to_owned(), &mut machine_st.arena), + Stream::stderr(&mut machine_st.arena), + ), + }; let mut wam = Machine { machine_st, @@ -473,7 +491,6 @@ impl Machine { user_output, user_error, load_contexts: vec![], - runtime, #[cfg(feature = "ffi")] foreign_function_table: Default::default(), rng: StdRng::from_entropy(), @@ -546,7 +563,7 @@ impl Machine { } wam.load_special_forms(); - wam.load_top_level(); + wam.load_top_level(config.toplevel); wam.configure_streams(); wam diff --git a/src/machine/parsed_results.rs b/src/machine/parsed_results.rs new file mode 100644 index 00000000..38632855 --- /dev/null +++ b/src/machine/parsed_results.rs @@ -0,0 +1,285 @@ +use crate::atom_table::*; +use ordered_float::OrderedFloat; +use dashu::*; +use std::collections::BTreeMap; +use std::collections::HashMap; + +pub type QueryResult = Result; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum QueryResolution { + True, + False, + Matches(Vec), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct QueryMatch { + pub bindings: BTreeMap, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum QueryResolutionLine { + True, + False, + Match(BTreeMap), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Value { + Integer(Integer), + Rational(Rational), + Float(OrderedFloat), + Atom(Atom), + String(String), + List(Vec), + Structure(Atom, Vec), + Var, +} + +impl From> for QueryMatch { + fn from(bindings: BTreeMap<&str, Value>) -> Self { + QueryMatch { + bindings: bindings + .into_iter() + .map(|(k, v)| (k.to_string(), v)) + .collect::>(), + } + } +} + +impl From> for QueryMatch { + fn from(bindings: BTreeMap) -> Self { + QueryMatch { bindings } + } +} + +impl From> for QueryResolution { + fn from(query_result_lines: Vec) -> Self { + // If there is only one line, and it is true or false, return that. + if query_result_lines.len() == 1 { + match query_result_lines[0].clone() { + QueryResolutionLine::True => return QueryResolution::True, + QueryResolutionLine::False => return QueryResolution::False, + _ => {} + } + } + + // If there is only one line, and it is an empty match, return true. + if query_result_lines.len() == 1 { + match query_result_lines[0].clone() { + QueryResolutionLine::Match(m) => { + if m.is_empty() { + return QueryResolution::True; + } + } + _ => {} + } + } + + // If there is at least one line with true and no matches, return true. + if query_result_lines + .iter() + .any(|l| l == &QueryResolutionLine::True) + && !query_result_lines.iter().any(|l| { + if let &QueryResolutionLine::Match(_) = l { + true + } else { + false + } + }) + { + return QueryResolution::True; + } + + // If there is at least one match, return all matches. + let all_matches = query_result_lines + .into_iter() + .filter(|l| { + if let &QueryResolutionLine::Match(_) = l { + true + } else { + false + } + }) + .map(|l| match l { + QueryResolutionLine::Match(m) => QueryMatch::from(m), + _ => unreachable!(), + }) + .collect::>(); + + if !all_matches.is_empty() { + return QueryResolution::Matches(all_matches); + } + + QueryResolution::False + } +} + +fn split_response_string(input: &str) -> Vec { + let mut level_bracket = 0; + let mut level_parenthesis = 0; + let mut in_double_quotes = false; + let mut in_single_quotes = false; + let mut start = 0; + let mut result = Vec::new(); + + for (i, c) in input.chars().enumerate() { + match c { + '[' => level_bracket += 1, + ']' => level_bracket -= 1, + '(' => level_parenthesis += 1, + ')' => level_parenthesis -= 1, + '"' => in_double_quotes = !in_double_quotes, + '\'' => in_single_quotes = !in_single_quotes, + ',' if level_bracket == 0 && level_parenthesis == 0 && !in_double_quotes && !in_single_quotes => { + result.push(input[start..i].trim().to_string()); + start = i + 1; + } + _ => {} + } + } + + result.push(input[start..].trim().to_string()); + result +} + +fn split_key_value_pairs(input: &str) -> Vec<(String, String)> { + let items = split_response_string(input); + let mut result = Vec::new(); + + for item in items { + let parts: Vec<&str> = item.splitn(2, '=').collect(); + if parts.len() == 2 { + let key = parts[0].trim().to_string(); + let value = parts[1].trim().to_string(); + result.push((key, value)); + } + } + + result +} + +fn parse_prolog_response(input: &str) -> HashMap { + let mut map: HashMap = HashMap::new(); + // Use regex to match strings including commas inside them + for result in split_key_value_pairs(input) { + let key = result.0; + let value = result.1; + // cut off at given characters/strings: + let value = value.split("\n").next().unwrap().to_string(); + let value = value.split(" ").next().unwrap().to_string(); + let value = value.split("\t").next().unwrap().to_string(); + let value = value.split("error").next().unwrap().to_string(); + map.insert(key, value); + } + + map +} + +impl TryFrom for QueryResolutionLine { + type Error = (); + fn try_from(string: String) -> Result { + match string.as_str() { + "true" => Ok(QueryResolutionLine::True), + "false" => Ok(QueryResolutionLine::False), + _ => Ok(QueryResolutionLine::Match( + parse_prolog_response(&string) + .iter() + .map(|(k, v)| -> Result<(String, Value), ()> { + let key = k.to_string(); + let value = v.to_string(); + Ok((key, Value::try_from(value)?)) + }) + .filter_map(Result::ok) + .collect::>() + ) + ), + } + } +} + +fn split_nested_list(input: &str) -> Vec { + let mut level = 0; + let mut start = 0; + let mut result = Vec::new(); + + for (i, c) in input.chars().enumerate() { + match c { + '[' => level += 1, + ']' => level -= 1, + ',' if level == 0 => { + result.push(input[start..i].trim().to_string()); + start = i + 1; + } + _ => {} + } + } + + result.push(input[start..].trim().to_string()); + result +} + +impl TryFrom for Value { + type Error = (); + fn try_from(string: String) -> Result { + let trimmed = string.trim(); + + if let Ok(float_value) = string.parse::() { + Ok(Value::Float(OrderedFloat(float_value))) + } else if let Ok(int_value) = string.parse::() { + Ok(Value::Integer(int_value.into())) + } else if trimmed.starts_with("'") && trimmed.ends_with("'") { + Ok(Value::String(trimmed[1..trimmed.len() - 1].into())) + } else if trimmed.starts_with("\"") && trimmed.ends_with("\"") { + Ok(Value::String(trimmed[1..trimmed.len() - 1].into())) + } else if trimmed.starts_with("[") && trimmed.ends_with("]") { + let split = split_nested_list(&trimmed[1..trimmed.len() - 1]); + + let values = split + .into_iter() + .map(Value::try_from) + .collect::, _>>()?; + + Ok(Value::List(values)) + } else if trimmed.starts_with("{") && trimmed.ends_with("}") { + let mut iter = trimmed[1..trimmed.len() - 1].split(","); + let mut values = vec![]; + + while let Some(value) = iter.next() { + let items: Vec<_> = value.split(":").collect(); + if items.len() == 2 { + let _key = items[0].to_string(); + let value = items[1].to_string(); + values.push(Value::try_from(value)?); + } + } + + Ok(Value::Structure(atom!("{}"), values)) + } else if trimmed.starts_with("<<") && trimmed.ends_with(">>") { + let mut iter = trimmed[2..trimmed.len() - 2].split(","); + let mut values = vec![]; + + while let Some(value) = iter.next() { + let items: Vec<_> = value.split(":").collect(); + if items.len() == 2 { + let _key = items[0].to_string(); + let value = items[1].to_string(); + values.push(Value::try_from(value)?); + } + } + + Ok(Value::Structure(atom!("<<>>"), values)) + } else if !trimmed.contains(",") && !trimmed.contains("'") && !trimmed.contains("\"") { + Ok(Value::String(trimmed.into())) + } else { + Err(()) + } + } +} + +impl From<&str> for Value { + fn from(str: &str) -> Self { + Value::String(str.to_string()) + } +} diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 1dfbfaa9..4f955050 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -21,7 +21,9 @@ use std::fmt::Debug; use std::fs::{File, OpenOptions}; use std::hash::Hash; use std::io; -use std::io::{BufRead, Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; +use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; +#[cfg(feature = "http")] +use std::io::BufRead; use std::mem; use std::net::{Shutdown, TcpStream}; use std::ops::{Deref, DerefMut}; diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 9642ec3d..f6e72b93 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -51,14 +51,20 @@ use std::env; use std::ffi::CString; use std::fs; use std::hash::{BuildHasher, BuildHasherDefault}; -use std::io::{ErrorKind, Read, BufRead, Write}; +use std::io::{ErrorKind, Read, Write}; +#[cfg(feature = "http")] +use std::io::BufRead; use std::iter::{once, FromIterator}; use std::mem; -use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs}; +use std::net::{TcpListener, TcpStream}; +#[cfg(feature = "http")] +use std::net::{SocketAddr, ToSocketAddrs}; use std::num::NonZeroU32; use std::ops::Sub; use std::process; +#[cfg(feature = "http")] use std::str::FromStr; +#[cfg(feature = "http")] use std::sync::{Mutex, Arc, Condvar}; use chrono::{offset::Local, DateTime}; @@ -100,6 +106,7 @@ use warp::hyper::{HeaderMap, Method}; use warp::{Buf, Filter}; #[cfg(feature = "http")] use reqwest::Url; +#[cfg(feature = "http")] use futures::future; #[cfg(feature = "repl")] @@ -4443,14 +4450,17 @@ impl Machine { if let Some(address_str) = self.machine_st.value_to_str_like(address_sink) { let address_string = address_str.as_str(); let addr: SocketAddr = match address_string.to_socket_addrs().ok().and_then(|mut s| s.next()) { - Some(addr) => addr, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + Some(addr) => addr, + _ => { + self.machine_st.fail = true; + return Ok(()); + } + }; - let (tx, rx) = std::sync::mpsc::sync_channel(1024); + let (tx, rx) = std::sync::mpsc::sync_channel(1024); + + let runtime = tokio::runtime::Handle::current(); + let _guard = runtime.enter(); fn get_reader(body: impl Buf + Send + 'static) -> Box { Box::new(body.reader()) @@ -4499,7 +4509,7 @@ impl Machine { } }); - self.runtime.spawn(async move { + runtime.spawn(async move { match ssl_server { Some((key, cert)) => { warp::serve(serve).tls().key(key).cert(cert).run(addr).await @@ -4512,11 +4522,12 @@ impl Machine { let http_listener = HttpListener { incoming: rx }; let http_listener = arena_alloc!(http_listener, &mut self.machine_st.arena); - let addr = self.deref_register(2); - self.machine_st.bind( - addr.as_var().unwrap(), - typed_arena_ptr_as_cell!(http_listener), - ); + + let addr = self.deref_register(2); + self.machine_st.bind( + addr.as_var().unwrap(), + typed_arena_ptr_as_cell!(http_listener), + ); } Ok(()) } @@ -4598,8 +4609,13 @@ impl Machine { if interruption { self.machine_st.throw_interrupt_exception(); self.machine_st.backtrack(); - let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap()); - old_runtime.shutdown_background(); + // We have extracted controll over the Tokio runtime to the calling context for enabling library use case + // (see https://github.com/mthom/scryer-prolog/pull/1880) + // So we only have access to a runtime handle in here and can't shut it down. + // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880 + // was not merged, I'm only deactivating it for now. + //let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap()); + //old_runtime.shutdown_background(); break } } diff --git a/src/rcu.rs b/src/rcu.rs index a554208e..7631cace 100644 --- a/src/rcu.rs +++ b/src/rcu.rs @@ -6,19 +6,17 @@ use std::{ ptr::NonNull, sync::{ atomic::{AtomicPtr, AtomicU8}, - Arc, Weak, + Arc, Weak, RwLock }, }; -use tokio::sync::RwLock; - // the epoch counters of all threads that have ever accessed an Rcu // threads that have finished will have a dangling Weak reference and can be cleand up // having this be shared between all Rcu's is a tradeof, // writes will be slower as more epoch counters need to be waited for // reads should be faster as a thread only needs to register itself once on the first read // -static EPOCH_COUNTERS: RwLock>> = RwLock::const_new(Vec::new()); +static EPOCH_COUNTERS: RwLock>> = RwLock::new(Vec::new()); thread_local! { // odd value means the current thread is about to access the active_epoch of an Rcu @@ -53,7 +51,8 @@ impl Rcu { let epoch_counter = Arc::new(AtomicU8::new(0)); // register the current threads epoch counter on init EPOCH_COUNTERS - .blocking_write() + .write() + .unwrap() .push(Arc::downgrade(&epoch_counter)); epoch_counter }); @@ -113,7 +112,7 @@ impl Rcu { // - the Rcu itself holds one strong count let arc = unsafe { ManuallyDrop::new(Arc::from_raw(arc_ptr)) }; - let epochs = EPOCH_COUNTERS.blocking_read().clone(); + let epochs = EPOCH_COUNTERS.read().unwrap().clone(); let mut epochs = epochs .into_iter() .flat_map(|elem| { diff --git a/src/read.rs b/src/read.rs index 1baf8720..4955c670 100644 --- a/src/read.rs +++ b/src/read.rs @@ -24,7 +24,9 @@ use rustyline::history::DefaultHistory; use rustyline::{Config, Editor}; use std::collections::VecDeque; -use std::io::{Cursor, Error, ErrorKind, Read}; +use std::io::{Cursor, Read}; +#[cfg(feature = "repl")] +use std::io::{Error, ErrorKind}; use std::sync::Arc; type SubtermDeque = VecDeque<(usize, usize)>; @@ -83,6 +85,7 @@ impl MachineState { } static mut PROMPT: bool = false; +#[cfg(feature = "repl")] const HISTORY_FILE: &'static str = ".scryer_history"; pub(crate) fn set_prompt(value: bool) { @@ -91,6 +94,7 @@ pub(crate) fn set_prompt(value: bool) { } } +#[cfg(feature = "repl")] #[inline] fn get_prompt() -> &'static str { unsafe { @@ -107,6 +111,7 @@ pub struct ReadlineStream { #[cfg(feature = "repl")] rl: Editor, pending_input: CharReader>, + #[allow(dead_code)] add_history: bool, } @@ -145,6 +150,7 @@ impl ReadlineStream { } } + #[allow(unused_variables)] pub fn set_atoms_for_completion(&mut self, atoms: &Arc) { #[cfg(feature = "repl")] { @@ -215,6 +221,7 @@ impl ReadlineStream { } } + #[allow(dead_code)] #[cfg(not(feature = "repl"))] fn save_history(&mut self) {} diff --git a/src/toplevel.pl b/src/toplevel.pl index b804401b..dc7342c0 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -452,3 +452,4 @@ print_exception_with_check(E) :- % is expected to be printed instead. ; print_exception(E) ). + \ No newline at end of file