]> Repositorios git - scryer-prolog.git/commitdiff
give dynamic predicates a better respect for module bounds
authorMark Thom <[email protected]>
Wed, 6 Mar 2019 07:09:55 +0000 (00:09 -0700)
committerMark Thom <[email protected]>
Wed, 6 Mar 2019 07:09:55 +0000 (00:09 -0700)
src/prolog/machine/compile.rs
src/prolog/machine/dynamic_database.rs
src/prolog/machine/machine_errors.rs
src/prolog/machine/machine_indices.rs
src/prolog/machine/mod.rs
src/prolog/machine/system_calls.rs
src/prolog/write.rs

index 42cecfe6a3020a62d235abe2c3240441c542caf3..aed7d02f20328b224603a3c9cf9fe8e88ad8db7e 100644 (file)
@@ -158,6 +158,36 @@ pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession
     }
 }
 
+pub(super)
+fn compile_into_module<R: Read>(wam: &mut Machine, src: R, name: ClauseName) -> EvalSession
+{
+    let mut indices = default_index_store!(wam.atom_tbl_of(&name));
+    try_eval_session!(setup_indices(wam, name.owning_module(), &mut indices));
+
+    let mut compiler = ListingCompiler::new(&wam.code_repo);
+
+    let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
+    let module_code = try_eval_session!(compiler.generate_code(results.worker_results, wam,
+                                                               &mut indices.code_dir, 0));
+
+    let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len());
+    try_eval_session!(clause_code_generator.generate_clause_code(results.dynamic_clause_map,
+                                                                 wam));
+
+    match wam.indices.modules.get_mut(&name.owning_module()) {
+        Some(module) => {
+            let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new());            
+            module.code_dir.extend(as_module_code_dir(code_dir));                        
+        },
+        _ => unreachable!()
+    };
+    
+    wam.code_repo.code.extend(module_code.into_iter());
+    clause_code_generator.add_clause_code(wam);
+    
+    EvalSession::EntrySuccess
+}
+
 pub struct GatherResult {
     dynamic_clause_map: DynamicClauseMap,
     pub(crate) worker_results: Vec<PredicateCompileQueue>,
@@ -186,6 +216,15 @@ impl ClauseCodeGenerator {
                 continue;
             }
 
+            if let Some(idx) = wam.indices.code_dir.get(&(name.clone(), arity)) {
+                if !idx.is_undefined() && name.owning_module() != idx.module_name() {
+                    let err_str = format!("{}/{}", name.as_str(), arity);
+                    let err_str = clause_name!(err_str, wam.indices.atom_tbl());
+
+                    return Err(SessionError::CannotOverwriteDynamicClause(err_str));
+                }
+            }
+
             let predicate = Predicate(heads_and_tails.into_iter().map(|(head, tail)| {
                 let clause = Term::Clause(Cell::default(), clause_name!("clause"),
                                           vec![Box::new(head), Box::new(tail)],
@@ -360,7 +399,7 @@ impl ListingCompiler {
 
     pub(crate)
     fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>, wam: &Machine,
-                     code_dir: &mut CodeDir)
+                     code_dir: &mut CodeDir, code_offset: usize)
                      -> Result<Code, SessionError>
     {
         let mut code = vec![];
@@ -369,7 +408,7 @@ impl ListingCompiler {
             let (name, arity) = decl.predicate_indicator().ok_or(SessionError::NamelessEntry)?;
             let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
 
-            let p = code.len() + wam.code_size();
+            let p = code.len() + wam.code_size() + code_offset;
             let mut decl_code = compile_relation(&TopLevel::Predicate(decl), non_counted_bt,
                                                  wam.machine_flags())?;
 
@@ -541,9 +580,10 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
     let mut results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
 
     let module_code = try_eval_session!(compiler.generate_code(results.worker_results, wam,
-                                                               &mut indices.code_dir));
+                                                               &mut indices.code_dir, 0));
     let toplvl_code = try_eval_session!(compiler.generate_code(results.toplevel_results, wam,
-                                                               &mut results.toplevel_indices.code_dir));
+                                                               &mut results.toplevel_indices.code_dir,
+                                                               module_code.len()));
 
     if let Some(ref mut module) = &mut compiler.module {
         module.term_expansions = results.addition_results.take_term_expansions();
@@ -556,13 +596,18 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
     try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags));
 
     if let Some(module) = compiler.module.take() {
-        try_eval_session!(add_non_module_code(wam, results.dynamic_clause_map, toplvl_code,
-                                              results.toplevel_indices));
+        let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len() + toplvl_code.len());
+
+        try_eval_session!(clause_code_generator.generate_clause_code(results.dynamic_clause_map, wam));
+        try_eval_session!(wam.check_toplevel_code(&results.toplevel_indices));
 
         add_module_code(wam, module, module_code, indices);
+        add_toplevel_code(wam, toplvl_code, results.toplevel_indices);
+
+        clause_code_generator.add_clause_code(wam);
     } else {
         try_eval_session!(add_non_module_code(wam, results.dynamic_clause_map, module_code,
-                                              indices));        
+                                              indices));
     }
 
     EvalSession::EntrySuccess
