add support for printing cyclic terms.
This commit is contained in:
@@ -135,8 +135,8 @@ impl MachineState {
|
||||
pub(super) fn throw_exception(&mut self, err: MachineError) {
|
||||
let h = self.heap.h;
|
||||
|
||||
self.ball.0 = 0;
|
||||
self.ball.1.truncate(0);
|
||||
self.ball.boundary = 0;
|
||||
self.ball.stub.truncate(0);
|
||||
|
||||
self.heap.append(err);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use prolog::and_stack::*;
|
||||
use prolog::ast::*;
|
||||
use prolog::copier::*;
|
||||
use prolog::machine::machine_errors::MachineStub;
|
||||
use prolog::num::{BigInt, BigUint, Zero, One};
|
||||
use prolog::or_stack::*;
|
||||
use prolog::heap_print::*;
|
||||
@@ -14,6 +15,22 @@ use std::mem::swap;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(super) struct Ball {
|
||||
pub(super) boundary: usize, // ball.0
|
||||
pub(super) stub: MachineStub, // ball.1
|
||||
}
|
||||
|
||||
impl Ball {
|
||||
pub(super) fn new() -> Self {
|
||||
Ball { boundary: 0, stub: MachineStub::new() }
|
||||
}
|
||||
|
||||
pub(super) fn reset(&mut self) {
|
||||
self.boundary = 0;
|
||||
self.stub.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CodeDirs<'a> {
|
||||
code_dir: &'a CodeDir,
|
||||
modules: &'a HashMap<ClauseName, Module>
|
||||
@@ -109,7 +126,7 @@ impl<'a> Index<usize> for DuplicateBallTerm<'a> {
|
||||
&self.state.heap[index]
|
||||
} else {
|
||||
let index = index - self.heap_boundary;
|
||||
&self.state.ball.1[index]
|
||||
&self.state.ball.stub[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,7 +137,7 @@ impl<'a> IndexMut<usize> for DuplicateBallTerm<'a> {
|
||||
&mut self.state.heap[index]
|
||||
} else {
|
||||
let index = index - self.heap_boundary;
|
||||
&mut self.state.ball.1[index]
|
||||
&mut self.state.ball.stub[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,11 +149,11 @@ impl<'a> CopierTarget for DuplicateBallTerm<'a> {
|
||||
}
|
||||
|
||||
fn threshold(&self) -> usize {
|
||||
self.heap_boundary + self.state.ball.1.len()
|
||||
self.heap_boundary + self.state.ball.stub.len()
|
||||
}
|
||||
|
||||
fn push(&mut self, hcv: HeapCellValue) {
|
||||
self.state.ball.1.push(hcv);
|
||||
self.state.ball.stub.push(hcv);
|
||||
}
|
||||
|
||||
fn store(&self, a: Addr) -> Addr {
|
||||
@@ -203,7 +220,8 @@ pub struct MachineState {
|
||||
pub(super) tr: usize,
|
||||
pub(super) hb: usize,
|
||||
pub(super) block: usize, // an offset into the OR stack.
|
||||
pub(super) ball: (usize, Vec<HeapCellValue>), // heap boundary, and a term copy
|
||||
pub(super) ball: Ball,
|
||||
pub(super) redirect: CellRedirect,
|
||||
pub(super) interms: Vec<Number>, // intermediate numbers.
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ impl MachineState {
|
||||
tr: 0,
|
||||
hb: 0,
|
||||
block: 0,
|
||||
ball: (0, Vec::new()),
|
||||
ball: Ball::new(),
|
||||
redirect: CellRedirect::new(),
|
||||
interms: vec![Number::default(); 256]
|
||||
}
|
||||
}
|
||||
@@ -97,7 +98,7 @@ impl MachineState {
|
||||
fn print_var_eq<Fmt, Outputter>(&self, var: Rc<Var>, addr: Addr, var_dir: &HeapVarDict,
|
||||
fmt: Fmt, mut output: Outputter)
|
||||
-> Outputter
|
||||
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
||||
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
||||
{
|
||||
let orig_len = output.len();
|
||||
|
||||
@@ -106,8 +107,8 @@ impl MachineState {
|
||||
output.append(var.as_str());
|
||||
output.append(" = ");
|
||||
|
||||
let printer = HCPrinter::from_heap_locs(&self, addr, fmt, output, var_dir);
|
||||
let mut output = printer.print();
|
||||
let printer = HCPrinter::from_heap_locs(&self, fmt, output, var_dir);
|
||||
let mut output = printer.print(addr);
|
||||
|
||||
if output.ends_with(var.as_str()) {
|
||||
output.truncate(orig_len);
|
||||
@@ -115,13 +116,23 @@ impl MachineState {
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn print_exception<Fmt, Outputter>(&self, addr: Addr, var_dir: &HeapVarDict,
|
||||
fmt: Fmt, output: Outputter)
|
||||
-> Outputter
|
||||
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
||||
{
|
||||
let printer = HCPrinter::from_heap_locs_as_seen(&self, fmt, output, var_dir);
|
||||
printer.print(addr)
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn print_term<Fmt, Outputter>(&self, addr: Addr, fmt: Fmt, output: Outputter) -> Outputter
|
||||
where Fmt: HCValueFormatter, Outputter: HCValueOutputter
|
||||
{
|
||||
let printer = HCPrinter::new(&self, addr, fmt, output);
|
||||
printer.print()
|
||||
let printer = HCPrinter::new(&self, fmt, output);
|
||||
printer.print(addr)
|
||||
}
|
||||
|
||||
pub(super) fn unify(&mut self, a1: Addr, a2: Addr) {
|
||||
@@ -1089,26 +1100,25 @@ impl MachineState {
|
||||
Some((name, arity + narity - 1))
|
||||
}
|
||||
|
||||
pub(super) fn copy_and_align_ball_to_heap(&mut self) {
|
||||
let diff = if self.ball.0 > self.heap.h {
|
||||
self.ball.0 - self.heap.h
|
||||
fn heap_ball_boundary_diff(&self) -> usize {
|
||||
if self.ball.boundary > self.heap.h {
|
||||
self.ball.boundary - self.heap.h
|
||||
} else {
|
||||
self.heap.h - self.ball.0
|
||||
};
|
||||
|
||||
for heap_value in self.ball.1.iter().cloned() {
|
||||
self.heap.h - self.ball.boundary
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn copy_and_align_ball_to_heap(&mut self) -> usize {
|
||||
let diff = self.heap_ball_boundary_diff();
|
||||
|
||||
for heap_value in self.ball.stub.iter().cloned() {
|
||||
self.heap.push(match heap_value {
|
||||
HeapCellValue::Addr(Addr::Con(c)) =>
|
||||
HeapCellValue::Addr(Addr::Con(c)),
|
||||
HeapCellValue::Addr(Addr::Lis(a)) =>
|
||||
HeapCellValue::Addr(Addr::Lis(a - diff)),
|
||||
HeapCellValue::Addr(Addr::HeapCell(hc)) =>
|
||||
HeapCellValue::Addr(Addr::HeapCell(hc - diff)),
|
||||
HeapCellValue::Addr(Addr::Str(s)) =>
|
||||
HeapCellValue::Addr(Addr::Str(s - diff)),
|
||||
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
|
||||
_ => heap_value
|
||||
});
|
||||
}
|
||||
|
||||
diff
|
||||
}
|
||||
|
||||
pub(super) fn is_cyclic_term(&self, addr: Addr) -> bool {
|
||||
@@ -1179,6 +1189,25 @@ impl MachineState {
|
||||
self.p += 1;
|
||||
}
|
||||
|
||||
// everything in self.redirect is potentially offset on the heap by 'offset',
|
||||
// so correct for that when building the HeapVarDict.
|
||||
pub(super) fn reconstruct_dict(&self, heap_locs: &HeapVarDict, offset: usize) -> HeapVarDict
|
||||
{
|
||||
let mut dest_heap_locs = HeapVarDict::new();
|
||||
|
||||
'outer:
|
||||
for (orig_addr, addr) in self.redirect.0.iter() {
|
||||
for (var, var_addr) in heap_locs.iter() {
|
||||
if orig_addr == &self.store(self.deref(var_addr.clone())) {
|
||||
dest_heap_locs.insert(var.clone(), addr.clone() + offset);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dest_heap_locs
|
||||
}
|
||||
|
||||
pub(super) fn compare_term(&mut self, qt: CompareTermQT) {
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
let a2 = self[temp_v!(2)].clone();
|
||||
@@ -1433,8 +1462,7 @@ impl MachineState {
|
||||
try_or_fail!(self, call_policy.trust_me(self));
|
||||
},
|
||||
&BuiltInInstruction::EraseBall => {
|
||||
self.ball.0 = 0;
|
||||
self.ball.1.truncate(0);
|
||||
self.ball.reset();
|
||||
self.p += 1;
|
||||
},
|
||||
&BuiltInInstruction::GetArg(lco) =>
|
||||
@@ -1460,7 +1488,7 @@ impl MachineState {
|
||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let h = self.heap.h;
|
||||
|
||||
if self.ball.1.len() > 0 {
|
||||
if self.ball.stub.len() > 0 {
|
||||
self.copy_and_align_ball_to_heap();
|
||||
} else {
|
||||
self.fail = true;
|
||||
@@ -1608,13 +1636,14 @@ impl MachineState {
|
||||
},
|
||||
&BuiltInInstruction::SetBall => {
|
||||
let addr = self[temp_v!(1)].clone();
|
||||
self.ball.0 = self.heap.h;
|
||||
self.ball.boundary = self.heap.h;
|
||||
|
||||
{
|
||||
let cell_redirect = {
|
||||
let mut duplicator = DuplicateBallTerm::new(self);
|
||||
duplicator.duplicate_term(addr);
|
||||
}
|
||||
duplicator.duplicate_term(addr)
|
||||
};
|
||||
|
||||
self.redirect.0.extend(cell_redirect.0.into_iter());
|
||||
self.p += 1;
|
||||
},
|
||||
&BuiltInInstruction::SetCutPoint(r) =>
|
||||
@@ -2323,6 +2352,8 @@ impl MachineState {
|
||||
self.or_stack.clear();
|
||||
self.registers = vec![Addr::HeapCell(0); 64];
|
||||
self.block = 0;
|
||||
self.ball = (0, Vec::new());
|
||||
|
||||
self.ball.reset();
|
||||
self.redirect.0.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +57,11 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> {
|
||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
|
||||
if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) {
|
||||
println!("warning: overwriting {}/{}", &name, arity);
|
||||
set_code_index!(code_idx, idx.0, idx.1);
|
||||
set_code_index!(code_idx, idx.0, idx.1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
self.code_dir.insert((name, arity), CodeIndex::from(idx));
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ impl Machine {
|
||||
if &code_idx.borrow().1 != &module_name {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
self.code_dir.remove(&(name.clone(), arity));
|
||||
|
||||
// remove or respecify ops.
|
||||
@@ -194,7 +194,7 @@ impl Machine {
|
||||
Some(&CodeIndex (ref idx)) if idx.borrow().1 != clause_name!("user") =>
|
||||
return EvalSession::from(SessionError::ImpermissibleEntry(format!("{}/{}",
|
||||
name,
|
||||
arity))),
|
||||
arity))),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
@@ -370,18 +370,20 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn fail(&mut self) -> EvalSession
|
||||
fn fail(&mut self, heap_locs: &HeapVarDict) -> EvalSession
|
||||
{
|
||||
if self.ms.ball.1.len() > 0 {
|
||||
if self.ms.ball.stub.len() > 0 {
|
||||
let h = self.ms.heap.h;
|
||||
self.ms.copy_and_align_ball_to_heap();
|
||||
|
||||
let msg = self.ms.print_term(Addr::HeapCell(h),
|
||||
TermFormatter {},
|
||||
PrinterOutputter::new())
|
||||
.result();
|
||||
let heap_locs = self.ms.reconstruct_dict(heap_locs, h);
|
||||
let error_str = self.ms.print_exception(Addr::HeapCell(h),
|
||||
&heap_locs,
|
||||
TermFormatter {},
|
||||
PrinterOutputter::new())
|
||||
.result();
|
||||
|
||||
EvalSession::from(SessionError::QueryFailureWithException(msg))
|
||||
EvalSession::from(SessionError::QueryFailureWithException(error_str))
|
||||
} else {
|
||||
EvalSession::from(SessionError::QueryFailure)
|
||||
}
|
||||
@@ -395,7 +397,7 @@ impl Machine {
|
||||
self.run_query(&alloc_locs, &mut heap_locs);
|
||||
|
||||
if self.failed() {
|
||||
self.fail()
|
||||
self.fail(&heap_locs)
|
||||
} else {
|
||||
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
|
||||
}
|
||||
@@ -414,7 +416,7 @@ impl Machine {
|
||||
self.run_query(alloc_l, heap_l);
|
||||
|
||||
if self.failed() {
|
||||
self.fail()
|
||||
self.fail(&heap_l)
|
||||
} else {
|
||||
EvalSession::SubsequentQuerySuccess
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user