]> Repositorios git - scryer-prolog.git/commitdiff
add support for printing cyclic terms.
authorMark Thom <[email protected]>
Sat, 5 May 2018 07:53:05 +0000 (01:53 -0600)
committerMark Thom <[email protected]>
Sat, 5 May 2018 07:53:05 +0000 (01:53 -0600)
src/prolog/ast.rs
src/prolog/copier.rs
src/prolog/heap_iter.rs
src/prolog/heap_print.rs
src/prolog/machine/machine_errors.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/tests.rs

index ad20473f6681c2d7b1d54248610536b00e2f9815..af5e319bb1b43ddcabb50b6a73168848a3f43164 100644 (file)
@@ -1362,6 +1362,32 @@ impl Addr {
     }
 }
 
+impl Add<usize> for Addr {
+    type Output = Addr;
+
+    fn add(self, rhs: usize) -> Self::Output {
+        match self {
+            Addr::Lis(a) => Addr::Lis(a + rhs),
+            Addr::HeapCell(hc) => Addr::HeapCell(hc + rhs),
+            Addr::Str(s) => Addr::Str(s + rhs),
+            _ => self
+        }
+    }
+}
+
+impl Sub<usize> for Addr {
+    type Output = Addr;
+
+    fn sub(self, rhs: usize) -> Self::Output {
+        match self {
+            Addr::Lis(a) => Addr::Lis(a - rhs),
+            Addr::HeapCell(hc) => Addr::HeapCell(hc - rhs),
+            Addr::Str(s) => Addr::Str(s - rhs),
+            _ => self
+        }
+    }
+}
+
 impl From<Ref> for Addr {
     fn from(r: Ref) -> Self {
         match r {
@@ -1371,7 +1397,7 @@ impl From<Ref> for Addr {
     }
 }
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, Hash, Eq, PartialEq)]
 pub enum Ref {
     HeapCell(usize),
     StackCell(usize, usize)
index 5ca2d08ef5d6e4553529a96182f485cb15f8502a..e79d9e463fcebd41efdfd751845ce67cca14828f 100644 (file)
@@ -4,6 +4,19 @@ use prolog::ast::*;
 use std::collections::HashMap;
 use std::ops::IndexMut;
 
+// 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.
+pub struct CellRedirect(pub HashMap<Addr, Addr>);
+
+impl CellRedirect {
+    pub fn new() -> Self {
+        CellRedirect(HashMap::new())
+    }
+}
+
+pub type Trail = Vec<(Ref, HeapCellValue)>;
+
 pub trait CopierTarget
 {
     fn source(&self) -> usize;
@@ -13,21 +26,50 @@ 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>
+    {
+        let mut cell_redirect: HashMap<Addr, Addr> = HashMap::new();
+        
+        for (r, hcv) in 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::StackCell(fr, sc) => {
+                    cell_redirect.insert(addr, self.stack()[fr][sc].clone() - old_h);
+                    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));
+        }
+
+        CellRedirect(cell_redirect)
+    }
+    
     // duplicate_term(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, a: Addr) where Self: IndexMut<usize, Output=HeapCellValue>
+    fn duplicate_term(&mut self, addr: Addr) -> CellRedirect
+      where Self: IndexMut<usize, Output=HeapCellValue>
     {
-        let mut trail: Vec<(Ref, HeapCellValue)>= Vec::new();
-        let mut scan = self.source();
-        let old_h = self.threshold();
+        let mut trail = Trail::new();
+        let mut scan = self.source();        
+        let old_h = self.threshold();        
 
-        // Lists have a flattened representation as structures,
-        // removing the need for a NamedStr variant, so we use a
-        // redirection table for reconstructing lists.
+        // 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(a));
+        self.push(HeapCellValue::Addr(addr));
 
         while scan < self.threshold() {
             match self[scan].clone() {
@@ -110,11 +152,6 @@ pub trait CopierTarget
             }
         }
 
-        for (r, hcv) in trail {
-            match r {
-                Ref::HeapCell(hc) => self[hc] = hcv,
-                Ref::StackCell(fr, sc) => self.stack()[fr][sc] = hcv.as_addr(0)
-            }
-        }
+        self.compile_redirect(trail, list_redirect, old_h)
     }
 }
