]> Repositorios git - scryer-prolog.git/commitdiff
add qualified imports
authorMark Thom <[email protected]>
Tue, 6 Mar 2018 04:13:07 +0000 (21:13 -0700)
committerMark Thom <[email protected]>
Tue, 6 Mar 2018 04:13:07 +0000 (21:13 -0700)
README.md
src/prolog/ast.rs
src/prolog/io.rs
src/prolog/machine/mod.rs
src/prolog/parser

index 54a9be1acae4929f52f6697143aec90ae2f75ae9..88d5e64e061286ad3cf0bd491b670c5847ddc480 100644 (file)
--- a/README.md
+++ b/README.md
@@ -263,4 +263,12 @@ prolog> :{{
 
 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.
index 849c5d69da429cf9acd0f8d9a50732baf8d394f5..45810283ffe8c3edb5e4e4e5a6adb42283ba9611 100644 (file)
@@ -170,45 +170,69 @@ impl SubModuleUser for Module {
 
 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 {
index 32b94f88d1c448b1d8521628eafd9d2ac59597ca..70f7be5a70b22bf36df955574ee59a04f50038c8 100644 (file)
@@ -551,6 +551,8 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSe
         },
         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),
         _ => {
@@ -629,6 +631,18 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
 
                 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();
index 7afe46eac9aabe718ff436f627d88efa1323f059..c94b8a067ec2c74e1ca74310a284bfbd7d9a3d66 100644 (file)
@@ -54,14 +54,14 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> {
 
     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 {}),
@@ -73,21 +73,21 @@ impl Machine {
             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()
@@ -105,7 +105,7 @@ impl Machine {
                         }
 
                         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));
                             }
@@ -116,7 +116,7 @@ impl Machine {
             };
         }
     }
-    
+
     pub fn failed(&self) -> bool {
         self.ms.fail
     }
@@ -125,30 +125,46 @@ impl Machine {
         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());
     }
 
@@ -156,7 +172,7 @@ impl Machine {
         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)) {
@@ -176,14 +192,14 @@ impl Machine {
     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 {
@@ -291,7 +307,7 @@ impl Machine {
                 },
                 &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);
@@ -304,8 +320,8 @@ impl Machine {
 
     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)] {
@@ -327,7 +343,7 @@ impl Machine {
                     if heap_locs.is_empty() {
                         self.record_var_places(0, alloc_locs, heap_locs);
                     }
-                    
+
                     break;
                 }
             };
@@ -350,7 +366,7 @@ impl Machine {
             EvalSession::from(EvalError::QueryFailure)
         }
     }
-    
+
     pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession
     {
         let mut heap_locs = HashMap::new();
index e95c45f411a278f6bacf2aca5ee2f1448fd1a915..54c9d9394b4e17bac5ce7748a483a8b6c8cbb519 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e95c45f411a278f6bacf2aca5ee2f1448fd1a915
+Subproject commit 54c9d9394b4e17bac5ce7748a483a8b6c8cbb519