[package]
name = "scryer-prolog"
-version = "0.8.55"
+version = "0.8.56"
repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust."
pub fn remove(&self, op_dir: &mut OpDir) {
self.insert_into_op_dir(clause_name!(""), op_dir, 0);
}
-
+
fn insert_into_op_dir(&self, module: ClauseName, op_dir: &mut OpDir, prec: usize)
{
let (spec, name) = (self.1, self.2.clone());
}
}
+pub
+fn fetch_atom_op_spec(name: ClauseName, spec: Option<SharedOpDesc>, op_dir: &OpDir)
+ -> Option<SharedOpDesc>
+{
+ fetch_op_spec(name.clone(), 1, spec.clone(), op_dir)
+ .or_else(|| fetch_op_spec(name, 2, spec, op_dir))
+}
+
+pub
+fn fetch_op_spec(name: ClauseName, arity: usize, spec: Option<SharedOpDesc>, op_dir: &OpDir)
+ -> Option<SharedOpDesc>
+{
+ spec.or_else(|| {
+ match arity {
+ 2 => op_dir.get(&(name, Fixity::In)).and_then(|OpDirValue(spec, _)|
+ if spec.prec() > 0 {
+ Some(spec.clone())
+ } else {
+ None
+ }),
+ 1 => {
+ if let Some(OpDirValue(spec, _)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
+ if spec.prec() > 0 {
+ return Some(spec.clone());
+ }
+ }
+
+ op_dir.get(&(name.clone(), Fixity::Post))
+ .and_then(|OpDirValue(spec, _)|
+ if spec.prec() > 0 {
+ Some(spec.clone())
+ } else {
+ None
+ })
+ },
+ _ => None
+ }
+ })
+}
+
pub type ModuleDir = HashMap<ClauseName, Module>;
#[derive(Clone)]
use prolog_parser::string_list::*;
use prolog::clause_types::*;
+use prolog::forms::{fetch_atom_op_spec, fetch_op_spec};
use prolog::heap_iter::*;
use prolog::machine::machine_indices::*;
use prolog::machine::machine_state::*;
* encountered on the way an infix or postfix operator, unblocked
* by brackets.
*/
- fn leftmost_leaf_is_positive_number(&self) -> bool {
+ fn leftmost_leaf_has_property<P>(&self, property_check: P) -> bool
+ where P: Fn(Constant) -> bool
+ {
let mut addr = match self.state_stack.last().cloned() {
Some(addr) => addr,
None => return false
return false
},
Addr::Con(Constant::Number(n)) =>
- return n.is_positive(),
+ return property_check(Constant::Number(n)),
_ =>
return false
}
}
}
+
+ fn immediate_leaf_has_property<P>(&self, property_check: P) -> bool
+ where P: Fn(Constant) -> bool
+ {
+ let addr = match self.state_stack.last().cloned() {
+ Some(addr) => addr,
+ None => return false
+ };
+
+ match self.machine_st.store(self.machine_st.deref(addr)) {
+ Addr::Con(c) => property_check(c),
+ _ => false
+ }
+ }
}
fn char_to_string(c: char) -> String {
fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option<DirectedOp>) -> bool
{
if let &Some(ref op) = op {
- op.is_negative_sign() && iter.leftmost_leaf_is_positive_number()
+ op.is_negative_sign() && iter.leftmost_leaf_has_property(|c| {
+ match c {
+ Constant::Number(n) => n.is_positive(),
+ _ => false
+ }
+ })
} else {
false
}
pub struct HCPrinter<'a, Outputter> {
outputter: Outputter,
machine_st: &'a MachineState,
+ op_dir: &'a OpDir,
state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>,
heap_locs: ReverseHeapVarDict,
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
{
- pub fn new(machine_st: &'a MachineState, output: Outputter) -> Self
+ pub fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self
{
HCPrinter { outputter: output,
machine_st,
+ op_dir,
state_stack: vec![],
heap_locs: ReverseHeapVarDict::new(),
toplevel_spec: None,
ignore_ops: false }
}
- pub fn from_heap_locs(machine_st: &'a MachineState, output: Outputter,
+ pub fn from_heap_locs(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter,
heap_locs: &'a HeapVarDict)
-> Self
{
- let mut printer = Self::new(machine_st, output);
+ let mut printer = Self::new(machine_st, op_dir, output);
printer.toplevel_spec = Some(DirectedOp::Right(clause_name!("="), SharedOpDesc::new(700, XFX)));
printer.heap_locs = reverse_heap_locs(machine_st, heap_locs);
return;
}
}
-
+
if let Some(spec) = ct.spec() {
if "." == ct.name().as_str() && is_infix!(spec.assoc()) {
if !self.ignore_ops {
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue>
{
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));
+
match self.heap_locs.get(&addr).cloned() {
Some(var) => if !self.printed_vars.contains(&addr) {
self.printed_vars.insert(addr);
fn print_constant(&mut self, c: Constant, op: &Option<DirectedOp>) {
match c {
- Constant::Atom(ref atom, Some(ref spec)) if spec.prec() > 0 => {
- let mut result = String::new();
+ Constant::Atom(atom, spec) =>
+ if let Some(_) = fetch_atom_op_spec(atom.clone(), spec, self.op_dir) {
+ let mut result = String::new();
- if let Some(ref op) = op {
- if self.outputter.ends_with(&format!(" {}", op.as_str())) {
- result.push(' ');
+ if let Some(ref op) = op {
+ if self.outputter.ends_with(&format!(" {}", op.as_str())) {
+ result.push(' ');
+ }
+
+ result.push('(');
}
-
- result.push('(');
- }
-
- result += &self.print_op_addendum(atom.as_str());
-
- if op.is_some() {
- result.push(')');
- }
-
- push_space_if_amb!(self, &result, {
- self.append_str(&result);
- });
- },
- Constant::Atom(ref atom, _) =>
- push_space_if_amb!(self, atom.as_str(), {
- self.print_atom(atom);
- }),
+
+ result += &self.print_op_addendum(atom.as_str());
+
+ if op.is_some() {
+ result.push(')');
+ }
+
+ push_space_if_amb!(self, &result, {
+ self.append_str(&result);
+ });
+ } else {
+ push_space_if_amb!(self, atom.as_str(), {
+ self.print_atom(&atom);
+ });
+ },
Constant::Char(c) if non_quoted_token(once(c)) => {
let c = char_to_string(c);
self.state_stack.push(TokenOrRedirect::OpenList(cell));
}
+ fn handle_op_as_struct(&mut self, name: ClauseName, arity: usize, iter: &mut HCPreOrderIterator,
+ op: &Option<DirectedOp>, is_functor_redirect: bool, spec: SharedOpDesc,
+ negated_operand: bool)
+ {
+ let add_brackets = if !self.ignore_ops {
+ negated_operand || if let Some(ref op) = op {
+ if self.numbervars && arity == 1 && name.as_str() == "$VAR" {
+ !iter.immediate_leaf_has_property(|c| {
+ match c {
+ Constant::Number(n) => n.is_zero() || n.is_positive(),
+ _ => false
+ }
+ }) && needs_bracketing(&spec, op)
+ } else {
+ needs_bracketing(&spec, op)
+ }
+ } else {
+ is_functor_redirect && spec.prec() >= 1000
+ }
+ } else {
+ false
+ };
+
+ if add_brackets {
+ self.state_stack.push(TokenOrRedirect::Close);
+ }
+
+ let ct = ClauseType::from(name.clone(), arity, Some(spec));
+ self.format_clause(iter, arity, ct);
+
+ if add_brackets {
+ self.state_stack.push(TokenOrRedirect::Open);
+
+ if let Some(ref op) = &op {
+ if op.is_left() && requires_space(op.as_str(), "(") {
+ self.state_stack.push(TokenOrRedirect::Space);
+ }
+ }
+ }
+ }
+
+
fn handle_heap_term(&mut self, iter: &mut HCPreOrderIterator, op: Option<DirectedOp>,
is_functor_redirect: bool)
{
- let add_brackets = negated_op_needs_bracketing(iter, &op);
+ let negated_operand = negated_op_needs_bracketing(iter, &op);
let heap_val = match self.check_for_seen(iter) {
Some(heap_val) => heap_val,
};
match heap_val {
- HeapCellValue::NamedStr(arity, name, Some(spec)) => {
- let add_brackets = if !self.ignore_ops {
- add_brackets || if let Some(ref op) = &op {
- needs_bracketing(&spec, op)
- } else {
- is_functor_redirect && spec.prec() >= 1000
- }
+ HeapCellValue::NamedStr(arity, name, spec) =>
+ if let Some(spec) = fetch_op_spec(name.clone(), arity, spec.clone(), self.op_dir) {
+ self.handle_op_as_struct(name, arity, iter, &op, is_functor_redirect, spec,
+ negated_operand);
} else {
- false
- };
-
- if add_brackets {
- self.state_stack.push(TokenOrRedirect::Close);
- }
-
- let ct = ClauseType::from(name.clone(), arity, Some(spec));
- self.format_clause(iter, arity, ct);
-
- if add_brackets {
- self.state_stack.push(TokenOrRedirect::Open);
-
- if let Some(ref op) = &op {
- if op.is_left() && requires_space(op.as_str(), "(") {
- self.state_stack.push(TokenOrRedirect::Space);
- }
- }
- }
- },
- HeapCellValue::NamedStr(0, name, fixity) =>
- push_space_if_amb!(self, name.as_str(), {
- let ct = ClauseType::from(name, 0, fixity);
- self.format_clause(iter, 0, ct);
- }),
- HeapCellValue::NamedStr(arity, name, fixity) => {
- let ct = ClauseType::from(name, arity, fixity);
- self.format_clause(iter, arity, ct);
- },
+ push_space_if_amb!(self, name.as_str(), {
+ let ct = ClauseType::from(name, arity, spec);
+ self.format_clause(iter, arity, ct);
+ });
+ },
HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
if !self.at_cdr("") {
self.append_str("[]");
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
}
- fn print_attribute_goals_string(&mut self, var_dict: &HeapVarDict) -> String
+ fn print_attribute_goals_string(&mut self, op_dir: &OpDir, var_dict: &HeapVarDict) -> String
{
let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]);
let mut output = PrinterOutputter::new();
for goal_addr in attr_goals {
- let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict);
+ let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output, var_dict);
printer.see_all_locs();
printer.numbervars = false;
self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo,
&mut readline::input_stream());
- self.machine_st.print_attribute_goals_string(var_dict)
+ self.machine_st.print_attribute_goals_string(&self.indices.op_dir, var_dict)
}
}
output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
for addr in addrs {
- let mut printer = HCPrinter::new(&self.machine_st, output);
+ let mut printer = HCPrinter::new(&self.machine_st, &self.indices.op_dir, output);
printer.quoted = true;
output = printer.print(addr);
pub(super) fn take(&mut self) -> Ball {
let boundary = self.boundary;
self.boundary = 0;
-
+
Ball {
boundary,
stub: mem::replace(&mut self.stub, vec![])
pub(crate) flags: MachineFlags
}
-impl MachineState {
+impl MachineState {
fn call_at_index(&mut self, arity: usize, p: usize)
{
self.cp.assign_if_local(self.p.clone() + 1);
let a3 = machine_st[temp_v!(3)].clone();
let c = match machine_st.compare_term_test(&a2, &a3) {
- Ordering::Greater => Addr::Con(Constant::Atom(clause_name!(">"),
- Some(SharedOpDesc::new(700, XFX)))),
- Ordering::Equal => Addr::Con(Constant::Atom(clause_name!("="),
- Some(SharedOpDesc::new(700, XFX)))),
- Ordering::Less => Addr::Con(Constant::Atom(clause_name!("<"),
- Some(SharedOpDesc::new(700, XFX))))
+ Ordering::Greater => {
+ let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir);
+ Addr::Con(Constant::Atom(clause_name!(">"), spec))
+ },
+ Ordering::Equal => {
+ let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
+ Addr::Con(Constant::Atom(clause_name!("="), spec))
+ },
+ Ordering::Less => {
+ let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir);
+ Addr::Con(Constant::Atom(clause_name!("<"), spec))
+ }
};
machine_st.unify(a1, c);
},
&BuiltInClauseType::Read => {
readline::toggle_prompt(false);
-
+
match machine_st.read(parsing_stream, indices.atom_tbl.clone(), &indices.op_dir) {
Ok(offset) => {
let addr = machine_st[temp_v!(1)].clone();
}
pub(super)
- fn print_var_eq<Outputter>(&self, var: Rc<Var>, addr: Addr, var_dict: &HeapVarDict,
+ fn print_var_eq<Outputter>(&self, var: Rc<Var>, addr: Addr, op_dir: &OpDir, var_dict: &HeapVarDict,
mut output: Outputter)
-> Outputter
where Outputter: HCValueOutputter
output.append(var.as_str());
output.append(" = ");
- let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict);
+ let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output, var_dict);
printer.numbervars = false;
printer.quoted = true;
let mut output = printer.print(addr);
-
+
let bad_ending = format!("= {}", &var);
if output.ends_with(&bad_ending) {
self.try_functor_unify_components(a1, Addr::Con(integer!(0))),
Addr::Str(o) =>
match self.heap[o].clone() {
- HeapCellValue::NamedStr(arity, name, spec) =>
- self.try_functor_compound_case(name, arity, spec),
+ HeapCellValue::NamedStr(arity, name, spec) => {
+ let spec = fetch_op_spec(name.clone(), arity, spec, op_dir);
+ self.try_functor_compound_case(name, arity, spec)
+ },
_ => self.fail = true
},
Addr::Lis(_) => {
- let shared_op_desc = op_dir.get(&(clause_name!("."), Fixity::In))
- .map(|val| val.0.clone());
+ let shared_op_desc = fetch_op_spec(clause_name!("."), 2, None, op_dir);
self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc)
},
Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => {
Addr::Con(_) if arity == 0 =>
self.unify(a1, name),
Addr::Con(Constant::Atom(name, spec)) => {
+ let spec = fetch_atom_op_spec(name.clone(), spec, op_dir);
+
let f_a = if name.as_str() == "." && arity == 2 {
Addr::Lis(self.heap.h)
} else {
};
}
- let term_output = self.machine_st.print_query(term, &var_dict);
+ let term_output = self.machine_st.print_query(term, &self.indices.op_dir,
+ &var_dict);
term_output.result()
},
Err(err_stub) => {
for (var, addr) in sorted_vars {
let addr = self.machine_st.store(self.machine_st.deref(addr.clone()));
- output = self.machine_st.print_var_eq(var.clone(), addr, var_dir, output);
+ output = self.machine_st.print_var_eq(var.clone(), addr, &self.indices.op_dir, var_dir,
+ output);
}
output
}
#[cfg(test)]
- pub fn test_heap_view<Outputter>(&self, var_dir: &HeapVarDict, mut output: Outputter) -> Outputter
+ pub fn test_heap_view<Outputter>(&self, var_dir: &HeapVarDict, mut output: Outputter)
+ -> Outputter
where Outputter: HCValueOutputter
{
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 {
- output = self.machine_st.print_var_eq(var.clone(), addr.clone(), var_dir, output);
+ output = self.machine_st.print_var_eq(var.clone(), addr.clone(), &self.indices.op_dir,
+ var_dir, output);
}
output
impl MachineState {
- fn print_query(&self, addr: Addr, var_dict: &HeapVarDict) -> PrinterOutputter
+ fn print_query(&self, addr: Addr, op_dir: &OpDir, var_dict: &HeapVarDict) -> PrinterOutputter
{
let output = PrinterOutputter::new();
- let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict);
+ let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output, var_dict);
printer.quoted = true;
printer.numbervars = false;
use prolog_parser::tabled_rc::*;
use prolog::clause_types::*;
+use prolog::forms::*;
use prolog::heap_print::*;
use prolog::machine::copier::*;
use prolog::machine::machine_errors::*;
_ => unreachable!()
};
- let module = op.owning_module();
+ let module = op.owning_module();
let result = to_op_decl(priority, specifier.as_str(), op)
.map_err(SessionError::from)
},
_ => unreachable!()
},
- Addr::Con(Constant::Atom(name, op_spec)) => {
+ Addr::Con(Constant::Atom(name, spec)) => {
let module = name.owning_module();
- indices.predicate_exists(name, module, 0, op_spec)
+ let spec = fetch_atom_op_spec(name.clone(), spec, &indices.op_dir);
+
+ indices.predicate_exists(name, module, 0, spec)
},
head => {
let err = MachineError::type_error(ValidType::Callable, head);
let var_atom = Constant::Atom(var_atom, None);
let h = self.heap.h;
- let op_desc = Some(SharedOpDesc::new(700, XFX));
+ let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
- self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), op_desc));
+ self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
self.heap.push(HeapCellValue::Addr(Addr::Con(var_atom)));
self.heap.push(HeapCellValue::Addr(binding));
let numbervars = self.store(self.deref(self[temp_v!(3)].clone()));
let quoted = self.store(self.deref(self[temp_v!(4)].clone()));
- let mut printer = HCPrinter::new(&self, PrinterOutputter::new());
+ let mut printer = HCPrinter::new(&self, &indices.op_dir, PrinterOutputter::new());
if let &Addr::Con(Constant::Atom(ref name, ..)) = &ignore_ops {
printer.ignore_ops = name.as_str() == "true";
impl MachineState {
pub(super)
- fn print_with_locs(&self, addr: Addr, var_dict: &HeapVarDict) -> PrinterOutputter
+ fn print_with_locs(&self, addr: Addr, op_dir: &OpDir, var_dict: &HeapVarDict) -> PrinterOutputter
{
let output = PrinterOutputter::new();
- let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict);
+ let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output, var_dict);
let mut max_var_length = 0;
for var in var_dict.keys() {
None
} else {
let &TermWriteResult { heap_loc: _, ref var_dict } = &term_write_result;
- let output = self.print_with_locs(Addr::HeapCell(h), var_dict);
+ let output = self.print_with_locs(Addr::HeapCell(h), &indices.op_dir, var_dict);
self.reset();
Some(output.result())
assert_prolog_success!(&mut wam, "clause(legs(I, 6), Body).",
[["I = _1", "Body = insect(_1)"]]);
assert_prolog_success!(&mut wam, "clause(legs(C, 7), Body).",
- [["C = _1", "Body = ','(_1, call(C))"]]);
+ [["C = _1", "Body = (_1,call(C))"]]);
assert_prolog_success!(&mut wam, "clause(insect(I), T).",
[["I = ant", "T = true"],
["I = bee", "T = true"]]);