local_member(X, Xs) :- member(X, Xs).
}}:
-```
\ No newline at end of file
+```
+`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.
pub trait SubModuleUser {
fn op_dir(&mut self) -> &mut OpDir;
- fn code_dir(&mut self) -> &mut CodeDir;
+ fn code_dir(&mut self) -> &mut CodeDir;
- fn use_module(&mut self, submodule: &Module) -> EvalSession {
- for (name, arity) in submodule.module_decl.exports.iter().cloned() {
- let name = name.defrock_brackets();
+ // 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 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 self.code_dir().contains_key(&(name.clone(), arity)) {
- println!("warning: overwriting {}/{}", &name, arity);
+ 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 let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
- self.code_dir().insert((name, arity), code_data.clone());
- } else {
+ 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 {
+ for (name, arity) in submodule.module_decl.exports.iter().cloned() {
+ if !self.import_decl(name, arity, submodule) {
+ return EvalSession::from(EvalError::ModuleDoesNotContainExport);
+ }
+ }
+
+ EvalSession::EntrySuccess
+ }
}
pub enum Declaration {
Module(ModuleDecl),
Op(OpDecl),
- UseModule(ClauseName)
+ UseModule(ClauseName),
+ UseQualifiedModule(ClauseName, Vec<PredicateKey>)
}
pub enum TopLevel {
},
TopLevel::Declaration(Declaration::UseModule(name)) =>
wam.use_module_in_toplevel(name),
+ TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)) =>
+ wam.use_qualified_module_in_toplevel(name, exports),
TopLevel::Declaration(_) =>
EvalSession::from(ParserError::InvalidModuleDecl),
_ => {
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(decl, queue) => {
let p = code.len() + wam.code_size();
fn code_dir(&mut self) -> &mut CodeDir {
self.code_dir
- }
+ }
}
impl Machine {
pub fn new() -> Self {
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
let (code, code_dir, op_dir) = default_build();
-
+
Machine {
ms: MachineState::new(atom_tbl),
call_policy: Box::new(DefaultCallPolicy {}),
cached_query: None
}
}
-
+
fn remove_module(&mut self, module_name: ClauseName) {
let iter = if let Some(submodule) = self.modules.get(&module_name) {
submodule.module_decl.exports.iter().cloned()
} else {
return;
};
-
+
for (name, arity) in iter {
let name = name.defrock_brackets();
-
+
match self.code_dir.get(&(name.clone(), arity)).cloned() {
Some((_, ref mod_name)) if mod_name == &module_name => {
self.code_dir.remove(&(name.clone(), arity));
-
+
// remove or respecify ops.
if arity == 2 {
if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::In)).cloned()
}
if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::Post)).cloned()
- {
+ {
if mod_name == module_name {
self.op_dir.remove(&(name.clone(), Fixity::Post));
}
};
}
}
-
+
pub fn failed(&self) -> bool {
self.ms.fail
}
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 {
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_module(module)
},
None => EvalSession::from(EvalError::ModuleNotFound)
}
}
-
+
pub fn get_module(&self, name: ClauseName) -> Option<&Module> {
self.modules.get(&name)
}
-
+
pub fn add_batched_code(&mut self, mut code: Code, code_dir: CodeDir) {
self.code.append(&mut code);
self.code_dir.extend(code_dir.into_iter());
}
- pub fn add_batched_ops(&mut self, op_dir: OpDir) {
+ pub fn add_batched_ops(&mut self, op_dir: OpDir) {
self.op_dir.extend(op_dir.into_iter());
}
self.modules.insert(module.module_decl.name.clone(), module);
self.code.extend(code.into_iter());
}
-
+
pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession
{
match self.code_dir.get(&(name.clone(), arity)) {
pub fn code_size(&self) -> usize {
self.code.len()
}
-
+
fn cached_query_size(&self) -> usize {
match &self.cached_query {
&Some(ref query) => query.len(),
_ => 0
}
}
-
+
fn execute_instr(&mut self)
{
let instr = match self.ms.p {
},
&VarData::Temp(cn, _, _) if cn == chunk_num => {
let r = var_data.as_reg_type();
-
+
if r.reg_num() != 0 {
let addr = self.ms[r].clone();
heap_locs.insert(var.clone(), addr);
fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
{
- let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());
-
+ let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());
+
while self.ms.p < end_ptr {
if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
match &self[CodePtr::TopLevel(cn, p)] {
if heap_locs.is_empty() {
self.record_var_places(0, alloc_locs, heap_locs);
}
-
+
break;
}
};
EvalSession::from(EvalError::QueryFailure)
}
}
-
+
pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession
{
let mut heap_locs = HashMap::new();
-Subproject commit e95c45f411a278f6bacf2aca5ee2f1448fd1a915
+Subproject commit 54c9d9394b4e17bac5ce7748a483a8b6c8cbb519