add call_with_inference_limit

This commit is contained in:
Mark Thom
2018-02-19 22:34:56 -07:00
parent 8b566ab4e5
commit 7313472a70
12 changed files with 541 additions and 171 deletions

View File

@@ -1,11 +1,18 @@
use prolog::and_stack::*;
use prolog::builtins::CodeDir;
use prolog::ast::*;
use prolog::copier::*;
use prolog::num::{BigInt, BigUint, Zero, One};
use prolog::or_stack::*;
use prolog::tabled_rc::*;
use downcast::Any;
use std::cmp::Ordering;
use std::collections::binary_heap::BinaryHeap;
use std::mem::swap;
use std::ops::{Index, IndexMut};
use std::rc::Rc;
pub(super) struct DuplicateTerm<'a> {
state: &'a mut MachineState
@@ -176,6 +183,288 @@ pub struct MachineState {
pub(super) interms: Vec<Number>, // intermediate numbers.
}
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
pub(crate) trait CallPolicy: Any {
fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: TabledRc<Atom>, arity: usize)
-> CallResult
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
match compiled_tl_index {
Some(compiled_tl_index) => {
machine_st.cp = machine_st.p + 1;
machine_st.num_of_args = arity;
machine_st.b0 = machine_st.b;
machine_st.p = CodePtr::DirEntry(compiled_tl_index);
},
None => machine_st.fail = true
};
Ok(())
}
fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: TabledRc<Atom>, arity: usize)
-> CallResult
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
match compiled_tl_index {
Some(compiled_tl_index) => {
machine_st.num_of_args = arity;
machine_st.b0 = machine_st.b;
machine_st.p = CodePtr::DirEntry(compiled_tl_index);
},
None => machine_st.fail = true
};
Ok(())
}
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
{
let b = machine_st.b - 1;
let n = machine_st.or_stack[b].num_args();
for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
machine_st.or_stack[b].bp = machine_st.p + offset;
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
machine_st.unwind_trail(old_tr, curr_tr);
machine_st.tr = machine_st.or_stack[b].tr;
machine_st.trail.truncate(machine_st.tr);
machine_st.heap.truncate(machine_st.or_stack[b].h);
machine_st.hb = machine_st.heap.h;
machine_st.p += 1;
Ok(())
}
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
{
let b = machine_st.b - 1;
let n = machine_st.or_stack[b].num_args();
for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
machine_st.or_stack[b].bp = machine_st.p + 1;
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
machine_st.unwind_trail(old_tr, curr_tr);
machine_st.tr = machine_st.or_stack[b].tr;
machine_st.trail.truncate(machine_st.tr);
machine_st.heap.truncate(machine_st.or_stack[b].h);
machine_st.hb = machine_st.heap.h;
machine_st.p += offset;
Ok(())
}
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
{
let b = machine_st.b - 1;
let n = machine_st.or_stack[b].num_args();
for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
machine_st.unwind_trail(old_tr, curr_tr);
machine_st.tr = machine_st.or_stack[b].tr;
machine_st.trail.truncate(machine_st.tr);
machine_st.heap.truncate(machine_st.or_stack[b].h);
machine_st.b = machine_st.or_stack[b].b;
machine_st.or_stack.truncate(machine_st.b);
machine_st.hb = machine_st.heap.h;
machine_st.p += offset;
Ok(())
}
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult
{
let b = machine_st.b - 1;
let n = machine_st.or_stack[b].num_args();
for i in 1 .. n + 1 {
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
machine_st.unwind_trail(old_tr, curr_tr);
machine_st.tr = machine_st.or_stack[b].tr;
machine_st.trail.truncate(machine_st.tr);
machine_st.heap.truncate(machine_st.or_stack[b].h);
machine_st.b = machine_st.or_stack[b].b;
machine_st.or_stack.truncate(machine_st.b);
machine_st.hb = machine_st.heap.h;
machine_st.p += 1;
Ok(())
}
}
downcast!(CallPolicy);
pub(crate) struct DefaultCallPolicy {}
impl CallPolicy for DefaultCallPolicy {}
#[derive(Clone, Eq, PartialEq)]
struct InferenceLimit(BigUint);
// ensure the heap behaves as a min-heap.
impl Ord for InferenceLimit {
fn cmp(&self, other: &InferenceLimit) -> Ordering {
other.0.cmp(&self.0)
}
}
impl PartialOrd for InferenceLimit {
fn partial_cmp(&self, other: &InferenceLimit) -> Option<Ordering> {
Some(self.cmp(other))
}
}
pub(crate) struct CallWithInferenceLimitCallPolicy {
atom_tbl: TabledData<Atom>,
pub(crate) prev_policy: Box<CallPolicy>,
count: BigUint,
limits: BinaryHeap<InferenceLimit>
}
impl CallWithInferenceLimitCallPolicy {
pub(crate) fn new_in_place(atom_tbl: TabledData<Atom>, policy: &mut Box<CallPolicy>)
{
let mut prev_policy: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
swap(&mut prev_policy, policy);
let new_policy = CallWithInferenceLimitCallPolicy { atom_tbl, prev_policy,
count: BigUint::zero(),
limits: BinaryHeap::new() };
*policy = Box::new(new_policy);
}
fn increment(&mut self) -> CallResult {
if let Some(ref limit) = self.limits.peek() {
if self.count == limit.0 {
return Err(vec![heap_atom!("inference_limit_exceeded", self.atom_tbl)])
} else {
self.count = BigUint::one() + &self.count;
}
}
Ok(())
}
pub(crate) fn add_limit(&mut self, limit: Rc<BigInt>) {
match limit.to_biguint() {
Some(limit) => self.limits.push(InferenceLimit(limit + &self.count)),
_ => panic!("add_limit: expected unsigned integer.")
};
}
pub(crate) fn remove_limit(&mut self) -> Option<BigUint> {
self.limits.pop().map(|i| i.0 - &self.count)
}
pub(crate) fn is_empty(&self) -> bool {
self.limits.is_empty()
}
pub(crate) fn into_inner(&mut self) -> Box<CallPolicy> {
let mut new_inner: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
swap(&mut self.prev_policy, &mut new_inner);
new_inner
}
}
impl CallPolicy for CallWithInferenceLimitCallPolicy {
fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: TabledRc<Atom>, arity: usize)
-> CallResult
{
self.prev_policy.try_call(machine_st, code_dir, name, arity)?;
self.increment()
}
fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: TabledRc<Atom>, arity: usize)
-> CallResult
{
self.prev_policy.try_execute(machine_st, code_dir, name, arity)?;
self.increment()
}
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
{
self.prev_policy.retry_me_else(machine_st, offset)?;
self.increment()
}
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
{
self.prev_policy.retry(machine_st, offset)?;
self.increment()
}
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult
{
self.prev_policy.trust_me(machine_st)?;
self.increment()
}
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
{
self.prev_policy.trust(machine_st, offset)?;
self.increment()
}
}
pub(crate) trait CutPolicy: Any {
fn cut(&mut self, &mut MachineState, RegType);
}
@@ -200,20 +489,20 @@ impl CutPolicy for DefaultCutPolicy {
return;
}
machine_st.p += 1;
machine_st.p += 1;
}
}
pub(crate) struct SetupCallCleanupCutPolicy {
// locations of cleaners, cut points, the previous block
cont_pts: Vec<(Addr, usize, usize)>
cont_pts: Vec<(Addr, usize, usize)>
}
impl SetupCallCleanupCutPolicy {
pub(crate) fn new() -> Self {
SetupCallCleanupCutPolicy { cont_pts: vec![] }
}
pub(crate) fn out_of_cont_pts(&self) -> bool {
self.cont_pts.is_empty()
}
@@ -243,7 +532,7 @@ impl CutPolicy for SetupCallCleanupCutPolicy {
}
machine_st.p += 1;
if !self.out_of_cont_pts() {
machine_st.cp = machine_st.p;
machine_st.num_of_args = 0;

View File

@@ -185,7 +185,7 @@ impl MachineState {
}
}
fn unwind_trail(&mut self, a1: usize, a2: usize) {
pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) {
for i in a1 .. a2 {
match self.trail[i] {
Ref::HeapCell(r) =>
@@ -932,36 +932,7 @@ impl MachineState {
}
}
fn try_call_predicate(&mut self, code_dir: &CodeDir, name: TabledRc<Atom>, arity: usize)
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.cp = self.p + 1;
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
}
fn try_execute_predicate(&mut self, code_dir: &CodeDir, name: TabledRc<Atom>, arity: usize)
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
}
fn handle_internal_call_n(&mut self, code_dir: &CodeDir)
fn handle_internal_call_n(&mut self, call_policy: &mut Box<CallPolicy>, code_dir: &CodeDir)
{
let arity = self.num_of_args + 1;
let pred = self.registers[1].clone();
@@ -974,7 +945,7 @@ impl MachineState {
self.registers[arity - 1] = pred;
if let Some((name, arity)) = self.setup_call_n(arity - 1) {
self.try_execute_predicate(code_dir, name, arity);
try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity));
}
} else {
self.fail = true;
@@ -1266,7 +1237,8 @@ impl MachineState {
}
pub(super) fn execute_built_in_instr(&mut self, code_dir: &CodeDir,
cut_policy: &mut Box<CutPolicy>,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,
instr: &BuiltInInstruction)
{
match instr {
@@ -1276,12 +1248,21 @@ impl MachineState {
self.compare_numbers(cmp, n1, n2);
},
&BuiltInInstruction::DefaultTrustMe => {
let mut call_policy = DefaultCallPolicy {};
try_or_fail!(self, call_policy.trust_me(self));
},
&BuiltInInstruction::DynamicCompareNumber(cmp) => {
let n1 = try_or_fail!(self, self.arith_eval_by_metacall(temp_v!(1)));
let n2 = try_or_fail!(self, self.arith_eval_by_metacall(temp_v!(2)));
self.compare_numbers(cmp, n1, n2);
},
&BuiltInInstruction::EraseBall => {
self.ball.0 = 0;
self.ball.1.truncate(0);
self.p += 1;
},
&BuiltInInstruction::GetArgCall =>
try_or_fail!(self, {
let val = self.try_get_arg();
@@ -1301,11 +1282,6 @@ impl MachineState {
self.write_constant_to_var(addr, c);
self.p += 1;
},
&BuiltInInstruction::EraseBall => {
self.ball.0 = 0;
self.ball.1.truncate(0);
self.p += 1;
},
&BuiltInInstruction::GetBall => {
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
let h = self.heap.h;
@@ -1333,6 +1309,24 @@ impl MachineState {
self.p += 1;
},
&BuiltInInstruction::InferenceLevel => { // X1 = R, X2 = B.
let a1 = self[temp_v!(1)].clone();
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
match a2 {
Addr::Con(Constant::Usize(bp)) =>
if self.b <= bp {
let a2 = Addr::Con(atom!("!", self.atom_tbl));
self.unify(a1, a2);
} else {
let a2 = Addr::Con(atom!("true", self.atom_tbl));
self.unify(a1, a2);
},
_ => self.fail = true
};
self.p += 1;
},
&BuiltInInstruction::InstallCleaner => {
let addr = self[temp_v!(1)].clone();
let b = self.b;
@@ -1351,6 +1345,31 @@ SetupCallCleanupCutPolicy.")
self.p += 1;
},
&BuiltInInstruction::InstallInferenceCounter(r) => {
let addr = self.store(self.deref(self[r].clone()));
if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
CallWithInferenceLimitCallPolicy::new_in_place(self.atom_tbl.clone(), call_policy);
}
self.p += 1;
match addr {
Addr::Con(Constant::Number(Number::Integer(n))) =>
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => call_policy.add_limit(n),
None => panic!("install_inference_counter: should have installed \\
CallWithInferenceLimitCallPolicy.")
},
_ => {
let atom_tbl = self.atom_tbl.clone();
self.throw_exception(functor!(atom_tbl,
"type_error",
1,
[heap_atom!("integer_expected", atom_tbl)]))
}
};
},
&BuiltInInstruction::IsAtomic(r) => {
let d = self.store(self.deref(self[r].clone()));
@@ -1415,6 +1434,33 @@ SetupCallCleanupCutPolicy.")
_ => self.fail = true
};
},
&BuiltInInstruction::RemoveInferenceCounter(r) => {
let restore_default =
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => {
if let Some(diff) = call_policy.remove_limit() {
let addr = self[r].clone();
self.unify(addr, Addr::Con(integer!(diff)));
} else {
panic!("remove_inference_counters: no limit found.");
}
if call_policy.is_empty() {
Some(call_policy.into_inner())
} else {
None
}
},
None => panic!("remove_inference_counters: requires \\
CallWithInferenceLimitCallPolicy.")
};
if let Some(new_policy) = restore_default {
*call_policy = new_policy;
}
self.p += 1;
},
&BuiltInInstruction::RestoreCutPolicy => {
let restore_default =
if let Ok(cut_policy) = cut_policy.downcast_ref::<SetupCallCleanupCutPolicy>() {
@@ -1492,7 +1538,7 @@ SetupCallCleanupCutPolicy.")
self.fail = true;
},
&BuiltInInstruction::InternalCallN =>
self.handle_internal_call_n(code_dir),
self.handle_internal_call_n(call_policy, code_dir),
&BuiltInInstruction::Fail => {
self.fail = true;
self.p += 1;
@@ -1683,7 +1729,9 @@ SetupCallCleanupCutPolicy.")
false
}
pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, cut_policy: &mut Box<CutPolicy>,
pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,
instr: &ControlInstruction)
{
match instr {
@@ -1728,7 +1776,7 @@ SetupCallCleanupCutPolicy.")
self.p = CodePtr::DirEntry(150);
},
&ControlInstruction::Call(ref name, arity, _) =>
self.try_call_predicate(code_dir, name.clone(), arity),
try_or_fail!(self, call_policy.try_call(self, code_dir, name.clone(), arity)),
&ControlInstruction::CatchCall => {
self.cp = self.p + 1;
self.num_of_args = 3;
@@ -1742,7 +1790,7 @@ SetupCallCleanupCutPolicy.")
},
&ControlInstruction::CallN(arity) =>
if let Some((name, arity)) = self.setup_call_n(arity) {
self.try_call_predicate(code_dir, name, arity);
try_or_fail!(self, call_policy.try_call(self, code_dir, name, arity))
},
&ControlInstruction::CheckCpExecute => {
let a = self.store(self.deref(self[temp_v!(2)].clone()));
@@ -1838,10 +1886,10 @@ SetupCallCleanupCutPolicy.")
self.p = self.cp;
},
&ControlInstruction::Execute(ref name, arity) =>
self.try_execute_predicate(code_dir, name.clone(), arity),
try_or_fail!(self, call_policy.try_execute(self, code_dir, name.clone(), arity)),
&ControlInstruction::ExecuteN(arity) =>
if let Some((name, arity)) = self.setup_call_n(arity) {
self.try_execute_predicate(code_dir, name, arity);
try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity))
},
&ControlInstruction::FunctorCall =>
try_or_fail!(self, {
@@ -1936,7 +1984,8 @@ SetupCallCleanupCutPolicy.")
};
}
pub(super) fn execute_indexed_choice_instr(&mut self, instr: &IndexedChoiceInstruction)
pub(super) fn execute_indexed_choice_instr(&mut self, instr: &IndexedChoiceInstruction,
call_policy: &mut Box<CallPolicy>)
{
match instr {
&IndexedChoiceInstruction::Try(l) => {
@@ -1963,63 +2012,15 @@ SetupCallCleanupCutPolicy.")
self.hb = self.heap.h;
self.p += l;
},
&IndexedChoiceInstruction::Retry(l) => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
self.or_stack[b].bp = self.p + 1;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.hb = self.heap.h;
self.p += l;
},
&IndexedChoiceInstruction::Trust(l) => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.b = self.or_stack[b].b;
self.or_stack.truncate(self.b);
self.hb = self.heap.h;
self.p += l;
},
&IndexedChoiceInstruction::Retry(l) =>
try_or_fail!(self, call_policy.retry(self, l)),
&IndexedChoiceInstruction::Trust(l) =>
try_or_fail!(self, call_policy.trust(self, l))
};
}
pub(super) fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
pub(super) fn execute_choice_instr(&mut self, instr: &ChoiceInstruction,
call_policy: &mut Box<CallPolicy>)
{
match instr {
&ChoiceInstruction::TryMeElse(offset) => {
@@ -2046,60 +2047,10 @@ SetupCallCleanupCutPolicy.")
self.hb = self.heap.h;
self.p += 1;
},
&ChoiceInstruction::RetryMeElse(offset) => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
self.or_stack[b].bp = self.p + offset;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.hb = self.heap.h;
self.p += 1;
},
&ChoiceInstruction::TrustMe => {
let b = self.b - 1;
let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 {
self.registers[i] = self.or_stack[b][i].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
let old_tr = self.or_stack[b].tr;
let curr_tr = self.tr;
self.unwind_trail(old_tr, curr_tr);
self.tr = self.or_stack[b].tr;
self.trail.truncate(self.tr);
self.heap.truncate(self.or_stack[b].h);
self.b = self.or_stack[b].b;
self.or_stack.truncate(self.b);
self.hb = self.heap.h;
self.p += 1;
}
&ChoiceInstruction::RetryMeElse(offset) =>
try_or_fail!(self, call_policy.retry_me_else(self, offset)),
&ChoiceInstruction::TrustMe =>
try_or_fail!(self, call_policy.trust_me(self))
}
}

View File

@@ -19,6 +19,7 @@ use std::rc::Rc;
pub struct Machine {
ms: MachineState,
call_policy: Box<CallPolicy>,
cut_policy: Box<CutPolicy>,
code: Code,
code_dir: CodeDir,
@@ -47,9 +48,9 @@ impl Machine {
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
let (code, code_dir, op_dir) = build_code_dir(atom_tbl.clone());
Machine {
ms: MachineState::new(atom_tbl),
call_policy: Box::new(DefaultCallPolicy {}),
cut_policy: Box::new(DefaultCutPolicy {}),
code,
code_dir,
@@ -106,13 +107,15 @@ impl Machine {
&Line::Arithmetic(ref arith_instr) =>
self.ms.execute_arith_instr(arith_instr),
&Line::BuiltIn(ref built_in_instr) =>
self.ms.execute_built_in_instr(&self.code_dir, &mut self.cut_policy, built_in_instr),
self.ms.execute_built_in_instr(&self.code_dir, &mut self.call_policy,
&mut self.cut_policy, built_in_instr),
&Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(choice_instr),
self.ms.execute_choice_instr(choice_instr, &mut self.call_policy),
&Line::Cut(ref cut_instr) =>
self.ms.execute_cut_instr(cut_instr, &mut self.cut_policy),
&Line::Control(ref control_instr) =>
self.ms.execute_ctrl_instr(&self.code_dir, &mut self.cut_policy, control_instr),
self.ms.execute_ctrl_instr(&self.code_dir, &mut self.call_policy,
&mut self.cut_policy, control_instr),
&Line::Fact(ref fact) => {
for fact_instr in fact {
if self.failed() {
@@ -127,7 +130,7 @@ impl Machine {
&Line::Indexing(ref indexing_instr) =>
self.ms.execute_indexing_instr(&indexing_instr),
&Line::IndexedChoice(ref choice_instr) =>
self.ms.execute_indexed_choice_instr(choice_instr),
self.ms.execute_indexed_choice_instr(choice_instr, &mut self.call_policy),
&Line::Query(ref query) => {
for query_instr in query {
if self.failed() {