]> Repositorios git - scryer-prolog.git/commitdiff
properly handle cyclic terms in the printer.
authorMark Thom <[email protected]>
Sat, 5 May 2018 18:33:29 +0000 (12:33 -0600)
committerMark Thom <[email protected]>
Sat, 5 May 2018 18:33:29 +0000 (12:33 -0600)
src/prolog/copier.rs
src/prolog/heap_print.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/tests.rs

index e79d9e463fcebd41efdfd751845ce67cca14828f..7a08365652d1deb7755fee49494a9d5dd6f769cd 100644 (file)
@@ -4,6 +4,14 @@ use prolog::ast::*;
 use std::collections::HashMap;
 use std::ops::IndexMut;
 
+pub type Trail = Vec<(Ref, HeapCellValue)>;
+
+pub struct RedirectInfo {
+    trail: Trail,
+    list_redirect: HashMap<usize, usize>,
+    offset: usize
+}
+
 // allows us to reconstruct a HeapVarDict by relating variables
 // in an existing HeapVarDict to the ones created in fn duplicate_term.
 // It is used to create meaningful error reports at the toplevel.
@@ -13,9 +21,11 @@ impl CellRedirect {
     pub fn new() -> Self {
         CellRedirect(HashMap::new())
     }
-}
 
-pub type Trail = Vec<(Ref, HeapCellValue)>;
+    pub fn clear(&mut self) {
+        self.0.clear();
+    }
+}
 
 pub trait CopierTarget
 {
@@ -26,49 +36,60 @@ pub trait CopierTarget
     fn deref(&self, Addr) -> Addr;
     fn stack(&mut self) -> &mut AndStack;
 
-    fn compile_redirect(&mut self, trail: Trail, list_redirect: HashMap<usize, usize>, old_h: usize)
-                        -> CellRedirect
-        where Self: IndexMut<usize, Output=HeapCellValue>
+    // unwind the trail *and* compute a cell redirection table.
+    fn unwind_and_redirect(&mut self, redirect: RedirectInfo) -> CellRedirect
+      where Self: IndexMut<usize, Output=HeapCellValue>
     {
         let mut cell_redirect: HashMap<Addr, Addr> = HashMap::new();
-        
-        for (r, hcv) in trail {
+
+        for (r, hcv) in redirect.trail {
             let addr = Addr::from(r);
-            
+
             match r {
-                Ref::HeapCell(hc) => {                    
-                    cell_redirect.insert(addr, self[hc].as_addr(hc) - old_h);                    
-                    self[hc] = hcv;
+                Ref::HeapCell(h) => {
+                    cell_redirect.insert(addr, self[h].as_addr(h) - redirect.offset);
+                    self[h] = hcv;
                 },
                 Ref::StackCell(fr, sc) => {
-                    cell_redirect.insert(addr, self.stack()[fr][sc].clone() - old_h);
+                    cell_redirect.insert(addr, self.stack()[fr][sc].clone() - redirect.offset);
                     self.stack()[fr][sc] = hcv.as_addr(0);
                 }
-            }
+            };
         }
 
-        for (l, h) in list_redirect {
-            cell_redirect.insert(Addr::Lis(l), Addr::Lis(h - old_h));
+        for (l, h) in redirect.list_redirect {
+            cell_redirect.insert(Addr::Lis(l), Addr::Lis(h - redirect.offset));
         }
 
         CellRedirect(cell_redirect)
     }
-    
-    // duplicate_term(L1, L2) uses Cheney's algorithm to copy the term
+
+    fn unwind_trail(&mut self, redirect: RedirectInfo)
+      where Self: IndexMut<usize, Output=HeapCellValue>
+    {
+        for (r, hcv) in redirect.trail {
+            match r {
+                Ref::HeapCell(hc) => self[hc] = hcv.clone(),
+                Ref::StackCell(fr, sc) => self.stack()[fr][sc] = hcv.as_addr(0)
+            }
+        }
+    }
+
+    // duplicate_term_impl(L1, L2) uses Cheney's algorithm to copy the term
     // at L1 to L2. trail is kept to restore the innards of L1 after
     // it's been copied to L2.
-    fn duplicate_term(&mut self, addr: Addr) -> CellRedirect
+    fn duplicate_term_impl(&mut self, addr: Addr) -> RedirectInfo
       where Self: IndexMut<usize, Output=HeapCellValue>
     {
         let mut trail = Trail::new();
-        let mut scan = self.source();        
-        let old_h = self.threshold();        
+        let mut scan = self.source();
+        let old_h = self.threshold();
 
         // Lists have a compressed representation as structures,
         // removing the need for NamedStr, so we use a redirection
         // table for copying lists.
         let mut list_redirect = HashMap::new();
-        
+
         self.push(HeapCellValue::Addr(addr));
 
         while scan < self.threshold() {
@@ -84,15 +105,15 @@ pub trait CopierTarget
                                 continue;
                             }
 
-                            list_redirect.insert(a, self.threshold());                            
+                            list_redirect.insert(a, self.threshold());
                             self[scan] = HeapCellValue::Addr(Addr::Lis(self.threshold()));
-                            
+
                             let hcv = self[a].clone();
                             self.push(hcv);
-                            
+
                             let hcv = self[a+1].clone();
                             self.push(hcv);
-                            
+
                             scan += 1;
                         },
                         Addr::HeapCell(_) | Addr::StackCell(_, _) => {
@@ -152,6 +173,20 @@ pub trait CopierTarget
             }
         }
 
-        self.compile_redirect(trail, list_redirect, old_h)
+        RedirectInfo { trail, list_redirect, offset: old_h }
+    }
+
+    fn duplicate_term_and_redirect(&mut self, addr: Addr) -> CellRedirect
+      where Self: IndexMut<usize, Output=HeapCellValue>
+    {
+        let redirect = self.duplicate_term_impl(addr);
+        self.unwind_and_redirect(redirect)
+    }
+
+    fn duplicate_term(&mut self, addr: Addr)
+      where Self: IndexMut<usize, Output=HeapCellValue>
+    {
+        let redirect = self.duplicate_term_impl(addr);
+        self.unwind_trail(redirect);
     }
 }
