add provisional max_depth option to write_term, speed printing of non-cyclic terms

This commit is contained in:
Mark Thom
2020-03-15 00:09:20 -06:00
parent 3620f72b6c
commit 325df8a6e3
6 changed files with 379 additions and 95 deletions

View File

@@ -29,3 +29,6 @@ prolog_parser = { version = "0.8.47", default-features = false }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
rug = { version = "1.4.0", optional = true } rug = { version = "1.4.0", optional = true }
rustyline = "6.0.0" rustyline = "6.0.0"
[profile.release]
debug = true

View File

@@ -535,7 +535,7 @@ impl SystemClauseType {
("$use_qualified_module_from_file", 2) => ("$use_qualified_module_from_file", 2) =>
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)), Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
("$variant", 2) => Some(SystemClauseType::Variant), ("$variant", 2) => Some(SystemClauseType::Variant),
("$write_term", 5) => Some(SystemClauseType::WriteTerm), ("$write_term", 6) => Some(SystemClauseType::WriteTerm),
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions), ("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
_ => None, _ => None,
} }

View File

@@ -159,21 +159,21 @@ fn char_to_string(is_quoted: bool, c: char) -> String {
} }
#[derive(Clone)] #[derive(Clone)]
pub enum TokenOrRedirect { enum TokenOrRedirect {
Atom(ClauseName), Atom(ClauseName),
BarAsOp, BarAsOp,
Op(ClauseName, SharedOpDesc), Op(ClauseName, SharedOpDesc),
NumberedVar(String), NumberedVar(String),
CompositeRedirect(DirectedOp), CompositeRedirect(usize, DirectedOp),
FunctorRedirect, FunctorRedirect(usize),
Open, Open,
Close, Close,
Comma, Comma,
Space, Space,
LeftCurly, LeftCurly,
RightCurly, RightCurly,
OpenList(Rc<Cell<bool>>), OpenList(Rc<Cell<(bool, usize)>>),
CloseList(Rc<Cell<bool>>), CloseList(Rc<Cell<(bool, usize)>>),
HeadTailSeparator, HeadTailSeparator,
} }
@@ -315,12 +315,14 @@ pub struct HCPrinter<'a, Outputter> {
printed_vars: IndexSet<Addr>, printed_vars: IndexSet<Addr>,
last_item_idx: usize, last_item_idx: usize,
cyclic_terms: IndexMap<Addr, usize>, cyclic_terms: IndexMap<Addr, usize>,
non_cyclic_terms: IndexSet<usize>,
pub(crate) var_names: IndexMap<Addr, Var>, pub(crate) var_names: IndexMap<Addr, Var>,
pub(crate) numbervars_offset: Integer, pub(crate) numbervars_offset: Integer,
pub(crate) numbervars: bool, pub(crate) numbervars: bool,
pub(crate) quoted: bool, pub(crate) quoted: bool,
pub(crate) ignore_ops: bool, pub(crate) ignore_ops: bool,
pub(crate) print_strings_as_strs: bool, pub(crate) print_strings_as_strs: bool,
pub(crate) max_depth: usize,
} }
macro_rules! push_space_if_amb { macro_rules! push_space_if_amb {
@@ -430,6 +432,18 @@ fn non_quoted_token<Iter: Iterator<Item = char>>(mut iter: Iter) -> bool {
} }
} }
#[inline]
fn functor_location(addr: &Addr) -> Option<usize> {
Some(match addr {
&Addr::Lis(l) => l,
&Addr::Str(s) => s,
&Addr::PStrLocation(h, _) | &Addr::PStrTail(h, _) => h,
_ => {
return None;
}
})
}
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
pub fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self { pub fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self {
HCPrinter { HCPrinter {
@@ -446,8 +460,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
quoted: false, quoted: false,
ignore_ops: false, ignore_ops: false,
cyclic_terms: IndexMap::new(), cyclic_terms: IndexMap::new(),
non_cyclic_terms: IndexSet::new(),
var_names: IndexMap::new(), var_names: IndexMap::new(),
print_strings_as_strs: false, print_strings_as_strs: false,
max_depth: 0,
} }
} }
@@ -485,53 +501,110 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
requires_space(tail, atom) requires_space(tail, atom)
} }
fn enqueue_op(&mut self, ct: ClauseType, spec: SharedOpDesc) { fn enqueue_op(
&mut self,
iter: &mut HCPreOrderIterator,
mut max_depth: usize,
ct: ClauseType,
spec: SharedOpDesc,
) {
if is_postfix!(spec.assoc()) { if is_postfix!(spec.assoc()) {
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
let right_directed_op = DirectedOp::Right(ct.name(), spec.clone()); let right_directed_op = DirectedOp::Right(ct.name(), spec.clone());
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
self.state_stack self.state_stack.push(TokenOrRedirect::CompositeRedirect(
.push(TokenOrRedirect::CompositeRedirect(right_directed_op)); max_depth,
right_directed_op,
));
} else if is_prefix!(spec.assoc()) { } else if is_prefix!(spec.assoc()) {
match ct.name().as_str() { match ct.name().as_str() {
"-" | "\\" => { "-" | "\\" => {
self.format_prefix_op_with_space(ct.name(), spec); self.format_prefix_op_with_space(iter, max_depth, ct.name(), spec);
return; return;
} }
_ => {} _ => {}
}; };
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
return;
}
let left_directed_op = DirectedOp::Left(ct.name(), spec.clone()); let left_directed_op = DirectedOp::Left(ct.name(), spec.clone());
self.state_stack self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
.push(TokenOrRedirect::CompositeRedirect(left_directed_op));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
} else { } else {
// if is_infix!(spec.assoc()) // if is_infix!(spec.assoc())
match ct.name().as_str() { match ct.name().as_str() {
"|" => { "|" => {
self.format_bar_separator_op(ct.name(), spec); self.format_bar_separator_op(iter, max_depth, ct.name(), spec);
return; return;
} }
_ => {} _ => {}
}; };
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
let left_directed_op = DirectedOp::Left(ct.name(), spec.clone()); let left_directed_op = DirectedOp::Left(ct.name(), spec.clone());
let right_directed_op = DirectedOp::Right(ct.name(), spec.clone()); let right_directed_op = DirectedOp::Right(ct.name(), spec.clone());
self.state_stack self.state_stack
.push(TokenOrRedirect::CompositeRedirect(left_directed_op)); .push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec));
self.state_stack self.state_stack
.push(TokenOrRedirect::CompositeRedirect(right_directed_op)); .push(TokenOrRedirect::CompositeRedirect(max_depth, right_directed_op));
} }
} }
fn format_struct(&mut self, arity: usize, name: ClauseName) { fn format_struct(
&mut self,
iter: &mut HCPreOrderIterator,
mut max_depth: usize,
arity: usize,
name: ClauseName,
) -> bool
{
if self.check_max_depth(&mut max_depth) {
for _ in 0 .. arity {
iter.stack().pop();
}
self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(name));
return false;
}
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
for _ in 0..arity { for _ in 0 .. arity {
self.state_stack.push(TokenOrRedirect::FunctorRedirect); self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
} }
@@ -539,29 +612,77 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Atom(name));
true
} }
fn format_prefix_op_with_space(&mut self, name: ClauseName, spec: SharedOpDesc) { fn format_prefix_op_with_space(
&mut self,
iter: &mut HCPreOrderIterator,
mut max_depth: usize,
name: ClauseName,
spec: SharedOpDesc)
{
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::Space);
self.state_stack.push(TokenOrRedirect::Atom(name));
return;
}
let op = DirectedOp::Left(name.clone(), spec); let op = DirectedOp::Left(name.clone(), spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(op)); self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Space);
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Atom(name));
} }
fn format_bar_separator_op(&mut self, name: ClauseName, spec: SharedOpDesc) { fn format_bar_separator_op(
&mut self,
iter: &mut HCPreOrderIterator,
mut max_depth: usize,
name: ClauseName,
spec: SharedOpDesc,
)
{
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::BarAsOp);
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
let left_directed_op = DirectedOp::Left(name.clone(), spec.clone()); let left_directed_op = DirectedOp::Left(name.clone(), spec.clone());
let right_directed_op = DirectedOp::Right(name.clone(), spec.clone()); let right_directed_op = DirectedOp::Right(name.clone(), spec.clone());
self.state_stack.push(TokenOrRedirect::CompositeRedirect(left_directed_op)); self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
self.state_stack.push(TokenOrRedirect::BarAsOp); self.state_stack.push(TokenOrRedirect::BarAsOp);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(right_directed_op)); self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, right_directed_op));
} }
fn format_curly_braces(&mut self) { fn format_curly_braces(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) -> bool
{
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
self.state_stack.push(TokenOrRedirect::RightCurly);
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::LeftCurly);
return false;
}
self.state_stack.push(TokenOrRedirect::RightCurly); self.state_stack.push(TokenOrRedirect::RightCurly);
self.state_stack.push(TokenOrRedirect::FunctorRedirect); self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::LeftCurly); self.state_stack.push(TokenOrRedirect::LeftCurly);
true
} }
fn format_numbered_vars(&mut self, iter: &mut HCPreOrderIterator) -> bool { fn format_numbered_vars(&mut self, iter: &mut HCPreOrderIterator) -> bool {
@@ -577,29 +698,36 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
false false
} }
fn format_clause(&mut self, iter: &mut HCPreOrderIterator, arity: usize, ct: ClauseType) { fn format_clause(
&mut self,
iter: &mut HCPreOrderIterator,
max_depth: usize,
arity: usize,
ct: ClauseType,
) -> bool {
if self.numbervars && is_numbered_var(&ct, arity) { if self.numbervars && is_numbered_var(&ct, arity) {
if self.format_numbered_vars(iter) { if self.format_numbered_vars(iter) {
return; return true;
} }
} }
if let Some(spec) = ct.spec() { if let Some(spec) = ct.spec() {
if "." == ct.name().as_str() && is_infix!(spec.assoc()) { if "." == ct.name().as_str() && is_infix!(spec.assoc()) {
if !self.ignore_ops { if !self.ignore_ops {
self.push_list(); self.push_list(iter, max_depth);
return; return true;
} }
} }
if !self.ignore_ops && spec.prec() > 0 { if !self.ignore_ops && spec.prec() > 0 {
return self.enqueue_op(ct, spec); self.enqueue_op(iter, max_depth, ct, spec);
return true;
} }
} }
match (ct.name().as_str(), arity) { return match (ct.name().as_str(), arity) {
("{}", 1) if !self.ignore_ops => self.format_curly_braces(), ("{}", 1) if !self.ignore_ops => self.format_curly_braces(iter, max_depth),
_ => self.format_struct(arity, ct.name()), _ => self.format_struct(iter, max_depth, arity, ct.name()),
}; };
} }
@@ -646,7 +774,60 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue> { fn record_children_as_non_cyclic(&mut self, addr: &Addr) {
match addr {
&Addr::Lis(l) => {
let c1 = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
let c2 = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l + 1)));
if let Some(c) = functor_location(&c1) {
self.non_cyclic_terms.insert(c);
}
if let Some(c) = functor_location(&c2) {
self.non_cyclic_terms.insert(c);
}
}
&Addr::Str(s) => {
let arity =
match &self.machine_st.heap[s] {
HeapCellValue::NamedStr(arity, ..) => {
arity
}
_ => {
unreachable!()
}
};
for i in 1 .. arity + 1 {
let c = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(s + i)));
if let Some(c) = functor_location(&c) {
self.non_cyclic_terms.insert(c);
}
}
}
&Addr::PStrLocation(h, _) | &Addr::PStrTail(h, _) => {
let tail = match &self.machine_st.heap[h] {
&HeapCellValue::PartialString(ref pstr) => pstr.tail_addr().clone(),
_ => unreachable!()
};
let tail = self.machine_st.store(self.machine_st.deref(tail));
if let Some(c) = functor_location(&tail) {
self.non_cyclic_terms.insert(c);
}
}
_ => {
}
}
}
fn check_for_seen(
&mut self,
iter: &mut HCPreOrderIterator,
) -> Option<HeapCellValue> {
iter.stack().last().cloned().and_then(|addr| { iter.stack().last().cloned().and_then(|addr| {
let addr = self.machine_st.store(self.machine_st.deref(addr)); let addr = self.machine_st.store(self.machine_st.deref(addr));
@@ -661,6 +842,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
return iter.next(); return iter.next();
} else { } else {
iter.stack().pop(); iter.stack().pop();
push_space_if_amb!(self, &var, { push_space_if_amb!(self, &var, {
self.append_str(&var); self.append_str(&var);
}); });
@@ -669,30 +851,38 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
None => { None => {
if self.machine_st.is_cyclic_term(addr.clone()) { let offset = match functor_location(&addr) {
match self.cyclic_terms.get(&addr).cloned() { Some(offset) => offset,
Some(reps) => { None => {
if reps > 0 { return iter.next();
self.cyclic_terms.insert(addr, reps - 1); }
iter.next() };
} else {
push_space_if_amb!(self, "...", {
self.append_str("...");
});
iter.stack().pop(); if !self.non_cyclic_terms.contains(&offset) {
self.cyclic_terms.swap_remove(&addr); if let Some(reps) = self.cyclic_terms.get(&addr).cloned() {
None if reps > 0 {
} self.cyclic_terms.insert(addr, reps - 1);
} } else {
None => { push_space_if_amb!(self, "...", {
self.append_str("...");
});
iter.stack().pop();
self.cyclic_terms.insert(addr, 2); self.cyclic_terms.insert(addr, 2);
iter.next()
return None;
} }
} else if self.machine_st.is_cyclic_term(addr.clone()) {
self.cyclic_terms.insert(addr, 2);
} else {
self.record_children_as_non_cyclic(&addr);
self.non_cyclic_terms.insert(offset);
} }
} else { } else {
iter.next() self.record_children_as_non_cyclic(&addr);
} }
iter.next()
} }
} }
}) })
@@ -807,8 +997,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn print_constant(&mut self, iter: &mut HCPreOrderIterator, c: Constant, op: &Option<DirectedOp>) fn print_constant(
{ &mut self,
iter: &mut HCPreOrderIterator,
max_depth: usize,
c: Constant,
op: &Option<DirectedOp>,
) {
match c { match c {
Constant::Atom(atom, spec) => { Constant::Atom(atom, spec) => {
if let Some(_) = fetch_atom_op_spec(atom.clone(), spec, self.op_dir) { if let Some(_) = fetch_atom_op_spec(atom.clone(), spec, self.op_dir) {
@@ -862,7 +1057,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.print_string_as_str(iter, n, s); self.print_string_as_str(iter, n, s);
} }
Constant::String(n, s) => { Constant::String(n, s) => {
self.print_string(iter, n, s); self.print_string(iter, max_depth, n, s);
} }
Constant::Usize(i) => { Constant::Usize(i) => {
self.append_str(&format!("u{}", i)); self.append_str(&format!("u{}", i));
@@ -891,39 +1086,77 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
iter.stack().pop(); iter.stack().pop();
} }
fn print_string(&mut self, iter: &mut HCPreOrderIterator, offset: usize, s: Rc<String>) { fn print_string(
&mut self,
iter: &mut HCPreOrderIterator,
mut max_depth: usize,
offset: usize,
s: Rc<String>)
{
if !self.machine_st.machine_flags().double_quotes.is_atom() { if !self.machine_st.machine_flags().double_quotes.is_atom() {
if self.check_max_depth(&mut max_depth) {
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
return;
}
if s.len() <= offset && !self.at_cdr("") { if s.len() <= offset && !self.at_cdr("") {
self.append_str("[]"); self.append_str("[]");
} else if self.ignore_ops { } else if self.ignore_ops {
let mut paren_count = 0; let mut char_count = 0;
let mut byte_len = 0;
for c in s[offset ..].chars() { let iter: Box<dyn Iterator<Item=char>> =
if self.max_depth == 0 {
Box::new(s[offset ..].chars())
} else {
Box::new(s[offset ..].chars().take(max_depth))
};
for c in iter {
self.print_char('.'); self.print_char('.');
self.push_char('('); self.push_char('(');
self.print_char(c); self.print_char(c);
self.push_char(','); self.push_char(',');
paren_count += 1; char_count += 1;
byte_len += c.len_utf8();
} }
self.append_str("[]"); if self.max_depth > 0 && byte_len < s[offset ..].len() {
self.append_str("...");
} else {
self.append_str("[]");
}
for _ in 0 .. paren_count { for _ in 0 .. char_count {
self.push_char(')'); self.push_char(')');
} }
} else { } else {
self.push_char('['); self.push_char('[');
for c in s[offset ..].chars() { let iter: Box<dyn Iterator<Item=char>> =
if self.max_depth == 0 {
Box::new(s[offset ..].chars())
} else {
Box::new(s[offset ..].chars().take(max_depth))
};
let mut byte_len = 0;
for c in iter {
self.print_char(c); self.print_char(c);
self.push_char(','); self.push_char(',');
byte_len += c.len_utf8();
} }
self.outputter.truncate(self.outputter.len() - ','.len_utf8()); if self.max_depth > 0 && byte_len < s[offset ..].len() {
self.append_str("...|...]");
self.push_char(']'); } else {
self.outputter.truncate(self.outputter.len() - ','.len_utf8());
self.push_char(']');
}
} }
iter.stack().pop(); iter.stack().pop();
@@ -939,15 +1172,43 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn push_list(&mut self) { fn check_max_depth(&mut self, max_depth: &mut usize) -> bool {
let cell = Rc::new(Cell::new(true)); if self.max_depth > 0 && *max_depth == 0 {
return true;
}
self.state_stack if *max_depth > 0 {
.push(TokenOrRedirect::CloseList(cell.clone())); *max_depth -= 1;
}
self.state_stack.push(TokenOrRedirect::FunctorRedirect); false
}
fn push_list(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) {
if self.check_max_depth(&mut max_depth) {
iter.stack().pop();
iter.stack().pop();
let cell = Rc::new(Cell::new((true, 0)));
self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("...")));
self.state_stack.push(TokenOrRedirect::OpenList(cell));
return;
}
let cell = Rc::new(Cell::new((true, max_depth)));
self.state_stack.push(TokenOrRedirect::CloseList(cell.clone()));
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar
self.state_stack.push(TokenOrRedirect::FunctorRedirect); self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::OpenList(cell)); self.state_stack.push(TokenOrRedirect::OpenList(cell));
} }
@@ -961,6 +1222,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
is_functor_redirect: bool, is_functor_redirect: bool,
spec: SharedOpDesc, spec: SharedOpDesc,
negated_operand: bool, negated_operand: bool,
max_depth: usize,
) { ) {
let add_brackets = if !self.ignore_ops { let add_brackets = if !self.ignore_ops {
negated_operand negated_operand
@@ -987,14 +1249,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
let ct = ClauseType::from(name.clone(), arity, Some(spec)); let ct = ClauseType::from(name.clone(), arity, Some(spec));
self.format_clause(iter, arity, ct);
if add_brackets { if self.format_clause(iter, max_depth, arity, ct) {
self.state_stack.push(TokenOrRedirect::Open); if add_brackets {
self.state_stack.push(TokenOrRedirect::Open);
if let Some(ref op) = &op { if let Some(ref op) = &op {
if op.is_left() && requires_space(op.as_str(), "(") { if op.is_left() && requires_space(op.as_str(), "(") {
self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Space);
}
} }
} }
} }
@@ -1005,6 +1268,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
iter: &mut HCPreOrderIterator, iter: &mut HCPreOrderIterator,
op: Option<DirectedOp>, op: Option<DirectedOp>,
is_functor_redirect: bool, is_functor_redirect: bool,
max_depth: usize,
) { ) {
let negated_operand = negated_op_needs_bracketing(iter, &op); let negated_operand = negated_op_needs_bracketing(iter, &op);
@@ -1026,11 +1290,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
is_functor_redirect, is_functor_redirect,
spec, spec,
negated_operand, negated_operand,
max_depth,
); );
} else { } else {
push_space_if_amb!(self, name.as_str(), { push_space_if_amb!(self, name.as_str(), {
let ct = ClauseType::from(name, arity, spec); let ct = ClauseType::from(name, arity, spec);
self.format_clause(iter, arity, ct); self.format_clause(iter, max_depth, arity, ct);
}); });
} }
} }
@@ -1039,12 +1304,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.append_str("[]"); self.append_str("[]");
} }
} }
HeapCellValue::Addr(Addr::Con(c)) => self.print_constant(iter, c, &op), HeapCellValue::Addr(Addr::Con(c)) => {
self.print_constant(iter, max_depth, c, &op);
}
HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => { HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => {
if self.ignore_ops { if self.ignore_ops {
self.format_struct(2, clause_name!(".")); self.format_struct(iter, max_depth, 2, clause_name!("."));
} else { } else {
self.push_list(); self.push_list(iter, max_depth);
} }
} }
HeapCellValue::Addr(Addr::Stream(stream)) => { HeapCellValue::Addr(Addr::Stream(stream)) => {
@@ -1099,11 +1366,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
TokenOrRedirect::BarAsOp => self.append_str(" | "), TokenOrRedirect::BarAsOp => self.append_str(" | "),
TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()), TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()),
TokenOrRedirect::NumberedVar(num_var) => self.append_str(num_var.as_str()), TokenOrRedirect::NumberedVar(num_var) => self.append_str(num_var.as_str()),
TokenOrRedirect::CompositeRedirect(op) => { TokenOrRedirect::CompositeRedirect(max_depth, op) => {
self.handle_heap_term(&mut iter, Some(op), false) self.handle_heap_term(&mut iter, Some(op), false, max_depth)
} }
TokenOrRedirect::FunctorRedirect => { TokenOrRedirect::FunctorRedirect(max_depth) => {
self.handle_heap_term(&mut iter, None, true) self.handle_heap_term(&mut iter, None, true, max_depth)
} }
TokenOrRedirect::Close => self.push_char(')'), TokenOrRedirect::Close => self.push_char(')'),
TokenOrRedirect::Open => self.push_char('('), TokenOrRedirect::Open => self.push_char('('),
@@ -1111,11 +1378,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if !self.at_cdr(",") { if !self.at_cdr(",") {
self.push_char('['); self.push_char('[');
} else { } else {
delimit.set(false); let (_, max_depth) = delimit.get();
delimit.set((false, max_depth));
} }
} }
TokenOrRedirect::CloseList(delimit) => { TokenOrRedirect::CloseList(delimit) => {
if delimit.get() { if delimit.get().0 {
self.push_char(']'); self.push_char(']');
} }
} }
@@ -1127,7 +1395,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} else if !iter.stack().is_empty() { } else if !iter.stack().is_empty() {
let spec = self.toplevel_spec.take(); let spec = self.toplevel_spec.take();
self.handle_heap_term(&mut iter, spec, false); self.handle_heap_term(&mut iter, spec, false, self.max_depth);
} else { } else {
break; break;
} }

