track the parent operator of the current operator in heap_print to emit space if necessary (#1906)

This commit is contained in:
Mark
2023-07-24 20:05:28 -06:00
parent 762e6d3ba4
commit 287c308bc3
2 changed files with 84 additions and 61 deletions

View File

@@ -26,7 +26,6 @@ use std::cell::Cell;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::iter::once; use std::iter::once;
use std::net::{IpAddr, TcpListener}; use std::net::{IpAddr, TcpListener};
use std::ops::{Range, RangeFrom};
use std::rc::Rc; use std::rc::Rc;
/* contains the location, name, precision and Specifier of the parent op. */ /* contains the location, name, precision and Specifier of the parent op. */
@@ -64,11 +63,7 @@ impl DirectedOp {
#[inline] #[inline]
fn is_left(&self) -> bool { fn is_left(&self) -> bool {
if let &DirectedOp::Left(..) = self { matches!(self, DirectedOp::Left(..))
true
} else {
false
}
} }
} }
@@ -330,8 +325,7 @@ pub trait HCValueOutputter {
fn ends_with(&self, s: &str) -> bool; fn ends_with(&self, s: &str) -> bool;
fn len(&self) -> usize; fn len(&self) -> usize;
fn truncate(&mut self, len: usize); fn truncate(&mut self, len: usize);
fn range(&self, range: Range<usize>) -> &str; fn as_str(&self) -> &str;
fn range_from(&self, range: RangeFrom<usize>) -> &str;
} }
#[derive(Debug)] #[derive(Debug)]
@@ -386,12 +380,8 @@ impl HCValueOutputter for PrinterOutputter {
self.contents.truncate(len); self.contents.truncate(len);
} }
fn range(&self, index: Range<usize>) -> &str { fn as_str(&self) -> &str {
&self.contents.as_str()[index] &self.contents
}
fn range_from(&self, index: RangeFrom<usize>) -> &str {
&self.contents.as_str().get(index).unwrap_or("")
} }
} }
@@ -492,6 +482,8 @@ pub struct HCPrinter<'a, Outputter> {
state_stack: Vec<TokenOrRedirect>, state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>, toplevel_spec: Option<DirectedOp>,
last_item_idx: usize, last_item_idx: usize,
num_ops_on_stack: usize,
parent_of_first_op: Option<(DirectedOp, usize)>,
pub var_names: IndexMap<HeapCellValue, VarPtr>, pub var_names: IndexMap<HeapCellValue, VarPtr>,
pub numbervars_offset: Integer, pub numbervars_offset: Integer,
pub numbervars: bool, pub numbervars: bool,
@@ -567,6 +559,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
state_stack: vec![], state_stack: vec![],
toplevel_spec: None, toplevel_spec: None,
last_item_idx: 0, last_item_idx: 0,
num_ops_on_stack: 0,
parent_of_first_op: None,
numbervars: false, numbervars: false,
numbervars_offset: Integer::from(0), numbervars_offset: Integer::from(0),
quoted: false, quoted: false,
@@ -580,7 +574,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
#[inline] #[inline]
fn ambiguity_check(&self, atom: &str) -> bool { fn ambiguity_check(&self, atom: &str) -> bool {
let tail = self.outputter.range_from(self.last_item_idx..); let tail = &self.outputter.as_str()[self.last_item_idx..];
if !self.quoted || non_quoted_token(atom.chars()) { if !self.quoted || non_quoted_token(atom.chars()) {
requires_space(tail, atom) requires_space(tail, atom)
@@ -589,7 +583,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn enqueue_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) { fn set_parent_of_first_op(&mut self, parent_op: Option<DirectedOp>) {
self.parent_of_first_op = parent_op.map(|op| (op, self.last_item_idx));
}
fn enqueue_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc, parent_op: Option<DirectedOp>) {
if is_postfix!(spec.get_spec()) { if is_postfix!(spec.get_spec()) {
if self.max_depth_exhausted(max_depth) { if self.max_depth_exhausted(max_depth) {
self.iter.pop_stack(); self.iter.pop_stack();
@@ -600,17 +598,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
} else {
let right_directed_op = DirectedOp::Right(name, spec);
return; self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
));
} }
let right_directed_op = DirectedOp::Right(name, spec);
self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(
max_depth,
right_directed_op,
));
} else if is_prefix!(spec.get_spec()) { } else if is_prefix!(spec.get_spec()) {
if self.max_depth_exhausted(max_depth) { if self.max_depth_exhausted(max_depth) {
self.iter.pop_stack(); self.iter.pop_stack();
@@ -620,15 +616,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.iter.pop_stack(); self.iter.pop_stack();
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Op(name, spec));
} else {
let op = DirectedOp::Left(name, spec);
return; self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
self.state_stack.push(TokenOrRedirect::Op(name, spec));
} }
let op = DirectedOp::Left(name, spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
self.state_stack.push(TokenOrRedirect::Atom(name));
} else { } else {
match name.as_str() { match name.as_str() {
"|" => { "|" => {
@@ -638,15 +632,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
_ => {} _ => {}
}; };
let left_directed_op = DirectedOp::Left(name, spec);
let right_directed_op = DirectedOp::Right(name, spec);
if self.max_depth_exhausted(max_depth) { if self.max_depth_exhausted(max_depth) {
self.iter.pop_stack(); self.iter.pop_stack();
self.iter.pop_stack(); self.iter.pop_stack();
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
return; return;
} else if self.check_max_depth(&mut max_depth) { } else if self.check_max_depth(&mut max_depth) {
self.iter.pop_stack(); self.iter.pop_stack();
@@ -655,14 +645,21 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
} else {
let left_directed_op = DirectedOp::Left(name, spec);
let right_directed_op = DirectedOp::Right(name, spec);
return; self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, right_directed_op));
} }
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, left_directed_op));
self.state_stack.push(TokenOrRedirect::Op(name, spec));
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, right_directed_op));
} }
if self.num_ops_on_stack == 0 {
self.set_parent_of_first_op(parent_op);
}
self.num_ops_on_stack += 1;
} }
fn format_struct(&mut self, mut max_depth: usize, arity: usize, name: Atom) -> bool { fn format_struct(&mut self, mut max_depth: usize, arity: usize, name: Atom) -> bool {
@@ -776,6 +773,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
arity: usize, arity: usize,
name: Atom, name: Atom,
op_desc: Option<OpDesc>, op_desc: Option<OpDesc>,
parent_op: Option<DirectedOp>,
) -> bool { ) -> bool {
if self.numbervars && is_numbered_var(name, arity) { if self.numbervars && is_numbered_var(name, arity) {
if self.format_numbered_vars() { if self.format_numbered_vars() {
@@ -794,7 +792,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
if !self.ignore_ops && spec.get_prec() > 0 { if !self.ignore_ops && spec.get_prec() > 0 {
self.enqueue_op(max_depth, name, spec); self.enqueue_op(max_depth, name, spec, parent_op);
return true; return true;
} }
} }
@@ -976,7 +974,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}); });
} }
Number::Rational(r) => { Number::Rational(r) => {
self.print_rational(max_depth, r); self.print_rational(max_depth, r, *op);
} }
n => { n => {
let output_str = format!("{}", n); let output_str = format!("{}", n);
@@ -1007,7 +1005,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn print_rational(&mut self, mut max_depth: usize, r: TypedArenaPtr<Rational>) { fn print_rational(
&mut self,
mut max_depth: usize,
r: TypedArenaPtr<Rational>,
parent_op: Option<DirectedOp>,
) {
if self.check_max_depth(&mut max_depth) { if self.check_max_depth(&mut max_depth) {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
@@ -1050,15 +1053,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
NumberFocus::Denominator(r), NumberFocus::Denominator(r),
left_directed_op, left_directed_op,
)); ));
self.state_stack.push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
self.state_stack
.push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth, max_depth,
NumberFocus::Numerator(r), NumberFocus::Numerator(r),
right_directed_op, right_directed_op,
)); ));
self.num_ops_on_stack += 1;
self.set_parent_of_first_op(parent_op);
} else { } else {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
@@ -1347,7 +1350,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
&mut self, &mut self,
name: Atom, name: Atom,
arity: usize, arity: usize,
op: &Option<DirectedOp>, op: Option<DirectedOp>,
is_functor_redirect: bool, is_functor_redirect: bool,
op_desc: OpDesc, op_desc: OpDesc,
negated_operand: bool, negated_operand: bool,
@@ -1378,20 +1381,33 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if add_brackets { if add_brackets {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
} self.format_clause(max_depth, arity, name, Some(op_desc), op);
if self.format_clause(max_depth, arity, name, Some(op_desc)) && add_brackets {
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
if let Some(ref op) = &op { let parent_op = self.parent_of_first_op
if !self.outputter.ends_with(" ") { .and_then(|(parent_op, last_item_idx)| {
if op.is_left() { // if parent_op isn't printed to the output string
if op.is_prefix() || requires_space(op.as_atom().as_str(), "(") { // already, then it doesn't border the present op
// and we should return None.
if self.last_item_idx == last_item_idx {
Some(parent_op)
} else {
None
}
});
for op in &[op, parent_op] {
if let Some(ref op) = &op {
if !self.outputter.ends_with(" ") {
if op.is_left() && (op.is_prefix() || requires_space(op.as_atom().as_str(), "(")) {
self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Space);
break;
} }
} }
} }
} }
} else {
self.format_clause(max_depth, arity, name, Some(op_desc), op);
} }
} }
@@ -1500,7 +1516,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
printer.handle_op_as_struct( printer.handle_op_as_struct(
name, name,
arity, arity,
&op, op,
is_functor_redirect, is_functor_redirect,
spec, spec,
negated_operand, negated_operand,
@@ -1508,7 +1524,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
); );
} else { } else {
push_space_if_amb!(printer, name.as_str(), { push_space_if_amb!(printer, name.as_str(), {
printer.format_clause(max_depth, arity, name, None); printer.format_clause(max_depth, arity, name, None, op);
}); });
} }
} else if fetch_op_spec(name, arity, printer.op_dir).is_some() { } else if fetch_op_spec(name, arity, printer.op_dir).is_some() {
@@ -1566,7 +1582,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.handle_op_as_struct( self.handle_op_as_struct(
name, name,
arity, arity,
&op, op,
is_functor_redirect, is_functor_redirect,
spec, spec,
negated_operand, negated_operand,
@@ -1574,7 +1590,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
); );
} else { } else {
push_space_if_amb!(self, name.as_str(), { push_space_if_amb!(self, name.as_str(), {
self.format_clause(max_depth, arity, name, None); self.format_clause(max_depth, arity, name, None, op);
}); });
} }
} }
@@ -1655,7 +1671,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
TokenOrRedirect::Atom(atom) => self.print_impromptu_atom(atom), TokenOrRedirect::Atom(atom) => self.print_impromptu_atom(atom),
TokenOrRedirect::BarAsOp => append_str!(self, " | "), TokenOrRedirect::BarAsOp => append_str!(self, " | "),
TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c), TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c),
TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()), TokenOrRedirect::Op(atom, ..) => {
self.num_ops_on_stack -= 1;
self.parent_of_first_op = None;
self.print_op(atom.as_str());
}
TokenOrRedirect::NumberedVar(num_var) => append_str!(self, &num_var), TokenOrRedirect::NumberedVar(num_var) => append_str!(self, &num_var),
TokenOrRedirect::CompositeRedirect(max_depth, op) => { TokenOrRedirect::CompositeRedirect(max_depth, op) => {
self.handle_heap_term(Some(op), false, max_depth) self.handle_heap_term(Some(op), false, max_depth)

View File

@@ -998,6 +998,9 @@ test_310 :- test_syntax_error("writeq({\\+ (}).", syntax_error(incomplete_reduct
test_311 :- test_syntax_error("Finis ().", syntax_error(incomplete_reduction)). test_311 :- test_syntax_error("Finis ().", syntax_error(incomplete_reduction)).
test_318 :- writeq_term_to_chars(+((1*2)^3), C),
C == "+ (1*2)^3".
run_tests([Test|Tests]) --> run_tests([Test|Tests]) -->
( { call(Test) } -> ( { call(Test) } ->
[] []