MachineBuilder
This commit is contained in:
@@ -66,7 +66,7 @@ pub fn eval_code(s: &str) -> String {
|
|||||||
/// The entry point for the Scryer Prolog CLI.
|
/// The entry point for the Scryer Prolog CLI.
|
||||||
pub fn run_binary() -> std::process::ExitCode {
|
pub fn run_binary() -> std::process::ExitCode {
|
||||||
use crate::atom_table::Atom;
|
use crate::atom_table::Atom;
|
||||||
use crate::machine::{Machine, INTERRUPT};
|
use crate::machine::INTERRUPT;
|
||||||
|
|
||||||
#[cfg(feature = "repl")]
|
#[cfg(feature = "repl")]
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
@@ -87,7 +87,9 @@ pub fn run_binary() -> std::process::ExitCode {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let mut wam = Machine::new(Default::default());
|
let mut wam = MachineBuilder::default()
|
||||||
|
.with_streams(StreamConfig::stdio())
|
||||||
|
.build();
|
||||||
wam.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 0))
|
wam.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 0))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
|
use rand::{rngs::StdRng, SeedableRng};
|
||||||
|
|
||||||
|
use crate::Machine;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
bootstrapping_compile, current_dir, import_builtin_impls, libraries, load_module, Atom,
|
||||||
|
CompilationTarget, IndexStore, ListingSource, MachineArgs, MachineState, Stream, StreamOptions,
|
||||||
|
};
|
||||||
|
|
||||||
/// Describes how the streams of a [`Machine`](crate::Machine) will be handled.
|
/// Describes how the streams of a [`Machine`](crate::Machine) will be handled.
|
||||||
///
|
|
||||||
/// Defaults to using standard IO.
|
|
||||||
pub struct StreamConfig {
|
pub struct StreamConfig {
|
||||||
pub(crate) inner: StreamConfigInner,
|
inner: StreamConfigInner,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for StreamConfig {
|
impl Default for StreamConfig {
|
||||||
|
/// Defaults to using in-memory streams.
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::stdio()
|
Self::in_memory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,27 +37,28 @@ impl StreamConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum StreamConfigInner {
|
enum StreamConfigInner {
|
||||||
Stdio,
|
Stdio,
|
||||||
Memory,
|
Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes how a [`Machine`](crate::Machine) will be configured.
|
/// Describes how a [`Machine`](crate::Machine) will be configured.
|
||||||
pub struct MachineConfig {
|
pub struct MachineBuilder {
|
||||||
pub(crate) streams: StreamConfig,
|
pub(crate) streams: StreamConfig,
|
||||||
pub(crate) toplevel: &'static str,
|
pub(crate) toplevel: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MachineConfig {
|
impl Default for MachineBuilder {
|
||||||
|
/// Defaults to using in-memory streams.
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MachineConfig {
|
MachineBuilder {
|
||||||
streams: Default::default(),
|
streams: Default::default(),
|
||||||
toplevel: default_toplevel(),
|
toplevel: default_toplevel(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineConfig {
|
impl MachineBuilder {
|
||||||
/// Creates a default configuration.
|
/// Creates a default configuration.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
@@ -66,6 +75,114 @@ impl MachineConfig {
|
|||||||
self.toplevel = toplevel;
|
self.toplevel = toplevel;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the [`Machine`](crate::Machine) from this configuration.
|
||||||
|
pub fn build(self) -> Machine {
|
||||||
|
let args = MachineArgs::new();
|
||||||
|
let mut machine_st = MachineState::new();
|
||||||
|
|
||||||
|
let (user_input, user_output, user_error) = match self.streams.inner {
|
||||||
|
StreamConfigInner::Stdio => (
|
||||||
|
Stream::stdin(&mut machine_st.arena, args.add_history),
|
||||||
|
Stream::stdout(&mut machine_st.arena),
|
||||||
|
Stream::stderr(&mut machine_st.arena),
|
||||||
|
),
|
||||||
|
StreamConfigInner::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,
|
||||||
|
indices: IndexStore::new(),
|
||||||
|
code: vec![],
|
||||||
|
user_input,
|
||||||
|
user_output,
|
||||||
|
user_error,
|
||||||
|
load_contexts: vec![],
|
||||||
|
#[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::get("ops_and_meta_predicates")
|
||||||
|
.expect("library ops_and_meta_predicates should exist"),
|
||||||
|
&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::get("builtins").expect("library builtins should exist"),
|
||||||
|
&mut wam.machine_st.arena,
|
||||||
|
),
|
||||||
|
&mut wam,
|
||||||
|
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(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(self.toplevel);
|
||||||
|
wam.configure_streams();
|
||||||
|
|
||||||
|
wam
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a static string slice to the default toplevel
|
/// Returns a static string slice to the default toplevel
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use crate::atom_table;
|
||||||
use crate::machine::machine_indices::VarKey;
|
use crate::machine::machine_indices::VarKey;
|
||||||
use crate::machine::mock_wam::CompositeOpDir;
|
use crate::machine::mock_wam::CompositeOpDir;
|
||||||
use crate::machine::{BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS};
|
use crate::machine::{BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS};
|
||||||
use crate::parser::ast::{Var, VarPtr};
|
use crate::parser::ast::{Var, VarPtr};
|
||||||
use crate::parser::parser::{Parser, Tokens};
|
use crate::parser::parser::{Parser, Tokens};
|
||||||
use crate::read::{write_term_to_heap, TermWriteResult};
|
use crate::read::{write_term_to_heap, TermWriteResult};
|
||||||
use crate::{atom_table, StreamConfig};
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
streams::Stream, Atom, AtomCell, HeapCellValue, HeapCellValueTag, LeafAnswer, Machine,
|
streams::Stream, Atom, AtomCell, HeapCellValue, HeapCellValueTag, LeafAnswer, Machine,
|
||||||
MachineConfig, PrologTerm,
|
PrologTerm,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An iterator though the leaf answers of a query.
|
/// An iterator though the leaf answers of a query.
|
||||||
@@ -166,11 +166,6 @@ impl Iterator for QueryState<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
/// Creates a new [`Machine`] configured for use as a library.
|
|
||||||
pub fn new_lib() -> Self {
|
|
||||||
Machine::new(MachineConfig::default().with_streams(StreamConfig::in_memory()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Loads a module into the [`Machine`] from a string.
|
/// Loads a module into the [`Machine`] from a string.
|
||||||
pub fn load_module_string(&mut self, module_name: &str, program: impl Into<String>) {
|
pub fn load_module_string(&mut self, module_name: &str, program: impl Into<String>) {
|
||||||
let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena);
|
let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ pub use crate::machine::*;
|
|||||||
pub use crate::parser::ast::*;
|
pub use crate::parser::ast::*;
|
||||||
use crate::read::*;
|
use crate::read::*;
|
||||||
pub use crate::types::*;
|
pub use crate::types::*;
|
||||||
use crate::StreamConfig;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -232,11 +231,6 @@ pub(crate) fn parse_and_write_parsed_term_to_heap(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
/// For use in tests.
|
|
||||||
pub fn with_test_streams() -> Self {
|
|
||||||
Machine::new(MachineConfig::default().with_streams(StreamConfig::in_memory()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For use in tests.
|
/// For use in tests.
|
||||||
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
|
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
|
||||||
let stream = Stream::from_owned_string(
|
let stream = Stream::from_owned_string(
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ use lazy_static::lazy_static;
|
|||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use rand::rngs::StdRng;
|
use rand::rngs::StdRng;
|
||||||
use rand::SeedableRng;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@@ -63,7 +62,6 @@ use std::path::PathBuf;
|
|||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use self::config::MachineConfig;
|
|
||||||
use self::parsed_results::*;
|
use self::parsed_results::*;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@@ -71,6 +69,8 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An instance of Scryer Prolog.
|
/// An instance of Scryer Prolog.
|
||||||
|
///
|
||||||
|
/// Created with [`MachineBuilder::build`](crate::machine::config::MachineBuilder::build).
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
pub(super) machine_st: MachineState,
|
pub(super) machine_st: MachineState,
|
||||||
@@ -482,115 +482,6 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new [`Machine`] from a [`MachineConfig`].
|
|
||||||
#[allow(clippy::new_without_default)]
|
|
||||||
pub fn new(config: MachineConfig) -> Self {
|
|
||||||
let args = MachineArgs::new();
|
|
||||||
let mut machine_st = MachineState::new();
|
|
||||||
|
|
||||||
let (user_input, user_output, user_error) = match config.streams.inner {
|
|
||||||
config::StreamConfigInner::Stdio => (
|
|
||||||
Stream::stdin(&mut machine_st.arena, args.add_history),
|
|
||||||
Stream::stdout(&mut machine_st.arena),
|
|
||||||
Stream::stderr(&mut machine_st.arena),
|
|
||||||
),
|
|
||||||
config::StreamConfigInner::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,
|
|
||||||
indices: IndexStore::new(),
|
|
||||||
code: vec![],
|
|
||||||
user_input,
|
|
||||||
user_output,
|
|
||||||
user_error,
|
|
||||||
load_contexts: vec![],
|
|
||||||
#[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::get("ops_and_meta_predicates")
|
|
||||||
.expect("library ops_and_meta_predicates should exist"),
|
|
||||||
&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::get("builtins").expect("library builtins should exist"),
|
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
),
|
|
||||||
&mut wam,
|
|
||||||
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Some(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(config.toplevel);
|
|
||||||
wam.configure_streams();
|
|
||||||
|
|
||||||
wam
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn configure_streams(&mut self) {
|
pub(crate) fn configure_streams(&mut self) {
|
||||||
self.user_input
|
self.user_input
|
||||||
.options_mut()
|
.options_mut()
|
||||||
|
|||||||
Reference in New Issue
Block a user