]> Repositorios git - scryer-prolog.git/commitdiff
fix unsafe variable handling
authorMark Thom <[email protected]>
Fri, 25 Jan 2019 06:38:53 +0000 (23:38 -0700)
committerMark Thom <[email protected]>
Fri, 25 Jan 2019 06:38:53 +0000 (23:38 -0700)
13 files changed:
Cargo.lock
src/prolog/and_stack.rs
src/prolog/codegen.rs
src/prolog/compile.rs
src/prolog/fixtures.rs
src/prolog/heap_print.rs
src/prolog/instructions.rs
src/prolog/lib/builtins.pl
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/machine/system_calls.rs
src/prolog/write.rs
src/tests.rs

index 0179cf3d39a0de819c7ddd6031d8bbd498992f11..eeba396642bf1a944a0b4e505d69e659b225e67a 100644 (file)
@@ -108,7 +108,7 @@ dependencies = [
 
 [[package]]
 name = "rusty-wam"
-version = "0.7.16"
+version = "0.7.17"
 dependencies = [
  "downcast 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
index e012b631793b877178b5f0d0ecab3ea2a868640b..520fe452e9130f3e1b0201903e9c1686f56ebb9d 100644 (file)
@@ -46,18 +46,18 @@ impl AndStack {
     pub fn clear(&mut self) {
         self.0.clear()
     }
-    
-    pub fn resize(&mut self, fr: usize, n: usize) {                        
-        let len = self[fr].perms.len();               
-        
+
+    pub fn resize(&mut self, fr: usize, n: usize) {
+        let len = self[fr].perms.len();
+
         if len < n {
             self[fr].perms.reserve(n - len);
 
-            for i in len .. n {                
+            for i in len .. n {
                 self[fr].perms.push(Addr::StackCell(fr, i));
             }
         }
-    }    
+    }
 }
 
 impl Index<usize> for AndStack {
index 66e94f1ee97c9ffa31feba51f50ca37b64684b75..9409bf46a23bb9341b5c02fa4a16d737f1f2fb53 100644 (file)
@@ -43,6 +43,30 @@ impl<'a> ConjunctInfo<'a>
     fn perm_var_offset(&self) -> usize {
         self.has_deep_cut as usize
     }
+
+    fn mark_unsafe_vars(&self, mut unsafe_var_marker: UnsafeVarMarker, code: &mut Code) {
+        // target the last goal of the rule for handling unsafe variables.
+        // we use this weird logic to find the last goal.
+        let index = if let &Line::Control(_) = code.last().unwrap() {
+            code.len() - 2
+        } else {
+            code.len() - 1
+        };
+
+        if let Line::Query(_) = &code[index] {
+            unsafe_var_marker.record_unsafe_vars(&self.perm_vs);
+
+            for line in code.iter_mut() {
+                if let &mut Line::Query(ref mut query) = line {
+                    unsafe_var_marker.mark_safe_vars(query);
+                }
+            }
+        }
+
+        if let &mut Line::Query(ref mut query) = &mut code[index] {
+            unsafe_var_marker.mark_unsafe_vars(query);
+        }
+    }
 }
 
 impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
@@ -544,9 +568,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
         self.compile_seq_prelude(&conjunct_info, &mut code);
 
         let iter = FactIterator::from_rule_head_clause(args);
-        let fact = self.compile_target(iter, GenContext::Head, false);
+        let mut fact = self.compile_target(iter, GenContext::Head, false);
+
+        let mut unsafe_var_marker = UnsafeVarMarker::new();
 
         if !fact.is_empty() {
+            unsafe_var_marker = self.mark_unsafe_fact_vars(&mut fact);
             code.push(Line::Fact(fact));
         }
 
@@ -554,23 +581,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
         try!(self.compile_seq(iter, &conjunct_info, &mut code, false));
 
         if conjunct_info.allocates() {
-            let index = if let &Line::Control(_) = code.last().unwrap() {
-                code.len() - 2
-            } else {
-                code.len() - 1
-            };
-
-            if let &mut Line::Query(ref mut query) = &mut code[index] {
-                let head_iter = FactIterator::from_rule_head_clause(args);
-                conjunct_info.perm_vs.mark_unsafe_vars_in_rule(head_iter, query);
-            }
+            conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
         }
 
         Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
         Ok(code)
     }
 
-    fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact)
+    fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker
     {
         let mut unsafe_vars = HashMap::new();
 
@@ -587,14 +605,15 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
                             *fact_instr = FactInstruction::UnifyLocalValue(reg);
                         }
                     },
