From 41d99938e74a7eaf30e1fd6add440c4b6e0b186e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 6 Nov 2017 22:01:54 -0700 Subject: [PATCH] fix arithmetic bugs. --- src/prolog/arithmetic.rs | 88 +++++++++++++++---------------- src/prolog/ast.rs | 31 +++++------ src/prolog/codegen.rs | 108 ++++++++++++++++++++------------------- src/prolog/io.rs | 35 +++++-------- src/prolog/machine.rs | 56 +++++++++----------- src/prolog/macros.rs | 18 +++++-- 6 files changed, 161 insertions(+), 175 deletions(-) diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 6c8b1d71..8a93ed3f 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -1,5 +1,7 @@ use prolog::ast::*; use prolog::fixtures::*; +use prolog::num::{BigInt, Zero}; +use prolog::ordered_float::{OrderedFloat}; use std::cell::Cell; use std::cmp::{min, max}; @@ -93,7 +95,7 @@ impl<'a> ArithmeticEvaluator<'a> { ArithmeticEvaluator { bindings, interm: Vec::new(), interm_c: 1 } } - fn get_un_instr(name: &Atom, a1: ArithmeticTerm, t: ArithEvalPlace) + fn get_un_instr(name: &Atom, a1: ArithmeticTerm, t: usize) -> Result { match name.as_str() { @@ -102,7 +104,7 @@ impl<'a> ArithmeticEvaluator<'a> { } } - fn gen_bin_instr(name: &Atom, a1: ArithmeticTerm, a2: ArithmeticTerm, t: ArithEvalPlace) + fn gen_bin_instr(name: &Atom, a1: ArithmeticTerm, a2: ArithmeticTerm, t: usize) -> Result { match name.as_str() { @@ -124,53 +126,45 @@ impl<'a> ArithmeticEvaluator<'a> { temp } - fn instr_from_clause(&mut self, name: &Atom, terms: &Vec>, deep: bool) + fn instr_from_clause(&mut self, name: &Atom, terms: &Vec>) -> Result { match terms.len() { 1 => { let a1 = self.interm.pop().unwrap(); - if deep { - let ninterm = if a1.interm_or(0) == 0 { - self.incr_interm() - } else { - self.interm.push(a1.clone()); - a1.interm_or(0) - }; - - Self::get_un_instr(name, a1, ArithEvalPlace::Interm(ninterm)) + let ninterm = if a1.interm_or(0) == 0 { + self.incr_interm() } else { - Self::get_un_instr(name, a1, ArithEvalPlace::Reg(RegType::Temp(2))) - } + self.interm.push(a1.clone()); + a1.interm_or(0) + }; + + Self::get_un_instr(name, a1, ninterm) }, 2 => { let a2 = self.interm.pop().unwrap(); let a1 = self.interm.pop().unwrap(); - if deep { - let min_interm = min(a1.interm_or(0), a2.interm_or(0)); + let min_interm = min(a1.interm_or(0), a2.interm_or(0)); - let ninterm = if min_interm == 0 { - let max_interm = max(a1.interm_or(0), a2.interm_or(0)); + let ninterm = if min_interm == 0 { + let max_interm = max(a1.interm_or(0), a2.interm_or(0)); - if max_interm == 0 { - self.incr_interm() - } else { - self.interm.push(ArithmeticTerm::Interm(max_interm)); - self.interm_c = max_interm + 1; - max_interm - } + if max_interm == 0 { + self.incr_interm() } else { - self.interm.push(ArithmeticTerm::Interm(min_interm)); - self.interm_c = min_interm + 1; - min_interm - }; - - Self::gen_bin_instr(name, a1, a2, ArithEvalPlace::Interm(ninterm)) + self.interm.push(ArithmeticTerm::Interm(max_interm)); + self.interm_c = max_interm + 1; + max_interm + } } else { - Self::gen_bin_instr(name, a1, a2, ArithEvalPlace::Reg(RegType::Temp(2))) - } + self.interm.push(ArithmeticTerm::Interm(min_interm)); + self.interm_c = min_interm + 1; + min_interm + }; + + Self::gen_bin_instr(name, a1, a2, ninterm) }, _ => Err(ArithmeticError::InvalidOp) } @@ -200,7 +194,7 @@ impl<'a> ArithmeticEvaluator<'a> { let r = if vr.get().norm().reg_num() == 0 { match self.bindings.get(name) { Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t), - Some(&VarData::Perm(p)) => RegType::Perm(p), + Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p), _ => return Err(ArithmeticError::UninstantiatedVar) } } else { @@ -210,11 +204,11 @@ impl<'a> ArithmeticEvaluator<'a> { self.interm.push(ArithmeticTerm::Reg(r)); }, TermRef::Clause(ClauseType::Deep(_, _, name), terms) => { - code.push(Line::Arithmetic(self.instr_from_clause(name, terms, true)?)); + code.push(Line::Arithmetic(self.instr_from_clause(name, terms)?)); }, TermRef::Clause(ClauseType::Root, terms) => { let name = term.name().unwrap(); - code.push(Line::Arithmetic(self.instr_from_clause(name, terms, false)?)); + code.push(Line::Arithmetic(self.instr_from_clause(name, terms)?)); }, _ => return Err(ArithmeticError::InvalidTerm) @@ -223,20 +217,22 @@ impl<'a> ArithmeticEvaluator<'a> { if let Some(arith_term) = self.interm.pop() { match arith_term { - ArithmeticTerm::Integer(n) => { - let n = Constant::Integer(n); - code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]); + n @ ArithmeticTerm::Integer(_) => { + let zero = ArithmeticTerm::Integer(BigInt::zero()); + code.push(arith![add!(zero, n, 1)]); + }, + n @ ArithmeticTerm::Float(_) => { + let zero = ArithmeticTerm::Float(OrderedFloat(0f64)); + code.push(arith![add!(zero, n, 1)]); }, - ArithmeticTerm::Float(n) => { - let n = Constant::Float(n); - code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]); + r @ ArithmeticTerm::Reg(_) => { + let zero = ArithmeticTerm::Integer(BigInt::zero()); + code.push(arith![add!(zero, r, 1)]); }, - ArithmeticTerm::Reg(r) => - code.push(query![put_value!(r, 2)]), - _ => return Err(ArithmeticError::InvalidTerm) + _ => {} }; } - + Ok(code) } } diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index d51756b0..05fc31b5 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -556,17 +556,12 @@ impl ArithmeticTerm { } } -#[derive(Clone, Copy)] -pub enum ArithEvalPlace { - Interm(usize), Reg(RegType) -} - pub enum ArithmeticInstruction { - Add(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), - Sub(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), - Mul(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), - IDiv(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), - Neg(ArithmeticTerm, ArithEvalPlace) + Add(ArithmeticTerm, ArithmeticTerm, usize), + Sub(ArithmeticTerm, ArithmeticTerm, usize), + Mul(ArithmeticTerm, ArithmeticTerm, usize), + IDiv(ArithmeticTerm, ArithmeticTerm, usize), + Neg(ArithmeticTerm, usize) } pub enum BuiltInInstruction { @@ -588,20 +583,20 @@ pub enum BuiltInInstruction { } pub enum ControlInstruction { - Allocate(usize), - Call(Atom, usize, usize), - CallN(usize), + Allocate(usize), // num_frames. + Call(Atom, usize, usize), // name, arity, perm_vars after threshold. + CallN(usize), // arity. CatchCall, CatchExecute, Deallocate, Execute(Atom, usize), ExecuteN(usize), Goto(usize, usize), // p, arity. + IsCall(RegType), + IsExecute(RegType), Proceed, ThrowCall, - ThrowExecute, - UnifyCall, - UnifyExecute + ThrowExecute, } impl ControlInstruction { @@ -617,8 +612,8 @@ impl ControlInstruction { &ControlInstruction::ThrowExecute => true, &ControlInstruction::Goto(_, _) => true, &ControlInstruction::Proceed => true, - &ControlInstruction::UnifyCall => true, - &ControlInstruction::UnifyExecute => true, + &ControlInstruction::IsCall(_) => true, + &ControlInstruction::IsExecute(_) => true, _ => false } } diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index d5164e5f..b8625a23 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -7,6 +7,7 @@ use prolog::iterators::*; use prolog::targets::*; use std::collections::HashMap; +use std::mem::swap; use std::vec::Vec; pub struct CodeGenerator<'a, TermMarker> { @@ -218,9 +219,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> }, QueryTermRef::Catch(_) => compiled_query.push(Line::Control(ControlInstruction::CatchCall)), - QueryTermRef::IsAtomic(_) => - compiled_query.push(proceed!()), - QueryTermRef::IsVar(_) => + QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) => compiled_query.push(proceed!()), QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => { let call = ControlInstruction::Call(atom.clone(), 0, pvs); @@ -236,41 +235,29 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> } } - fn lco(code: &mut Code, toc: QueryTermRef<'a>) -> usize + fn lco(code: &mut Code) -> usize { - let last_arity = toc.arity(); let mut dealloc_index = code.len() - 1; - match toc { - QueryTermRef::Term(&Term::Clause(_, ref name, _)) - | QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref name))) => - if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { - *ctrl = ControlInstruction::Execute(name.clone(), last_arity); - }, - QueryTermRef::CallN(terms) => - if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { - *ctrl = ControlInstruction::ExecuteN(terms.len()); - }, - QueryTermRef::Catch(_) => - if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { - *ctrl = ControlInstruction::CatchExecute; - }, - QueryTermRef::Cut => {}, - QueryTermRef::Throw(_) => - if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { - *ctrl = ControlInstruction::ThrowExecute; - }, - QueryTermRef::Is(_) => - if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { - *ctrl = ControlInstruction::UnifyExecute; - }, - QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) => { - dealloc_index = code.len(); - code.push(proceed!()); - }, - _ => dealloc_index = code.len() - }; - + if let Some(&mut Line::Control(ref mut ctrl)) = code.last_mut() { + let mut instr = ControlInstruction::Proceed; + swap(ctrl, &mut instr); + + match instr { + ControlInstruction::Call(name, arity, _) => + *ctrl = ControlInstruction::Execute(name, arity), + ControlInstruction::CallN(arity) => + *ctrl = ControlInstruction::ExecuteN(arity), + ControlInstruction::IsCall(r) => + *ctrl = ControlInstruction::IsExecute(r), + ControlInstruction::CatchCall => + *ctrl = ControlInstruction::CatchExecute, + ControlInstruction::ThrowCall => + *ctrl = ControlInstruction::ThrowExecute, + _ => dealloc_index += 1 // = code.len() + } + } + dealloc_index } @@ -310,31 +297,39 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings()); evaluator.eval(terms[1].as_ref())? }; - + code.append(&mut arith_code); match terms[0].as_ref() { - &Term::Var(ref vr, ref name) => { - let mut target = Vec::new(); + &Term::Var(ref vr, ref name) => + match self.marker.bindings().get(name) { + Some(&VarData::Temp(_, t, _)) if t != 0 => + code.push(is_call!(temp_v!(t))), + Some(&VarData::Perm(p)) if p != 0 => + code.push(is_call!(perm_v!(p))), + _ => { + let mut target = Vec::new(); - self.marker.advance(term_loc, *term); - self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); + // reset self.marker.arg_c to 1. + self.marker.advance(term_loc, *term); + self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); - code.push(Line::Query(target)); - code.push(unify_call!()); - }, + code.push(Line::Query(target)); + code.push(is_call!(vr.get().norm())); + } + }, &Term::Constant(_, Constant::Float(fl)) => { code.push(query![put_constant!(Level::Shallow, Constant::Float(fl), temp_v!(1))]); - code.push(unify_call!()); + code.push(is_call!(temp_v!(1))); }, &Term::Constant(_, Constant::Integer(ref bi)) => { let bi = bi.clone(); code.push(query![put_constant!(Level::Shallow, Constant::Integer(bi), temp_v!(1))]); - code.push(unify_call!()); + code.push(is_call!(temp_v!(1))); }, _ => { return Err(ParserError::from(ArithmeticError::InvalidTerm)); @@ -357,9 +352,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(is_atomic!(RegType::Perm(p))), _ => { let mut target = Vec::new(); - + // reset self.marker.arg_c to 1. - self.marker.advance(term_loc, *term); + self.marker.advance(term_loc, *term); self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); code.push(Line::Query(target)); @@ -383,9 +378,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(is_var!(RegType::Perm(p))), _ => { let mut target = Vec::new(); - + // reset self.marker.arg_c to 1. - self.marker.advance(term_loc, *term); + self.marker.advance(term_loc, *term); self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); code.push(Line::Query(target)); @@ -419,19 +414,26 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> let perm_vars = conjunct_info.perm_vars(); body.push(Line::Control(ControlInstruction::Allocate(perm_vars))); - + if conjunct_info.has_deep_cut { body.push(Line::Cut(CutInstruction::GetLevel)); } } } - fn compile_cleanup(body: &mut Code, conjunct_info: &ConjunctInfo, toc: QueryTermRef<'a>) + fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: QueryTermRef<'a>) { - let dealloc_index = Self::lco(body, toc); + //TODO: temporary workaround for inlined builtins. + match toc { + QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) => + code.push(proceed!()), + _ => {} + } + + let dealloc_index = Self::lco(code); if conjunct_info.allocates() { - body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); + code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); } } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 0b64587f..38f46bfe 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -107,10 +107,10 @@ impl fmt::Display for ControlInstruction { write!(f, "call_throw"), &ControlInstruction::ThrowExecute => write!(f, "execute_throw"), - &ControlInstruction::UnifyCall => - write!(f, "unify_call"), - &ControlInstruction::UnifyExecute => - write!(f, "unify_execute"), + &ControlInstruction::IsCall(r) => + write!(f, "is_call {}", r), + &ControlInstruction::IsExecute(r) => + write!(f, "is_execute {}", r), } } } @@ -203,30 +203,19 @@ impl fmt::Display for ArithmeticTerm { } } -impl fmt::Display for ArithEvalPlace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ArithEvalPlace::Reg(r) => - write!(f, "{}", r), - &ArithEvalPlace::Interm(i) => - write!(f, "@{}", i) - } - } -} - impl fmt::Display for ArithmeticInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &ArithmeticInstruction::Add(ref a1, ref a2, ref t) => - write!(f, "add {}, {}, {}", a1, a2, t), + write!(f, "add {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::Sub(ref a1, ref a2, ref t) => - write!(f, "sub {}, {}, {}", a1, a2, t), + write!(f, "sub {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::Mul(ref a1, ref a2, ref t) => - write!(f, "mul {}, {}, {}", a1, a2, t), + write!(f, "mul {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) => - write!(f, "idiv {}, {}, {}", a1, a2, t), + write!(f, "idiv {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::Neg(ref a, ref t) => - write!(f, "neg {}, {}", a, t) + write!(f, "neg {}, @{}", a, t) } } } @@ -343,7 +332,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<' Ok(pred) => pred, Err(e) => return EvalSession::ParserError(e) }; - + wam.add_predicate(clauses, compiled_pred) }, &TopLevel::Fact(ref fact) => { @@ -359,7 +348,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<' Ok(rule) => rule, Err(e) => return EvalSession::ParserError(e) }; - + wam.add_rule(rule, compiled_rule) }, &TopLevel::Query(ref query) => { @@ -369,7 +358,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<' Ok(query) => query, Err(e) => return EvalSession::ParserError(e) }; - + wam.submit_query(compiled_query, cg.take_vars()) } } diff --git a/src/prolog/machine.rs b/src/prolog/machine.rs index fcca23c2..68374c92 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -765,7 +765,7 @@ impl MachineState { Ref::HeapCell(r) => self.heap[r] = HeapCellValue::Ref(Ref::HeapCell(r)), Ref::StackCell(fr, sc) => - self.and_stack[fr][sc] = Addr::StackCell(fr, sc) + self.and_stack[fr][sc] = Addr::StackCell(fr, sc) } } } @@ -848,42 +848,33 @@ impl MachineState { Err("is/2: variable not instantiated to number.") } }, - &ArithmeticTerm::Interm(i) => Ok(self.interms[i].clone()), + &ArithmeticTerm::Interm(i) => Ok(self.interms[i-1].clone()), &ArithmeticTerm::Float(fl) => Ok(Number::Float(fl)), &ArithmeticTerm::Integer(ref bi) => Ok(Number::Integer(bi.clone())) } } - fn assign_arith(&mut self, t: ArithEvalPlace, n: Number) { - match t { - ArithEvalPlace::Reg(r) => - self[r] = Addr::Con(Constant::from(n)), - ArithEvalPlace::Interm(i) => - self.interms[i] = n - } - } - fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { match instr { &ArithmeticInstruction::Add(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.assign_arith(t, n1 + n2); + self.interms[t - 1] = n1 + n2; self.p += 1; }, &ArithmeticInstruction::Sub(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.assign_arith(t, n1 - n2); + self.interms[t - 1] = n1 - n2; self.p += 1; }, &ArithmeticInstruction::Mul(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.assign_arith(t, n1 * n2); + self.interms[t - 1] = n1 * n2; self.p += 1; }, &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { @@ -899,7 +890,7 @@ impl MachineState { return; } - self.assign_arith(t, Number::Integer(n1 / n2)); + self.interms[t - 1] = Number::Integer(n1 / n2); self.p += 1; }, _ => { @@ -913,7 +904,7 @@ impl MachineState { &ArithmeticInstruction::Neg(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.assign_arith(t, - n1); + self.interms[t - 1] = - n1; self.p += 1; } }; @@ -1492,8 +1483,7 @@ impl MachineState { let d = self.deref(self[r].clone()); match d { - Addr::HeapCell(_) | Addr::StackCell(_,_) => - self.p += 1, + Addr::HeapCell(_) | Addr::StackCell(_,_) => self.p += 1, _ => self.fail = true }; }, @@ -1507,23 +1497,19 @@ impl MachineState { self.p += 1; }, &BuiltInInstruction::Unify => { - self.inline_unify(); + let a1 = self[temp_v!(1)].clone(); + let a2 = self[temp_v!(2)].clone(); + + self.unify(a1, a2); self.p += 1; } }; } - fn inline_unify(&mut self) { - let a1 = self[temp_v!(1)].clone(); - let a2 = self[temp_v!(2)].clone(); - - self.unify(a1, a2); - } - fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction) { match instr { - &ControlInstruction::Allocate(num_cells) => { + &ControlInstruction::Allocate(num_cells) => { let num_frames = self.num_frames(); self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells); @@ -1575,14 +1561,20 @@ impl MachineState { &ControlInstruction::ThrowExecute => { self.goto_throw(); }, - &ControlInstruction::UnifyCall => { - self.inline_unify(); + &ControlInstruction::IsCall(r) => { + let a1 = self[r].clone(); + let a2 = Addr::Con(Constant::from(self.interms[0].clone())); + + self.unify(a1, a2); self.p += 1; }, - &ControlInstruction::UnifyExecute => { - self.inline_unify(); + &ControlInstruction::IsExecute(r) => { + let a1 = self[r].clone(); + let a2 = Addr::Con(Constant::from(self.interms[0].clone())); + + self.unify(a1, a2); self.p = self.cp; - } + } }; } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 1fa4b4d0..75ee4eb6 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -22,6 +22,12 @@ macro_rules! query { ) } +macro_rules! arith { + ($x:expr) => ( + Line::Arithmetic($x) + ) +} + macro_rules! string { ($str:expr) => { vec![HeapCellValue::Con(Constant::String(String::from($str)))] @@ -105,6 +111,12 @@ macro_rules! put_unsafe_value { ) } +macro_rules! add { + ($r1:expr, $r2:expr, $t:expr) => ( + ArithmeticInstruction::Add($r1, $r2, $t) + ) +} + macro_rules! try_me_else { ($o:expr) => ( Line::Choice(ChoiceInstruction::TryMeElse($o)) @@ -209,9 +221,9 @@ macro_rules! unify { ) } -macro_rules! unify_call { - () => ( - Line::Control(ControlInstruction::UnifyCall) +macro_rules! is_call { + ($r:expr) => ( + Line::Control(ControlInstruction::IsCall($r)) ) } -- 2.54.0