index 8532e55adeb37e1848333e54c3067c490767bc5e..58129249bbf04bf830e5771715fd2293ef2378ee 100644 (file)
@@ -179,45 +179,6 @@ where HCIter: Iterator<Item=HeapCellValue> + MutStackHCIterator
     }
 }
 
-pub struct HCDerefAcyclicIterator<HCIter> {
-    iter: HCIter,
-    seen: HashSet<Addr>
-}
-
-pub type HCDerefAcyclicPreOrderIterator<'a> = HCDerefAcyclicIterator<HCPreOrderIterator<'a>>;
-
-impl<'a> HCPreOrderIterator<'a> {
-    pub fn deref_acyclic_iter(self) -> HCDerefAcyclicPreOrderIterator<'a> {
-        HCDerefAcyclicIterator::new(self)
-    }
-}
-
-impl<HCIter: MutStackHCIterator> HCDerefAcyclicIterator<HCIter>
-{
-    pub fn new(iter: HCIter) -> Self {
-        HCDerefAcyclicIterator { iter, seen: HashSet::new() }
-    }
-}
-
-impl<HCIter> Iterator for HCDerefAcyclicIterator<HCIter>
-   where HCIter: Iterator<Item=HeapCellValue> + MutStackHCIterator
-{
-    type Item = HeapCellValue;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        loop {
-            match self.iter.next() {
-                Some(HeapCellValue::Addr(addr)) =>
-                    if !self.seen.contains(&addr) {
-                        self.seen.insert(addr.clone());
-                        return Some(HeapCellValue::Addr(addr));
-                    },
-                item => return item
-            }
-        }
-    }
-}
-
 pub struct HCZippedAcyclicIterator<HCIter> {
     i1: HCIter,
     i2: HCIter,
index 3923f72bd79ba275f790f70d80f62603cd923b22..765415da98d88938b7308f68fa63d871161b708d 100644 (file)
@@ -4,6 +4,7 @@ use prolog::machine::machine_state::MachineState;
 
 use std::borrow::Cow;
 use std::cell::Cell;
+use std::collections::HashSet;
 use std::rc::Rc;
 
 #[derive(Clone)]
@@ -58,7 +59,7 @@ pub struct PrinterOutputter {
     contents: String
 }
 
-impl HCValueOutputter for PrinterOutputter {    
+impl HCValueOutputter for PrinterOutputter {
     type Output = String;
 
     fn new() -> Self {
@@ -102,7 +103,7 @@ impl HCValueFormatter for DisplayFormatter {
             let mut new_name = String::from("'");
             new_name += ct.name().as_str();
             new_name += "'";
-            
+
             self.format_struct(arity, ct.name(), state_stack);
         } else {
             self.format_struct(arity, ct.name(), state_stack);
@@ -142,41 +143,90 @@ impl HCValueFormatter for TermFormatter {
 }
 
 pub struct HCPrinter<'a, Formatter, Outputter> {
-    formatter:   Formatter,
-    outputter:   Outputter,
-    iter:        HCDerefAcyclicPreOrderIterator<'a>,
-    state_stack: Vec<TokenOrRedirect>,
-    heap_locs:   Cow<'a, HeapVarDict>
+    formatter:    Formatter,
+    outputter:    Outputter,
+    machine_st:   &'a MachineState,
+    state_stack:  Vec<TokenOrRedirect>,
+    heap_locs:    Cow<'a, HeapVarDict>,
+    printed_vars: HashSet<Addr>
 }
 
 impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
     HCPrinter<'a, Formatter, Outputter>
 {
-    pub fn new(machine_st: &'a MachineState, addr: Addr, fmt: Formatter, output: Outputter) -> Self
+    pub fn new(machine_st: &'a MachineState, fmt: Formatter, output: Outputter) -> Self
     {
-        let iter = HCPreOrderIterator::new(&machine_st, addr);
-        
         HCPrinter { formatter: fmt,
                     outputter: output,
-                    iter: iter.deref_acyclic_iter(),
+                    machine_st,
                     state_stack: vec![],
-                    heap_locs: Cow::default() }
+                    heap_locs: Cow::default(),
+                    printed_vars: HashSet::new() }
     }
 
-    pub fn from_heap_locs(machine_st: &'a MachineState, addr: Addr, fmt: Formatter,
+    pub fn from_heap_locs(machine_st: &'a MachineState, fmt: Formatter,
                           output: Outputter, heap_locs: &'a HeapVarDict)
                           -> Self
     {
-        let iter = HCPreOrderIterator::new(&machine_st, addr);
+        let mut printer = Self::new(machine_st, fmt, output);
         
-        HCPrinter { formatter: fmt,
-                    outputter: output,
-                    iter: iter.deref_acyclic_iter(),
-                    state_stack: vec![],
-                    heap_locs: Cow::Borrowed(heap_locs) }
+        printer.heap_locs = Cow::Borrowed(heap_locs);
+        printer
+    }
+
+    pub fn from_heap_locs_as_seen(machine_st: &'a MachineState, fmt: Formatter,
+                                  output: Outputter, heap_locs: &'a HeapVarDict)
+                                  -> Self
+    {
+        let mut printer = Self::from_heap_locs(machine_st, fmt, output, heap_locs);
+
+        for (_, addr) in heap_locs.iter() {
+            let addr = machine_st.store(machine_st.deref(addr.clone()));
+            printer.printed_vars.insert(addr.clone());
+        }
+        
+        printer
     }
     
-    fn handle_heap_term(&mut self, heap_val: HeapCellValue) {
+    // 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| {
+            let addr = self.machine_st.store(self.machine_st.deref(addr));
+
+            for (var, var_addr) in self.heap_locs.iter() {
+                if &addr == &self.machine_st.store(self.machine_st.deref(var_addr.clone())) {
+                    if !self.printed_vars.contains(&addr) {
+                        self.printed_vars.insert(addr);
+                        return iter.next();
+                    } else {
+                        iter.stack().pop();
+                        self.outputter.append(var.as_str());
+
+                        return None;
+                    }
+                }
+            }
+
+            // 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
+            } else {
+                iter.next()
+            }
+        })
+    }
+
+    fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator)
+    {
+        let heap_val = match self.check_for_seen(iter) {
+            Some(heap_val) => heap_val,
+            _ => return
+        };
+        
         match heap_val {
             HeapCellValue::NamedStr(arity, name, fixity) => {
                 let ct = ClauseType::from(name, arity, fixity);
@@ -220,7 +270,11 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
         }
     }
 
-    pub fn print(mut self) -> Outputter {
+    //TODO: idea: hand a mutable ref to iter to handle_heap_term,
+    // and have it query the stack before getting the next thing.
+    pub fn print(mut self, addr: Addr) -> Outputter {
+        let mut iter = HCPreOrderIterator::new(&self.machine_st, addr);
+
         loop {
             if let Some(loc_data) = self.state_stack.pop() {
                 match loc_data {
@@ -228,10 +282,8 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
                         self.outputter.append(" "),
                     TokenOrRedirect::Atom(atom) =>
                         self.outputter.append(atom.as_str()),
-                    TokenOrRedirect::Redirect => {
-                        let heap_val = self.iter.next().unwrap();
-                        self.handle_heap_term(heap_val);
-                    },
+                    TokenOrRedirect::Redirect =>
+                        self.handle_heap_term(&mut iter),
                     TokenOrRedirect::Close =>
                         self.outputter.append(")"),
                     TokenOrRedirect::Open =>
@@ -251,8 +303,8 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
                     TokenOrRedirect::Comma =>
                         self.outputter.append(", ")
                 }
-            } else if let Some(heap_val) = self.iter.next() {
-                self.handle_heap_term(heap_val);
+            } else if !iter.stack().is_empty() {
+                self.handle_heap_term(&mut iter);
             } else {
                 break;
             }
index bff1c9d50a87159c81d348a66898bb5234261576..e16111d8b470bf69456c27893c29d7acf6a4a46f 100644 (file)
@@ -135,8 +135,8 @@ impl MachineState {
     pub(super) fn throw_exception(&mut self, err: MachineError) {
         let h = self.heap.h;
 
-        self.ball.0 = 0;
-        self.ball.1.truncate(0);
+        self.ball.boundary = 0;
+        self.ball.stub.truncate(0);
 
         self.heap.append(err);
 
index 84b54a9be514616a416f59b14d7ecf7a077141e0..51804f55a59c5edc2ff93c979bebe71e187db643 100644 (file)
@@ -1,6 +1,7 @@
 use prolog::and_stack::*;
 use prolog::ast::*;
 use prolog::copier::*;
+use prolog::machine::machine_errors::MachineStub;
 use prolog::num::{BigInt, BigUint, Zero, One};
 use prolog::or_stack::*;
 use prolog::heap_print::*;
@@ -14,6 +15,22 @@ use std::mem::swap;
 use std::ops::{Index, IndexMut};
 use std::rc::Rc;
 
+pub(super) struct Ball {
+    pub(super) boundary: usize, // ball.0
+    pub(super) stub: MachineStub, // ball.1    
+}
+
+impl Ball {
+    pub(super) fn new() -> Self {
+        Ball { boundary: 0, stub: MachineStub::new() }
+    }
+    
+    pub(super) fn reset(&mut self) {
+        self.boundary = 0;
+        self.stub.clear();
+    }
+}
+
 pub(crate) struct CodeDirs<'a> {
     code_dir: &'a CodeDir,
     modules: &'a HashMap<ClauseName, Module>
@@ -109,7 +126,7 @@ impl<'a> Index<usize> for DuplicateBallTerm<'a> {
             &self.state.heap[index]
         } else {
             let index = index - self.heap_boundary;
-            &self.state.ball.1[index]
+            &self.state.ball.stub[index]
         }
     }
 }
@@ -120,7 +137,7 @@ impl<'a> IndexMut<usize> for DuplicateBallTerm<'a> {
             &mut self.state.heap[index]
         } else {
             let index = index - self.heap_boundary;
-            &mut self.state.ball.1[index]
+            &mut self.state.ball.stub[index]
         }
     }
 }
@@ -132,11 +149,11 @@ impl<'a> CopierTarget for DuplicateBallTerm<'a> {
     }
 
     fn threshold(&self) -> usize {
-        self.heap_boundary + self.state.ball.1.len()
+        self.heap_boundary + self.state.ball.stub.len()
     }
 
     fn push(&mut self, hcv: HeapCellValue) {
-        self.state.ball.1.push(hcv);
+        self.state.ball.stub.push(hcv);
     }
 
     fn store(&self, a: Addr) -> Addr {
@@ -203,7 +220,8 @@ pub struct MachineState {
     pub(super) tr: usize,
     pub(super) hb: usize,
     pub(super) block: usize, // an offset into the OR stack.
-    pub(super) ball: (usize, Vec<HeapCellValue>), // heap boundary, and a term copy
+    pub(super) ball: Ball,
+    pub(super) redirect: CellRedirect,
     pub(super) interms: Vec<Number>, // intermediate numbers.
 }
 
index d0cf402e05751bbf2ee94bc66e8897bbd56ab5d9..6592fc207e98dc40540484f676149a8a42a14035 100644 (file)
@@ -49,7 +49,8 @@ impl MachineState {
             tr: 0,
             hb: 0,
             block: 0,
-            ball: (0, Vec::new()),
+            ball: Ball::new(),
+            redirect: CellRedirect::new(),
             interms: vec![Number::default(); 256]
         }
     }
@@ -97,7 +98,7 @@ impl MachineState {
     fn print_var_eq<Fmt, Outputter>(&self, var: Rc<Var>, addr: Addr, var_dir: &HeapVarDict,
                                     fmt: Fmt, mut output: Outputter)
                                     -> Outputter
-        where Fmt: HCValueFormatter, Outputter: HCValueOutputter
+      where Fmt: HCValueFormatter, Outputter: HCValueOutputter
     {
         let orig_len = output.len();
         
@@ -106,8 +107,8 @@ impl MachineState {
         output.append(var.as_str());
         output.append(" = ");
         
-        let printer    = HCPrinter::from_heap_locs(&self, addr, fmt, output, var_dir);
-        let mut output = printer.print();
+        let printer    = HCPrinter::from_heap_locs(&self, fmt, output, var_dir);
+        let mut output = printer.print(addr);
 
         if output.ends_with(var.as_str()) {
             output.truncate(orig_len);
@@ -115,13 +116,23 @@ impl MachineState {
 
         output
     }
+
+    pub(super)
+    fn print_exception<Fmt, Outputter>(&self, addr: Addr, var_dir: &HeapVarDict,
+                                       fmt: Fmt, output: Outputter)
+                                       -> Outputter
+      where Fmt: HCValueFormatter, Outputter: HCValueOutputter
+    {
+        let printer = HCPrinter::from_heap_locs_as_seen(&self, fmt, output, var_dir);
+        printer.print(addr)
+    }
     
     pub(super)
     fn print_term<Fmt, Outputter>(&self, addr: Addr, fmt: Fmt, output: Outputter) -> Outputter
       where Fmt: HCValueFormatter, Outputter: HCValueOutputter
     {
-        let printer = HCPrinter::new(&self, addr, fmt, output);
-        printer.print()
+        let printer = HCPrinter::new(&self, fmt, output);
+        printer.print(addr)
     }
 
     pub(super) fn unify(&mut self, a1: Addr, a2: Addr) {
@@ -1089,26 +1100,25 @@ impl MachineState {
         Some((name, arity + narity - 1))
     }
 
-    pub(super) fn copy_and_align_ball_to_heap(&mut self) {
-        let diff = if self.ball.0 > self.heap.h {
-            self.ball.0 - self.heap.h
+    fn heap_ball_boundary_diff(&self) -> usize {
+        if self.ball.boundary > self.heap.h {
+            self.ball.boundary - self.heap.h
         } else {
-            self.heap.h - self.ball.0
-        };
-
-        for heap_value in self.ball.1.iter().cloned() {
+            self.heap.h - self.ball.boundary
+        }
+    }
+    
+    pub(super) fn copy_and_align_ball_to_heap(&mut self) -> usize {
+        let diff = self.heap_ball_boundary_diff();
+        
+        for heap_value in self.ball.stub.iter().cloned() {
             self.heap.push(match heap_value {
-                HeapCellValue::Addr(Addr::Con(c)) =>
-                    HeapCellValue::Addr(Addr::Con(c)),
-                HeapCellValue::Addr(Addr::Lis(a)) =>
-                    HeapCellValue::Addr(Addr::Lis(a - diff)),
-                HeapCellValue::Addr(Addr::HeapCell(hc)) =>
-                    HeapCellValue::Addr(Addr::HeapCell(hc - diff)),
-                HeapCellValue::Addr(Addr::Str(s)) =>
-                    HeapCellValue::Addr(Addr::Str(s - diff)),
+                HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
                 _ => heap_value
             });
         }
+
+        diff
     }
 
     pub(super) fn is_cyclic_term(&self, addr: Addr) -> bool {
@@ -1179,6 +1189,25 @@ 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();
@@ -1433,8 +1462,7 @@ impl MachineState {
                 try_or_fail!(self, call_policy.trust_me(self));
             },
             &BuiltInInstruction::EraseBall => {
-                self.ball.0 = 0;
-                self.ball.1.truncate(0);
+                self.ball.reset();                
                 self.p += 1;
             },
             &BuiltInInstruction::GetArg(lco) =>
@@ -1460,7 +1488,7 @@ impl MachineState {
                 let addr = self.store(self.deref(self[temp_v!(1)].clone()));
                 let h = self.heap.h;
 
-                if self.ball.1.len() > 0 {
+                if self.ball.stub.len() > 0 {
                     self.copy_and_align_ball_to_heap();
                 } else {
                     self.fail = true;
@@ -1608,13 +1636,14 @@ impl MachineState {
             },
             &BuiltInInstruction::SetBall => {
                 let addr = self[temp_v!(1)].clone();
-                self.ball.0 = self.heap.h;
+                self.ball.boundary = self.heap.h;
 
-                {
+                let cell_redirect = {
                     let mut duplicator = DuplicateBallTerm::new(self);
-                    duplicator.duplicate_term(addr);
-                }
+                    duplicator.duplicate_term(addr)                                        
+                };
 
+                self.redirect.0.extend(cell_redirect.0.into_iter());
                 self.p += 1;
             },
             &BuiltInInstruction::SetCutPoint(r) =>
@@ -2323,6 +2352,8 @@ impl MachineState {
         self.or_stack.clear();
         self.registers = vec![Addr::HeapCell(0); 64];
         self.block = 0;
-        self.ball = (0, Vec::new());
+        
+        self.ball.reset();
+        self.redirect.0.clear();
     }
 }
index b8294658a4299e0d61b137d13f158506dd8753b5..9cf732f478f7da2ccb5423ece3a9001f5fac0b11 100644 (file)
@@ -57,11 +57,11 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> {
     fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
         if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) {
             println!("warning: overwriting {}/{}", &name, arity);
-            set_code_index!(code_idx, idx.0, idx.1); 
+            set_code_index!(code_idx, idx.0, idx.1);
 
             return;
         }
-        
+
         self.code_dir.insert((name, arity), CodeIndex::from(idx));
     }
 }
@@ -99,7 +99,7 @@ impl Machine {
                     if &code_idx.borrow().1 != &module_name {
                         continue;
                     }
-                    
+
                     self.code_dir.remove(&(name.clone(), arity));
 
                     // remove or respecify ops.
@@ -194,7 +194,7 @@ impl Machine {
             Some(&CodeIndex (ref idx)) if idx.borrow().1 != clause_name!("user") =>
                     return EvalSession::from(SessionError::ImpermissibleEntry(format!("{}/{}",
                                                                                    name,
-                                                                                   arity))),                
+                                                                                   arity))),
             _ => {}
         };
 
@@ -370,18 +370,20 @@ impl Machine {
         }
     }
 
-    fn fail(&mut self) -> EvalSession
+    fn fail(&mut self, heap_locs: &HeapVarDict) -> EvalSession
     {
-        if self.ms.ball.1.len() > 0 {
+        if self.ms.ball.stub.len() > 0 {
             let h = self.ms.heap.h;
             self.ms.copy_and_align_ball_to_heap();
 
-            let msg = self.ms.print_term(Addr::HeapCell(h),
-                                         TermFormatter {},
-                                         PrinterOutputter::new())
-                          .result();
+            let heap_locs = self.ms.reconstruct_dict(heap_locs, h);
+            let error_str = self.ms.print_exception(Addr::HeapCell(h),
+                                                    &heap_locs,
+                                                    TermFormatter {},
+                                                    PrinterOutputter::new())
+                                .result();
 
-            EvalSession::from(SessionError::QueryFailureWithException(msg))
+            EvalSession::from(SessionError::QueryFailureWithException(error_str))
         } else {
             EvalSession::from(SessionError::QueryFailure)
         }
@@ -395,7 +397,7 @@ impl Machine {
         self.run_query(&alloc_locs, &mut heap_locs);
 
         if self.failed() {
-            self.fail()
+            self.fail(&heap_locs)
         } else {
             EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
         }
@@ -414,7 +416,7 @@ impl Machine {
             self.run_query(alloc_l, heap_l);
 
             if self.failed() {
-                self.fail()
+                self.fail(&heap_l)
             } else {
                 EvalSession::SubsequentQuerySuccess
             }
index 5b94ddb410418ac72a4bbce2fee100ba71298bf8..d33a10397b8fd21220f8399e39b8b932453084ee 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), _7)"]]);
+                           [["X = h", "Y = g(b)", "Z = f(f(a), g(b), _)"]]);
     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 = [_3]"]]);
+    assert_prolog_success!(&mut wam, "?- p([Z | W]).", [["Z = _0", "W = [_]"]]);
     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(_9))]", "X = a", "Z = c"]]);
+    assert_prolog_success!(&mut wam, "?- p(X, Y), q(Y, Z).", [["Y = [f(g(_))]", "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(_9))]"],
+                           [["X = a",  "Z = c", "Y = [f(g(_))]"],
                             ["X = _0", "Z = c", "Y = c"]]);
     assert_prolog_success!(&mut wam, "?- p(X, Y), !, q(Y, Z).",
-                           [["Z = c", "Y = [f(g(_9))]", "X = a"]]);
+                           [["Z = c", "Y = [f(g(_))]", "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(_2, _3, _4)"]]);
-    assert_prolog_success!(&mut wam, "?- functor(Func, f, 4).", [["Func = f(_2, _3, _4, _5)"]]);
+    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, "?- 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 = [_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]"]],
+                                       ["N = 1", "Xs = [_]"],
+                                       ["N = 2", "Xs = [_, _]"],
+                                       ["N = 3", "Xs = [_, _, _]"],
+                                       ["N = 4", "Xs = [_, _, _, _]"],
+                                       ["N = 5", "Xs = [_, _, _, _, _]"]],
                                       6);
 
-    assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_2, _5, _8]"]]);
+    assert_prolog_success!(&mut wam, "?- length(Xs, 3).", [["Xs = [_, _, _]"]]);
     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,11 +1413,14 @@ 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(_7)]"]]);
+                           [["Sorted = [1 - a, 1 - z, 1 - a, 2 - 99, 2 - 44, 3 - f(_)]"]]);
     assert_prolog_success!(&mut wam, "?- keysort([X-1,1-1],[2-1,1-1]).",
                            [["X = 2"]]);
-    //TODO: enable the printer to print cyclic terms. Then run this test.
-    //assert_prolog_failure!(&mut wam, "?- Pairs = [a-a|Pairs], keysort(Pairs, _).");
+
+    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, "?- keysort([], L).",
                            [["L = []"]]);
     assert_prolog_success!(&mut wam, "?- catch(keysort([a|_], _), error(E, _), true).",
@@ -1425,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, _12)"]]);
+                           [["E = type_error(list, _)"]]);
     assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [_|b]), error(E, _), true).",
-                           [["E = type_error(list, [_23 | b])"]]);
+                           [["E = type_error(list, [_ | 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).",
@@ -1440,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, _12)"]]);
+                           [["E = type_error(list, _)"]]);
     assert_prolog_success!(&mut wam, "?- catch(sort([a,b,c], not_a_list), error(E, _), true).",
                            [["E = type_error(list, not_a_list)"]]);