abstract Outputter of heap_print

This commit is contained in:
Mark Thom
2018-01-15 20:18:08 -07:00
parent 579b9f21dc
commit f265546203
4 changed files with 126 additions and 61 deletions

View File

@@ -40,6 +40,57 @@ pub trait HeapCellValueFormatter {
fn format_clause(&self, usize, Rc<Atom>, Option<Fixity>, &mut Vec<TokenOrRedirect>); fn format_clause(&self, usize, Rc<Atom>, Option<Fixity>, &mut Vec<TokenOrRedirect>);
} }
pub trait HeapCellValueOutputter {
type Output;
fn new() -> Self;
fn append(&mut self, &str);
fn begin_new_var(&mut self);
fn result(self) -> Self::Output;
fn ends_with(&self, &str) -> bool;
fn len(&self) -> usize;
fn truncate(&mut self, usize);
}
pub struct PrinterOutputter {
contents: String
}
impl HeapCellValueOutputter for PrinterOutputter {
fn new() -> Self {
PrinterOutputter { contents: String::new() }
}
type Output = String;
fn append(&mut self, contents: &str) {
self.contents += contents;
}
fn begin_new_var(&mut self) {
if self.contents.len() != 0 {
self.contents += ", ";
}
}
fn result(self) -> Self::Output {
self.contents
}
fn ends_with(&self, s: &str) -> bool {
self.contents.ends_with(s)
}
fn len(&self) -> usize {
self.contents.len()
}
fn truncate(&mut self, len: usize) {
self.contents.truncate(len);
}
}
// the 'classic' display corresponding to the display predicate. // the 'classic' display corresponding to the display predicate.
pub struct DisplayFormatter {} pub struct DisplayFormatter {}
@@ -51,7 +102,7 @@ impl HeapCellValueFormatter for DisplayFormatter {
let mut new_name = String::from("'"); let mut new_name = String::from("'");
new_name += name.as_ref(); new_name += name.as_ref();
new_name += "'"; new_name += "'";
let name = Rc::new(new_name); let name = Rc::new(new_name);
self.format_struct(arity, name, state_stack); self.format_struct(arity, name, state_stack);
} else { } else {
@@ -92,28 +143,30 @@ impl HeapCellValueFormatter for TermFormatter {
} }
} }
pub struct HeapCellPrinter<'a, Formatter> { pub struct HeapCellPrinter<'a, Formatter, Outputter> {
formatter: Formatter, formatter: Formatter,
outputter: Outputter,
iter: HeapCellIterator<'a>, iter: HeapCellIterator<'a>,
state_stack: Vec<TokenOrRedirect> state_stack: Vec<TokenOrRedirect>
} }
impl<'a, Formatter: HeapCellValueFormatter> HeapCellPrinter<'a, Formatter> impl<'a, Formatter: HeapCellValueFormatter, Outputter: HeapCellValueOutputter>
HeapCellPrinter<'a, Formatter, Outputter>
{ {
pub fn new(iter: HeapCellIterator<'a>, formatter: Formatter) -> Self { pub fn new(iter: HeapCellIterator<'a>, formatter: Formatter, outputter: Outputter) -> Self {
HeapCellPrinter { formatter, iter, state_stack: vec![] } HeapCellPrinter { formatter, outputter, iter, state_stack: vec![] }
} }
fn handle_heap_term(&mut self, heap_val: HeapCellValue, result: &mut String) { fn handle_heap_term(&mut self, heap_val: HeapCellValue) {
match heap_val { match heap_val {
HeapCellValue::NamedStr(arity, name, fixity) => HeapCellValue::NamedStr(arity, name, fixity) =>
self.formatter.format_clause(arity, name, fixity, &mut self.state_stack), self.formatter.format_clause(arity, name, fixity, &mut self.state_stack),
HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) => HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
if !Self::at_cdr(result, "") { if !self.at_cdr("") {
*result += "[]"; self.outputter.append("[]");
}, },
HeapCellValue::Addr(Addr::Con(c)) => HeapCellValue::Addr(Addr::Con(c)) =>
*result += format!("{}", c).as_str(), self.outputter.append(format!("{}", c).as_str()),
HeapCellValue::Addr(Addr::Lis(_)) => { HeapCellValue::Addr(Addr::Lis(_)) => {
let cell = Rc::new(Cell::new(true)); let cell = Rc::new(Cell::new(true));
@@ -126,65 +179,64 @@ impl<'a, Formatter: HeapCellValueFormatter> HeapCellPrinter<'a, Formatter>
self.state_stack.push(TokenOrRedirect::OpenList(cell)); self.state_stack.push(TokenOrRedirect::OpenList(cell));
}, },
HeapCellValue::Addr(Addr::HeapCell(h)) => HeapCellValue::Addr(Addr::HeapCell(h)) =>
*result += format!("_{}", h).as_str(), self.outputter.append(format!("_{}", h).as_str()),
HeapCellValue::Addr(Addr::StackCell(fr, sc)) => HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
*result += format!("s_{}_{}", fr, sc).as_str(), self.outputter.append(format!("s_{}_{}", fr, sc).as_str()),
HeapCellValue::Addr(Addr::Str(_)) => {} HeapCellValue::Addr(Addr::Str(_)) => {}
} }
} }
fn at_cdr(result: &mut String, tr: &str) -> bool { fn at_cdr(&mut self, tr: &str) -> bool {
let len = result.len(); let len = self.outputter.len();
if self.outputter.ends_with(" | ") {
self.outputter.truncate(len - 3);
self.outputter.append(tr);
if result.ends_with(" | ") {
result.truncate(len - 3);
*result += tr;
true true
} else { } else {
false false
} }
} }
pub fn print(&mut self) -> String { pub fn print(mut self) -> Outputter {
let mut result = String::new();
loop { loop {
if let Some(loc_data) = self.state_stack.pop() { if let Some(loc_data) = self.state_stack.pop() {
match loc_data { match loc_data {
TokenOrRedirect::Space => TokenOrRedirect::Space =>
result += " ", self.outputter.append(" "),
TokenOrRedirect::Atom(atom) => TokenOrRedirect::Atom(atom) =>
result += atom.as_str(), self.outputter.append(atom.as_str()),
TokenOrRedirect::Redirect => { TokenOrRedirect::Redirect => {
let heap_val = self.iter.next().unwrap(); let heap_val = self.iter.next().unwrap();
self.handle_heap_term(heap_val, &mut result); self.handle_heap_term(heap_val);
}, },
TokenOrRedirect::Close => TokenOrRedirect::Close =>
result += ")", self.outputter.append(")"),
TokenOrRedirect::Open => TokenOrRedirect::Open =>
result += "(", self.outputter.append("("),
TokenOrRedirect::OpenList(delimit) => TokenOrRedirect::OpenList(delimit) =>
if !Self::at_cdr(&mut result, ", ") { if !self.at_cdr(", ") {
result += "["; self.outputter.append("[");
} else { } else {
delimit.set(false); delimit.set(false);
}, },
TokenOrRedirect::CloseList(delimit) => TokenOrRedirect::CloseList(delimit) =>
if delimit.get() == true { if delimit.get() == true {
result += "]"; self.outputter.append("]");
}, },
TokenOrRedirect::HeadTailSeparator => TokenOrRedirect::HeadTailSeparator =>
result += " | ", self.outputter.append(" | "),
TokenOrRedirect::Comma => TokenOrRedirect::Comma =>
result += ", " self.outputter.append(", ")
} }
} else if let Some(heap_val) = self.iter.next() { } else if let Some(heap_val) = self.iter.next() {
self.handle_heap_term(heap_val, &mut result); self.handle_heap_term(heap_val);
} else { } else {
break; break;
} }
} }
result self.outputter
} }
} }