View File

@@ -289,6 +289,7 @@ is_write_option(Functor) :-
( Arg == true -> true ( Arg == true -> true
; Arg == false -> true ; Arg == false -> true
; Name == variable_names -> must_be_var_names_list(Arg) ; Name == variable_names -> must_be_var_names_list(Arg)
; Name == max_depth -> integer(Arg), Arg >= 0
; var(Arg) -> throw(error(instantiation_error, write_term/2)) ; var(Arg) -> throw(error(instantiation_error, write_term/2))
; throw(error(domain_error(write_option, Functor), write_term/2)) ; throw(error(domain_error(write_option, Functor), write_term/2))
), % 8.14.2.3 e) ), % 8.14.2.3 e)
@@ -296,6 +297,7 @@ is_write_option(Functor) :-
; Name == quoted -> true ; Name == quoted -> true
; Name == numbervars -> true ; Name == numbervars -> true
; Name == variable_names -> true ; Name == variable_names -> true
; Name == max_depth -> true
; throw(error(domain_error(write_option, Functor), write_term/2)) ; throw(error(domain_error(write_option, Functor), write_term/2))
). % 8.14.2.3 e) ). % 8.14.2.3 e)
@@ -338,7 +340,8 @@ write_term(Term, Options) :-
inst_member_or(Options, numbervars(NumberVars), numbervars(false)), inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
inst_member_or(Options, quoted(Quoted), quoted(false)), inst_member_or(Options, quoted(Quoted), quoted(false)),
inst_member_or(Options, variable_names(VarNames), variable_names([])), inst_member_or(Options, variable_names(VarNames), variable_names([])),
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames). inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth).
write(Term) :- write_term(Term, [numbervars(true)]). write(Term) :- write_term(Term, [numbervars(true)]).