index 765415da98d88938b7308f68fa63d871161b708d..11a23ae1f3e926836c41fab5107a0c6c8a5680f2 100644 (file)
@@ -169,7 +169,7 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
                           -> Self
     {
         let mut printer = Self::new(machine_st, fmt, output);
-        
+
         printer.heap_locs = Cow::Borrowed(heap_locs);
         printer
     }
@@ -184,10 +184,20 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
             let addr = machine_st.store(machine_st.deref(addr.clone()));
             printer.printed_vars.insert(addr.clone());
         }
-        
+
         printer
     }
-    
+
+    fn print_offset(&mut self, addr: Addr) {
+        match addr {
+            Addr::HeapCell(h) | Addr::Lis(h) =>
+                self.outputter.append(format!("_{}", h).as_str()),
+            Addr::StackCell(fr, sc) =>
+                self.outputter.append(format!("s_{}_{}", fr, sc).as_str()),
+            _ => {}
+        }
+    }
+
     // returns a HeapCellValue iff the next element to come hasn't been seen previously.
     fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue> {
         iter.stack().last().cloned().and_then(|addr| {
@@ -207,13 +217,16 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
                 }
             }
 
-            // addr is not the address of a named variable. If it is a variable,
-            // it must be anonymous.
-            if addr.is_ref() {
-                self.outputter.append("_");
-                iter.stack().pop();
-                
-                None
+            if self.machine_st.is_cyclic_term(addr.clone()) {
+                if self.printed_vars.contains(&addr) {
+                    iter.stack().pop();
+                    self.print_offset(addr);
+                    
+                    None
+                } else {
+                    self.printed_vars.insert(addr);
+                    iter.next()
+                }
             } else {
                 iter.next()
             }
@@ -226,7 +239,7 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
             Some(heap_val) => heap_val,
             _ => return
         };
-        
+
         match heap_val {
             HeapCellValue::NamedStr(arity, name, fixity) => {
                 let ct = ClauseType::from(name, arity, fixity);
@@ -249,11 +262,7 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
 
                 self.state_stack.push(TokenOrRedirect::OpenList(cell));
             },
-            HeapCellValue::Addr(Addr::HeapCell(h)) =>
-                self.outputter.append(format!("_{}", h).as_str()),
-            HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
-                self.outputter.append(format!("s_{}_{}", fr, sc).as_str()),
-            HeapCellValue::Addr(Addr::Str(_)) => {}
+            HeapCellValue::Addr(addr) => self.print_offset(addr)
         }
     }
 
index 6592fc207e98dc40540484f676149a8a42a14035..8f1fd505e40c0989023f4359162f94415c98a143 100644 (file)
@@ -1121,10 +1121,9 @@ impl MachineState {
         diff
     }
 