View File

@@ -1,6 +1,7 @@
use prolog::ast::*; use prolog::ast::*;
use prolog::codegen::*; use prolog::codegen::*;
use prolog::debray_allocator::*; use prolog::debray_allocator::*;
use prolog::heap_print::*;
use prolog::machine::*; use prolog::machine::*;
use termion::raw::IntoRawMode; use termion::raw::IntoRawMode;
@@ -440,7 +441,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
loop { loop {
let mut result = EvalSession::QueryFailure; let mut result = EvalSession::QueryFailure;
let bindings = wam.heap_view(&heap_locs); let bindings = wam.heap_view::<PrinterOutputter>(&heap_locs);
let stdin = stdin(); let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap(); let mut stdout = stdout().into_raw_mode().unwrap();

View File

@@ -256,25 +256,28 @@ impl MachineState {
self.trail(r1); self.trail(r1);
} }
fn print_var<Fmt>(&self, r: Ref, fmt: Fmt) -> String fn print_var<Fmt, Outputter>(&self, r: Ref, fmt: Fmt, output: Outputter) -> Outputter
where Fmt: HeapCellValueFormatter where Fmt: HeapCellValueFormatter, Outputter: HeapCellValueOutputter
{ {
let iter = HeapCellIterator::new(&self, r); let iter = HeapCellIterator::new(&self, r);
let mut printer = HeapCellPrinter::new(iter, fmt); let printer = HeapCellPrinter::new(iter, fmt, output);
printer.print() printer.print()
} }
pub(super) fn print_term<Fmt>(&self, addr: &Addr, fmt: Fmt) -> String pub(super) fn print_term<Fmt, Outputter>(&self, addr: &Addr, fmt: Fmt, mut output: Outputter)
where Fmt: HeapCellValueFormatter -> Outputter
where Fmt: HeapCellValueFormatter, Outputter: HeapCellValueOutputter
{ {
match addr { match addr {
&Addr::Con(ref c) => &Addr::Con(ref c) => {
format!("{}", c), output.append(format!("{}", c).as_str());
output
},
&Addr::Lis(h) | &Addr::HeapCell(h) | &Addr::Str(h) => &Addr::Lis(h) | &Addr::HeapCell(h) | &Addr::Str(h) =>
self.print_var(Ref::HeapCell(h), fmt), self.print_var(Ref::HeapCell(h), fmt, output),
&Addr::StackCell(fr, sc) => &Addr::StackCell(fr, sc) =>
self.print_var(Ref::StackCell(fr, sc), fmt) self.print_var(Ref::StackCell(fr, sc), fmt, output)
} }
} }
@@ -1520,15 +1523,21 @@ impl MachineState {
self.p += 1; self.p += 1;
}, },
&ControlInstruction::DisplayCall => { &ControlInstruction::DisplayCall => {
let result = self.print_term(&self[temp_v!(1)], DisplayFormatter {}); let output = self.print_term(&self[temp_v!(1)],
println!("{}", result); DisplayFormatter {},
PrinterOutputter::new());
println!("{}", output.result());
self.p += 1; self.p += 1;
}, },
&ControlInstruction::DisplayExecute => { &ControlInstruction::DisplayExecute => {
let result = self.print_term(&self[temp_v!(1)], DisplayFormatter {}); let output = self.print_term(&self[temp_v!(1)],
println!("{}", result); DisplayFormatter {},
PrinterOutputter::new());
println!("{}", output.result());
self.p = self.cp; self.p = self.cp;
}, },

