* 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;
* 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) => ({
* 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,
}
#[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)
}
#[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)
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(),
));
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);
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));
}
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;
}
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);
}
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);
}
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() => {
// 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, {
}
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,
// 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;
}
}
}
} else {
- while self.iter.pop_stack().is_none() {}
+ while self.iter.pop_stack().is_some() {}
None
}
}
.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);
}
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);
}
}
/* 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());
* 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> {
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,
* 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 {
* "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,
}
}
-#[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")]
* + (mode declarations under the mode syntax, which currently have no effect)
* -
* ?
- */
+*/
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
mut terms: Vec<Term>,
/* A simple macro to count the arguments in a variadic list
* of token trees.
- */
+*/
macro_rules! char_as_cell {
($c: expr) => {
* wrapping it a Bytes struct.
*
* Unlike BufReader, its buffer is peekable as a char.
- */
+*/
use smallvec::*;
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 {