further improvements to cyclic partial list printing (#2635)

This commit is contained in:
Mark Thom
2025-08-23 11:51:56 -07:00
parent b14bda310f
commit ad29f0f180
13 changed files with 84 additions and 58 deletions

View File

@@ -16,7 +16,7 @@ use to_syn_value_derive::ToDeriveInput;
* of Instruction. They mimick most of the structure of the previous * of Instruction. They mimick most of the structure of the previous
* Line instruction type. The strum crate is used to provide reflection * Line instruction type. The strum crate is used to provide reflection
* on each of the node types to the tree walker. * on each of the node types to the tree walker.
*/ */
use std::any::*; use std::any::*;
use std::rc::Rc; use std::rc::Rc;

View File

@@ -30,7 +30,7 @@ macro_rules! count {
* in round parentheses for rustc to parse them. See the tests module * in round parentheses for rustc to parse them. See the tests module
* below for examples, especially those involving atom! * below for examples, especially those involving atom!
* subexpressions. * subexpressions.
*/ */
macro_rules! functor { macro_rules! functor {
($name:expr) => ({ ($name:expr) => ({

View File

@@ -28,7 +28,7 @@ pub fn eager_stackful_preorder_iter(
* cyclic terms for the sake of skipping them at the second visit but * cyclic terms for the sake of skipping them at the second visit but
* leaves them marked until it is dropped. This makes for, e.g., more * leaves them marked until it is dropped. This makes for, e.g., more
* efficient ground/1 and term_variables/2 definitions. * efficient ground/1 and term_variables/2 definitions.
*/ */
pub struct EagerStackfulPreOrderHeapIter<'a> { pub struct EagerStackfulPreOrderHeapIter<'a> {
start_value: HeapCellValue, start_value: HeapCellValue,
@@ -175,7 +175,7 @@ impl IterStackLoc {
} }
#[inline] #[inline]
fn mark_loc(h: usize, heap_or_stack: HeapOrStackTag) -> Self { pub fn marked_loc(h: usize, heap_or_stack: HeapOrStackTag) -> Self {
IterStackLoc::new() IterStackLoc::new()
.with_tag(IterStackLocTag::Marked) .with_tag(IterStackLocTag::Marked)
.with_heap_or_stack(heap_or_stack) .with_heap_or_stack(heap_or_stack)
@@ -183,7 +183,7 @@ impl IterStackLoc {
} }
#[inline] #[inline]
fn pending_mark_loc(h: usize, heap_or_stack: HeapOrStackTag) -> Self { fn pending_marked_loc(h: usize, heap_or_stack: HeapOrStackTag) -> Self {
IterStackLoc::new() IterStackLoc::new()
.with_tag(IterStackLocTag::PendingMark) .with_tag(IterStackLocTag::PendingMark)
.with_heap_or_stack(heap_or_stack) .with_heap_or_stack(heap_or_stack)
@@ -386,7 +386,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
while let Some(h) = self.stack.pop() { while let Some(h) = self.stack.pop() {
if h.is_pending_mark() { if h.is_pending_mark() {
self.push_if_unmarked(h); self.push_if_unmarked(h);
self.stack.push(IterStackLoc::mark_loc( self.stack.push(IterStackLoc::marked_loc(
h.value() as usize, h.value() as usize,
h.heap_or_stack(), h.heap_or_stack(),
)); ));
@@ -414,7 +414,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap); let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap);
self.push_if_unmarked(loc); self.push_if_unmarked(loc);
self.stack.push(IterStackLoc::mark_loc(vh, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::marked_loc(vh, HeapOrStackTag::Heap));
} }
(HeapCellValueTag::Lis, vh) => { (HeapCellValueTag::Lis, vh) => {
let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap); let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap);
@@ -428,8 +428,8 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
self.push_if_unmarked(loc); self.push_if_unmarked(loc);
self.stack.push(IterStackLoc::pending_mark_loc(vh + 1, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::pending_marked_loc(vh + 1, HeapOrStackTag::Heap));
self.stack.push(IterStackLoc::mark_loc(vh, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::marked_loc(vh, HeapOrStackTag::Heap));
return Some(self.read_cell(h)); return Some(self.read_cell(h));
} }
@@ -438,14 +438,14 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
self.forward_if_referent_marked(loc); self.forward_if_referent_marked(loc);
self.push_if_unmarked(loc); self.push_if_unmarked(loc);
self.stack.push(IterStackLoc::mark_loc(vh, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::marked_loc(vh, HeapOrStackTag::Heap));
} }
(HeapCellValueTag::StackVar, vs) => { (HeapCellValueTag::StackVar, vs) => {
let loc = IterStackLoc::iterable_loc(vs, HeapOrStackTag::Stack); let loc = IterStackLoc::iterable_loc(vs, HeapOrStackTag::Stack);
self.forward_if_referent_marked(loc); self.forward_if_referent_marked(loc);
self.push_if_unmarked(loc); self.push_if_unmarked(loc);
self.stack.push(IterStackLoc::mark_loc(vs, HeapOrStackTag::Stack)); self.stack.push(IterStackLoc::marked_loc(vs, HeapOrStackTag::Stack));
} }
(HeapCellValueTag::PStrLoc, vh) => { (HeapCellValueTag::PStrLoc, vh) => {
let cell = *cell; let cell = *cell;
@@ -461,7 +461,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
} }
self.stack.push(IterStackLoc::iterable_loc(tail_idx - 1, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::iterable_loc(tail_idx - 1, HeapOrStackTag::Heap));
self.stack.push(IterStackLoc::pending_mark_loc(tail_idx, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::pending_marked_loc(tail_idx, HeapOrStackTag::Heap));
return Some(cell); return Some(cell);
} }
@@ -469,14 +469,14 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
let l = h.value() as usize; let l = h.value() as usize;
for l in (l + 2 .. l + arity + 1).rev() { for l in (l + 2 .. l + arity + 1).rev() {
self.stack.push(IterStackLoc::pending_mark_loc(l, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::pending_marked_loc(l, HeapOrStackTag::Heap));
} }
if arity > 0 { if arity > 0 {
let first_arg_loc = IterStackLoc::iterable_loc(l+1, HeapOrStackTag::Heap); let first_arg_loc = IterStackLoc::iterable_loc(l+1, HeapOrStackTag::Heap);
self.push_if_unmarked(first_arg_loc); self.push_if_unmarked(first_arg_loc);
self.stack.push(IterStackLoc::mark_loc(l+1, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::marked_loc(l+1, HeapOrStackTag::Heap));
self.forward_if_referent_marked(first_arg_loc); self.forward_if_referent_marked(first_arg_loc);
} }

View File

@@ -849,10 +849,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if let Some(mut orig_cell) = self.iter.next() { if let Some(mut orig_cell) = self.iter.next() {
loop { loop {
let is_cyclic = orig_cell.get_forwarding_bit(); let is_cyclic = orig_cell.get_forwarding_bit();
let derefed_cell = heap_bound_deref(self.iter.heap, orig_cell);
let cell = let cell = unmark_cell_bits!(heap_bound_store(self.iter.heap, derefed_cell));
heap_bound_store(self.iter.heap, heap_bound_deref(self.iter.heap, orig_cell));
let cell = unmark_cell_bits!(cell);
match self.var_names.get(&cell).cloned() { match self.var_names.get(&cell).cloned() {
Some(var) if cell.is_var() => { Some(var) if cell.is_var() => {
@@ -860,8 +858,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
// a name via heap_locs, append the name to // a name via heap_locs, append the name to
// the current output, and return None. None // the current output, and return None. None
// short-circuits handle_heap_term. // short-circuits handle_heap_term.
// self.iter.pop_stack();
let var_str = var.borrow().to_string(); let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, { push_space_if_amb!(self, &var_str, {
@@ -872,8 +868,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
var_opt => { var_opt => {
if is_cyclic && cell.is_compound(self.iter.heap) { if is_cyclic && cell.is_compound(self.iter.heap) {
// self-referential variables are marked "cyclic". // self-referential variables are marked "cyclic"
match var_opt { match var_opt {
Some(var) => { Some(var) => {
// If the term is bound to a named variable, // If the term is bound to a named variable,
@@ -889,34 +884,61 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
// otherwise, contract it to an ellipsis. // otherwise, contract it to an ellipsis.
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
} else { } else {
debug_assert!(cell.is_ref()); let h = read_heap_cell!(derefed_cell,
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
let h = match cell.get_tag() { self.iter.heap[h].set_forwarding_bit(false);
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => { h
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
self.iter.focus().value() as usize self.iter.focus().value() as usize
} }
_ => cell.get_value() as usize, _ => {
}; cell.get_value() as usize
match cell.get_tag() {
HeapCellValueTag::Lis => {
self.state_stack
.push(TokenOrRedirect::Atom(atom!("...")));
return None;
} }
HeapCellValueTag::PStrLoc => { );
*max_depth -= 1;
let h = IterStackLoc::marked_loc(h, HeapOrStackTag::Heap);
self.iter.push_stack(h);
if let Some(next_cell) = self.iter.next() {
if next_cell.get_forwarding_bit() {
debug_assert_eq!(
cell.get_value(),
next_cell.get_value()
);
/*
* next_cell is forwarded here only if, for lists,
* X = [X|T]. in this case, self.iter has *not*
* pushed X's arguments to its stack, but T is
* at its top from the previous expansion of X.
*
* in this case, expand the iter stack rep to X =
* [[X|T]|T] and continue, terminating recursion
* when max_depth == 0.
*
* similar logic here for PStrLoc, which can only
* recurse from its tail.
*/
read_heap_cell!(next_cell,
(HeapCellValueTag::Lis, l) => {
let tail_h = IterStackLoc::marked_loc(l+1, HeapOrStackTag::Heap);
self.iter.push_stack(tail_h);
self.iter.push_stack(h);
return Some(unmark_cell_bits!(next_cell));
}
(HeapCellValueTag::PStrLoc) => {
self.iter.push_stack(h);
return Some(unmark_cell_bits!(next_cell));
}
_ => {}
);
} }
_ => {}
}
self.iter.push_stack(IterStackLoc::iterable_loc( orig_cell = next_cell;
h,
HeapOrStackTag::Heap,
));
if let Some(cell) = self.iter.next() {
orig_cell = cell;
continue; continue;
} }
@@ -933,7 +955,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
} else { } else {
while self.iter.pop_stack().is_none() {} while self.iter.pop_stack().is_some() {}
None None
} }
} }
@@ -1414,7 +1436,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
.push(TokenOrRedirect::FunctorRedirect(max_depth)); .push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
self.state_stack self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); .push(TokenOrRedirect::FunctorRedirect(max_depth));
self.open_list(switch); self.open_list(switch);
} }
@@ -1603,15 +1625,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Char(c)); self.state_stack.push(TokenOrRedirect::Char(c));
} else { } else {
self.iter.pop_stack();
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} }
} else if self.max_depth_exhausted(max_depth) { } else if self.max_depth_exhausted(max_depth) {
self.iter.pop_stack();
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} else { } else {
self.state_stack self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); .push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} }
} }

View File

@@ -41,7 +41,7 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> b
/* This function walks the code of a single predicate, supposed to /* This function walks the code of a single predicate, supposed to
* begin in code at the offset p. Each instruction is passed to the * begin in code at the offset p. Each instruction is passed to the
* walker function. * walker function.
*/ */
pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) { pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) {
let mut stack = vec![p]; let mut stack = vec![p];
let mut visited_indices = IndexSet::with_hasher(FxBuildHasher::default()); let mut visited_indices = IndexSet::with_hasher(FxBuildHasher::default());

View File

@@ -19,7 +19,7 @@ use crate::types::*;
* Commonalities with the GC marking algorithm: * Commonalities with the GC marking algorithm:
* - The contents of forwarded cells are modified only when they are unforwarded * - The contents of forwarded cells are modified only when they are unforwarded
* - Marked (but unforwarded!) cells immediately shift to the backward phase * - Marked (but unforwarded!) cells immediately shift to the backward phase
*/ */
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> { pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {

View File

@@ -18,7 +18,7 @@ use std::collections::VecDeque;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)] #[derive(Debug, Clone)]//, PartialOrd, PartialEq, Eq, Hash)]
pub struct BranchNumber { pub struct BranchNumber {
branch_num: Rational, branch_num: Rational,
delta: Rational, delta: Rational,

View File

@@ -46,7 +46,7 @@ use std::rc::Rc;
* loader fail later, all changes must be rolled back, restoring the * loader fail later, all changes must be rolled back, restoring the
* WAM to its prior state. Retraction records describe individual changes * WAM to its prior state. Retraction records describe individual changes
* made by the loader, and they may be used later. * made by the loader, and they may be used later.
*/ */
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum RetractionRecord { pub(crate) enum RetractionRecord {
@@ -108,7 +108,7 @@ pub(crate) enum RetractionRecord {
* "extent" of a code vector is its length prior to an attempted * "extent" of a code vector is its length prior to an attempted
* module load. The only code vector of the WAM's IndexStore, "code", * module load. The only code vector of the WAM's IndexStore, "code",
* is shared by all modules, including the default "user" module. * is shared by all modules, including the default "user" module.
*/ */
pub(super) struct RetractionInfo { pub(super) struct RetractionInfo {
orig_code_extent: usize, orig_code_extent: usize,

View File

@@ -136,7 +136,7 @@ impl IndexPtr {
} }
} }
#[derive(Debug, Clone, Copy)] // , Ord, Hash, PartialOrd, Eq, PartialEq)] #[derive(Debug, Clone, Copy)]// , Ord, Hash, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(CodeIndexOffset); pub struct CodeIndex(CodeIndexOffset);
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]

View File

@@ -246,7 +246,7 @@ fn setup_qualified_import(mut terms: Vec<Term>) -> Result<UseModuleExport, Compi
* + (mode declarations under the mode syntax, which currently have no effect) * + (mode declarations under the mode syntax, which currently have no effect)
* - * -
* ? * ?
*/ */
fn setup_meta_predicate<'a, LS: LoadState<'a>>( fn setup_meta_predicate<'a, LS: LoadState<'a>>(
mut terms: Vec<Term>, mut terms: Vec<Term>,

View File

@@ -1,6 +1,6 @@
/* A simple macro to count the arguments in a variadic list /* A simple macro to count the arguments in a variadic list
* of token trees. * of token trees.
*/ */
macro_rules! char_as_cell { macro_rules! char_as_cell {
($c: expr) => { ($c: expr) => {

View File

@@ -8,7 +8,7 @@
* wrapping it a Bytes struct. * wrapping it a Bytes struct.
* *
* Unlike BufReader, its buffer is peekable as a char. * Unlike BufReader, its buffer is peekable as a char.
*/ */
use smallvec::*; use smallvec::*;

View File

@@ -197,7 +197,7 @@ pub enum TrailRef {
BlackboardOffset(Atom, HeapCellValue), // key atom, key value BlackboardOffset(Atom, HeapCellValue), // key atom, key value
} }
#[allow(clippy::enum_variant_names)] // allow the common "Trailed" prefix #[allow(clippy::enum_variant_names)]// allow the common "Trailed" prefix
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 6] #[bits = 6]
pub(crate) enum TrailEntryTag { pub(crate) enum TrailEntryTag {