From e089c8bdd242281d15686262e4ae9f5751d1aa4f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 18 Apr 2019 20:32:50 -0600 Subject: [PATCH] fix conformity testing #274 --- Cargo.toml | 2 +- src/prolog/forms.rs | 42 ++++- src/prolog/heap_print.rs | 178 +++++++++++++-------- src/prolog/machine/attributed_variables.rs | 6 +- src/prolog/machine/dynamic_database.rs | 2 +- src/prolog/machine/machine_state.rs | 24 +-- src/prolog/machine/machine_state_impl.rs | 17 +- src/prolog/machine/mod.rs | 16 +- src/prolog/machine/system_calls.rs | 15 +- src/prolog/machine/term_expansion.rs | 6 +- src/tests.rs | 2 +- 11 files changed, 203 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 454fb1c4..070107a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.55" +version = "0.8.56" authors = ["Mark Thom "] repository = "https://github.com/mthom/scryer-prolog" description = "A modern Prolog implementation written mostly in Rust." diff --git a/src/prolog/forms.rs b/src/prolog/forms.rs index 2a994391..e6168f36 100644 --- a/src/prolog/forms.rs +++ b/src/prolog/forms.rs @@ -181,7 +181,7 @@ impl OpDecl { 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()); @@ -229,6 +229,46 @@ impl OpDecl { } } +pub +fn fetch_atom_op_spec(name: ClauseName, spec: Option, op_dir: &OpDir) + -> Option +{ + 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, op_dir: &OpDir) + -> Option +{ + 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; #[derive(Clone)] diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 1d30ac4c..5a2e3734 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -2,6 +2,7 @@ use prolog_parser::ast::*; 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::*; @@ -86,7 +87,9 @@ impl<'a> HCPreOrderIterator<'a> { * 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

(&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 @@ -110,12 +113,26 @@ impl<'a> HCPreOrderIterator<'a> { return false }, Addr::Con(Constant::Number(n)) => - return n.is_positive(), + return property_check(Constant::Number(n)), _ => return false } } } + + fn immediate_leaf_has_property

(&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 { @@ -229,7 +246,12 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool { fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option) -> 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 } @@ -265,6 +287,7 @@ type ReverseHeapVarDict = HashMap>; pub struct HCPrinter<'a, Outputter> { outputter: Outputter, machine_st: &'a MachineState, + op_dir: &'a OpDir, state_stack: Vec, toplevel_spec: Option, heap_locs: ReverseHeapVarDict, @@ -371,10 +394,11 @@ fn non_quoted_token>(mut iter: Iter) -> bool { 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, @@ -386,11 +410,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> 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); @@ -515,7 +539,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> return; } } - + if let Some(spec) = ct.spec() { if "." == ct.name().as_str() && is_infix!(spec.assoc()) { if !self.ignore_ops { @@ -562,8 +586,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option { 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); @@ -688,31 +712,32 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> fn print_constant(&mut self, c: Constant, op: &Option) { 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); @@ -787,10 +812,52 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> self.state_stack.push(TokenOrRedirect::OpenList(cell)); } + fn handle_op_as_struct(&mut self, name: ClauseName, arity: usize, iter: &mut HCPreOrderIterator, + op: &Option, 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, 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, @@ -798,43 +865,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> }; 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("[]"); diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index 70628760..ba21dd43 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -140,7 +140,7 @@ impl MachineState { 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![]); @@ -154,7 +154,7 @@ impl MachineState { 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; @@ -188,6 +188,6 @@ impl Machine { 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) } } diff --git a/src/prolog/machine/dynamic_database.rs b/src/prolog/machine/dynamic_database.rs index abbb421d..ac6ba36a 100644 --- a/src/prolog/machine/dynamic_database.rs +++ b/src/prolog/machine/dynamic_database.rs @@ -62,7 +62,7 @@ impl Machine { 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); diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 1456fcfc..8fcac8d1 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -40,7 +40,7 @@ impl Ball { pub(super) fn take(&mut self) -> Ball { let boundary = self.boundary; self.boundary = 0; - + Ball { boundary, stub: mem::replace(&mut self.stub, vec![]) @@ -238,7 +238,7 @@ pub struct MachineState { 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); @@ -548,12 +548,18 @@ pub(crate) trait CallPolicy: Any { 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); @@ -584,7 +590,7 @@ pub(crate) trait CallPolicy: Any { }, &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(); diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 9914d69c..516dccc6 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -186,7 +186,7 @@ impl MachineState { } pub(super) - fn print_var_eq(&self, var: Rc, addr: Addr, var_dict: &HeapVarDict, + fn print_var_eq(&self, var: Rc, addr: Addr, op_dir: &OpDir, var_dict: &HeapVarDict, mut output: Outputter) -> Outputter where Outputter: HCValueOutputter @@ -198,13 +198,13 @@ impl MachineState { 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) { @@ -2038,13 +2038,14 @@ impl MachineState { 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(..) => { @@ -2079,6 +2080,8 @@ impl MachineState { 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 { diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index afc638f1..131fa4e4 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -413,7 +413,8 @@ impl Machine { }; } - 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) => { @@ -627,21 +628,24 @@ impl Machine { 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(&self, var_dir: &HeapVarDict, mut output: Outputter) -> Outputter + pub fn test_heap_view(&self, var_dir: &HeapVarDict, mut output: Outputter) + -> Outputter where Outputter: HCValueOutputter { let mut sorted_vars: Vec<(&Rc, &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 @@ -654,10 +658,10 @@ impl Machine { 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; diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index de4f6e75..8c2a5557 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -3,6 +3,7 @@ use prolog_parser::parser::{get_desc, get_clause_spec}; 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::*; @@ -908,7 +909,7 @@ impl MachineState { _ => 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) @@ -1167,9 +1168,11 @@ impl MachineState { }, _ => 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); @@ -1423,9 +1426,9 @@ impl MachineState { 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)); @@ -1503,7 +1506,7 @@ impl MachineState { 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"; diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index 72999709..f2d952ff 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -289,10 +289,10 @@ impl<'a, R: Read> TermStream<'a, R> { 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() { @@ -338,7 +338,7 @@ impl MachineState { 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()) diff --git a/src/tests.rs b/src/tests.rs index f6d788ff..57eaefeb 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1838,7 +1838,7 @@ insect(bee)."); 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"]]); -- 2.54.0