View File

@@ -264,7 +264,10 @@ impl Machine {
let h = self.ms.heap.h; let h = self.ms.heap.h;
self.ms.copy_and_align_ball_to_heap(); self.ms.copy_and_align_ball_to_heap();
let msg = self.ms.print_term(&Addr::HeapCell(h), TermFormatter {}); let msg = self.ms.print_term(&Addr::HeapCell(h),
TermFormatter {},
PrinterOutputter::new())
.result();
EvalSession::QueryFailureWithException(msg) EvalSession::QueryFailureWithException(msg)
} else { } else {
@@ -346,21 +349,21 @@ impl Machine {
} }
} }
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String { pub fn heap_view<Outputter>(&self, var_dir: &HeapVarDict) -> Outputter::Output
let mut result = String::new(); where Outputter: HeapCellValueOutputter
{
let mut output = Outputter::new();
for (var, addr) in var_dir { for (var, addr) in var_dir {
if result != "" { output.begin_new_var();
result += "\n\r";
}
result += var.as_str();
result += " = ";
result += self.ms.print_term(addr, TermFormatter {}).as_str(); output.append(var.as_str());
output.append(" = ");
output = self.ms.print_term(addr, TermFormatter {}, output);
} }
result output.result()
} }
pub fn or_stack_is_empty(&self) -> bool { pub fn or_stack_is_empty(&self) -> bool {