From: Mark Thom Date: Sat, 5 May 2018 07:53:05 +0000 (-0600) Subject: add support for printing cyclic terms. X-Git-Tag: v0.8.110~470 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=d6495c8195a64051bfbf056ad1bea473a74037e9;p=scryer-prolog.git add support for printing cyclic terms. --- diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index ad20473f..af5e319b 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -1362,6 +1362,32 @@ impl Addr { } } +impl Add 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 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 for Addr { fn from(r: Ref) -> Self { match r { @@ -1371,7 +1397,7 @@ impl From for Addr { } } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Hash, Eq, PartialEq)] pub enum Ref { HeapCell(usize), StackCell(usize, usize) diff --git a/src/prolog/copier.rs b/src/prolog/copier.rs index 5ca2d08e..e79d9e46 100644 --- a/src/prolog/copier.rs +++ b/src/prolog/copier.rs @@ -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); + +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, old_h: usize) + -> CellRedirect + where Self: IndexMut + { + let mut cell_redirect: HashMap = 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 + fn duplicate_term(&mut self, addr: Addr) -> CellRedirect + where Self: IndexMut { - 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) } } diff --git a/src/prolog/heap_iter.rs b/src/prolog/heap_iter.rs index 8532e55a..58129249 100644 --- a/src/prolog/heap_iter.rs +++ b/src/prolog/heap_iter.rs @@ -179,45 +179,6 @@ where HCIter: Iterator + MutStackHCIterator } } -pub struct HCDerefAcyclicIterator { - iter: HCIter, - seen: HashSet -} - -pub type HCDerefAcyclicPreOrderIterator<'a> = HCDerefAcyclicIterator>; - -impl<'a> HCPreOrderIterator<'a> { - pub fn deref_acyclic_iter(self) -> HCDerefAcyclicPreOrderIterator<'a> { - HCDerefAcyclicIterator::new(self) - } -} - -impl HCDerefAcyclicIterator -{ - pub fn new(iter: HCIter) -> Self { - HCDerefAcyclicIterator { iter, seen: HashSet::new() } - } -} - -impl Iterator for HCDerefAcyclicIterator - where HCIter: Iterator + MutStackHCIterator -{ - type Item = HeapCellValue; - - fn next(&mut self) -> Option { - 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 { i1: HCIter, i2: HCIter, diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 3923f72b..765415da 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -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, - heap_locs: Cow<'a, HeapVarDict> + formatter: Formatter, + outputter: Outputter, + machine_st: &'a MachineState, + state_stack: Vec, + heap_locs: Cow<'a, HeapVarDict>, + printed_vars: HashSet } 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 { + 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; } diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index bff1c9d5..e16111d8 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -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); diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 84b54a9b..51804f55 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -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 @@ -109,7 +126,7 @@ impl<'a> Index 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 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), // heap boundary, and a term copy + pub(super) ball: Ball, + pub(super) redirect: CellRedirect, pub(super) interms: Vec, // intermediate numbers. } diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index d0cf402e..6592fc20 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -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(&self, var: Rc, 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(&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(&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(); } } diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index b8294658..9cf732f4 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -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 } diff --git a/src/tests.rs b/src/tests.rs index 5b94ddb4..d33a1039 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -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)"]]);