From: Mark Thom Date: Mon, 30 Sep 2019 16:26:29 +0000 (-0600) Subject: add use_module/{1,2} as full fledged predicates X-Git-Tag: v0.8.110~35 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=9df14cf890650c042628dfa7281677cb9ccd7da7;p=scryer-prolog.git add use_module/{1,2} as full fledged predicates --- diff --git a/Cargo.toml b/Cargo.toml index 7546f162..cf68711d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/README.md b/README.md index 242db38d..a52927a2 100644 --- 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` diff --git a/src/main.rs b/src/main.rs index 61ed623b..4530d63b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(); } diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 3d0d1aef..aec99d5a 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -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), diff --git a/src/prolog/debray_allocator.rs b/src/prolog/debray_allocator.rs index de5a8651..8d3560e0 100644 --- a/src/prolog/debray_allocator.rs +++ b/src/prolog/debray_allocator.rs @@ -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); diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index c04b4223..083d10ff 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -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 } } diff --git a/src/prolog/machine/compile.rs b/src/prolog/machine/compile.rs index ee0392b1..6d391f9a 100644 --- a/src/prolog/machine/compile.rs +++ b/src/prolog/machine/compile.rs @@ -78,7 +78,7 @@ fn load_module(wam: &mut Machine, name: &str, stream: ParsingStream) 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 Result { match LIBRARIES.borrow().get(name.as_str()) { Some(code) => load_module(wam, name.as_str(), parsing_stream(code.as_bytes())), diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index cb2586a6..efdfa7a9 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -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 for LocalCodePtr { fn partial_cmp(&self, other: &LocalCodePtr) -> Option { 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 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 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 { - self.modules.remove(&name) + self.modules.swap_remove(&name) } #[inline] diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index ca381672..ac737a7e 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -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; diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 56bfa3b9..a1a228fa 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -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 + { + 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(&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(&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, &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(), diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 0ed454f6..ba2eef93 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -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(&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::().ok() { diff --git a/src/prolog/machine/toplevel.rs b/src/prolog/machine/toplevel.rs index a330ad9d..6eca3e08 100644 --- a/src/prolog/machine/toplevel.rs +++ b/src/prolog/machine/toplevel.rs @@ -743,12 +743,13 @@ impl RelationWorker { terms: Vec>, blocks_cuts: bool, ) -> Result { + /* 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, diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index b4937520..0119a801 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -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. @@ -17,3 +34,41 @@ 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)) + ). diff --git a/src/prolog/write.rs b/src/prolog/write.rs index ff53b3a5..e9f40996 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -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") } } }