]> Repositorios git - scryer-prolog.git/commitdiff
add use_module/{1,2} as full fledged predicates
authorMark Thom <[email protected]>
Mon, 30 Sep 2019 16:26:29 +0000 (10:26 -0600)
committerMark Thom <[email protected]>
Mon, 30 Sep 2019 16:26:29 +0000 (10:26 -0600)
14 files changed:
Cargo.toml
README.md
src/main.rs
src/prolog/clause_types.rs
src/prolog/debray_allocator.rs
src/prolog/heap_print.rs
src/prolog/machine/compile.rs
src/prolog/machine/machine_indices.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/machine/system_calls.rs
src/prolog/machine/toplevel.rs
src/prolog/toplevel.pl
src/prolog/write.rs

index 7546f16257d0b5f36cfce25898fffcd8cbed513c..cf68711d1438bb8a624c794d5cb157b54cde86e9 100644 (file)
@@ -11,7 +11,6 @@ license = "BSD-3-Clause"
 indexmap = "1.0.2"
 
 [dependencies]
-cfg-if = "0.1.7"
 dirs = "2.0.2"
 downcast = "0.10.0"
 indexmap = "1.0.2"
index 242db38d6968ee8e360b371a66570ff4d2ad1b06..a52927a280e8ae8c56fafcffd8c0101f3ee0b732 100644 (file)
--- a/README.md
+++ b/README.md
@@ -236,6 +236,7 @@ The following predicates are built-in to Scryer.
 * `throw/1`
 * `true/0`
 * `unify_with_occurs_check/2`
+* `use_module/{1,2}`
 * `user:goal_expansion/2`
 * `user:term_expansion/2`
 * `var/1`
index 61ed623b15d22d1875d772a8f1b96b3ed2157e1d..4530d63b61501c9492b8598fc5569770a16c3659 100644 (file)
@@ -1,19 +1,10 @@
 #[macro_use]
-extern crate cfg_if;
-#[macro_use]
 extern crate downcast;
 extern crate indexmap;
 #[macro_use]
 extern crate prolog_parser;
 #[macro_use]
 extern crate ref_thread_local;
-
-cfg_if! {
-    if #[cfg(feature = "readline_rs_compat")] {
-        extern crate readline_rs_compat;
-    }
-}
-
 extern crate termion;
 
 mod prolog;
@@ -25,9 +16,6 @@ use prolog::read::*;
 mod tests;
 
 fn main() {
-//    #[cfg(feature = "readline_rs_compat")]
-//    readline::readline_initialize();
-
-    let mut wam = Machine::new(readline::input_stream());
-    wam.run_toplevel();
+    let mut wam = Machine::new(readline::input_stream());  
+    wam.run_top_level();
 }
index 3d0d1aef48ac9b103c2b3b1937d1d1f38c3c8899..aec99d5a9fabfa552898dee04c60d71db225a973 100644 (file)
@@ -261,6 +261,16 @@ impl SystemClauseType {
             &SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) => {
                 clause_name!("$submit_query_and_print_results")
             }
+           &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
+           &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
+               clause_name!("$use_qualified_module")
+           }
+           &SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => {
+               clause_name!("$use_module_from_file")
+           }
+           &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
+               clause_name!("$use_qualified_module_from_file")
+           }
             &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
             &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
             &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
@@ -437,6 +447,13 @@ impl SystemClauseType {
             ("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
             ("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
             ("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
+           ("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
+           ("$use_module_from_file", 1) =>
+               Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)),       
+           ("$use_qualified_module", 2) =>
+               Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)),
+           ("$use_qualified_module_from_file", 2) =>
+               Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
             ("$variant", 2) => Some(SystemClauseType::Variant),
             ("$write_term", 5) => Some(SystemClauseType::WriteTerm),
             ("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
index de5a86513df1a90dcd76166f1f1b39fc0365ee6b..8d3560e05399469ee01b14b641c88d894589d1bd 100644 (file)
@@ -134,7 +134,7 @@ impl DebrayAllocator {
 
                     target.push(Target::move_to_register(r, k));
 
-                    self.contents.remove(&k);
+                    self.contents.swap_remove(&k);
                     self.contents.insert(r.reg_num(), var.clone());
 
                     self.record_register(var, r);
index c04b422369093b30b439528b69e079edb30666d5..083d10ff9b2b8f6482e678467129060d7517b5a3 100644 (file)
@@ -652,7 +652,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                                     });
 
                                     iter.stack().pop();
-                                    self.cyclic_terms.remove(&addr);
+                                    self.cyclic_terms.swap_remove(&addr);
                                     None
                                 }
                             }
