add support for printing cyclic terms.

This commit is contained in:
Mark Thom
2018-05-05 01:53:05 -06:00
parent c369ce9a7f
commit d6495c8195
9 changed files with 279 additions and 149 deletions

View File

@@ -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);

View File

@@ -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.
}

View File

@@ -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();
}
}

View File

@@ -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
}