From: Mark Thom Date: Sat, 23 Aug 2025 18:51:56 +0000 (-0700) Subject: further improvements to cyclic partial list printing (#2635) X-Git-Tag: v0.10.0~17 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=ad29f0f180a161976ce7e25480035b7c2596d667;p=scryer-prolog.git further improvements to cyclic partial list printing (#2635) --- diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 91144ea9..65fc971e 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -16,7 +16,7 @@ use to_syn_value_derive::ToDeriveInput; * of Instruction. They mimick most of the structure of the previous * Line instruction type. The strum crate is used to provide reflection * on each of the node types to the tree walker. - */ +*/ use std::any::*; use std::rc::Rc; diff --git a/src/functor_macro.rs b/src/functor_macro.rs index 591fa185..88e5a5a2 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -30,7 +30,7 @@ macro_rules! count { * in round parentheses for rustc to parse them. See the tests module * below for examples, especially those involving atom! * subexpressions. - */ +*/ macro_rules! functor { ($name:expr) => ({ diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 7726b49b..a57101b9 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -28,7 +28,7 @@ pub fn eager_stackful_preorder_iter( * 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 * efficient ground/1 and term_variables/2 definitions. - */ +*/ pub struct EagerStackfulPreOrderHeapIter<'a> { start_value: HeapCellValue, @@ -175,7 +175,7 @@ impl IterStackLoc { } #[inline] - fn mark_loc(h: usize, heap_or_stack: HeapOrStackTag) -> Self { + pub fn marked_loc(h: usize, heap_or_stack: HeapOrStackTag) -> Self { IterStackLoc::new() .with_tag(IterStackLocTag::Marked) .with_heap_or_stack(heap_or_stack) @@ -183,7 +183,7 @@ impl IterStackLoc { } #[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() .with_tag(IterStackLocTag::PendingMark) .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() { if h.is_pending_mark() { self.push_if_unmarked(h); - self.stack.push(IterStackLoc::mark_loc( + self.stack.push(IterStackLoc::marked_loc( h.value() as usize, h.heap_or_stack(), )); @@ -414,7 +414,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap); 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) => { 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.stack.push(IterStackLoc::pending_mark_loc(vh + 1, HeapOrStackTag::Heap)); - self.stack.push(IterStackLoc::mark_loc(vh, HeapOrStackTag::Heap)); + self.stack.push(IterStackLoc::pending_marked_loc(vh + 1, HeapOrStackTag::Heap)); + self.stack.push(IterStackLoc::marked_loc(vh, HeapOrStackTag::Heap)); return Some(self.read_cell(h)); } @@ -438,14 +438,14 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> self.forward_if_referent_marked(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) => { let loc = IterStackLoc::iterable_loc(vs, HeapOrStackTag::Stack); self.forward_if_referent_marked(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) => { 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::pending_mark_loc(tail_idx, HeapOrStackTag::Heap)); + self.stack.push(IterStackLoc::pending_marked_loc(tail_idx, HeapOrStackTag::Heap)); return Some(cell); } @@ -469,14 +469,14 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> let l = h.value() as usize; 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 { let first_arg_loc = IterStackLoc::iterable_loc(l+1, HeapOrStackTag::Heap); 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); } diff --git a/src/heap_print.rs b/src/heap_print.rs index d1d7bdb4..9e2ffb40 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -849,10 +849,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if let Some(mut orig_cell) = self.iter.next() { loop { let is_cyclic = orig_cell.get_forwarding_bit(); - - let cell = - heap_bound_store(self.iter.heap, heap_bound_deref(self.iter.heap, orig_cell)); - let cell = unmark_cell_bits!(cell); + let derefed_cell = heap_bound_deref(self.iter.heap, orig_cell); + let cell = unmark_cell_bits!(heap_bound_store(self.iter.heap, derefed_cell)); match self.var_names.get(&cell).cloned() { 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 // the current output, and return None. None // short-circuits handle_heap_term. - // self.iter.pop_stack(); - let var_str = var.borrow().to_string(); push_space_if_amb!(self, &var_str, { @@ -872,8 +868,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } var_opt => { if is_cyclic && cell.is_compound(self.iter.heap) { - // self-referential variables are marked "cyclic". - + // self-referential variables are marked "cyclic" match var_opt { Some(var) => { // 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. self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); } else { - debug_assert!(cell.is_ref()); - - let h = match cell.get_tag() { - HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => { + let h = read_heap_cell!(derefed_cell, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + self.iter.heap[h].set_forwarding_bit(false); + h + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { self.iter.focus().value() as usize } - _ => cell.get_value() as usize, - }; - - match cell.get_tag() { - HeapCellValueTag::Lis => { - self.state_stack - .push(TokenOrRedirect::Atom(atom!("..."))); - return None; + _ => { + cell.get_value() as usize } - 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( - h, - HeapOrStackTag::Heap, - )); - - if let Some(cell) = self.iter.next() { - orig_cell = cell; + orig_cell = next_cell; continue; } @@ -933,7 +955,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } } else { - while self.iter.pop_stack().is_none() {} + while self.iter.pop_stack().is_some() {} None } } @@ -1414,7 +1436,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { .push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); + .push(TokenOrRedirect::FunctorRedirect(max_depth)); self.open_list(switch); } @@ -1603,15 +1625,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Char(c)); } else { + self.iter.pop_stack(); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } } else if self.max_depth_exhausted(max_depth) { + self.iter.pop_stack(); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } else { self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); + .push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } } diff --git a/src/machine/code_walker.rs b/src/machine/code_walker.rs index 84f4cc93..1cbfde8b 100644 --- a/src/machine/code_walker.rs +++ b/src/machine/code_walker.rs @@ -41,7 +41,7 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec) -> b /* This function walks the code of a single predicate, supposed to * begin in code at the offset p. Each instruction is passed to the * walker function. - */ +*/ pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) { let mut stack = vec![p]; let mut visited_indices = IndexSet::with_hasher(FxBuildHasher::default()); diff --git a/src/machine/cycle_detection.rs b/src/machine/cycle_detection.rs index a800a9b6..25c24ea2 100644 --- a/src/machine/cycle_detection.rs +++ b/src/machine/cycle_detection.rs @@ -19,7 +19,7 @@ use crate::types::*; * Commonalities with the GC marking algorithm: * - The contents of forwarded cells are modified only when they are unforwarded * - Marked (but unforwarded!) cells immediately shift to the backward phase - */ +*/ #[derive(Debug)] pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> { diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index 4ecac7bc..49cf8c14 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -18,7 +18,7 @@ use std::collections::VecDeque; use std::hash::{Hash, Hasher}; use std::ops::{Deref, DerefMut}; -#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)] +#[derive(Debug, Clone)]//, PartialOrd, PartialEq, Eq, Hash)] pub struct BranchNumber { branch_num: Rational, delta: Rational, diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 4906ce53..6efe1984 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -46,7 +46,7 @@ use std::rc::Rc; * loader fail later, all changes must be rolled back, restoring the * WAM to its prior state. Retraction records describe individual changes * made by the loader, and they may be used later. - */ +*/ #[derive(Debug)] pub(crate) enum RetractionRecord { @@ -108,7 +108,7 @@ pub(crate) enum RetractionRecord { * "extent" of a code vector is its length prior to an attempted * module load. The only code vector of the WAM's IndexStore, "code", * is shared by all modules, including the default "user" module. - */ +*/ pub(super) struct RetractionInfo { orig_code_extent: usize, diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 7f7bfe35..8a0b6d41 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -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); #[cfg(target_pointer_width = "32")] diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index dc1ede62..2968d66d 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -246,7 +246,7 @@ fn setup_qualified_import(mut terms: Vec) -> Result>( mut terms: Vec, diff --git a/src/macros.rs b/src/macros.rs index 79470f18..0bf7b6af 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,6 +1,6 @@ /* A simple macro to count the arguments in a variadic list * of token trees. - */ +*/ macro_rules! char_as_cell { ($c: expr) => { diff --git a/src/parser/char_reader.rs b/src/parser/char_reader.rs index b1c20060..4d5d7d74 100644 --- a/src/parser/char_reader.rs +++ b/src/parser/char_reader.rs @@ -8,7 +8,7 @@ * wrapping it a Bytes struct. * * Unlike BufReader, its buffer is peekable as a char. - */ +*/ use smallvec::*; diff --git a/src/types.rs b/src/types.rs index 60b3b132..1564edeb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -197,7 +197,7 @@ pub enum TrailRef { 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)] #[bits = 6] pub(crate) enum TrailEntryTag {