From 378307058574aa9800020cd6ff95d6ca1c6d6d9c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 25 Apr 2019 22:27:23 -0600 Subject: [PATCH] use ellipses to indicate infinite terms in printer --- Cargo.toml | 2 +- src/prolog/heap_print.rs | 48 ++++++++++++++++++++++------------------ src/tests.rs | 4 ++-- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a1749aa..a7033886 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.65" +version = "0.8.66" authors = ["Mark Thom "] repository = "https://github.com/mthom/scryer-prolog" description = "A modern Prolog implementation written mostly in Rust." diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 5a2e3734..8757b3b7 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -293,6 +293,7 @@ pub struct HCPrinter<'a, Outputter> { heap_locs: ReverseHeapVarDict, printed_vars: HashSet, last_item_idx: usize, + cyclic_terms: HashMap, pub(crate) numbervars_offset: BigInt, pub(crate) numbervars: bool, pub(crate) quoted: bool, @@ -407,7 +408,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> numbervars: false, numbervars_offset: BigInt::zero(), quoted: false, - ignore_ops: false } + ignore_ops: false, + cyclic_terms: HashMap::new() } } pub fn from_heap_locs(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter, @@ -601,24 +603,26 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> return None; }, None => if self.machine_st.is_cyclic_term(addr.clone()) { - if self.printed_vars.contains(&addr) { - iter.stack().pop(); - - if let Some(offset_str) = self.offset_as_string(addr) { - push_space_if_amb!(self, &offset_str, { - self.append_str(&offset_str); - }); + match self.cyclic_terms.get(&addr).cloned() { + Some(reps) => + if reps > 0 { + self.cyclic_terms.insert(addr, reps - 1); + iter.next() + } else { + if !self.at_cdr(", ...") { + push_space_if_amb!(self, "...", { + self.append_str("..."); + }); + } + + iter.stack().pop(); + self.cyclic_terms.remove(&addr); + None + }, + None => { + self.cyclic_terms.insert(addr, 2); + iter.next() } - - None - } else { - if let Some(s) = self.offset_as_string(addr.clone()) { - let var = Rc::new(s); - self.heap_locs.insert(addr.clone(), var); - } - - self.printed_vars.insert(addr); - iter.next() } } else { iter.next() @@ -720,16 +724,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> if self.outputter.ends_with(&format!(" {}", op.as_str())) { result.push(' '); } - + result.push('('); } - + result += &self.print_op_addendum(atom.as_str()); - + if op.is_some() { result.push(')'); } - + push_space_if_amb!(self, &result, { self.append_str(&result); }); diff --git a/src/tests.rs b/src/tests.rs index 13f73315..46e09ff9 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1526,7 +1526,7 @@ fn test_queries_on_builtins() assert_prolog_success!(&mut wam, "X = g(X, Y), Y = f(X), copy_term(Y, f(Z)).", [["Y = f(g(X, Y))", "X = g(X, f(X))", "Z = g(Z, f(Z))"]]); assert_prolog_success!(&mut wam, "X = g(X, Y), Y = f(X), copy_term(Y, V).", - [["Y = f(g(X, Y))", "X = g(X, f(X))", "V = f(g(_9, V))"]]); + [["V = f(g(g(g(..., V), V), V))", "X = g(X, f(X))", "Y = f(g(X, Y))"]]); assert_prolog_success!(&mut wam, "f(Y,Y,[X,a,[],Y]) = Term, copy_term(Term, NewTerm).", [["NewTerm = f(_16, _16, [_19, a, [], _16])", "Term = f(_0, Y, [_6, a, [], Y])", @@ -1638,7 +1638,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 | _25])", "Pairs = [a-a | Pairs]"]]); + [["E = type_error(list, [a-a, a-a, a-a, ...])", "Pairs = [a-a | Pairs]"]]); assert_prolog_success!(&mut wam, "keysort([], L).", [["L = []"]]); -- 2.54.0