-    pub(super) fn is_cyclic_term(&self, addr: Addr) -> bool {
+    pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool {
         let mut seen = HashSet::new();
         let mut fail = false;
-
         let mut iter = self.pre_order_iter(addr);
 
         loop {
@@ -1188,26 +1187,7 @@ impl MachineState {
 
         self.p += 1;
     }
-
-    // everything in self.redirect is potentially offset on the heap by 'offset',
-    // so correct for that when building the HeapVarDict.
-    pub(super) fn reconstruct_dict(&self, heap_locs: &HeapVarDict, offset: usize) -> HeapVarDict
-    {
-        let mut dest_heap_locs = HeapVarDict::new();
-
-      'outer:
-        for (orig_addr, addr) in self.redirect.0.iter() {            
-            for (var, var_addr) in heap_locs.iter() {
-                if orig_addr == &self.store(self.deref(var_addr.clone())) {
-                    dest_heap_locs.insert(var.clone(), addr.clone() + offset);
-                    continue 'outer;
-                }
-            }
-        }
-
-        dest_heap_locs
-    }
-    
+            
     pub(super) fn compare_term(&mut self, qt: CompareTermQT) {
         let a1 = self[temp_v!(1)].clone();
         let a2 = self[temp_v!(2)].clone();
@@ -1638,12 +1618,11 @@ impl MachineState {
                 let addr = self[temp_v!(1)].clone();
                 self.ball.boundary = self.heap.h;
 
-                let cell_redirect = {
+                self.redirect = {
                     let mut duplicator = DuplicateBallTerm::new(self);
-                    duplicator.duplicate_term(addr)                                        
+                    duplicator.duplicate_term_and_redirect(addr)
                 };
-
-                self.redirect.0.extend(cell_redirect.0.into_iter());
+                
                 self.p += 1;
             },
             &BuiltInInstruction::SetCutPoint(r) =>
@@ -2354,6 +2333,6 @@ impl MachineState {
         self.block = 0;
         
         self.ball.reset();
-        self.redirect.0.clear();
+        self.redirect.clear();
     }
 }
index 9cf732f478f7da2ccb5423ece3a9001f5fac0b11..f2a4ad81ac247cd49f4c23ed57ab5df4b4a7d102 100644 (file)
@@ -375,8 +375,7 @@ impl Machine {
         if self.ms.ball.stub.len() > 0 {
             let h = self.ms.heap.h;
             self.ms.copy_and_align_ball_to_heap();
-
-            let heap_locs = self.ms.reconstruct_dict(heap_locs, h);
+            
             let error_str = self.ms.print_exception(Addr::HeapCell(h),
                                                     &heap_locs,
                                                     TermFormatter {},
index d33a10397b8fd21220f8399e39b8b932453084ee..9477caf23e5619bef402591e1dbe8f6df55cead7 100644 (file)
@@ -271,7 +271,7 @@ fn test_queries_on_rules() {
     assert_prolog_success!(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).",
                            [["Z = b", "Y = b", "X = f(a)"]]);
     assert_prolog_success!(&mut wam, "?- p(Z, Y, X).",
-                           [["X = h", "Y = g(b)", "Z = f(f(a), g(b), _)"]]);
+                           [["X = h", "Y = g(b)", "Z = f(f(a), g(b), _7)"]]);
     assert_prolog_success!(&mut wam, "?- p(f(X, Y, Z), Y, h).",
                            [["Y = g(b)", "Z = _3", "X = f(a)"]]);
 
@@ -539,7 +539,7 @@ fn test_queries_on_lists()
 
     assert_prolog_success!(&mut wam, "?- p([Z, Z]).", [["Z = _0"]]);
     assert_prolog_failure!(&mut wam, "?- p([Z, W, Y]).");
-    assert_prolog_success!(&mut wam, "?- p([Z | W]).", [["Z = _0", "W = [_]"]]);
+    assert_prolog_success!(&mut wam, "?- p([Z | W]).", [["Z = _0", "W = [_3]"]]);
     assert_prolog_success!(&mut wam, "?- p([Z | [Z]]).", [["Z = _0"]]);
     assert_prolog_success!(&mut wam, "?- p([Z | [W]]).", [["Z = _2", "W = _0"]]);
     assert_prolog_failure!(&mut wam, "?- p([Z | []]).");
@@ -600,7 +600,7 @@ fn test_queries_on_conjuctive_queries() {
     submit(&mut wam, "p(a, [f(g(X))]).");
     submit(&mut wam, "q(Y, c).");
 
-    assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).", [["Y = [f(g(_))]", "X = a", "Z = c"]]);
+    assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).", [["Y = [f(g(_9))]", "X = a", "Z = c"]]);
     assert_prolog_failure!(&mut wam, "?- p(X, Y), q(Y, X).");
 
     submit(&mut wam, "member(X, [X|_]).
@@ -632,10 +632,10 @@ fn test_queries_on_conjuctive_queries() {
     submit(&mut wam, "q(Y, c).");
 
     assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).",
-                           [["X = a",  "Z = c", "Y = [f(g(_))]"],
+                           [["X = a",  "Z = c", "Y = [f(g(_9))]"],
                             ["X = _0", "Z = c", "Y = c"]]);
     assert_prolog_success!(&mut wam, "?- p(X, Y), !, q(Y, Z).",
-                           [["Z = c", "Y = [f(g(_))]", "X = a"]]);
+                           [["Z = c", "Y = [f(g(_9))]", "X = a"]]);
 
     submit(&mut wam, "q([f(g(x))], Z). q([f(g(y))], Y). q([f(g(z))], a).");
 
@@ -1260,8 +1260,8 @@ fn test_queries_on_builtins()
 
     assert_prolog_success!(&mut wam, "?- functor(F, f, 0).", [["F = f"]]);
 
-    assert_prolog_success!(&mut wam, "?- functor(Func, f, 3).", [["Func = f(_, _, _)"]]);
-    assert_prolog_success!(&mut wam, "?- functor(Func, f, 4).", [["Func = f(_, _, _, _)"]]);
+    assert_prolog_success!(&mut wam, "?- functor(Func, f, 3).", [["Func = f(_2, _3, _4)"]]);
+    assert_prolog_success!(&mut wam, "?- functor(Func, f, 4).", [["Func = f(_2, _3, _4, _5)"]]);
 
     assert_prolog_success!(&mut wam, "?- catch(functor(F, \"sdf\", 3), error(E, _), true).",
                            [["E = instantiation_error", "F = _1"]]);
@@ -1289,14 +1289,14 @@ fn test_queries_on_builtins()
 
     assert_prolog_success_with_limit!(&mut wam, "?- length(Xs, N).",
                                       [["N = 0", "Xs = []"],
-                                       ["N = 1", "Xs = [_]"],
-                                       ["N = 2", "Xs = [_, _]"],
-                                       ["N = 3", "Xs = [_, _, _]"],
-                                       ["N = 4", "Xs = [_, _, _, _]"],
-                                       ["N = 5", "Xs = [_, _, _, _, _]"]],
+                                       ["N = 1", "Xs = [_3]"],
+                                       ["N = 2", "Xs = [_3, _6]"],
+                                       ["N = 3", "Xs = [_3, _6, _9]"],
+                                       ["N = 4", "Xs = [_3, _6, _9, _12]"],
+                                       ["N = 5", "Xs = [_3, _6, _9, _12, _15]"]],
                                       6);
 
-    assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_, _, _]"]]);
+    assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_2, _5, _8]"]]);
     assert_prolog_success!(&mut wam, "?- length([a,b,c], N).", [["N = 3"]]);
     assert_prolog_success!(&mut wam, "?- length([], N).", [["N = 0"]]);
     assert_prolog_success!(&mut wam, "?- length(Xs, 0).", [["Xs = []"]]);
@@ -1413,13 +1413,13 @@ fn test_queries_on_builtins()
     assert_prolog_success!(&mut wam, "?- keysort([1-1, 1-1], Sorted).",
                            [["Sorted = [1 - 1, 1 - 1]"]]);
     assert_prolog_success!(&mut wam, "?- keysort([2-99, 1-a, 3-f(_), 1-z, 1-a, 2-44], Sorted).",
-                           [["Sorted = [1 - a, 1 - z, 1 - a, 2 - 99, 2 - 44, 3 - f(_)]"]]);
+                           [["Sorted = [1 - a, 1 - z, 1 - a, 2 - 99, 2 - 44, 3 - f(_7)]"]]);
     assert_prolog_success!(&mut wam, "?- keysort([X-1,1-1],[2-1,1-1]).",
                            [["X = 2"]]);
-
+    
     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, Pairs)", "Pairs = [a - a | Pairs]"]]);
+    assert_prolog_success!(&mut wam, "?- Pairs = [a-a|Pairs], catch(keysort(Pairs, _), error(E, _), true).",
+                           [["E = type_error(list, [a - a | _21])", "Pairs = [a - a | Pairs]"]]);
     
     assert_prolog_success!(&mut wam, "?- keysort([], L).",
                            [["L = []"]]);
@@ -1428,9 +1428,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, _)"]]);
+                           [["E = type_error(list, _12)"]]);
     assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [_|b]), error(E, _), true).",
-                           [["E = type_error(list, [_ | b])"]]);
+                           [["E = type_error(list, [_23 | 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).",
@@ -1443,7 +1443,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, _)"]]);
+                           [["E = type_error(list, _12)"]]);
     assert_prolog_success!(&mut wam, "?- catch(sort([a,b,c], not_a_list), error(E, _), true).",
                            [["E = type_error(list, not_a_list)"]]);