From: Mark Thom Date: Wed, 10 Mar 2021 23:11:43 +0000 (-0700) Subject: fix is_cyclic_term (#864) X-Git-Tag: v0.9.0~131 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=d4d47182b4b75dcca9dec27c76dae121dcfcce13;p=scryer-prolog.git fix is_cyclic_term (#864) --- diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index ca80d23e..71852bfb 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1750,28 +1750,57 @@ impl MachineState { let mut seen = IndexSet::new(); let mut fail = false; let mut iter = self.pre_order_iter(addr); + let mut parent_stack = vec![]; - let is_composite = |addr: &Addr| match *addr { + let is_composite = |addr: Addr| match addr { Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => true, _ => false, }; - loop { - if let Some(addr) = iter.stack().last() { + 'outer: loop { + if let Some(addr) = iter.stack().last().cloned() { + let addr = self.store(self.deref(addr)); + if is_composite(addr) { - if !seen.contains(addr) { - seen.insert(*addr); + if !seen.contains(&addr) { + seen.insert(addr); } else { - fail = true; - break; + // when we again encounter a seen composite + // term, check that it precedes itself as a + // parent in the post-order traversal. in the + // future, when value cells have mark bits, + // use them to designate parenthood instead of + // this linear search. + + for (_, prec_addr) in parent_stack.iter().rev().cloned() { + if prec_addr == addr { + fail = true; + break 'outer; + } + } } - } else { - iter.stack().pop(); + + let arity = match addr { + Addr::Str(h) => match &self.heap[h] { + &HeapCellValue::NamedStr(arity, ..) => arity, + _ => unreachable!(), + }, + _ => 2, + }; + + parent_stack.push((arity, addr)); } } if iter.next().is_none() { break; + } else { + while let Some((rem_children, addr)) = parent_stack.pop() { + if rem_children > 0 { + parent_stack.push((rem_children - 1, addr)); + break; + } + } } }