From: Mark Thom Date: Fri, 19 Jun 2020 06:57:56 +0000 (-0600) Subject: allow paths in use_module(library(..)) (#604) X-Git-Tag: v0.8.127~28 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=cfd15f4e027b4df216e723bbd35facac28a09a1c;p=scryer-prolog.git allow paths in use_module(library(..)) (#604) --- diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 517c4a94..32ed3ee3 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -600,30 +600,44 @@ fn load_library( name: ClauseName, suppress_warnings: bool, ) -> Result { - match LIBRARIES.borrow().get(name.as_str()) { - Some(code) => { - let mut lib_path = current_dir(); + let mut lib_path = current_dir(); - lib_path.pop(); - lib_path.push("lib"); + lib_path.pop(); + lib_path.push("lib"); - let listing_src = ListingSource::from_file_and_path(name, lib_path); + let (stream, listing_src) = + match LIBRARIES.borrow().get(name.as_str()) { + Some(code) => { + let listing_src = ListingSource::from_file_and_path(name, lib_path); + (Stream::from(*code), listing_src) + } + None => { + // assume that name is a path. + lib_path.push(name.as_str()); + lib_path.set_extension("pl"); + + let file = + match File::open(&lib_path) { + Ok(file) => { + file + } + Err(_) => { + let err = ExistenceError::ModuleSource(ModuleSource::Library(name)); + return Err(SessionError::ExistenceError(err)); + } + }; - load_module( - wam, - Stream::from(*code), - suppress_warnings, - &listing_src, - ) - } - None => { - let err = ExistenceError::ModuleSource(ModuleSource::Library( - name.clone() - )); + let listing_src = ListingSource::from_file_and_path(name.clone(), lib_path); + (Stream::from_file_as_input(name, file), listing_src) + } + }; - Err(SessionError::ExistenceError(err)) - } - } + load_module( + wam, + stream, + suppress_warnings, + &listing_src, + ) } impl ListingCompiler { diff --git a/src/machine/mod.rs b/src/machine/mod.rs index cf44a693..ea454547 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -666,21 +666,27 @@ impl Machine { Ok(exports) } - fn use_module(&mut self, to_src: ToSource) - where ToSource: Fn(ClauseName) -> ModuleSource + fn use_module(&mut self, to_src: impl 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 = { + let (name, is_path) = { let addr = self.machine_st.store(self.machine_st.deref(module_spec)); match self.machine_st.heap.index_addr(&addr).as_ref() { HeapCellValue::Atom(name, _) => - name.clone(), + (name.clone(), name.as_str().contains('/')), HeapCellValue::Addr(Addr::Char(c)) => - clause_name!(c.to_string(), self.indices.atom_tbl), + (clause_name!(c.to_string(), self.indices.atom_tbl), false), + HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => { + let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(*addr); + let filename = heap_pstr_iter.to_string(); + let is_path = filename.contains('/'); + + (clause_name!(filename, self.indices.atom_tbl), is_path) + } _ => unreachable!(), } @@ -688,14 +694,18 @@ impl Machine { let load_result = match to_src(name) { ModuleSource::Library(name) => - if let Some(module) = self.indices.take_module(name.clone()) { - self.indices.remove_module(clause_name!("user"), &module); - self.indices.modules.insert(name.clone(), module); - - Ok(name) - } else { - load_library(self, name, false) - }, + if is_path { + load_library(self, name, false) + } else { + if let Some(module) = self.indices.take_module(name.clone()) { + self.indices.remove_module(clause_name!("user"), &module); + self.indices.modules.insert(name.clone(), module); + + Ok(name) + } else { + load_library(self, name, false) + } + } ModuleSource::File(name) => load_module_from_file(self, PathBuf::from(name.as_str()), false) }; @@ -717,21 +727,27 @@ impl Machine { } } - fn use_qualified_module(&mut self, to_src: ToSource) - where ToSource: Fn(ClauseName) -> ModuleSource + fn use_qualified_module(&mut self, to_src: impl 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 = { + let (name, is_path) = { let addr = self.machine_st.store(self.machine_st.deref(module_spec)); match self.machine_st.heap.index_addr(&addr).as_ref() { HeapCellValue::Atom(name, _) => - name.clone(), + (name.clone(), name.as_str().contains('/')), HeapCellValue::Addr(Addr::Char(c)) => - clause_name!(c.to_string(), self.indices.atom_tbl), + (clause_name!(c.to_string(), self.indices.atom_tbl), false), + HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => { + let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(*addr); + let filename = heap_pstr_iter.to_string(); + let is_path = filename.contains('/'); + + (clause_name!(filename, self.indices.atom_tbl), is_path) + } _ => unreachable!(), } @@ -747,14 +763,18 @@ impl Machine { let load_result = match to_src(name) { ModuleSource::Library(name) => - if let Some(module) = self.indices.take_module(name.clone()) { - self.indices.remove_module(clause_name!("user"), &module); - self.indices.modules.insert(name.clone(), module); - - Ok(name) - } else { - load_library(self, name, false) - }, + if is_path { + load_library(self, name, false) + } else { + if let Some(module) = self.indices.take_module(name.clone()) { + self.indices.remove_module(clause_name!("user"), &module); + self.indices.modules.insert(name.clone(), module); + + Ok(name) + } else { + load_library(self, name, false) + } + }, ModuleSource::File(name) => load_module_from_file(self, PathBuf::from(name.as_str()), false) }; diff --git a/src/machine/toplevel.rs b/src/machine/toplevel.rs index 9937fffe..2e553cea 100644 --- a/src/machine/toplevel.rs +++ b/src/machine/toplevel.rs @@ -340,16 +340,39 @@ fn setup_module_decl( } } -fn setup_use_module_decl(mut terms: Vec>) -> Result { +fn read_library_path(term: Term, atom_tbl: TabledData) -> Option { + match term { + Term::Constant(_, Constant::Atom(atom, _)) => { + Some(atom.defrock_brackets()) + } + _ => { + let mut atoms = vec![]; + + for term in unfold_by_str(term, "/") { + match term { + Term::Constant(_, Constant::Atom(atom, _)) => { + atoms.push(atom.as_str().to_owned()); + } + _ => { + return None; + } + } + } + + Some(clause_name!(atoms.join("/"), atom_tbl)) + } + } +} + +fn setup_use_module_decl( + mut terms: Vec>, + atom_tbl: TabledData, +) -> Result { match *terms.pop().unwrap() { Term::Clause(_, ref name, ref mut terms, None) if name.as_str() == "library" && terms.len() == 1 => { - terms - .pop() - .unwrap() - .to_constant() - .and_then(|c| c.to_atom()) + read_library_path(*terms.pop().unwrap(), atom_tbl) .map(|c| ModuleSource::Library(c)) .ok_or(ParserError::InvalidUseModuleDecl) } @@ -396,11 +419,7 @@ fn setup_qualified_import( Term::Clause(_, ref name, ref mut terms, None) if name.as_str() == "library" && terms.len() == 1 => { - terms - .pop() - .unwrap() - .to_constant() - .and_then(|c| c.to_atom()) + read_library_path(*terms.pop().unwrap(), atom_tbl.clone()) .map(|c| ModuleSource::Library(c)) .ok_or(ParserError::InvalidUseModuleDecl) } @@ -685,7 +704,7 @@ fn setup_declaration<'a, 'b, 'c>( } } ("use_module", 1) => { - Ok(Declaration::UseModule(setup_use_module_decl(terms)?)) + Ok(Declaration::UseModule(setup_use_module_decl(terms, indices.atom_tbl())?)) } ("use_module", 2) => { let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?; diff --git a/src/toplevel.pl b/src/toplevel.pl index f07b30d4..23e7decd 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -387,8 +387,11 @@ consult(Item) :- use_module(Module) :- ( nonvar(Module) -> - ( Module = library(Filename) -> '$use_module'(Filename) - ; atom(Module) -> '$use_module_from_file'(Module) + ( Module = library(Filename) -> + write_term_to_chars(Filename, [], FilenameString), + '$use_module'(FilenameString) + ; atom(Module) -> + '$use_module_from_file'(Module) ; throw(error(invalid_module_specifier, use_module/1)) ) ; throw(error(instantiation_error, use_module/1)) @@ -399,7 +402,8 @@ use_module(Module, QualifiedExports) :- ( list_si(QualifiedExports) -> maplist('$module_export'(use_module/2), QualifiedExports) -> ( Module = library(Filename) -> - '$use_qualified_module'(Filename, QualifiedExports) + write_term_to_chars(Filename, [], FilenameString), + '$use_qualified_module'(FilenameString, QualifiedExports) ; atom(Module) -> '$use_qualified_module_from_file'(Module, QualifiedExports) ; throw(error(invalid_module_specifier, use_module/2))