-                &mut FactInstruction::UnifyVariable(reg) => {
+                &mut FactInstruction::UnifyVariable(reg) =>
                     if let Some(found) = unsafe_vars.get_mut(&reg) {
                         *found = true;
-                    }
-                },
+                    },
                 _ => {}
             };
         }
+
+        UnsafeVarMarker { unsafe_vars }
     }
 
     pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code
@@ -653,15 +672,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
         try!(self.compile_seq(iter, &conjunct_info, &mut code, true));
 
         if conjunct_info.allocates() {
-            let index = if let &Line::Control(_) = code.last().unwrap() {
-                code.len() - 2
-            } else {
-                code.len() - 1
-            };
-
-            if let &mut Line::Query(ref mut query) = &mut code[index] {
-                conjunct_info.perm_vs.mark_unsafe_vars_in_query(query);
-            }
+            conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code);
         }
 
         if let Some(query_term) = query.last() {
index 6cd23f92601ef0c50f615301ffad3e6a0ed7d72b..6160489f1d034153bafdeb53df28425587037cb1 100644 (file)
@@ -122,7 +122,7 @@ fn compile_query(terms: Vec<QueryTerm>, queue: VecDeque<TopLevel>, flags: Machin
     let mut code = try!(cg.compile_query(&terms));
 
     compile_appendix(&mut code, &queue, false, flags)?;
-
+    
     Ok((code, cg.take_vars()))
 }
 
index 1cbcd713d2be14c241341cd71c262dc1d61a0831..71805c5c58d570f2bc432d6cc44ee4f8b8e9c2c1 100644 (file)
@@ -174,25 +174,58 @@ impl<'a> VariableFixtures<'a>
             }
         }
     }
+}
+
+pub struct UnsafeVarMarker {
+    pub unsafe_vars: HashMap<RegType, bool>
+}
+
+impl UnsafeVarMarker {
+    pub fn new() -> Self {
+        UnsafeVarMarker {
+            unsafe_vars: HashMap::new()
+        }
+    }
+
+    pub fn record_unsafe_vars(&mut self, fixtures: &VariableFixtures) {
+        for &(_, ref cb) in fixtures.values() {
+            if let Some(index) = cb.first() {
+                if !self.unsafe_vars.contains_key(&index.get().norm()) {
+                    self.unsafe_vars.insert(index.get().norm(), false);
+                }
+            }
+        }
+    }
+
+    pub fn mark_safe_vars(&mut self, query: &mut CompiledQuery) {
+        for query_instr in query.iter_mut() {
+            match query_instr {
+                &mut QueryInstruction::PutVariable(RegType::Temp(r), _) =>
+                    if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(r)) {
+                        *found = true;
+                    },
+                &mut QueryInstruction::SetVariable(reg) =>
+                    if let Some(found) = self.unsafe_vars.get_mut(&reg) {
+                        *found = true;
+                    },
+                _ => {}
+            }
+        }
+    }
 
