From: Mark Thom Date: Mon, 7 Feb 2022 04:12:54 +0000 (-0700) Subject: use printer cycle detection when printing partial strings (#1263), refactor skip_max_... X-Git-Tag: v0.9.0^2~29 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=9ba503cd6bcf5896b62eddb8b9743973880ed582;p=scryer-prolog.git use printer cycle detection when printing partial strings (#1263), refactor skip_max_list functions --- diff --git a/src/heap_print.rs b/src/heap_print.rs index 0a664c6a..1dfba375 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -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); + 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())); - let mut iter = heap_pstr_iter.chars(); - let mut char_count = 0; + let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus); + let pstr = cell_as_string!(self.iter.heap[h]); - while let Some(c) = iter.next() { - print_char!(self, self.quoted, c); - push_char!(self, ','); + let pstr = pstr.as_str_from(offset.get_num() as usize); - char_count += 1; + if max_depth > 0 && pstr.chars().count() + 1 >= max_depth { + if value.get_tag() != HeapCellValueTag::CStr { + self.iter.pop_stack(); + } - if max_depth > 0 && max_depth <= char_count { - break; - } - } + 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); + } - self.state_stack.push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0))))); + for (char_count, c) in pstr.chars().rev().enumerate() { + if max_depth > 0 && char_count + 1 >= max_depth { + break; + } - 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); - } + self.state_stack.push(TokenOrRedirect::Char(c)); + self.state_stack.push(TokenOrRedirect::Comma); + } - 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 let Some(TokenOrRedirect::Comma) = self.state_stack.last() { + self.state_stack.pop(); + } - if self.outputter.ends_with(",") { - self.outputter.truncate(self.outputter.len() - ','.len_utf8()); - } + self.state_stack.push(TokenOrRedirect::OpenList(switch)); + } + ); } } @@ -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) => { diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index cd6cb982..718a57b4 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -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; @@ -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())) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index f2f8edd9..ee4d152d 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -209,29 +209,27 @@ impl BrentAlgState { } ) } -} -impl MachineState { #[inline(always)] - pub fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { + fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option { 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 {