WIP: refactor to generalize Machine::run_top_level()

This commit is contained in:
Nicolas Luck
2023-07-17 21:34:26 +02:00
parent c0dd94c8a3
commit 5f8cc3c64b
7 changed files with 196 additions and 204 deletions

32
src/machine/config.rs Normal file
View 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
}
}

View 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
);
}
}

View File

@@ -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> {

View File

@@ -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
);
}
}