-    fn mark_unsafe_vars(&self, unsafe_vars: &mut HashMap<RegType, bool>, query: &mut CompiledQuery)
+    pub fn mark_unsafe_vars(&mut self, query: &mut CompiledQuery)
     {
         for query_instr in query.iter_mut() {
             match query_instr {
                 &mut QueryInstruction::PutValue(RegType::Perm(i), arg) =>
-                    if let Some(found) = unsafe_vars.get_mut(&RegType::Perm(i)) {
+                    if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) {
                         if !*found {
                             *found = true;
                             *query_instr = QueryInstruction::PutUnsafeValue(i, arg);
                         }
                     },
-                &mut QueryInstruction::SetVariable(reg)
-              | &mut QueryInstruction::PutVariable(reg, _) =>
-                    if let Some(found) = unsafe_vars.get_mut(&reg) {
-                        *found = true;
-                    },
                 &mut QueryInstruction::SetValue(reg) =>
-                    if let Some(found) = unsafe_vars.get_mut(&reg) {
+                    if let Some(found) = self.unsafe_vars.get_mut(&reg) {
                         if !*found {
                             *found = true;
                             *query_instr = QueryInstruction::SetLocalValue(reg);
@@ -202,43 +235,4 @@ impl<'a> VariableFixtures<'a>
             };
         }
     }
-
-    fn record_unsafe_vars(&self, unsafe_vars: &mut HashMap<RegType, bool>) {
-        for &(_, ref cb) in self.values() {
-            match cb.first() {
-                Some(index) => {
-                    unsafe_vars.insert(index.get().norm(), false);
-                },
-                None => {}
-            };
-        }
-    }
-
-    fn mark_head_vars_as_safe(&self, head_iter: FactIterator<'a>, unsafe_vars: &mut HashMap<RegType, bool>)
-    {
-        for term_ref in head_iter {
-            match term_ref {
-                TermRef::Var(Level::Shallow, cell, _) => {
-                    unsafe_vars.remove(&cell.get().norm());
-                },
-                _ => {}
-            };
-        }
-    }
-
-    pub fn mark_unsafe_vars_in_query(&self, query: &mut CompiledQuery) {
-        let mut unsafe_vars = HashMap::new();
-
-        self.record_unsafe_vars(&mut unsafe_vars);
-        self.mark_unsafe_vars(&mut unsafe_vars, query);
-    }
-
-    pub fn mark_unsafe_vars_in_rule(&self, head_iter: FactIterator<'a>, query: &mut CompiledQuery)
-    {
-        let mut unsafe_vars = HashMap::new();
-
-        self.record_unsafe_vars(&mut unsafe_vars);
-        self.mark_head_vars_as_safe(head_iter, &mut unsafe_vars);
-        self.mark_unsafe_vars(&mut unsafe_vars, query);
-    }
 }
index 3d85657ea684d0862ac7250fc5591f582a3dd3c8..28e6e48f5f831b102ef307ddd6048351c4838ca2 100644 (file)
@@ -628,7 +628,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
 
     pub fn print(mut self, addr: Addr) -> Outputter {
         let mut iter = self.machine_st.pre_order_iter(addr);
-
+        
         loop {
             if let Some(loc_data) = self.state_stack.pop() {
                 match loc_data {
index 21bfa59a915400148f4779b1f7b08ee04aa45ae5..70c9022cecd942dc9f8dc0d8d287c9b8f720d8c2 100644 (file)
@@ -4,7 +4,6 @@ use prolog_parser::tabled_rc::*;
 use std::cell::{Cell, RefCell};
 use std::collections::{BTreeSet, HashMap, VecDeque};
 use std::cmp::Ordering;
-use std::fmt;
 use std::ops::{Add, AddAssign, Index, IndexMut, Sub};
 use std::rc::Rc;
 
@@ -495,12 +494,12 @@ impl BuiltInClauseType {
 
 impl ClauseType {
     pub fn spec(&self) -> Option<(usize, Specifier)> {
-        match self {            
+        match self {
             &ClauseType::Op(ref op_decl, _) =>
                 Some((op_decl.0, op_decl.1)),
             &ClauseType::Inlined(InlinedClauseType::CompareNumber(..))
           | &ClauseType::BuiltIn(BuiltInClauseType::Is(..))
-          | &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_))      
+          | &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_))
           | &ClauseType::BuiltIn(BuiltInClauseType::NotEq)
           | &ClauseType::BuiltIn(BuiltInClauseType::Eq) =>
                 Some((700, XFX)),
@@ -715,18 +714,6 @@ pub enum Addr {
     Str(usize)
 }
 
-impl fmt::Display for Addr {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            &Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
-            &Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
-            &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
-            &Addr::StackCell(fr, sc)=> write!(f, "Addr::StackCell({}, {})", fr, sc),
-            &Addr::Str(s) => write!(f, "Addr::Str({})", s)
-        }
-    }
-}
-
 impl PartialEq<Ref> for Addr {
     fn eq(&self, r: &Ref) -> bool {
         self.as_var() == Some(*r)
@@ -1500,7 +1487,7 @@ impl OpDecl {
     pub fn name(&self) -> ClauseName {
         self.2.clone()
     }
-        
+
     pub fn submit(&self, module: ClauseName, op_dir: &mut OpDir) -> Result<(), SessionError>
     {
         let (prec, spec, name) = (self.0, self.1, self.2.clone());
index 1260f642a4a54889e43b6914071f2fcd4a5fe119..211bbc583553e7dd3cd9ac360750ffe595ceb087 100644 (file)
@@ -202,9 +202,9 @@ get_args([Arg|Args], Func, I0, N) :-
 
 % write, write_canonical, writeq, write_term.
 is_write_option(Functor) :-
-    Functor =.. [Name, Arg | Args],
-    ( Args == [], Arg == true -> true
-    ; Args == [], Arg == false -> true
+    Functor =.. [Name, Arg],
+    ( Arg == true -> true
+    ; Arg == false -> true
     ; throw(error(domain_error(write_option, Functor), write_term/2)) ), % 8.14.2.3 e)
     ( Name == ignore_ops -> true
     ; Name == quoted -> true
index d709540a330c97bd6ddf990504d936efa16eebd8..6dc36cebaf50135e0fa904f3574a4b2b38e9d83a 100644 (file)
@@ -59,6 +59,13 @@ impl MachineState {
         }
     }
 
+    #[allow(dead_code)]
+    pub fn print_heap(&self) {
+        for h in 0 .. self.heap.h {
+            println!("{} : {}", h, self.heap[h]);
+        }
+    }
+    
     #[inline]
     pub fn machine_flags(&self) -> MachineFlags {
         self.flags
@@ -1260,7 +1267,8 @@ impl MachineState {
 
                 if let Addr::HeapCell(hc) = addr {
                     if hc < h {
-                        self.heap.push(HeapCellValue::Addr(addr));
+                        let heap_val = self.heap[hc].clone();
+                        self.heap.push(heap_val);
                         return;
                     }
                 }
@@ -2112,14 +2120,14 @@ impl MachineState {
                 .unwrap_or(0);
 
             if and_gi > or_gi {
-                let index = self.e + 1;
+                let new_e = self.e + 1;
 
-                self.and_stack[index].e  = self.e;
-                self.and_stack[index].cp = self.cp.clone();
-                self.and_stack[index].global_index = gi;
+                self.and_stack[new_e].e  = self.e;
+                self.and_stack[new_e].cp = self.cp.clone();
+                self.and_stack[new_e].global_index = gi;
 
-                self.and_stack.resize(index, num_cells);
-                self.e = index;
+                self.and_stack.resize(new_e, num_cells);
+                self.e = new_e;
 
                 return;
             }
index cc3e0b061b39bf6c250bafd8256d30801ea27a02..d301eda98c5c6c6e123234bbe0c99615409b640b 100644 (file)
@@ -627,7 +627,7 @@ impl MachineState {
             }
 
             self.query_stepper(indices, policies, code_repo);
-
+            
             match self.p {
                 CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {},
                 _ => {
index 00c7dd722730795e5d482f68a6a362e034473f06..5de4f3970dae9618a960eb8827af13bd5df7650b 100644 (file)
@@ -516,9 +516,9 @@ impl MachineState {
             &SystemClauseType::WriteTerm => {
                 let addr = self[temp_v!(1)].clone();
 
-                let ignore_ops = self[temp_v!(2)].clone();
-                let numbervars = self[temp_v!(3)].clone();
-                let quoted = self[temp_v!(4)].clone();
+                let ignore_ops = self.store(self.deref(self[temp_v!(2)].clone()));
+                let numbervars = self.store(self.deref(self[temp_v!(3)].clone()));
+                let quoted = self.store(self.deref(self[temp_v!(4)].clone()));
 
                 let mut printer = HCPrinter::new(&self, PrinterOutputter::new());
 
index 798e0ff10f8df2d931822d6fb6047d5275ec4539..76fb48fd897540be3502aa5e1ec18f6c2ff4f224 100644 (file)
@@ -127,6 +127,32 @@ impl fmt::Display for ClauseType {
     }
 }
 
+impl fmt::Display for HeapCellValue {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            &HeapCellValue::Addr(ref addr) =>
+                write!(f, "{}", addr),
+            &HeapCellValue::NamedStr(arity, ref name, Some((priority, spec))) =>
+                write!(f, "{}/{} (op, priority: {}, spec: {})", name.as_str(), arity,
+                       priority, spec),
+            &HeapCellValue::NamedStr(arity, ref name, None) =>
+                write!(f, "{}/{}", name.as_str(), arity)
+        }
+    }
+}
+
+impl fmt::Display for Addr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            &Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
+            &Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
+            &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
+            &Addr::StackCell(fr, sc)=> write!(f, "Addr::StackCell({}, {})", fr, sc),
+            &Addr::Str(s) => write!(f, "Addr::Str({})", s)
+        }
+    }
+}
+
 impl fmt::Display for ControlInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
index e49829e2fe5f4394570ccb0c32729f4f1d264752..4e5ab35e125f4960b3768242d130e840aa3535a1 100644 (file)
@@ -1493,7 +1493,7 @@ fn test_queries_on_builtins()
                                        ["N = 5", "Xs = [_4, _8, _12, _16, _20]"]],
                                       6);
 
-    assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_4, _8, _12]"]]);
+    assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_5, _9, _13]"]]);
     assert_prolog_success!(&mut wam, "?- length([], N).", [["N = 0"]]);
     assert_prolog_success!(&mut wam, "?- length(Xs, 0).", [["Xs = []"]]);
     assert_prolog_success!(&mut wam, "?- length([a,b,[a,b,c]], 3).");
@@ -1630,7 +1630,7 @@ fn test_queries_on_builtins()
 
     assert_prolog_failure!(&mut wam, "?- Pairs = [a-a|Pairs], keysort(Pairs, _).");
     assert_prolog_success!(&mut wam, "?- Pairs = [a-a|Pairs], catch(keysort(Pairs, _), error(E, _), true).",
-                           [["E = type_error(list, [a-a | _22])", "Pairs = [a-a | Pairs]"]]);
+                           [["E = type_error(list, [a-a | _25])", "Pairs = [a-a | Pairs]"]]);
 
     assert_prolog_success!(&mut wam, "?- keysort([], L).",
                            [["L = []"]]);
@@ -1639,9 +1639,9 @@ fn test_queries_on_builtins()
     assert_prolog_success!(&mut wam, "?- catch(keysort([],[a|a]),error(Pat, _),true).",
                            [["Pat = type_error(list, [a | a])"]]);
     assert_prolog_success!(&mut wam, "?- catch(keysort(_, _), error(E, _), true).",
-                           [["E = type_error(list, _13)"]]);
+                           [["E = type_error(list, _16)"]]);
     assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [_|b]), error(E, _), true).",
-                           [["E = type_error(list, [_24 | b])"]]);
+                           [["E = type_error(list, [_27 | b])"]]);
     assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [a-b,c-d,a]), error(E, _), true).",
                            [["E = type_error(pair, a)"]]);
     assert_prolog_success!(&mut wam, "?- catch(keysort([a], [a-b]), error(E, _), true).",
@@ -1654,7 +1654,7 @@ fn test_queries_on_builtins()
     assert_prolog_success!(&mut wam, "?- sort([], L).",
                            [["L = []"]]);
     assert_prolog_success!(&mut wam, "?- catch(sort(_, []), error(E, _), true).",
-                           [["E = type_error(list, _13)"]]);
+                           [["E = type_error(list, _16)"]]);
     assert_prolog_success!(&mut wam, "?- catch(sort([a,b,c], not_a_list), error(E, _), true).",
                            [["E = type_error(list, not_a_list)"]]);