MachineBuilder

This commit is contained in:
bakaq
2024-10-12 16:07:13 -03:00
parent 79fbd9e90f
commit d336cbc86a
5 changed files with 134 additions and 135 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()