properly handle cyclic terms in the printer.

This commit is contained in:
Mark Thom
2018-05-05 12:33:29 -06:00
parent d6495c8195
commit 81a199836d
5 changed files with 113 additions and 91 deletions

View File

@@ -4,6 +4,14 @@ use prolog::ast::*;
use std::collections::HashMap;
use std::ops::IndexMut;
pub type Trail = Vec<(Ref, HeapCellValue)>;
pub struct RedirectInfo {
trail: Trail,
list_redirect: HashMap<usize, usize>,
offset: usize
}
// allows us to reconstruct a HeapVarDict by relating variables
// in an existing HeapVarDict to the ones created in fn duplicate_term.
// It is used to create meaningful error reports at the toplevel.
@@ -13,9 +21,11 @@ impl CellRedirect {
pub fn new() -> Self {
CellRedirect(HashMap::new())
}
}
pub type Trail = Vec<(Ref, HeapCellValue)>;
pub fn clear(&mut self) {
self.0.clear();
}
}
pub trait CopierTarget
{
@@ -26,49 +36,60 @@ pub trait CopierTarget
fn deref(&self, Addr) -> Addr;
fn stack(&mut self) -> &mut AndStack;
fn compile_redirect(&mut self, trail: Trail, list_redirect: HashMap<usize, usize>, old_h: usize)
-> CellRedirect
where Self: IndexMut<usize, Output=HeapCellValue>
// unwind the trail *and* compute a cell redirection table.
fn unwind_and_redirect(&mut self, redirect: RedirectInfo) -> CellRedirect
where Self: IndexMut<usize, Output=HeapCellValue>
{
let mut cell_redirect: HashMap<Addr, Addr> = HashMap::new();
for (r, hcv) in trail {
for (r, hcv) in redirect.trail {
let addr = Addr::from(r);
match r {
Ref::HeapCell(hc) => {
cell_redirect.insert(addr, self[hc].as_addr(hc) - old_h);
self[hc] = hcv;
Ref::HeapCell(h) => {
cell_redirect.insert(addr, self[h].as_addr(h) - redirect.offset);
self[h] = hcv;
},
Ref::StackCell(fr, sc) => {
cell_redirect.insert(addr, self.stack()[fr][sc].clone() - old_h);
cell_redirect.insert(addr, self.stack()[fr][sc].clone() - redirect.offset);
self.stack()[fr][sc] = hcv.as_addr(0);
}
}
};
}
for (l, h) in list_redirect {
cell_redirect.insert(Addr::Lis(l), Addr::Lis(h - old_h));
for (l, h) in redirect.list_redirect {
cell_redirect.insert(Addr::Lis(l), Addr::Lis(h - redirect.offset));
}
CellRedirect(cell_redirect)
}
// duplicate_term(L1, L2) uses Cheney's algorithm to copy the term
fn unwind_trail(&mut self, redirect: RedirectInfo)
where Self: IndexMut<usize, Output=HeapCellValue>
{
for (r, hcv) in redirect.trail {
match r {
Ref::HeapCell(hc) => self[hc] = hcv.clone(),
Ref::StackCell(fr, sc) => self.stack()[fr][sc] = hcv.as_addr(0)
}
}
}
// duplicate_term_impl(L1, L2) uses Cheney's algorithm to copy the term
// at L1 to L2. trail is kept to restore the innards of L1 after
// it's been copied to L2.
fn duplicate_term(&mut self, addr: Addr) -> CellRedirect
fn duplicate_term_impl(&mut self, addr: Addr) -> RedirectInfo
where Self: IndexMut<usize, Output=HeapCellValue>
{
let mut trail = Trail::new();
let mut scan = self.source();
let old_h = self.threshold();
let mut scan = self.source();
let old_h = self.threshold();
// Lists have a compressed representation as structures,
// removing the need for NamedStr, so we use a redirection
// table for copying lists.
let mut list_redirect = HashMap::new();
self.push(HeapCellValue::Addr(addr));
while scan < self.threshold() {
@@ -84,15 +105,15 @@ pub trait CopierTarget
continue;
}
list_redirect.insert(a, self.threshold());
list_redirect.insert(a, self.threshold());
self[scan] = HeapCellValue::Addr(Addr::Lis(self.threshold()));
let hcv = self[a].clone();
self.push(hcv);
let hcv = self[a+1].clone();
self.push(hcv);
scan += 1;
},
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
@@ -152,6 +173,20 @@ pub trait CopierTarget
}
}
self.compile_redirect(trail, list_redirect, old_h)
RedirectInfo { trail, list_redirect, offset: old_h }
}
fn duplicate_term_and_redirect(&mut self, addr: Addr) -> CellRedirect
where Self: IndexMut<usize, Output=HeapCellValue>
{
let redirect = self.duplicate_term_impl(addr);
self.unwind_and_redirect(redirect)
}
fn duplicate_term(&mut self, addr: Addr)
where Self: IndexMut<usize, Output=HeapCellValue>
{
let redirect = self.duplicate_term_impl(addr);
self.unwind_trail(redirect);
}
}