WIP: refactor to generalize Machine::run_top_level()
This commit is contained in:
@@ -6,6 +6,6 @@ fn main() {
|
||||
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));
|
||||
}
|
||||
|
||||
62
src/lib_toplevel.pl
Normal file
62
src/lib_toplevel.pl
Normal file
@@ -0,0 +1,62 @@
|
||||
:- 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.
|
||||
32
src/machine/config.rs
Normal file
32
src/machine/config.rs
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
71
src/machine/lib_machine.rs
Normal file
71
src/machine/lib_machine.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -215,104 +215,7 @@ 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
|
||||
};
|
||||
|
||||
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> {
|
||||
|
||||
@@ -5,10 +5,12 @@ pub mod code_walker;
|
||||
#[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;
|
||||
@@ -53,6 +55,7 @@ use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use self::config::MachineConfig;
|
||||
use self::parsed_results::*;
|
||||
|
||||
lazy_static! {
|
||||
@@ -221,23 +224,18 @@ impl Machine {
|
||||
|
||||
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);
|
||||
|
||||
@@ -292,7 +290,7 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -303,15 +301,12 @@ impl Machine {
|
||||
));
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -328,24 +323,6 @@ impl Machine {
|
||||
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 {
|
||||
@@ -461,18 +438,26 @@ 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);
|
||||
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,
|
||||
@@ -555,7 +540,7 @@ impl Machine {
|
||||
}
|
||||
|
||||
wam.load_special_forms();
|
||||
wam.load_top_level();
|
||||
wam.load_top_level(config.toplevel);
|
||||
wam.configure_streams();
|
||||
|
||||
wam
|
||||
@@ -936,40 +921,3 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,28 +429,4 @@ print_exception_with_check(E) :-
|
||||
% 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.
|
||||
).
|
||||
Reference in New Issue
Block a user