index ee0392b1f7752077ae9b35e552a908d7a1216373..6d391f9a580f6f4c880697882f403db2174877e7 100644 (file)
@@ -78,7 +78,7 @@ fn load_module<R: Read>(wam: &mut Machine, name: &str, stream: ParsingStream<R>)
     match compile_work_impl(&mut compiler, wam, indices, results) {
         EvalSession::Error(e) => Err(e),
         _ => Ok(module_name),
-    }    
+    }
 }
 
 pub(super)
@@ -91,7 +91,7 @@ fn load_module_from_file(wam: &mut Machine, filename: &str) -> Result<ClauseName
         Err(SessionError::InvalidFileName(filename))
     })?;
 
-    let file_stem = path.file_stem().unwrap().to_string_lossy();    
+    let file_stem = path.file_stem().unwrap().to_string_lossy();
     load_module(wam, &file_stem, parsing_stream(file_handle))
 }
 
@@ -442,7 +442,7 @@ fn add_module_code(wam: &mut Machine, mut module: Module, code: Code, mut indice
         if name.owning_module() == module.module_decl.name {
             wam.indices
                 .dynamic_code_dir
-                .remove(&(name.owning_module(), name, arity));
+                .swap_remove(&(name.owning_module(), name, arity));
         }
     }
 
@@ -466,6 +466,7 @@ fn add_non_module_code(
     Ok(())
 }
 
+pub(super)
 fn load_library(wam: &mut Machine, name: ClauseName) -> Result<ClauseName, SessionError> {
     match LIBRARIES.borrow().get(name.as_str()) {
         Some(code) => load_module(wam, name.as_str(), parsing_stream(code.as_bytes())),
index cb2586a6b6b5cf4c8f6fd9bce4c1b7cdd69df2c6..efdfa7a912a74705e8bc119e4bff5437ce3459dd 100644 (file)
@@ -291,6 +291,10 @@ pub enum DynamicTransactionType {
 pub enum REPLCodePtr {
     CompileBatch,
     SubmitQueryAndPrintResults,
+    UseModule,
+    UseQualifiedModule,
+    UseModuleFromFile,
+    UseQualifiedModuleFromFile
 }
 
 #[derive(Clone, PartialEq)]
@@ -307,8 +311,8 @@ impl CodePtr {
     pub fn local(&self) -> LocalCodePtr {
         match self {
             &CodePtr::BuiltInClause(_, ref local)
-            | &CodePtr::CallN(_, ref local)
-            | &CodePtr::Local(ref local) => local.clone(),
+          | &CodePtr::CallN(_, ref local)
+          | &CodePtr::Local(ref local) => local.clone(),
             &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
             &CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p,
         }
@@ -346,10 +350,10 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
     fn partial_cmp(&self, other: &LocalCodePtr) -> Option<Ordering> {
         match (self, other) {
             (&LocalCodePtr::InSituDirEntry(p1), &LocalCodePtr::InSituDirEntry(ref p2))
-            | (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2))
-            | (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2))
-            | (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2))
-            | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
+         | (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2))
+          | (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2))
+          | (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2))
+          | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
                 p1.partial_cmp(p2)
             }
             (_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less),
@@ -388,10 +392,10 @@ impl AddAssign<usize> for LocalCodePtr {
     fn add_assign(&mut self, rhs: usize) {
         match self {
             &mut LocalCodePtr::InSituDirEntry(ref mut p)
-            | &mut LocalCodePtr::UserGoalExpansion(ref mut p)
-            | &mut LocalCodePtr::UserTermExpansion(ref mut p)
-            | &mut LocalCodePtr::DirEntry(ref mut p)
-            | &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs,
+          | &mut LocalCodePtr::UserGoalExpansion(ref mut p)
+          | &mut LocalCodePtr::UserTermExpansion(ref mut p)
+          | &mut LocalCodePtr::DirEntry(ref mut p)
+          | &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs,
         }
     }
 }
