* `throw/1`
* `true/0`
* `var/1`
+* `write/1`
+* `write_canonical/1`
* `writeq/1`
+* `write_term/2`
## Tutorial
To enter a multi-clause predicate, the directive "[user]" is used.
HeadTailSeparator,
}
-pub trait HCValueFormatter {
- // this function belongs to the display predicate formatter, which it uses
- // to format all clauses.
- fn format_struct(&self, arity: usize, name: ClauseName, state_stack: &mut Vec<TokenOrRedirect>)
- {
- state_stack.push(TokenOrRedirect::Close);
-
- for _ in 0 .. arity {
- state_stack.push(TokenOrRedirect::Redirect);
- state_stack.push(TokenOrRedirect::Comma);
- }
-
- state_stack.pop();
- state_stack.push(TokenOrRedirect::Open);
-
- state_stack.push(TokenOrRedirect::Atom(name));
- }
-
- // this can be overloaded to handle special cases, falling back on the default of
- // format_struct when convenient.
- fn format_clause(&self, &mut HCPreOrderIterator, usize, ClauseType, &mut Vec<TokenOrRedirect>);
-}
-
pub trait HCValueOutputter {
type Output;
}
}
-// the 'classic' display corresponding to the display predicate.
-pub struct WriteqFormatter {}
-
#[inline]
fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
arity == 1 && if let &ClauseType::Named(ref name, _) = ct {
}
}
-fn print_op(ct: ClauseType, fixity: Fixity, state_stack: &mut Vec<TokenOrRedirect>) {
- match fixity {
- Fixity::Post => {
- state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
- state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Right(ct.name())));
- },
- Fixity::Pre => {
- state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Left(ct.name())));
- state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
- },
- Fixity::In => {
- state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Left(ct.name())));
- state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
- state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Right(ct.name())));
- }
- }
-}
-
-impl HCValueFormatter for WriteqFormatter {
- fn format_clause(&self, iter: &mut HCPreOrderIterator, arity: usize,
- ct: ClauseType, state_stack: &mut Vec<TokenOrRedirect>)
- {
- if let Some(fixity) = ct.fixity() {
- return print_op(ct, fixity, state_stack);
- } else if is_numbered_var(&ct, arity) {
- let addr = iter.stack().last().cloned().unwrap();
-
- // 7.10.4
- if let Some(var) = iter.machine_st.numbervar(addr) {
- iter.stack().pop();
- state_stack.push(TokenOrRedirect::NumberedVar(var));
- return;
- }
- }
-
- self.format_struct(arity, ct.name(), state_stack);
- }
-}
-
-pub struct TermFormatter {}
-
-impl HCValueFormatter for TermFormatter {
- fn format_clause(&self, _: &mut HCPreOrderIterator, arity: usize, ct: ClauseType,
- state_stack: &mut Vec<TokenOrRedirect>)
- {
- if let Some(fixity) = ct.fixity() {
- print_op(ct, fixity, state_stack);
- } else {
- self.format_struct(arity, ct.name(), state_stack);
- }
- }
-}
-
type ReverseHeapVarDict<'a> = HashMap<Addr, Rc<Var>>;
-pub struct HCPrinter<'a, Formatter, Outputter> {
- formatter: Formatter,
+pub struct HCPrinter<'a, Outputter> {
outputter: Outputter,
machine_st: &'a MachineState,
state_stack: Vec<TokenOrRedirect>,
heap_locs: ReverseHeapVarDict<'a>,
- printed_vars: HashSet<Addr>
+ printed_vars: HashSet<Addr>,
+ pub(crate) numbervars: bool,
+ pub(crate) quoted: bool,
+ pub(crate) ignore_ops: bool
}
macro_rules! push_space_if_amb {
}
}
-impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
- HCPrinter<'a, Formatter, Outputter>
+impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
{
- pub fn new(machine_st: &'a MachineState, fmt: Formatter, output: Outputter) -> Self
+ pub fn new(machine_st: &'a MachineState, output: Outputter) -> Self
{
- HCPrinter { formatter: fmt,
- outputter: output,
+ HCPrinter { outputter: output,
machine_st,
state_stack: vec![],
heap_locs: ReverseHeapVarDict::new(),
- printed_vars: HashSet::new() }
+ printed_vars: HashSet::new(),
+ numbervars: true,
+ quoted: true,
+ ignore_ops: false }
}
- pub fn from_heap_locs(machine_st: &'a MachineState, fmt: Formatter,
- output: Outputter, heap_locs: &'a HeapVarDict)
+ pub fn from_heap_locs(machine_st: &'a MachineState, output: Outputter,
+ heap_locs: &'a HeapVarDict)
-> Self
{
- let mut printer = Self::new(machine_st, fmt, output);
+ let mut printer = Self::new(machine_st, output);
printer.heap_locs = reverse_heap_locs(machine_st, heap_locs);
printer
}
+ fn enqueue_op(&mut self, ct: ClauseType, fixity: Fixity) {
+ match fixity {
+ Fixity::Post => {
+ self.state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
+ self.state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Right(ct.name())));
+ },
+ Fixity::Pre => {
+ self.state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Left(ct.name())));
+ self.state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
+ },
+ Fixity::In => {
+ self.state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Left(ct.name())));
+ self.state_stack.push(TokenOrRedirect::Op(ct.name(), fixity));
+ self.state_stack.push(TokenOrRedirect::CompositeRedirect(DirectedOp::Right(ct.name())));
+ }
+ }
+ }
+
+ fn format_struct(&mut self, arity: usize, name: ClauseName)
+ {
+ self.state_stack.push(TokenOrRedirect::Close);
+
+ for _ in 0 .. arity {
+ self.state_stack.push(TokenOrRedirect::Redirect);
+ self.state_stack.push(TokenOrRedirect::Comma);
+ }
+
+ self.state_stack.pop();
+ self.state_stack.push(TokenOrRedirect::Open);
+
+ self.state_stack.push(TokenOrRedirect::Atom(name));
+ }
+
+ fn format_clause(&mut self, iter: &mut HCPreOrderIterator, arity: usize, ct: ClauseType)
+ {
+ if let Some(fixity) = ct.fixity() {
+ if !self.ignore_ops {
+ return self.enqueue_op(ct, fixity);
+ }
+ } else if self.numbervars && is_numbered_var(&ct, arity) {
+ let addr = iter.stack().last().cloned().unwrap();
+
+ // 7.10.4
+ if let Some(var) = iter.machine_st.numbervar(addr) {
+ iter.stack().pop();
+ self.state_stack.push(TokenOrRedirect::NumberedVar(var));
+ return;
+ }
+ }
+
+ self.format_struct(arity, ct.name());
+ }
+
fn offset_as_string(&self, addr: Addr) -> Option<String> {
match addr {
Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) =>
match atom.as_str() {
"" => self.outputter.append("''"),
";" | "!" => self.outputter.append(atom.as_str()),
- s => if fixity.is_some() || non_quoted_token(s.chars()) {
+ s => if fixity.is_some() || !self.quoted || non_quoted_token(s.chars()) {
self.outputter.append(atom.as_str())
} else {
self.outputter.push_char('\'');
_ => self.outputter.append(&format!("\\x{:x}", c as u32))
};
}
-
+
fn print_constant(&mut self, c: Constant, op: &Option<DirectedOp>) {
match c {
Constant::Atom(ref atom, Some(fixity)) => {
}),
Constant::Char(c) if non_quoted_token(once(c)) =>
self.print_char(c),
- Constant::Char(c) => {
- self.outputter.push_char('\'');
- self.print_char(c);
- self.outputter.push_char('\'');
- },
+ Constant::Char(c) =>
+ if self.quoted {
+ self.outputter.push_char('\'');
+ self.print_char(c);
+ self.outputter.push_char('\'');
+ } else {
+ self.print_char(c);
+ },
Constant::EmptyList =>
self.outputter.append("[]"),
Constant::Number(Number::Float(fl)) =>
}
let ct = ClauseType::from(name.clone(), arity, Some(fixity));
- self.formatter.format_clause(iter, arity, ct, &mut self.state_stack);
+ self.format_clause(iter, arity, ct);
if op.is_some() {
self.state_stack.push(TokenOrRedirect::Open);
HeapCellValue::NamedStr(arity, name, fixity) =>
push_space_if_amb!(self, name.as_str(), &op, {
let ct = ClauseType::from(name, arity, fixity);
- self.formatter.format_clause(iter, arity, ct, &mut self.state_stack)
+ self.format_clause(iter, arity, ct);
}),
HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
if !self.at_cdr("") {
TokenOrRedirect::Open =>
self.outputter.append("("),
TokenOrRedirect::OpenList(delimit) =>
- if !self.at_cdr(", ") {
+ if self.ignore_ops {
+ self.format_struct(2, clause_name!("."));
+ } else if !self.at_cdr(", ") {
self.outputter.append("[");
} else {
delimit.set(false);
},
TokenOrRedirect::CloseList(delimit) =>
- if delimit.get() {
+ if !self.ignore_ops && delimit.get() {
self.outputter.append("]");
},
TokenOrRedirect::HeadTailSeparator =>
- self.outputter.append(" | "),
+ if !self.ignore_ops {
+ self.outputter.append(" | ");
+ },
TokenOrRedirect::Comma =>
self.outputter.append(", ")
}
SkipMaxList,
Succeed,
TermVariables,
- UnwindStack
+ UnwindStack,
+ WriteTerm
}
impl SystemClauseType {
&SystemClauseType::Succeed => clause_name!("$succeed"),
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
+ &SystemClauseType::WriteTerm => clause_name!("$write_term"),
}
}
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
+ ("$write_term", 4) => Some(SystemClauseType::WriteTerm),
_ => None
}
}
Compare,
CompareTerm(CompareTermQT),
CyclicTerm,
- Writeq,
CopyTerm,
Eq,
Functor,
&BuiltInClauseType::Compare => clause_name!("compare"),
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
&BuiltInClauseType::CyclicTerm => clause_name!("cyclic_term"),
- &BuiltInClauseType::Writeq => clause_name!("writeq"),
&BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
&BuiltInClauseType::Eq => clause_name!("=="),
&BuiltInClauseType::Functor => clause_name!("functor"),
&BuiltInClauseType::Compare => 2,
&BuiltInClauseType::CompareTerm(_) => 2,
&BuiltInClauseType::CyclicTerm => 1,
- &BuiltInClauseType::Writeq => 1,
&BuiltInClauseType::CopyTerm => 2,
&BuiltInClauseType::Eq => 2,
&BuiltInClauseType::Functor => 3,
("@=<", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)),
("\\=@=", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::NotEqual)),
("=@=", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::Equal)),
- ("writeq", 1) => Some(BuiltInClauseType::Writeq),
("copy_term", 2) => Some(BuiltInClauseType::CopyTerm),
("==", 2) => Some(BuiltInClauseType::Eq),
("functor", 3) => Some(BuiltInClauseType::Functor),
(==)/2, (\==)/2, (@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (=@=)/2,
(\=@=)/2, (:)/2, call_with_inference_limit/3, catch/3,
current_prolog_flag/2, expand_term/2, set_prolog_flag/2,
- term_variables/2,
- setup_call_cleanup/3, throw/1, true/0, false/0]).
+ setup_call_cleanup/3, term_variables/2, throw/1, true/0, false/0,
+ write/1, write_canonical/1, writeq/1, write_term/2]).
/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
'$call_with_default_policy'(I1 is I0 + 1),
'$call_with_default_policy'(get_args(Args, Func, I1, N)).
+% write, write_canonical, writeq, write_term.
+is_write_option(Functor) :-
+ Functor =.. [Name, Arg | Args],
+ ( Args == [], Arg == true -> true
+ ; Args == [], Arg == false -> true
+ ; throw(error(domain_error(write_option, Functor), write_term/2)) ), % 8.14.2.3 e)
+ ( Name == ignore_ops -> true
+ ; Name == quoted -> true
+ ; Name == numbervars -> true
+ ; throw(error(domain_error(write_option, Functor), write_term/2)) ). % 8.14.2.3 e)
+
+inst_member_or([X|Xs], Y, _) :-
+ ( nonvar(X), is_write_option(X) -> ( Y = X, ! ; inst_member_or(Xs, Y, _) )
+ ; throw(instantiation_error) ). % 8.14.2.3 b)
+inst_member_or([], Y, Y).
+
+write_term(Term, Options) :-
+ '$skip_max_list'(_, -1, Options, Options0),
+ ( Options0 == [] -> true
+ ; throw(error(type_error(list, Options), write_term/2)) ), % 8.14.2.3 c)
+ inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
+ inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
+ inst_member_or(Options, quoted(Quoted), quoted(false)),
+ '$write_term'(Term, IgnoreOps, NumberVars, Quoted).
+
+write(Term) :- write_term(Term, [numbervars(true)]).
+
+write_canonical(Term) :- write_term(Term, [ignore_ops(true), quoted(true)]).
+
+writeq(Term) :- write_term(Term, [quoted(true), numbervars(true)]).
+
% expand_term.
expand_term(Term0, Term) :- '$expand_term'(Term0, Term).
use prolog::instructions::*;
use prolog::and_stack::*;
use prolog::copier::*;
-use prolog::heap_print::*;
use prolog::machine::IndexStore;
use prolog::machine::machine_errors::*;
use prolog::num::{BigInt, BigUint, Zero, One};
return_from_clause!(machine_st.last_call, machine_st)
},
- &BuiltInClauseType::Writeq => {
- let output = machine_st.print_term(machine_st[temp_v!(1)].clone(),
- WriteqFormatter {},
- PrinterOutputter::new());
-
- println!("{}", output.result());
- return_from_clause!(machine_st.last_call, machine_st)
- },
&BuiltInClauseType::CopyTerm => {
machine_st.duplicate_term();
return_from_clause!(machine_st.last_call, machine_st)
machine_st.execute_inlined(&inlined),
ClauseType::Op(..) | ClauseType::Named(..) => {
let module = name.owning_module();
-
+
if let Some(idx) = indices.get_code_index((name.clone(), arity), module) {
self.context_call(machine_st, name, arity, idx, indices)?;
} else {
}
pub(super)
- fn print_var_eq<Fmt, Outputter>(&self, var: Rc<Var>, addr: Addr, var_dir: &HeapVarDict,
- fmt: Fmt, mut output: Outputter)
- -> Outputter
- where Fmt: HCValueFormatter, Outputter: HCValueOutputter
+ fn print_var_eq<Outputter>(&self, var: Rc<Var>, addr: Addr, var_dir: &HeapVarDict,
+ mut output: Outputter)
+ -> Outputter
+ where Outputter: HCValueOutputter
{
let orig_len = output.len();
output.append(var.as_str());
output.append(" = ");
- let printer = HCPrinter::from_heap_locs(&self, fmt, output, var_dir);
+ let mut printer = HCPrinter::from_heap_locs(&self, output, var_dir);
+ printer.numbervars = false;
+
let mut output = printer.print(addr);
let bad_ending = format!("= {}", &var);
}
pub(super)
- fn print_exception<Fmt, Outputter>(&self, addr: Addr, var_dir: &HeapVarDict,
- fmt: Fmt, output: Outputter)
- -> Outputter
- where Fmt: HCValueFormatter, Outputter: HCValueOutputter
+ fn print_exception<Outputter>(&self, addr: Addr, var_dir: &HeapVarDict, output: Outputter)
+ -> Outputter
+ where Outputter: HCValueOutputter
{
- let printer = HCPrinter::from_heap_locs(&self, fmt, output, var_dir);
- printer.print(addr)
- }
-
- pub(super)
- fn print_term<Fmt, Outputter>(&self, addr: Addr, fmt: Fmt, output: Outputter) -> Outputter
- where Fmt: HCValueFormatter, Outputter: HCValueOutputter
- {
- let printer = HCPrinter::new(&self, fmt, output);
+ let printer = HCPrinter::from_heap_locs(&self, output, var_dir);
printer.print(addr)
}
let error_str = self.machine_st.print_exception(Addr::HeapCell(h),
&heap_locs,
- TermFormatter {},
PrinterOutputter::new())
.result();
let mut sorted_vars: Vec<(&Rc<Var>, &Addr)> = var_dir.iter().collect();
sorted_vars.sort_by_key(|ref v| v.0);
- for (var, addr) in sorted_vars {
- let fmt = TermFormatter {};
- output = self.machine_st.print_var_eq(var.clone(), addr.clone(), var_dir, fmt, output);
+ for (var, addr) in sorted_vars {
+ output = self.machine_st.print_var_eq(var.clone(), addr.clone(), var_dir, output);
}
output
use prolog_parser::ast::*;
use prolog::heap_iter::*;
+use prolog::heap_print::*;
use prolog::instructions::*;
use prolog::machine::IndexStore;
use prolog::machine::machine_errors::*;
&SystemClauseType::TermVariables => {
let a1 = self[temp_v!(1)].clone();
let mut vars = Vec::new();
-
+
{
- let iter = HCPreOrderIterator::new(self, a1);
-
+ let iter = HCPreOrderIterator::new(self, a1);
+
for item in iter {
- match item {
+ match item {
HeapCellValue::Addr(Addr::HeapCell(h)) =>
- vars.push(Ref::HeapCell(h)),
+ vars.push(Ref::HeapCell(h)),
HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
- vars.push(Ref::StackCell(fr, sc)),
+ vars.push(Ref::StackCell(fr, sc)),
_ => {}
}
}
}
-
+
let mut h = self.heap.h;
let outcome = Addr::HeapCell(h);
let mut seen_vars = HashSet::new();
-
+
for r in vars {
if seen_vars.contains(&r) {
continue;
}
-
+
self.heap.push(HeapCellValue::Addr(Addr::Lis(h+1)));
self.heap.push(HeapCellValue::Addr(r.as_addr()));
let a2 = self[temp_v!(2)].clone();
self.unify(a2, outcome);
},
- &SystemClauseType::UnwindStack => self.unwind_stack()
+ &SystemClauseType::UnwindStack => self.unwind_stack(),
+ &SystemClauseType::WriteTerm => {
+ let addr = self[temp_v!(1)].clone();
+
+ let ignore_ops = self[temp_v!(2)].clone();
+ let numbervars = self[temp_v!(3)].clone();
+ let quoted = self[temp_v!(4)].clone();
+
+ let mut printer = HCPrinter::new(&self, PrinterOutputter::new());
+
+ if let &Addr::Con(Constant::Atom(ref name, ..)) = &ignore_ops {
+ printer.ignore_ops = name.as_str() == "true";
+ }
+
+ if let &Addr::Con(Constant::Atom(ref name, ..)) = &numbervars {
+ printer.numbervars = name.as_str() == "true";
+ }
+
+ if let &Addr::Con(Constant::Atom(ref name, ..)) = "ed {
+ printer.quoted = name.as_str() == "true";
+ }
+
+ let mut output = printer.print(addr);
+ println!("{}", output.result());
+ }
};
self.set_p();
self.reset();
Ok(None)
} else {
- let mut output = self.print_term(Addr::HeapCell(h),
- WriteqFormatter {},
- PrinterOutputter::new());
+ let mut output = {
+ let mut printer = HCPrinter::new(&self, PrinterOutputter::new());
+ printer.print(Addr::HeapCell(h))
+ };
+
output.push_char('.');
self.reset();