@@ -574,12 +619,12 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
 pub fn compile_special_form<R: Read>(wam: &mut Machine, src: R) -> Result<Code, SessionError>
 {
     let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
-    setup_indices(wam, &mut indices)?;
+    setup_indices(wam, clause_name!("builtins"), &mut indices)?;
 
     let mut compiler = ListingCompiler::new(&wam.code_repo);
     let results = compiler.gather_items(wam, src, &mut indices)?;
 
-    compiler.generate_code(results.worker_results, wam, &mut indices.code_dir)
+    compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)
 }
 
 #[inline]
@@ -596,12 +641,15 @@ pub fn compile_listing<R: Read>(wam: &mut Machine, src: R, indices: IndexStore)
     }
 }
 
-fn setup_indices(wam: &mut Machine, indices: &mut IndexStore) -> Result<(), SessionError> {
-    if let Some(builtins) = wam.indices.take_module(clause_name!("builtins")) {
+pub(super)
+fn setup_indices(wam: &mut Machine, module: ClauseName, indices: &mut IndexStore)
+                 -> Result<(), SessionError>
+{
+    if let Some(module) = wam.indices.take_module(module) {
         let flags  = wam.machine_flags();
-        let result = indices.use_module(&mut wam.code_repo, flags, &builtins);
+        let result = indices.use_module(&mut wam.code_repo, flags, &module);
 
-        wam.indices.insert_module(builtins);
+        wam.indices.insert_module(module);
         result
     } else {
         Err(SessionError::ModuleNotFound)
@@ -610,6 +658,6 @@ fn setup_indices(wam: &mut Machine, indices: &mut IndexStore) -> Result<(), Sess
 
 pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
     let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
-    try_eval_session!(setup_indices(wam, &mut indices));
+    try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices));
     compile_listing(wam, src, indices)
 }
index 4fe01ad6d902f624f1e7649b25750f3d353fcc2f..4351f263d1199c6ea3baa37b8f7f06db34578f97 100644 (file)
@@ -6,8 +6,27 @@ use prolog::machine::compile::*;
 use prolog::machine::machine_errors::*;
 use prolog::num::ToPrimitive;
 
+use std::io::Read;
+
 impl Machine {
-    fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey {
+    pub(super)
+    fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
+        match name {
+            &ClauseName::User(ref rc) => rc.table.clone(),
+            _ => self.indices.atom_tbl()
+        }
+    }
+    
+    fn compile_into_machine<R: Read>(&mut self, src: R, name: ClauseName) -> EvalSession
+    {
+        match name.owning_module().as_str() {
+            "user" => compile_user_module(self, src),
+            _ => compile_into_module(self, src, name)
+        }
+    }
+
+    fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey
+    {
         let name  = self.machine_st[name].clone();
         let arity = self.machine_st[arity].clone();
 
@@ -25,12 +44,10 @@ impl Machine {
         (name, arity)
     }
 
-    fn print_new_dynamic_clause(&self, addrs: VecDeque<Addr>, name: RegType, arity: RegType)
+    fn print_new_dynamic_clause(&self, addrs: VecDeque<Addr>, name: ClauseName, arity: usize)
                                 -> String
     {
         let mut output = PrinterOutputter::new();
-        let (name, arity) = self.get_predicate_key(name, arity);
-
         output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
 
         for addr in addrs {
@@ -56,18 +73,19 @@ impl Machine {
         self.indices.dynamic_code_dir.remove(&(name, arity));
     }
 
-    fn handle_eval_result_from_dynamic_compile(&mut self, pred_str: String, src: ClauseName)
+    fn handle_eval_result_from_dynamic_compile(&mut self, pred_str: String, name: ClauseName,
+                                               src: ClauseName)
     {
         let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
-        let result = compile_user_module(self, pred_str.as_bytes());
 
+        let result = self.compile_into_machine(pred_str.as_bytes(), name);
         self.machine_st = machine_st;
 
         if let EvalSession::Error(err) = result {
             let h    = self.machine_st.heap.h;
             let stub = MachineError::functor_stub(src, 1);
             let err  = MachineError::session_error(h, err);
-            let err  = self.machine_st.error_form(err, stub);            
+            let err  = self.machine_st.error_form(err, stub);
 
             self.machine_st.throw_exception(err);
         }
@@ -75,6 +93,8 @@ impl Machine {
 
     fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace)
     {
+        let (name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
+
         let stub = MachineError::functor_stub(place.predicate_name(), 1);
         let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) {
             Ok(addrs) => {
@@ -82,16 +102,17 @@ impl Machine {
                 let added_clause = self.machine_st[temp_v!(1)].clone();
 
                 place.push_to_queue(&mut addrs, added_clause);
-                self.print_new_dynamic_clause(addrs, temp_v!(3), temp_v!(4))
+                self.print_new_dynamic_clause(addrs, name.clone(), arity)
             },
             Err(err) =>
                 return self.machine_st.throw_exception(err)
         };
 
-        self.handle_eval_result_from_dynamic_compile(pred_str, place.predicate_name());
+        self.handle_eval_result_from_dynamic_compile(pred_str, name, place.predicate_name());
     }
 
-    fn retract_from_dynamic_predicate(&mut self) {
+    fn retract_from_dynamic_predicate(&mut self)
+    {
         let index = self.machine_st[temp_v!(3)].clone();
         let index = match self.machine_st.store(self.machine_st.deref(index)) {
             Addr::Con(Constant::Number(Number::Integer(n))) => n.to_usize().unwrap(),
@@ -99,6 +120,8 @@ impl Machine {
         };
 
         let stub = MachineError::functor_stub(clause_name!("retract"), 1);
+        let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
+
         let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
             Ok(addrs) => {
                 let mut addrs = VecDeque::from(addrs);
@@ -109,13 +132,13 @@ impl Machine {
                     return;
                 }
 
-                self.print_new_dynamic_clause(addrs, temp_v!(1), temp_v!(2))
+                self.print_new_dynamic_clause(addrs, name.clone(), arity)
             },
             Err(err) =>
                 return self.machine_st.throw_exception(err)
         };
 
-        self.handle_eval_result_from_dynamic_compile(pred_str, clause_name!("retract"));
+        self.handle_eval_result_from_dynamic_compile(pred_str, name, clause_name!("retract"));
     }
 
     pub(super)
index 5e7d2af93d4af71824b70334a97b59082342af58..566f30f14c0c68fda9171c5ebc4e9508664dff4f 100644 (file)
@@ -369,6 +369,7 @@ impl MachineState {
 
 pub enum SessionError {
     CannotOverwriteBuiltIn(ClauseName),
+    CannotOverwriteDynamicClause(ClauseName),
     CannotOverwriteImport(ClauseName),
     ModuleDoesNotContainExport,
     ModuleNotFound,
index 26db373ba0869fbf12e99eaa95c781c4a49c6dc1..2f515086e7100a8a3a2ffbfe2bd25917844ea4d3 100644 (file)
@@ -389,16 +389,27 @@ pub struct IndexStore {
 }
 
 impl IndexStore {
-    pub fn predicate_exists(&self, name: ClauseName, arity: usize,
+    pub fn predicate_exists(&self, name: ClauseName, module: ClauseName, arity: usize,
                             op_spec: Option<(usize, Specifier)>)
                             -> bool
     {
-        match ClauseType::from(name, arity, op_spec) {
-            ClauseType::Named(name, arity, _) =>
-                self.code_dir.contains_key(&(name, arity)),
-            ClauseType::Op(op_decl, ..) =>
-                self.code_dir.contains_key(&(op_decl.name(), op_decl.arity())),
-            _ => true
+        match self.modules.get(&module) {
+            Some(module) =>
+                match ClauseType::from(name, arity, op_spec) {
+                    ClauseType::Named(name, arity, _) =>
+                        module.code_dir.contains_key(&(name, arity)),
+                    ClauseType::Op(op_decl, ..) =>
+                        module.code_dir.contains_key(&(op_decl.name(), op_decl.arity())),
+                    _ => true
+                },
+            None =>
+                match ClauseType::from(name, arity, op_spec) {
+                    ClauseType::Named(name, arity, _) =>
+                        self.code_dir.contains_key(&(name, arity)),
+                    ClauseType::Op(op_decl, ..) =>
+                        self.code_dir.contains_key(&(op_decl.name(), op_decl.arity())),
+                    _ => true
+                }
         }
     }
 
index bee136315b0b56315570d164ce93185b7253466f..2eacb5d7a3ad2ddb5895f721734a5bd272ca2e0b 100644 (file)
@@ -226,7 +226,7 @@ impl Machine {
                 // ensure we don't try to overwrite an existing predicate from a different module.
                 if !existing_idx.is_undefined() && !idx.is_undefined() {
                     // allow the overwriting of user-level predicates by all other predicates.
-                    if existing_idx.module_name() == key.0.owning_module() {
+                    if existing_idx.module_name().as_str() == "user" {
                         continue;
                     }
 
index 3b7bcb32721e785d9c3a971a073327ebb91b6847..e4ff895e07a1de9cfcd8443bdcf030b42e9957cd 100644 (file)
@@ -370,18 +370,18 @@ impl MachineState {
             },
             &SystemClauseType::GetCurrentPredicateList => {
                 let mut addrs = vec![];
-                
+
                 for ((name, arity), idx) in indices.code_dir.iter() {
                     if idx.is_undefined() {
                         continue;
                     }
-                    
+
                     let h = self.heap.h;
 
                     self.heap.push(HeapCellValue::NamedStr(2, clause_name!("/"), Some((400, YFX))));
                     self.heap.push(HeapCellValue::Addr(Addr::Con(Constant::Atom(name.clone(), None))));
                     self.heap.push(heap_integer!(*arity));
-                    
+
                     addrs.push(Addr::Str(h));
                 }
 
@@ -614,12 +614,16 @@ impl MachineState {
                 self.fail = match self.store(self.deref(head)) {
                     Addr::Str(s) =>
                         match self.heap[s].clone() {
-                            HeapCellValue::NamedStr(arity, name, op_spec) =>
-                                indices.predicate_exists(name, arity, op_spec),
+                            HeapCellValue::NamedStr(arity, name, op_spec) => {
+                                let module = name.owning_module();
+                                indices.predicate_exists(name, module, arity, op_spec)
+                            },
                             _ => unreachable!()
                         },
-                    Addr::Con(Constant::Atom(name, op_spec)) =>
-                        indices.predicate_exists(name, 0, op_spec),
+                    Addr::Con(Constant::Atom(name, op_spec)) => {
+                        let module = name.owning_module();
+                        indices.predicate_exists(name, module, 0, op_spec)
+                    },
                     head => {
                         let err = MachineError::type_error(ValidType::Callable, head);
                         let stub = MachineError::functor_stub(clause_name!("clause"), 2);
index 641135b68e0c5b50ea6adf165ffcbfb1f3d26376..9d3dd8e5e89bee2afa9cae6140728ac5bef475e6 100644 (file)
@@ -249,19 +249,27 @@ impl fmt::Display for IndexingInstruction {
 impl fmt::Display for SessionError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
+            &SessionError::CannotOverwriteDynamicClause(ref msg) =>
+                write!(f, "cannot overwrite dynamic predicate {}", msg),
             &SessionError::CannotOverwriteBuiltIn(ref msg) =>
                 write!(f, "cannot overwrite {}", msg),
             &SessionError::CannotOverwriteImport(ref msg) =>
                 write!(f, "cannot overwrite import {}", msg),
             &SessionError::ModuleNotFound => write!(f, "module not found."),
-            &SessionError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."),
-            &SessionError::QueryFailure => write!(f, "false."),
-            &SessionError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)),
+            &SessionError::ModuleDoesNotContainExport =>
+                write!(f, "module does not contain claimed export."),
+            &SessionError::QueryFailure =>
+                write!(f, "false."),
+            &SessionError::QueryFailureWithException(ref e) =>
+                write!(f, "{}", error_string(e)),
             &SessionError::OpIsInfixAndPostFix =>
                 write!(f, "cannot define an op to be both postfix and infix."),
-            &SessionError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."),
-            &SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
-            &SessionError::UserPrompt => write!(f, "enter predicate at [user] prompt")
+            &SessionError::NamelessEntry =>
+                write!(f, "the predicate head is not an atom or clause."),
+            &SessionError::ParserError(ref e) =>
+                write!(f, "syntax_error({})", e.as_str()),
+            &SessionError::UserPrompt =>
+                write!(f, "enter predicate at [user] prompt")
         }
     }
 }