@@ -402,8 +406,8 @@ impl Add<usize> for CodePtr {
     fn add(self, rhs: usize) -> Self::Output {
         match self {
             p @ CodePtr::REPL(..)
-            | p @ CodePtr::VerifyAttrInterrupt(_)
-            | p @ CodePtr::DynamicTransaction(..) => p,
+          | p @ CodePtr::VerifyAttrInterrupt(_)
+          | p @ CodePtr::DynamicTransaction(..) => p,
             CodePtr::Local(local) => CodePtr::Local(local + rhs),
             CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => {
                 CodePtr::Local(local + rhs)
@@ -480,7 +484,7 @@ impl IndexStore {
 
     #[inline]
     pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
-        self.dynamic_code_dir.remove(&(module, name, arity));
+        self.dynamic_code_dir.swap_remove(&(module, name, arity));
     }
 
     #[inline]
@@ -495,7 +499,7 @@ impl IndexStore {
 
     #[inline]
     pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
-        self.modules.remove(&name)
+        self.modules.swap_remove(&name)
     }
 
     #[inline]
index ca38167253484b1f68baafc4b1033981d8ca5834..ac737a7e3b4ee3b4f10e96dfb39525f2b3de884f 100644 (file)
@@ -3387,7 +3387,7 @@ impl MachineState {
         }
     }
 
-    pub(super) fn reset(&mut self) {
+    pub fn reset(&mut self) {
         self.hb = 0;
         self.e = 0;
         self.b = 0;
index 56bfa3b9798c7b285e2fe98a186ef3ad0dc4012c..a1a228faeaa93d118d62e6385a0f7b7736cb9146 100644 (file)
@@ -216,15 +216,24 @@ impl Machine {
         self.machine_st.reset();
     }
 
-    pub fn run_toplevel(&mut self) {
+    pub fn run_top_level(&mut self) {
        use std::env;
-       use prolog::machine::compile::load_module_from_file;
 
-       for filename in env::args() {
-           load_module_from_file(self, &filename);
+       let mut filename_atoms = vec![];
+
+       // the first of these is the path to the scryer-prolog executable, so skip
+       // it.
+       for filename in env::args().skip(1) {
+           let atom = atom!(filename, self.indices.atom_tbl);
+           filename_atoms.push(Addr::Con(atom));
        }
-       
+
+       let list_addr =
+           Addr::HeapCell(self.machine_st.heap.to_list(filename_atoms.into_iter()));
+
+       self.machine_st[temp_v!(1)] = list_addr;
         self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
+
         self.run_query(&AllocVarDict::new());
     }
 
@@ -247,12 +256,13 @@ impl Machine {
         );
 
         wam.compile_special_forms();
-        wam.compile_top_level();
 
         compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()));
         compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()));
         compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()));
+        compile_user_module(&mut wam, parsing_stream(SI.as_bytes()));
 
+        wam.compile_top_level();
         wam.compile_scryerrc();
 
         wam
@@ -356,16 +366,132 @@ impl Machine {
         return;
     }
 
+    fn extract_predicate_indicator_list(&mut self) -> Vec<PredicateKey>
+    {
+       let export_list = self.machine_st[temp_v!(2)].clone();
+       let mut export_list = self.machine_st.store(self.machine_st.deref(export_list));
+       let mut exports = vec![];
+
+       while let Addr::Lis(l) = export_list {
+           match &self.machine_st.heap[l] {
+               &HeapCellValue::Addr(Addr::Str(s)) => {
+                   let name = match &self.machine_st.heap[s+1] {
+                       &HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
+                           name.clone(),
+                       _ =>
+                           unreachable!()
+                   };
+
+                   let arity = match &self.machine_st.heap[s+2] {
+                       &HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
+                           arity.to_usize().unwrap(),
+                       _ =>
+                           unreachable!()
+                   };
+
+                   exports.push((name, arity));
+               }
+               _ => unreachable!()
+           }
+
+           export_list = self.machine_st.heap[l+1].as_addr(l+1);
+       }
+
+       exports
+    }
+
+    fn use_module<ToSource>(&mut self, to_src: ToSource)
+       where ToSource: Fn(ClauseName) -> ModuleSource
+    {
+       // the term expander will overwrite the cached query, so save it here.
+       let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
+
+       let module_spec = self.machine_st[temp_v!(1)].clone();
+       let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
+           Addr::Con(Constant::Atom(name, _)) => name,
+           _ => unreachable!()
+       };
+
+       let load_result = match to_src(name) {
+           ModuleSource::Library(name) =>
+               if !self.indices.modules.contains_key(&name) {
+                   load_library(self, name)
+               } else {
+                   Ok(name)
+               },
+           ModuleSource::File(name) => load_module_from_file(self, name.as_str())
+       };
+
+       let result = load_result.and_then(|name| {
+           let module = self.indices.take_module(name).unwrap();
+
+           // remove previous exports.
+           self.indices.remove_module(clause_name!("user"), &module);
+           self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?;
+
+           Ok(self.indices.insert_module(module))
+       });
+
+       self.code_repo.cached_query = cached_query;
+
+       if let Err(e) = result {
+           self.throw_session_error(e, (clause_name!("use_module"), 1));
+       }
+    }
+
+    fn use_qualified_module<ToSource>(&mut self, to_src: ToSource)
+       where ToSource: Fn(ClauseName) -> ModuleSource
+    {
+       // the term expander will overwrite the cached query, so save it here.
+       let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
+
+       let module_spec = self.machine_st[temp_v!(1)].clone();
+       let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
+           Addr::Con(Constant::Atom(name, _)) => name,
+           _ => unreachable!()
+       };
+
+       let exports = self.extract_predicate_indicator_list();
+
+       let load_result = match to_src(name) {
+           ModuleSource::Library(name) =>
+               if !self.indices.modules.contains_key(&name) {
+                   load_library(self, name)
+               } else {
+                   Ok(name)
+               },
+           ModuleSource::File(name) => load_module_from_file(self, name.as_str())
+       };
+
+       let result = load_result.and_then(|name| {
+           let module = self.indices.take_module(name).unwrap();
+
+           // remove previous exports.
+           self.indices.remove_module(clause_name!("user"), &module);
+           self.indices.use_qualified_module(&mut self.code_repo,
+                                             self.machine_st.flags,
+                                             &module,
+                                             &exports)?;
+
+           Ok(self.indices.insert_module(module))
+       });
+
+       self.code_repo.cached_query = cached_query;
+
+       if let Err(e) = result {
+           self.throw_session_error(e, (clause_name!("use_module"), 1));
+       }
+    }
+
     fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
         match code_ptr {
             REPLCodePtr::CompileBatch => {
                 let src = readline::input_stream();
                 readline::set_prompt(false);
-                
-                match compile_user_module(self, src) {
-                    EvalSession::Error(e) => self.throw_session_error(e, (clause_name!("repl"), 0)),
-                    _ => {}
-                };
+
+                if let EvalSession::Error(e) = compile_user_module(self, src) {
+                    self.throw_session_error(e, (clause_name!("repl"), 0));
+                }
             }
             REPLCodePtr::SubmitQueryAndPrintResults => {
                 let term = self.machine_st[temp_v!(1)].clone();
@@ -416,6 +542,14 @@ impl Machine {
 
                 self.handle_eval_session(result, snapshot);
             }
+           REPLCodePtr::UseModule =>
+               self.use_module(ModuleSource::Library),
+           REPLCodePtr::UseModuleFromFile =>
+               self.use_module(ModuleSource::File),
+           REPLCodePtr::UseQualifiedModule =>
+               self.use_qualified_module(ModuleSource::Library),
+           REPLCodePtr::UseQualifiedModuleFromFile =>
+               self.use_qualified_module(ModuleSource::File)
         }
 
         self.machine_st.p = CodePtr::Local(p);
@@ -556,7 +690,8 @@ impl Machine {
     }
 
     pub(super) fn run_query(&mut self, alloc_locs: &AllocVarDict) {
-        let end_ptr = top_level_code_ptr!(0, self.code_repo.size_of_cached_query());
+       self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
+        let end_ptr = CodePtr::Local(self.machine_st.cp);
 
         while self.machine_st.p < end_ptr {
             if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.machine_st.p {
@@ -636,10 +771,7 @@ impl Machine {
     where
         Outputter: HCValueOutputter,
     {
-        let mut sorted_vars: Vec<_> = self.machine_st.heap_locs.iter().collect();
-        sorted_vars.sort_by_key(|ref v| v.0);
-
-        for (var, addr) in sorted_vars {
+        for (var, addr) in self.machine_st.heap_locs.iter() {
             let addr = self.machine_st.store(self.machine_st.deref(addr.clone()));
             output = self
                 .machine_st
@@ -654,10 +786,7 @@ impl Machine {
     where
         Outputter: HCValueOutputter,
     {
-        let mut sorted_vars: Vec<(&Rc<Var>, &Addr)> = self.machine_st.heap_locs.iter().collect();
-        sorted_vars.sort_by_key(|ref v| v.0);
-
-        for (var, addr) in sorted_vars {
+        for (var, addr) in self.machine_st.heap_locs.iter() {
             output = self.machine_st.print_var_eq(
                 var.clone(),
                 addr.clone(),
index 0ed454f68f3448dad76920fbaa3f4723883bfb21..ba2eef93a8940d855a686036263265c8c793789e 100644 (file)
@@ -339,8 +339,7 @@ impl MachineState {
             self.p.local() + 1
         };
 
-        self.p = CodePtr::REPL(repl_code_ptr, p);
-        return Ok(());
+        Ok(self.p = CodePtr::REPL(repl_code_ptr, p))
     }
 
     fn truncate_if_no_lifted_heap_diff<AddrConstr>(&mut self, addr_constr: AddrConstr)
@@ -1513,7 +1512,7 @@ impl MachineState {
                     _ => unreachable!(),
                 };
 
-                indices.global_variables.remove(&key);
+                indices.global_variables.swap_remove(&key);
             }
             &SystemClauseType::RemoveCallPolicyCheck => {
                 let restore_default = match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
index a330ad9dbc9f9437ace0499a4d876ac7b8e6b971..6eca3e084e1394f42bae4f3d40397673f207ea55 100644 (file)
@@ -743,12 +743,13 @@ impl RelationWorker {
         terms: Vec<Box<Term>>,
         blocks_cuts: bool,
     ) -> Result<TopLevel, ParserError> {
+       /*
         match setup_declaration(terms.iter().cloned().collect()) {
             Ok(Declaration::Op(..)) => {} // this is now a predicate call in the query context.
             Ok(decl) => return Ok(TopLevel::Declaration(decl)),
             _ => {}
         };
-
+       */
         Ok(TopLevel::Query(self.setup_query(
             indices,
             terms,
index b49375205beede8b85a1262ca733ea03ede73994..0119a801cb85dd526fd833ea8c4a4c225f381a31 100644 (file)
@@ -1,3 +1,20 @@
+/* 
+ *  inserting the modules should not result in the insertion of
+ *  code. this is because they're already loaded by this point -- see
+ *  Machine::new.
+*/
+
+:- use_module(library(lists)).
+:- use_module(library(si)).
+
+'$repl'(ListOfModules) :-
+    maplist('$use_list_of_modules', ListOfModules),
+    false.
+'$repl'(_) :- '$repl'.
+
+'$use_list_of_modules'(Module) :-
+    catch(use_module(Module), E, '$print_exception'(E)).
+
 '$repl' :-
     catch('$read_and_match', E, '$print_exception'(E)),
     false. %% this is for GC, until we get actual GC.
     write_term('caught: ', [quoted(false)]),
     writeq(E),
     nl.
+
+'$predicate_indicator'(Source, PI) :-
+    (  nonvar(PI) ->
+       (  PI = Name / Arity ->
+         (  var(Name) -> throw(error(instantiation_error, Source))
+         ;  integer(Arity) ->
+            (  \+ atom(Name) -> throw(error(type_error(atom, Name), Source))
+            ;  Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), Source))
+            ;  true
+            )
+         ;  throw(error(type_error(integer, Arity), Source))
+         )
+       ;  throw(error(type_error(predicate_indicator, PI), Source))
+       )
+    ;  throw(error(instantiation_error, Source))
+    ).
+
+use_module(Module) :-
+    (  nonvar(Module) ->
+       (  Module = library(Filename) -> '$use_module'(Filename)
+       ;  atom(Module) -> '$use_module_from_file'(Module)
+       ;  throw(error(invalid_module_specifier, use_module/1))
+       )
+    ;  throw(error(instantiation_error, use_module/1))
+    ).
+
+use_module(Module, QualifiedExports) :-
+    (  nonvar(Module) ->
+       (  list_si(QualifiedExports) ->
+         maplist('$predicate_indicator'(use_module/2), QualifiedExports), !,
+         (  Module = library(Filename) -> '$use_qualified_module'(Filename, QualifiedExports)
+         ;  atom(Module) -> '$use_qualified_module_from_file'(Module, QualifiedExports)
+         ;  throw(error(invalid_module_specifier, use_module/2))
+         )
+       ;  throw(error(type_error(list, QualifiedExports), use_module/2))
+       )
+    ;  throw(error(instantiation_error, use_module/2))
+    ).
index ff53b3a50e1ea0626b36f7e0fb66a6accfd37e69..e9f40996ec10f24d9ed25a06c8624cb233aa40e6 100644 (file)
@@ -33,6 +33,14 @@ impl fmt::Display for REPLCodePtr {
             REPLCodePtr::SubmitQueryAndPrintResults => {
                 write!(f, "REPLCodePtr::SubmitQueryAndPrintResults")
             }
+           REPLCodePtr::UseModule =>
+               write!(f, "REPLCodePtr::UseModule"),
+           REPLCodePtr::UseQualifiedModule =>
+               write!(f, "REPLCodePtr::UseQualifiedModule"),
+           REPLCodePtr::UseModuleFromFile =>
+               write!(f, "REPLCodePtr::UseModuleFromFile"),
+           REPLCodePtr::UseQualifiedModuleFromFile =>
+               write!(f, "REPLCodePtr::UseQualifiedModuleFromFile")
         }
     }
 }