]> Repositorios git - scryer-prolog.git/commitdiff
WIP: refactor to generalize Machine::run_top_level()
authorNicolas Luck <[email protected]>
Mon, 17 Jul 2023 19:34:26 +0000 (21:34 +0200)
committerNicolas Luck <[email protected]>
Mon, 17 Jul 2023 19:34:26 +0000 (21:34 +0200)
src/bin/scryer-prolog.rs
src/lib_toplevel.pl [new file with mode: 0644]
src/machine/config.rs [new file with mode: 0644]
src/machine/lib_machine.rs [new file with mode: 0644]
src/machine/mock_wam.rs
src/machine/mod.rs
src/toplevel.pl

index eae00fe23777d868d79d7641958550c083d61597..a7519defb51fcd682d1f4732f3e3e5b066dcdaec 100644 (file)
@@ -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));
 }
diff --git a/src/lib_toplevel.pl b/src/lib_toplevel.pl
new file mode 100644 (file)
index 0000000..7987a2f
--- /dev/null
@@ -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.
diff --git a/src/machine/config.rs b/src/machine/config.rs
new file mode 100644 (file)
index 0000000..6268c8d
--- /dev/null
@@ -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
+    }
+}
diff --git a/src/machine/lib_machine.rs b/src/machine/lib_machine.rs
new file mode 100644 (file)
index 0000000..7b74956
--- /dev/null
@@ -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
+        );
+    }
+}
index 2c16ba3af7fd7c720832427389b75c5f7d06c99c..77011b327d80467293b2fd0ec6146b9793ed135c 100644 (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> {
index c45d7cb49fa0b39a07aa0c2d9c52d77deec47dcd..6a3195973cd0440958563beaf670619befbe3050 100644 (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
-        );
-    }
-}
index 93b1a60d3c023f260e4d5e9572baab4a4371af5c..5a36aa77d25b1a891741ffeb834ba4b240d101b7 100644 (file)
@@ -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.
+    ).
\ No newline at end of file