add spaces between operators when there is an ambiguity
This commit is contained in:
@@ -11,12 +11,18 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum DirectedOp {
|
||||||
|
Left(ClauseName),
|
||||||
|
Right(ClauseName)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum TokenOrRedirect {
|
pub enum TokenOrRedirect {
|
||||||
Atom(ClauseName),
|
Atom(ClauseName),
|
||||||
Op(ClauseName),
|
Op(ClauseName, Fixity),
|
||||||
NumberedVar(String),
|
NumberedVar(String),
|
||||||
CompositeRedirect,
|
CompositeRedirect(DirectedOp),
|
||||||
Redirect,
|
Redirect,
|
||||||
Open,
|
Open,
|
||||||
Close,
|
Close,
|
||||||
@@ -141,17 +147,17 @@ impl MachineState {
|
|||||||
fn print_op(ct: ClauseType, fixity: Fixity, state_stack: &mut Vec<TokenOrRedirect>) {
|
fn print_op(ct: ClauseType, fixity: Fixity, state_stack: &mut Vec<TokenOrRedirect>) {
|
||||||
match fixity {
|
match fixity {
|
||||||
Fixity::Post => {
|
Fixity::Post => {
|
||||||
state_stack.push(TokenOrRedirect::Op(ct.name()));
|
state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
|
||||||
state_stack.push(TokenOrRedirect::CompositeRedirect);
|
state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Right(ct.name())));
|
||||||
},
|
},
|
||||||
Fixity::Pre => {
|
Fixity::Pre => {
|
||||||
state_stack.push(TokenOrRedirect::CompositeRedirect);
|
state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Left(ct.name())));
|
||||||
state_stack.push(TokenOrRedirect::Op(ct.name()));
|
state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
|
||||||
},
|
},
|
||||||
Fixity::In => {
|
Fixity::In => {
|
||||||
state_stack.push(TokenOrRedirect::CompositeRedirect);
|
state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Left(ct.name())));
|
||||||
state_stack.push(TokenOrRedirect::Op(ct.name()));
|
state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
|
||||||
state_stack.push(TokenOrRedirect::CompositeRedirect);
|
state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Right(ct.name())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,6 +208,56 @@ pub struct HCPrinter<'a, Formatter, Outputter> {
|
|||||||
printed_vars: HashSet<Addr>
|
printed_vars: HashSet<Addr>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum TrailingType {
|
||||||
|
Atom, Var
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! push_space_if_amb {
|
||||||
|
($self:expr, $atom:expr, $tt:expr, $op:expr, $action:block) => (
|
||||||
|
match $self.ambiguity_check($atom, $tt, $op) {
|
||||||
|
Some(DirectedOp::Left(_)) => {
|
||||||
|
$self.outputter.push_char(' ');
|
||||||
|
$action;
|
||||||
|
},
|
||||||
|
Some(DirectedOp::Right(_)) => {
|
||||||
|
$action;
|
||||||
|
$self.outputter.push_char(' ');
|
||||||
|
},
|
||||||
|
None => $action
|
||||||
|
};
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn continues_with_append(atom: &str, tt: TrailingType, op: &str) -> bool {
|
||||||
|
match tt {
|
||||||
|
TrailingType::Atom => match atom.chars().next() {
|
||||||
|
Some(ac) => op.chars().next().map(|oc| {
|
||||||
|
if alpha_char!(ac) {
|
||||||
|
alpha_numeric_char!(oc)
|
||||||
|
} else if graphic_token_char!(ac) {
|
||||||
|
graphic_char!(oc)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}).unwrap_or(false),
|
||||||
|
None => false,
|
||||||
|
},
|
||||||
|
TrailingType::Var => match atom.chars().next() {
|
||||||
|
Some(ac) => op.chars().next().map(|oc| {
|
||||||
|
if variable_indicator_char!(ac) {
|
||||||
|
alpha_numeric_char!(oc)
|
||||||
|
} else if capital_letter_char!(ac) {
|
||||||
|
alpha_numeric_char!(oc)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}).unwrap_or(false),
|
||||||
|
None => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn reverse_heap_locs<'a>(machine_st: &'a MachineState, heap_locs: &'a HeapVarDict)
|
fn reverse_heap_locs<'a>(machine_st: &'a MachineState, heap_locs: &'a HeapVarDict)
|
||||||
-> ReverseHeapVarDict<'a>
|
-> ReverseHeapVarDict<'a>
|
||||||
{
|
{
|
||||||
@@ -287,16 +343,29 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) =>
|
Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) =>
|
||||||
Some(format!("_{}", h)),
|
Some(format!("_{}", h)),
|
||||||
Addr::StackCell(fr, sc) =>
|
Addr::StackCell(fr, sc) =>
|
||||||
Some(format!("s_{}_{}", fr, sc)),
|
Some(format!("_s_{}_{}", fr, sc)),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_offset(&mut self, addr: Addr) {
|
// return op itself if there is an ambiguity to indicate the direction the op
|
||||||
self.offset_as_string(addr).map(|s| self.outputter.append(s.as_str()));
|
// lies, None otherwise.
|
||||||
|
fn ambiguity_check(&mut self, atom: &str, tt: TrailingType, op: &Option<DirectedOp>)
|
||||||
|
-> Option<DirectedOp>
|
||||||
|
{
|
||||||
|
match op {
|
||||||
|
&Some(DirectedOp::Left(ref lop)) if continues_with_append(lop.as_str(), tt, atom) =>
|
||||||
|
Some(DirectedOp::Left(lop.clone())),
|
||||||
|
&Some(DirectedOp::Right(ref rop)) if continues_with_append(atom, tt, rop.as_str()) =>
|
||||||
|
Some(DirectedOp::Right(rop.clone())),
|
||||||
|
_ =>
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue> {
|
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator, op: &Option<DirectedOp>)
|
||||||
|
-> 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));
|
||||||
|
|
||||||
@@ -306,14 +375,21 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
return iter.next();
|
return iter.next();
|
||||||
} else {
|
} else {
|
||||||
iter.stack().pop();
|
iter.stack().pop();
|
||||||
self.outputter.append(var.as_str());
|
push_space_if_amb!(self, &var, TrailingType::Var, op, {
|
||||||
|
self.outputter.append(&var);
|
||||||
|
});
|
||||||
|
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
None => if self.machine_st.is_cyclic_term(addr.clone()) {
|
None => if self.machine_st.is_cyclic_term(addr.clone()) {
|
||||||
if self.printed_vars.contains(&addr) {
|
if self.printed_vars.contains(&addr) {
|
||||||
iter.stack().pop();
|
iter.stack().pop();
|
||||||
self.print_offset(addr);
|
|
||||||
|
if let Some(offset_str) = self.offset_as_string(addr) {
|
||||||
|
push_space_if_amb!(self, &offset_str, TrailingType::Var, op, {
|
||||||
|
self.outputter.append(offset_str.as_str());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -332,12 +408,12 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_atom(&mut self, atom: &ClauseName, is_op: bool) {
|
fn print_atom(&mut self, atom: &ClauseName, fixity: Option<Fixity>) {
|
||||||
match atom.as_str() {
|
match atom.as_str() {
|
||||||
"" => self.outputter.append("''"),
|
"" => self.outputter.append("''"),
|
||||||
";" | "!" => self.outputter.append(atom.as_str()),
|
";" | "!" => self.outputter.append(atom.as_str()),
|
||||||
s => if is_op || non_quoted_token(s.chars()) {
|
s => if fixity.is_some() || non_quoted_token(s.chars()) {
|
||||||
self.outputter.append(atom.as_str());
|
self.outputter.append(atom.as_str())
|
||||||
} else {
|
} else {
|
||||||
self.outputter.push_char('\'');
|
self.outputter.push_char('\'');
|
||||||
|
|
||||||
@@ -363,22 +439,24 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_constant(&mut self, c: Constant, composite_brackets: bool) {
|
fn print_constant(&mut self, c: Constant, op: &Option<DirectedOp>) {
|
||||||
match c {
|
match c {
|
||||||
Constant::Atom(ref atom, Some(_)) => {
|
Constant::Atom(ref atom, Some(fixity)) => {
|
||||||
if composite_brackets {
|
if op.is_some() {
|
||||||
self.outputter.push_char('(');
|
self.outputter.push_char('(');
|
||||||
}
|
}
|
||||||
|
|
||||||
self.print_atom(atom, true);
|
self.print_atom(atom, Some(fixity));
|
||||||
|
|
||||||
if composite_brackets {
|
if op.is_some() {
|
||||||
self.outputter.push_char(')');
|
self.outputter.push_char(')');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Constant::Atom(ref atom, _) =>
|
Constant::Atom(ref atom, None) =>
|
||||||
self.print_atom(atom, false),
|
push_space_if_amb!(self, atom.as_str(), TrailingType::Atom, &op, {
|
||||||
Constant::Char(c) if non_quoted_token(once(c)) =>
|
self.print_atom(atom, None);
|
||||||
|
}),
|
||||||
|
Constant::Char(c) if non_quoted_token(once(c)) =>
|
||||||
self.print_char(c),
|
self.print_char(c),
|
||||||
Constant::Char(c) => {
|
Constant::Char(c) => {
|
||||||
self.outputter.push_char('\'');
|
self.outputter.push_char('\'');
|
||||||
@@ -389,12 +467,23 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
self.outputter.append("[]"),
|
self.outputter.append("[]"),
|
||||||
Constant::Number(Number::Float(fl)) =>
|
Constant::Number(Number::Float(fl)) =>
|
||||||
if &fl == &OrderedFloat(0f64) {
|
if &fl == &OrderedFloat(0f64) {
|
||||||
self.outputter.append("0");
|
push_space_if_amb!(self, "0", TrailingType::Atom, &op, {
|
||||||
|
self.outputter.append("0");
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
self.outputter.append(&format!("{}", fl));
|
let output_str = format!("{}", fl);
|
||||||
|
|
||||||
|
push_space_if_amb!(self, &output_str, TrailingType::Atom, &op, {
|
||||||
|
self.outputter.append(&output_str);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
Constant::Number(n) =>
|
Constant::Number(n) => {
|
||||||
self.outputter.append(&format!("{}", n)),
|
let output_str = format!("{}", n);
|
||||||
|
|
||||||
|
push_space_if_amb!(self, &output_str, TrailingType::Atom, &op, {
|
||||||
|
self.outputter.append(&output_str);
|
||||||
|
});
|
||||||
|
},
|
||||||
Constant::String(s) =>
|
Constant::String(s) =>
|
||||||
if self.machine_st.machine_flags().double_quotes.is_chars() {
|
if self.machine_st.machine_flags().double_quotes.is_chars() {
|
||||||
if !s.is_empty() {
|
if !s.is_empty() {
|
||||||
@@ -430,23 +519,23 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
self.state_stack.push(TokenOrRedirect::OpenList(cell));
|
self.state_stack.push(TokenOrRedirect::OpenList(cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator, composite_brackets: bool)
|
fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator, op: Option<DirectedOp>)
|
||||||
{
|
{
|
||||||
let heap_val = match self.check_for_seen(iter) {
|
let heap_val = match self.check_for_seen(iter, &op) {
|
||||||
Some(heap_val) => heap_val,
|
Some(heap_val) => heap_val,
|
||||||
_ => return
|
None => return
|
||||||
};
|
};
|
||||||
|
|
||||||
match heap_val {
|
match heap_val {
|
||||||
HeapCellValue::NamedStr(arity, ref name, Some(fixity)) if name.as_str() != "," => {
|
HeapCellValue::NamedStr(arity, ref name, Some(fixity)) if name.as_str() != "," => {
|
||||||
if composite_brackets {
|
if op.is_some() {
|
||||||
self.state_stack.push(TokenOrRedirect::Close);
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ct = ClauseType::from(name.clone(), arity, Some(fixity));
|
let ct = ClauseType::from(name.clone(), arity, Some(fixity));
|
||||||
self.formatter.format_clause(iter, arity, ct, &mut self.state_stack);
|
self.formatter.format_clause(iter, arity, ct, &mut self.state_stack);
|
||||||
|
|
||||||
if composite_brackets {
|
if op.is_some() {
|
||||||
self.state_stack.push(TokenOrRedirect::Open);
|
self.state_stack.push(TokenOrRedirect::Open);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -459,10 +548,15 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
self.outputter.append("[]");
|
self.outputter.append("[]");
|
||||||
},
|
},
|
||||||
HeapCellValue::Addr(Addr::Con(c)) =>
|
HeapCellValue::Addr(Addr::Con(c)) =>
|
||||||
self.print_constant(c, composite_brackets),
|
self.print_constant(c, &op),
|
||||||
HeapCellValue::Addr(Addr::Lis(_)) =>
|
HeapCellValue::Addr(Addr::Lis(_)) =>
|
||||||
self.push_list(),
|
self.push_list(),
|
||||||
HeapCellValue::Addr(addr) => self.print_offset(addr)
|
HeapCellValue::Addr(addr) =>
|
||||||
|
if let Some(offset_str) = self.offset_as_string(addr) {
|
||||||
|
push_space_if_amb!(self, &offset_str, TrailingType::Var, &op, {
|
||||||
|
self.outputter.append(offset_str.as_str());
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,15 +580,15 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
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::Atom(atom) =>
|
TokenOrRedirect::Atom(atom) =>
|
||||||
self.print_atom(&atom, false),
|
self.print_atom(&atom, None),
|
||||||
TokenOrRedirect::Op(atom) =>
|
TokenOrRedirect::Op(atom, fixity) =>
|
||||||
self.print_atom(&atom, true),
|
self.print_atom(&atom, Some(fixity)),
|
||||||
TokenOrRedirect::NumberedVar(num_var) =>
|
TokenOrRedirect::NumberedVar(num_var) =>
|
||||||
self.outputter.append(num_var.as_str()),
|
self.outputter.append(num_var.as_str()),
|
||||||
TokenOrRedirect::CompositeRedirect =>
|
TokenOrRedirect::CompositeRedirect(op) =>
|
||||||
self.handle_heap_term(&mut iter, true),
|
self.handle_heap_term(&mut iter, Some(op)),
|
||||||
TokenOrRedirect::Redirect =>
|
TokenOrRedirect::Redirect =>
|
||||||
self.handle_heap_term(&mut iter, false),
|
self.handle_heap_term(&mut iter, None),
|
||||||
TokenOrRedirect::Close =>
|
TokenOrRedirect::Close =>
|
||||||
self.outputter.append(")"),
|
self.outputter.append(")"),
|
||||||
TokenOrRedirect::Open =>
|
TokenOrRedirect::Open =>
|
||||||
@@ -515,7 +609,7 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
|||||||
self.outputter.append(", ")
|
self.outputter.append(", ")
|
||||||
}
|
}
|
||||||
} else if !iter.stack().is_empty() {
|
} else if !iter.stack().is_empty() {
|
||||||
self.handle_heap_term(&mut iter, false);
|
self.handle_heap_term(&mut iter, None);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ term_expansion(Term0, (ModHead :- ModBody)) :-
|
|||||||
append(Args, ['$VAR'(0), '$VAR'(N)], ModArgs),
|
append(Args, ['$VAR'(0), '$VAR'(N)], ModArgs),
|
||||||
ModHead =.. [RuleName | ModArgs],
|
ModHead =.. [RuleName | ModArgs],
|
||||||
nonvar(Body),
|
nonvar(Body),
|
||||||
expand_body(Body, ModBody, 0, N).
|
expand_body(Body, ModBody, 0, N),
|
||||||
|
writeq((ModHead :- ModBody)).
|
||||||
|
|
||||||
expand_body((Term, Terms), (ModTerm, ModTerms), N0, N) :-
|
expand_body((Term, Terms), (ModTerm, ModTerms), N0, N) :-
|
||||||
!, expand_body_term(Term, ModTerm, N0, N1),
|
!, expand_body_term(Term, ModTerm, N0, N1),
|
||||||
|
|||||||
Reference in New Issue
Block a user