add qualified imports

This commit is contained in:
Mark Thom
2018-03-05 21:13:07 -07:00
parent dbab7a8667
commit b1c41f211b
5 changed files with 108 additions and 46 deletions

View File

@@ -264,3 +264,11 @@ prolog> :{{
local_member(X, Xs) :- member(X, Xs). local_member(X, Xs) :- member(X, Xs).
}}: }}:
``` ```
`use_module` directives can be qualified by adding a list of imports:
```
prolog> :- use_module(library(lists), [member/2]).
```
A qualified `use_module` can be used to remove imports from the
toplevel by giving it an empty import list.

View File

@@ -172,31 +172,54 @@ pub trait SubModuleUser {
fn op_dir(&mut self) -> &mut OpDir; fn op_dir(&mut self) -> &mut OpDir;
fn code_dir(&mut self) -> &mut CodeDir; fn code_dir(&mut self) -> &mut CodeDir;
// returns true on successful import.
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
let name = name.defrock_brackets();
if arity == 1 {
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Pre)) {
self.op_dir().insert((name.clone(), Fixity::Pre), op_data.clone());
}
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Post)) {
self.op_dir().insert((name.clone(), Fixity::Post), op_data.clone());
}
} else if arity == 2 {
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::In)) {
self.op_dir().insert((name.clone(), Fixity::In), op_data.clone());
}
}
if self.code_dir().contains_key(&(name.clone(), arity)) {
println!("warning: overwriting {}/{}", &name, arity);
}
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
self.code_dir().insert((name, arity), code_data.clone());
true
} else {
false
}
}
fn use_qualified_module(&mut self, submodule: &Module, exports: Vec<PredicateKey>) -> EvalSession
{
for (name, arity) in exports {
if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
continue;
}
if !self.import_decl(name, arity, submodule) {
return EvalSession::from(EvalError::ModuleDoesNotContainExport);
}
}
EvalSession::EntrySuccess
}
fn use_module(&mut self, submodule: &Module) -> EvalSession { fn use_module(&mut self, submodule: &Module) -> EvalSession {
for (name, arity) in submodule.module_decl.exports.iter().cloned() { for (name, arity) in submodule.module_decl.exports.iter().cloned() {
let name = name.defrock_brackets(); if !self.import_decl(name, arity, submodule) {
if arity == 1 {
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Pre)) {
self.op_dir().insert((name.clone(), Fixity::Pre), op_data.clone());
}
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Post)) {
self.op_dir().insert((name.clone(), Fixity::Post), op_data.clone());
}
} else if arity == 2 {
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::In)) {
self.op_dir().insert((name.clone(), Fixity::In), op_data.clone());
}
}
if self.code_dir().contains_key(&(name.clone(), arity)) {
println!("warning: overwriting {}/{}", &name, arity);
}
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
self.code_dir().insert((name, arity), code_data.clone());
} else {
return EvalSession::from(EvalError::ModuleDoesNotContainExport); return EvalSession::from(EvalError::ModuleDoesNotContainExport);
} }
} }
@@ -208,7 +231,8 @@ pub trait SubModuleUser {
pub enum Declaration { pub enum Declaration {
Module(ModuleDecl), Module(ModuleDecl),
Op(OpDecl), Op(OpDecl),
UseModule(ClauseName) UseModule(ClauseName),
UseQualifiedModule(ClauseName, Vec<PredicateKey>)
} }
pub enum TopLevel { pub enum TopLevel {

View File

@@ -551,6 +551,8 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSe
}, },
TopLevel::Declaration(Declaration::UseModule(name)) => TopLevel::Declaration(Declaration::UseModule(name)) =>
wam.use_module_in_toplevel(name), wam.use_module_in_toplevel(name),
TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)) =>
wam.use_qualified_module_in_toplevel(name, exports),
TopLevel::Declaration(_) => TopLevel::Declaration(_) =>
EvalSession::from(ParserError::InvalidModuleDecl), EvalSession::from(ParserError::InvalidModuleDecl),
_ => { _ => {
@@ -629,6 +631,18 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
wam.use_module_in_toplevel(name); wam.use_module_in_toplevel(name);
}, },
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)), _) => {
if let Some(ref submodule) = wam.get_module(name.clone()) {
if let Some(ref mut module) = module {
module.use_qualified_module(submodule, exports);
continue;
}
} else {
return EvalSession::from(EvalError::ModuleNotFound);
}
wam.use_qualified_module_in_toplevel(name, exports);
},
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Op(..)), _) => {}, TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Op(..)), _) => {},
TopLevelPacket::Decl(decl, queue) => { TopLevelPacket::Decl(decl, queue) => {
let p = code.len() + wam.code_size(); let p = code.len() + wam.code_size();

View File

@@ -125,6 +125,22 @@ impl Machine {
self.ms.atom_tbl.clone() self.ms.atom_tbl.clone()
} }
pub fn use_qualified_module_in_toplevel(&mut self, name: ClauseName, exports: Vec<PredicateKey>)
-> EvalSession
{
self.remove_module(name.clone());
match self.modules.get(&name) {
Some(ref module) => {
let mut indices = MachineCodeIndex { code_dir: &mut self.code_dir,
op_dir: &mut self.op_dir };
indices.use_qualified_module(module, exports)
},
None => EvalSession::from(EvalError::ModuleNotFound)
}
}
pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession { pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession {
self.remove_module(name.clone()); self.remove_module(name.clone());