View File

@@ -2667,6 +2667,7 @@ impl MachineState {
let ignore_ops = self.store(self.deref(self[temp_v!(2)].clone())); let ignore_ops = self.store(self.deref(self[temp_v!(2)].clone()));
let numbervars = self.store(self.deref(self[temp_v!(3)].clone())); let numbervars = self.store(self.deref(self[temp_v!(3)].clone()));
let quoted = self.store(self.deref(self[temp_v!(4)].clone())); let quoted = self.store(self.deref(self[temp_v!(4)].clone()));
let max_depth = self.store(self.deref(self[temp_v!(6)].clone()));
let mut printer = HCPrinter::new(&self, &indices.op_dir, PrinterOutputter::new()); let mut printer = HCPrinter::new(&self, &indices.op_dir, PrinterOutputter::new());
@@ -2682,6 +2683,15 @@ impl MachineState {
printer.quoted = name.as_str() == "true"; printer.quoted = name.as_str() == "true";
} }
if let &Addr::Con(Constant::Integer(ref n)) = &max_depth {
if let Some(n) = n.to_usize() {
printer.max_depth = n;
} else {
self.fail = true;
return Ok(());
}
}
let stub = MachineError::functor_stub(clause_name!("write_term"), 2); let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
match self.try_from_list(temp_v!(5), stub.clone()) { match self.try_from_list(temp_v!(5), stub.clone()) {

View File

@@ -114,9 +114,9 @@
write(' = '), write(' = '),
( '$needs_bracketing'(Value, (=)) -> ( '$needs_bracketing'(Value, (=)) ->
write('('), write('('),
write_term(Value, [quoted(true), variable_names(VarList)]), write_term(Value, [quoted(true), variable_names(VarList), max_depth(0)]),
write(')') write(')')
; write_term(Value, [quoted(true), variable_names(VarList)]) ; write_term(Value, [quoted(true), variable_names(VarList), max_depth(0)])
) )
; G == [] -> ; G == [] ->
write('true') write('true')
@@ -129,9 +129,9 @@
write(' = '), write(' = '),
( '$needs_bracketing'(Value, (=)) -> ( '$needs_bracketing'(Value, (=)) ->
write('('), write('('),
write_term(Value, [quoted(true), variable_names(VarList)]), write_term(Value, [quoted(true), variable_names(VarList), max_depth(0)]),
write(')') write(')')
; write_term(Value, [quoted(true), variable_names(VarList)]), ; write_term(Value, [quoted(true), variable_names(VarList), max_depth(0)]),
( '$trailing_period_is_ambiguous'(Value) -> ( '$trailing_period_is_ambiguous'(Value) ->
write(' ') write(' ')
; true ; true
@@ -139,7 +139,7 @@
) )
; G == [] -> ; G == [] ->
write('true') write('true')
; write_term(G, [quoted(true), variable_names(VarList)]) ; write_term(G, [quoted(true), variable_names(VarList), max_depth(0)])
). ).
'$write_eq'((G1, G2), VarList) :- '$write_eq'((G1, G2), VarList) :-
@@ -215,7 +215,7 @@
). ).
'$print_exception'(E) :- '$print_exception'(E) :-
write_term('caught: ', [quoted(false)]), write_term('caught: ', [quoted(false), max_depth(20)]),
writeq(E), writeq(E),
nl. nl.