use printer cycle detection when printing partial strings (#1263), refactor skip_max_list functions

This commit is contained in:
Mark Thom
2022-02-06 21:12:54 -07:00
parent f3f3dccf8e
commit 9ba503cd6b
3 changed files with 107 additions and 88 deletions

View File

@@ -13,6 +13,7 @@ use crate::forms::*;
use crate::heap_iter::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::pstr_loc_and_offset;
use crate::machine::partial_string::*;
use crate::machine::streams::*;
use crate::types::*;
@@ -203,6 +204,7 @@ impl NumberFocus {
enum TokenOrRedirect {
Atom(Atom),
BarAsOp,
Char(char),
Op(Atom, OpDesc),
NumberedVar(String),
CompositeRedirect(usize, DirectedOp),
@@ -1130,20 +1132,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let end_h = heap_pstr_iter.focus();
let end_cell = heap_pstr_iter.focus;
self.remove_list_children(focus);
if self.check_max_depth(&mut max_depth) {
self.remove_list_children(focus);
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
return;
}
let at_cdr = self.at_cdr(",");
let at_cdr = self.outputter.ends_with("|");
if !at_cdr && !self.ignore_ops && end_cell.is_string_terminator(&self.iter.heap) {
self.remove_list_children(focus);
return self.print_proper_string(focus, max_depth);
}
if self.ignore_ops {
self.at_cdr(",");
self.remove_list_children(focus);
if !self.print_string_as_functor(focus, max_depth) {
if end_cell == empty_list_as_cell!() {
append_str!(self, "[]");
@@ -1153,49 +1158,52 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
} else {
let switch = if !at_cdr {
push_char!(self, '[');
true
} else {
false
};
let value = heap_bound_store(
self.iter.heap,
heap_bound_deref(self.iter.heap, self.iter.heap[focus]),
);
let heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus);
let mut iter = heap_pstr_iter.chars();
let mut char_count = 0;
while let Some(c) = iter.next() {
print_char!(self, self.quoted, c);
push_char!(self, ',');
char_count += 1;
if max_depth > 0 && max_depth <= char_count {
break;
read_heap_cell!(value,
(HeapCellValueTag::Lis) => {
return self.push_list(max_depth);
}
}
_ => {
let switch = Rc::new(Cell::new((!at_cdr, 0)));
self.state_stack.push(TokenOrRedirect::CloseList(switch.clone()));
self.state_stack.push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0)))));
let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus);
let pstr = cell_as_string!(self.iter.heap[h]);
if self.max_depth > 0 && iter.next().is_some() {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} else {
if iter.cycle_detected() {
self.iter.heap[end_h].set_forwarding_bit(true);
let pstr = pstr.as_str_from(offset.get_num() as usize);
if max_depth > 0 && pstr.chars().count() + 1 >= max_depth {
if value.get_tag() != HeapCellValueTag::CStr {
self.iter.pop_stack();
}
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} else if end_cell != empty_list_as_cell!() {
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
}
for (char_count, c) in pstr.chars().rev().enumerate() {
if max_depth > 0 && char_count + 1 >= max_depth {
break;
}
self.state_stack.push(TokenOrRedirect::Char(c));
self.state_stack.push(TokenOrRedirect::Comma);
}
if let Some(TokenOrRedirect::Comma) = self.state_stack.last() {
self.state_stack.pop();
}
self.state_stack.push(TokenOrRedirect::OpenList(switch));
}
if end_cell != empty_list_as_cell!() {
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
self.iter.push_stack(end_h);
}
}
if self.outputter.ends_with(",") {
self.outputter.truncate(self.outputter.len() - ','.len_utf8());
}
);
}
}
@@ -1507,6 +1515,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
match loc_data {
TokenOrRedirect::Atom(atom) => self.print_atom(atom),
TokenOrRedirect::BarAsOp => append_str!(self, " | "),
TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c),
TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()),
TokenOrRedirect::NumberedVar(num_var) => append_str!(self, &num_var),
TokenOrRedirect::CompositeRedirect(max_depth, op) => {

View File

@@ -5,6 +5,7 @@ use crate::forms::*;
use crate::machine::heap::*;
use crate::machine::loader::CompilationTarget;
use crate::machine::machine_state::*;
use crate::machine::system_calls::BrentAlgState;
use crate::types::*;
pub type MachineStub = Vec<HeapCellValue>;
@@ -783,10 +784,10 @@ impl MachineState {
pub(super) fn check_sort_errors(&mut self) -> CallResult {
let stub_gen = || functor_stub(atom!("sort"), 2);
let list = self.registers[1];
let list = self.store(self.deref(self.registers[1]));
let sorted = self.registers[2];
match self.detect_cycles(list) {
match BrentAlgState::detect_cycles(&self.heap, list) {
CycleSearchResult::PartialList(..) => {
let err = self.instantiation_error();
return Err(self.error_form(err, stub_gen()))
@@ -798,7 +799,7 @@ impl MachineState {
_ => {}
};
match self.detect_cycles(sorted) {
match BrentAlgState::detect_cycles(&self.heap, sorted) {
CycleSearchResult::NotList if !sorted.is_var() => {
let err = self.type_error(ValidType::List, sorted);
Err(self.error_form(err, stub_gen()))
@@ -810,7 +811,7 @@ impl MachineState {
fn check_for_list_pairs(&mut self, mut list: HeapCellValue) -> CallResult {
let stub_gen = || functor_stub(atom!("keysort"), 2);
match self.detect_cycles(list) {
match BrentAlgState::detect_cycles(&self.heap, list) {
CycleSearchResult::NotList if !list.is_var() => {
let err = self.type_error(ValidType::List, list);
Err(self.error_form(err, stub_gen()))
@@ -872,7 +873,7 @@ impl MachineState {
let pairs = self.store(self.deref(self[temp_v!(1)]));
let sorted = self.store(self.deref(self[temp_v!(2)]));
match self.detect_cycles(pairs) {
match BrentAlgState::detect_cycles(&self.heap, pairs) {
CycleSearchResult::PartialList(..) => {
let err = self.instantiation_error();
Err(self.error_form(err, stub_gen()))

View File

@@ -209,29 +209,27 @@ impl BrentAlgState {
}
)
}
}
impl MachineState {
#[inline(always)]
pub fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult> {
fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option<CycleSearchResult> {
loop {
let store_v = self.heap[brent_st.hare];
let value = heap[self.hare];
read_heap_cell!(store_v,
read_heap_cell!(value,
(HeapCellValueTag::PStrLoc, h) => {
return brent_st.add_pstr_chars_and_step(&self.heap, h);
return self.add_pstr_chars_and_step(&heap, h);
}
(HeapCellValueTag::CStr | HeapCellValueTag::PStrOffset) => {
return brent_st.add_pstr_chars_and_step(&self.heap, brent_st.hare);
return self.add_pstr_chars_and_step(&heap, self.hare);
}
(HeapCellValueTag::Lis, h) => {
return brent_st.step(h+1);
return self.step(h+1);
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
return if name == atom!(".") && arity == 2 {
brent_st.step(s+2)
self.step(s+2)
} else {
Some(CycleSearchResult::NotList)
};
@@ -240,18 +238,18 @@ impl MachineState {
debug_assert!(arity == 0);
return if name == atom!("[]") {
Some(CycleSearchResult::ProperList(brent_st.num_steps()))
Some(CycleSearchResult::ProperList(self.num_steps()))
} else {
Some(CycleSearchResult::NotList)
};
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if brent_st.hare == h {
let r = store_v.as_var().unwrap();
return Some(CycleSearchResult::PartialList(brent_st.num_steps(), r));
if self.hare == h {
let r = value.as_var().unwrap();
return Some(CycleSearchResult::PartialList(self.num_steps(), r));
}
brent_st.hare = h;
self.hare = h;
}
_ => {
return Some(CycleSearchResult::NotList);
@@ -260,25 +258,24 @@ impl MachineState {
}
}
pub fn detect_cycles(&self, value: HeapCellValue) -> CycleSearchResult {
let store_v = self.store(self.deref(value));
pub fn detect_cycles(heap: &[HeapCellValue], value: HeapCellValue) -> CycleSearchResult {
let mut pstr_chars = 0;
let hare = read_heap_cell!(store_v,
let hare = read_heap_cell!(value,
(HeapCellValueTag::Lis, offset) => {
offset+1
}
(HeapCellValueTag::PStrLoc, h) => {
let (h_offset, n) = pstr_loc_and_offset(&self.heap, h);
let (h_offset, n) = pstr_loc_and_offset(&heap, h);
let n = n.get_num() as usize;
let pstr = cell_as_string!(self.heap[h_offset]);
let pstr = cell_as_string!(heap[h_offset]);
pstr_chars = pstr.as_str_from(n).chars().count() - 1;
if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset {
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset);
if heap[h].get_tag() == HeapCellValueTag::PStrOffset {
debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset);
if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr {
if heap[h_offset].get_tag() == HeapCellValueTag::CStr {
return CycleSearchResult::ProperList(pstr_chars + 1);
}
}
@@ -293,7 +290,7 @@ impl MachineState {
return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count());
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
let (name, arity) = cell_as_atom_cell!(heap[s])
.get_name_and_arity();
if name == atom!("[]") && arity == 0 {
@@ -312,7 +309,7 @@ impl MachineState {
};
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
return CycleSearchResult::PartialList(0, store_v.as_var().unwrap());
return CycleSearchResult::PartialList(0, value.as_var().unwrap());
}
_ => {
return CycleSearchResult::NotList;
@@ -325,17 +322,20 @@ impl MachineState {
brent_st.pstr_chars = pstr_chars;
loop {
if let Some(result) = self.brents_alg_step(&mut brent_st) {
if let Some(result) = brent_st.cycle_step(heap) {
return result;
}
}
}
pub fn detect_cycles_with_max(&self, max_steps: usize, value: HeapCellValue) -> CycleSearchResult {
let store_v = self.store(self.deref(value));
pub fn detect_cycles_with_max(
heap: &[HeapCellValue],
max_steps: usize,
value: HeapCellValue,
) -> CycleSearchResult {
let mut pstr_chars = 0;
let hare = read_heap_cell!(store_v,
let hare = read_heap_cell!(value,
(HeapCellValueTag::Lis, offset) => {
if max_steps > 0 {
offset+1
@@ -344,16 +344,16 @@ impl MachineState {
}
}
(HeapCellValueTag::PStrLoc, h) => {
let (h_offset, n) = pstr_loc_and_offset(&self.heap, h);
let (h_offset, n) = pstr_loc_and_offset(&heap, h);
let n = n.get_num() as usize;
let pstr = cell_as_string!(self.heap[h_offset]);
let pstr = cell_as_string!(heap[h_offset]);
pstr_chars = pstr.as_str_from(n).chars().count() - 1;
if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset {
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset);
if heap[h].get_tag() == HeapCellValueTag::PStrOffset {
debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset);
if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr {
if heap[h_offset].get_tag() == HeapCellValueTag::CStr {
return if pstr_chars + 1 <= max_steps {
CycleSearchResult::ProperList(pstr_chars + 1)
} else {
@@ -386,7 +386,7 @@ impl MachineState {
};
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
if name == atom!("[]") && arity == 0 {
return CycleSearchResult::EmptyList;
@@ -408,7 +408,7 @@ impl MachineState {
};
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
return CycleSearchResult::PartialList(0, store_v.as_var().unwrap());
return CycleSearchResult::PartialList(0, value.as_var().unwrap());
}
_ => {
return CycleSearchResult::NotList;
@@ -422,15 +422,17 @@ impl MachineState {
loop {
if brent_st.num_steps() >= max_steps {
return brent_st.to_result(&self.heap);
return brent_st.to_result(&heap);
}
if let Some(result) = self.brents_alg_step(&mut brent_st) {
if let Some(result) = brent_st.cycle_step(heap) {
return result;
}
}
}
}
impl MachineState {
fn skip_max_list_cycle(&mut self, lam: usize) {
fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize {
loop {
@@ -479,10 +481,10 @@ impl MachineState {
let mut brent_st = BrentAlgState::new(h);
self.brents_alg_step(&mut brent_st);
brent_st.cycle_step(&self.heap);
while prev_hare != brent_st.hare {
self.brents_alg_step(&mut brent_st);
brent_st.cycle_step(&self.heap);
}
self.heap.pop();
@@ -507,9 +509,16 @@ impl MachineState {
fn skip_max_list_result(&mut self, max_steps: i64) {
let search_result = if max_steps == -1 {
self.detect_cycles(self.registers[3])
BrentAlgState::detect_cycles(
&self.heap,
self.store(self.deref(self.registers[3])),
)
} else {
self.detect_cycles_with_max(max_steps as usize, self.registers[3])
BrentAlgState::detect_cycles_with_max(
&self.heap,
max_steps as usize,
self.store(self.deref(self.registers[3])),
)
};
match search_result {