scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
}).unwrap();
- let mut wam = machine::Machine::new();
- wam.run_top_level();
+ let mut wam = machine::Machine::new(Default::default());
+ wam.run_top_level(atom!("$toplevel"), (atom!("$repl"), 1));
}
--- /dev/null
+:- module('$toplevel', [argv/1,
+ copy_term/3]).
+
+:- use_module(library(atts), [call_residue_vars/2]).
+:- use_module(library(charsio)).
+:- use_module(library(error)).
+:- use_module(library(files)).
+:- use_module(library(iso_ext)).
+:- use_module(library(lambda)).
+:- use_module(library(lists)).
+:- use_module(library(si)).
+
+:- use_module(library('$project_atts')).
+:- use_module(library('$atts')).
+
+:- dynamic(disabled_init_file/0).
+
+:- dynamic(argv/1).
+
+
+arg_type(g).
+arg_type(t).
+arg_type(g(_)).
+arg_type(t(_)).
+
+
+
+
+print_exception(E) :-
+ ( E == error('$interrupt_thrown', repl) -> nl % print the
+ % exception on a
+ % newline to evade
+ % "^C".
+ ; true
+ ),
+ loader:write_error(E),
+ nl.
+
+
+run_input_once :-
+ bb_put('$report_all', true),
+ catch(read_and_match_all_results, E, print_exception(E)).
+
+read_and_match_all_results :-
+ '$read_query_term'(_, Term, _, _, VarList),
+ bb_put('$answer_count', 0),
+ submit_query_and_print_all_results(Term, VarList).
+
+submit_query_and_print_all_results(Term, VarList) :-
+ '$get_b_value'(B),
+ bb_put('$report_all', true),
+ bb_put('$report_n_more', 0),
+ call(user:Term),
+ write_eqs_and_read_input(B, VarList),
+ !.
+submit_query_and_print_all_results(_, _) :-
+ ( bb_get('$answer_count', 0) ->
+ write(' ')
+ ; true
+ ),
+ write('false.'),
+ nl.
--- /dev/null
+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
+ }
+}
--- /dev/null
+use super::{Machine, MachineConfig, QueryResult, QueryResultLine, Atom};
+
+impl Machine {
+ pub fn new_lib() -> Self {
+ Machine::new(MachineConfig::in_memory().with_toplevel(include_str!("../lib_toplevel.pl")))
+ }
+
+ pub fn run_query(&mut self, query: String) -> QueryResult {
+ self.set_user_input(query);
+ self.run_top_level(atom!("$toplevel"), (atom!("run_input_once"), 0));
+ self.parse_output()
+ }
+
+ pub fn parse_output(&self) -> QueryResult {
+ let output = self.get_user_output();
+ output
+ .split(";")
+ .map(|s| s.trim())
+ .map(|s| s.replace(".", ""))
+ .filter(|s| !s.is_empty())
+ .map(QueryResultLine::try_from)
+ .filter_map(Result::ok)
+ .collect::<Vec<QueryResultLine>>()
+ .into()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::machine::{QueryMatch, Value};
+
+ #[test]
+ fn programatic_query() {
+ let mut machine = Machine::with_test_streams();
+
+ 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,
+ QueryResult::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")."#)),
+ QueryResult::True
+ );
+
+ assert_eq!(
+ machine.run_query(String::from(r#"triple("x","y","z")."#)),
+ QueryResult::False
+ );
+ }
+}
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
- };
-
- 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<u8> {
#[macro_use]
pub mod loader;
pub mod compile;
+pub mod config;
pub mod copier;
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;
use std::sync::atomic::AtomicBool;
use tokio::runtime::Runtime;
+use self::config::MachineConfig;
use self::parsed_results::*;
lazy_static! {
pub fn load_file(&mut self, path: &str, stream: Stream) {
self.machine_st.registers[1] = stream_as_cell!(stream);
- self.machine_st.registers[2] = atom_as_cell!(
- self.machine_st.atom_tbl.build_with(path)
- );
+ self.machine_st.registers[2] = atom_as_cell!(self.machine_st.atom_tbl.build_with(path));
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);
}
}
- pub fn run_top_level(&mut self) {
+ pub fn run_top_level(&mut self, module_name: Atom, key: PredicateKey) {
let mut arg_pstrs = vec![];
for arg in env::args() {
));
}
- self.machine_st.registers[1] = heap_loc_as_cell!(
- iter_to_heap_list(&mut self.machine_st.heap, arg_pstrs.into_iter())
- );
+ self.machine_st.registers[1] = heap_loc_as_cell!(iter_to_heap_list(
+ &mut self.machine_st.heap,
+ arg_pstrs.into_iter()
+ ));
- self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1));
- }
-
- pub fn run_input_once(&mut self) {
- self.run_module_predicate(atom!("$toplevel"), (atom!("run_input_once"), 0));
+ self.run_module_predicate(module_name, key);
}
pub fn set_user_input(&mut self, input: String) {
self.load_file(module_name, stream);
}
- pub fn run_query(&mut self, query: String) -> QueryResult{
- self.set_user_input(query);
- self.run_input_once();
- self.parse_output()
- }
-
- pub fn parse_output(&self) -> QueryResult {
- let output = self.get_user_output();
- output.split(";")
- .map(|s| s.trim())
- .map(|s| s.replace(".", ""))
- .filter(|s| !s.is_empty())
- .map(QueryResultLine::try_from)
- .filter_map(Result::ok)
- .collect::<Vec<QueryResultLine>>()
- .into()
- }
-
pub(crate) fn configure_modules(&mut self) {
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir, arena: &mut Arena) {
for arity in 1..66 {
}
}
- 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);
+ 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 runtime = tokio::runtime::Runtime::new()
- .unwrap();
+ let runtime = tokio::runtime::Runtime::new().unwrap();
let mut wam = Machine {
machine_st,
}
wam.load_special_forms();
- wam.load_top_level();
+ wam.load_top_level(config.toplevel);
wam.configure_streams();
wam
}
}
}
-
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn programatic_query() {
- let mut machine = Machine::with_test_streams();
-
- 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, QueryResult::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")."#)),
- QueryResult::True
- );
-
- assert_eq!(
- machine.run_query(String::from(r#"triple("x","y","z")."#)),
- QueryResult::False
- );
- }
-}
% number, a GNU-style error message
% is expected to be printed instead.
; print_exception(E)
- ).
-
-run_input_once :-
- bb_put('$report_all', true),
- catch(read_and_match_all_results, E, print_exception(E)).
-
-read_and_match_all_results :-
- '$read_query_term'(_, Term, _, _, VarList),
- bb_put('$answer_count', 0),
- submit_query_and_print_all_results(Term, VarList).
-
-submit_query_and_print_all_results(Term, VarList) :-
- '$get_b_value'(B),
- bb_put('$report_all', true),
- bb_put('$report_n_more', 0),
- call(user:Term),
- write_eqs_and_read_input(B, VarList),
- !.
-submit_query_and_print_all_results(_, _) :-
- ( bb_get('$answer_count', 0) ->
- write(' ')
- ; true
- ),
- write('false.'),
- nl.
+ ).
\ No newline at end of file