$call_with_default_policy.
pub type JumpStub = Vec<Term>;
pub enum QueryTerm {
- Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>),
+ // register, clause type, subterms, use default call policy.
+ Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
UnblockedCut(Cell<VarReg>),
GetLevelAndUnify(Cell<VarReg>, Rc<Var>),
}
impl QueryTerm {
+ pub fn set_default_caller(&mut self) {
+ match self {
+ &mut QueryTerm::Clause(_, _, _, ref mut use_default_cp) => *use_default_cp = true,
+ _ => {}
+ };
+ }
+
pub fn arity(&self) -> usize {
match self {
- &QueryTerm::Clause(_, _, ref subterms) => subterms.len(),
+ &QueryTerm::Clause(_, _, ref subterms, ..) => subterms.len(),
&QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => 0,
&QueryTerm::Jump(ref vars) => vars.len(),
&QueryTerm::GetLevelAndUnify(..) => 1,
#[derive(Clone)]
pub enum ControlInstruction {
Allocate(usize), // num_frames.
- CallClause(ClauseType, usize, usize, bool), // name, arity, perm_vars after threshold, last call.
+ // name, arity, perm_vars after threshold, last call, use default call policy.
+ CallClause(ClauseType, usize, usize, bool, bool),
Deallocate,
JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
Proceed
match qt {
&QueryTerm::Jump(ref vars) =>
code.push(jmp_call!(vars.len(), 0, pvs)),
- &QueryTerm::Clause(_, ref ct, ref terms) =>
+ &QueryTerm::Clause(_, ref ct, ref terms, true) =>
+ code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs)),
+ &QueryTerm::Clause(_, ref ct, ref terms, false) =>
code.push(call_clause!(ct.clone(), terms.len(), pvs)),
_ => {}
}
match code.last_mut() {
Some(&mut Line::Control(ref mut ctrl)) =>
match ctrl.clone() {
- ControlInstruction::CallClause(ct, arity, pvs, false) =>
- *ctrl = ControlInstruction::CallClause(ct, arity, pvs, true),
+ ControlInstruction::CallClause(ct, arity, pvs, false, use_default_cp) =>
+ *ctrl = ControlInstruction::CallClause(ct, arity, pvs, true, use_default_cp),
ControlInstruction::JmpBy(arity, offset, pvs, false) =>
*ctrl = ControlInstruction::JmpBy(arity, offset, pvs, true),
ControlInstruction::Proceed => {},
if !target.is_empty() {
code.push(Line::Query(target));
}
-
+
code.push(get_level_and_unify!(cell.get().norm()));
},
&QueryTerm::UnblockedCut(ref cell) =>
} else {
Line::Cut(CutInstruction::Cut(perm_v!(1)))
}),
- &QueryTerm::Clause(_, ClauseType::BuiltIn(BuiltInClauseType::Is(..)), ref terms)
+ &QueryTerm::Clause(_, ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
+ ref terms, use_default_call_policy)
=>
{
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
code.push(Line::Query(target));
}
- code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))));
+ if use_default_call_policy {
+ code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))));
+ } else {
+ code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))));
+ }
},
&Term::Constant(_, ref c @ Constant::Number(_)) => {
code.push(query![put_constant!(Level::Shallow,
c.clone(),
temp_v!(1))]);
- code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))));
+
+ if use_default_call_policy {
+ code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))));
+ } else {
+ code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))));
+ }
},
_ => {
code.push(fail!());
}
}
},
- &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms) =>
+ &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) =>
try!(self.compile_inlined(ct, terms, term_loc, code)),
_ => {
let num_perm_vars = if chunk_num == 0 {
// add a proceed to bookend any trailing cuts.
match toc {
&QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()),
- &QueryTerm::Clause(_, ClauseType::Inlined(..), _) => code.push(proceed!()),
+ &QueryTerm::Clause(_, ClauseType::Inlined(..), ..) => code.push(proceed!()),
_ => {}
};
ChoiceInstruction::RetryMeElse(offset)
}
}
-
+
fn compile_pred_subseq<'b: 'a>(&mut self, clauses: &'b [PredicateClause])
-> Result<Code, ParserError>
{
match self {
&ControlInstruction::Allocate(num_cells) =>
write!(f, "allocate {}", num_cells),
- &ControlInstruction::CallClause(ref ct, arity, pvs, true) =>
+ &ControlInstruction::CallClause(ref ct, arity, pvs, true, true) =>
+ write!(f, "call_with_default_policy {}/{}, {}", ct, arity, pvs),
+ &ControlInstruction::CallClause(ref ct, arity, pvs, false, true) =>
+ write!(f, "execute_with_default_policy {}/{}, {}", ct, arity, pvs),
+ &ControlInstruction::CallClause(ref ct, arity, pvs, true, false) =>
write!(f, "execute {}/{}, {}", ct, arity, pvs),
- &ControlInstruction::CallClause(ref ct, arity, pvs, false) =>
- write!(f, "call {}/{}, {}", ct, arity, pvs),
+ &ControlInstruction::CallClause(ref ct, arity, pvs, false, false) =>
+ write!(f, "call {}/{}, {}", ct, arity, pvs),
&ControlInstruction::Deallocate =>
write!(f, "deallocate"),
&ControlInstruction::JmpBy(arity, offset, pvs, false) =>
}
fn new(term: &'a QueryTerm) -> Self {
- match term {
- &QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms) => {
+ match term {
+ &QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms, _) => {
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN, terms);
QueryIterator { state_stack: vec![state] }
},
- &QueryTerm::Clause(ref cell, ref ct, ref terms) => {
+ &QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms);
QueryIterator { state_stack: vec![state] }
},
},
ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) =>
result.push(term),
- ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), _)) =>
+ ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) =>
result.push(term),
- ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::CallN, ref subterms)) =>
+ ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::CallN, ref subterms, _)) =>
{
result.push(term);
arity = subterms.len() + 1;
self.p += 1;
}
+ fn handle_call_clause<'a>(&mut self, code_dirs: CodeDirs<'a>,
+ call_policy: &mut Box<CallPolicy>,
+ cut_policy: &mut Box<CutPolicy>,
+ ct: &ClauseType,
+ arity: usize,
+ lco: bool,
+ use_default_cp: bool)
+ {
+ let mut default_call_policy: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
+ let call_policy = if use_default_cp {
+ &mut default_call_policy
+ } else {
+ call_policy
+ };
+
+ self.last_call = lco;
+
+ match ct {
+ &ClauseType::BuiltIn(ref ct) =>
+ try_or_fail!(self, call_policy.call_builtin(self, ct, Box::new(code_dirs))),
+ &ClauseType::CallN =>
+ try_or_fail!(self, call_policy.call_n(self, arity, Box::new(code_dirs))),
+ &ClauseType::Inlined(ref ct) =>
+ self.execute_inlined(ct),
+ &ClauseType::Named(ref name, ref idx) | &ClauseType::Op(ref name, _, ref idx) =>
+ try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
+ Box::new(code_dirs))),
+ &ClauseType::System(ref ct) =>
+ try_or_fail!(self, self.system_call(ct, code_dirs, call_policy, cut_policy))
+ };
+ }
+
pub(super) fn execute_ctrl_instr<'a>(&mut self, code_dirs: CodeDirs<'a>,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,
match instr {
&ControlInstruction::Allocate(num_cells) =>
self.allocate(num_cells),
- &ControlInstruction::CallClause(ClauseType::CallN, arity, _, lco) => {
- self.last_call = lco;
- try_or_fail!(self, call_policy.call_n(self, arity, Box::new(code_dirs)));
- },
- &ControlInstruction::CallClause(ClauseType::BuiltIn(ref ct), _, _, lco) => {
- self.last_call = lco;
- try_or_fail!(self, call_policy.call_builtin(self, ct, Box::new(code_dirs)));
- },
- &ControlInstruction::CallClause(ClauseType::Inlined(ref ct), ..) =>
- self.execute_inlined(ct),
- &ControlInstruction::CallClause(ClauseType::Named(ref name, ref idx), arity, _, lco)
- | &ControlInstruction::CallClause(ClauseType::Op(ref name, _, ref idx), arity, _, lco) => {
- self.last_call = lco;
- try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
- Box::new(code_dirs)));
- },
- &ControlInstruction::CallClause(ClauseType::System(ref ct), _, _, lco) => {
- self.last_call = lco;
- try_or_fail!(self, self.system_call(ct, code_dirs, call_policy, cut_policy));
- },
+ &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) =>
+ self.handle_call_clause(code_dirs, call_policy, cut_policy, ct, arity, lco,
+ use_default_cp),
&ControlInstruction::Deallocate => self.deallocate(),
&ControlInstruction::JmpBy(arity, offset, _, lco) => {
if !lco {
macro_rules! call_clause {
($ct:expr, $arity:expr, $pvs:expr) => (
- Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, false))
+ Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, false, false))
);
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => (
- Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, $lco))
+ Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, $lco, false))
+ )
+}
+
+macro_rules! call_clause_by_default {
+ ($ct:expr, $arity:expr, $pvs:expr) => (
+ Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, false, true))
+ );
+ ($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => (
+ Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, $lco, true))
)
}
)
}
+macro_rules! is_call_by_default {
+ ($r:expr, $at:expr) => (
+ call_clause_by_default!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
+ )
+}
+
macro_rules! set_cp {
($r:expr) => (
call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
if let Term::Constant(_, Constant::Atom(mod_name)) = mod_name {
if let Term::Clause(_, name, terms, _) = body {
let idx = CodeIndex(Rc::new(RefCell::new((IndexPtr::Module, mod_name))));
- return Ok(QueryTerm::Clause(Cell::default(), ClauseType::Named(name, idx), terms));
+ return Ok(QueryTerm::Clause(Cell::default(), ClauseType::Named(name, idx), terms,
+ false));
}
}
Ok(QueryTerm::BlockedCut)
} else {
let ct = indices.lookup(name, 0, None);
- Ok(QueryTerm::Clause(r, ct, vec![]))
+ Ok(QueryTerm::Clause(r, ct, vec![], false))
},
Term::Var(_, ref v) if v.as_str() == "!" =>
Ok(QueryTerm::UnblockedCut(Cell::default())),
}
} else {
let ct = indices.lookup(name, terms.len(), fixity);
- Ok(QueryTerm::Clause(Cell::default(), ct, terms))
+ Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
},
- Term::Var(_, _) =>
- Ok(QueryTerm::Clause(Cell::default(), ClauseType::CallN, vec![Box::new(term)])),
+ Term::Var(..) =>
+ Ok(QueryTerm::Clause(Cell::default(), ClauseType::CallN, vec![Box::new(term)],
+ false)),
_ =>
Err(ParserError::InadmissibleQueryTerm)
}
}
}
+ fn pre_query_term(&mut self, idx: &mut MachineCodeIndices, term: Term)
+ -> Result<QueryTerm, ParserError>
+ {
+ match term {
+ Term::Clause(r, name, mut subterms, fixity) =>
+ if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
+ self.to_query_term(idx, *subterms.pop().unwrap())
+ .map(|mut query_term| {
+ query_term.set_default_caller();
+ query_term
+ })
+ } else {
+ self.to_query_term(idx, Term::Clause(r, name, subterms, fixity))
+ },
+ _ => self.to_query_term(idx, term)
+ }
+ }
+
fn setup_query(&mut self, idx: &mut MachineCodeIndices, terms: Vec<Box<Term>>, blocks_cuts: bool)
-> Result<Vec<QueryTerm>, ParserError>
{
mark_cut_variable(&mut subterm);
}
- query_terms.push(try!(self.to_query_term(idx, subterm)));
+ query_terms.push(self.pre_query_term(idx, subterm)?);
}
}
assert_prolog_failure!(&mut wam, "?- Pairs = [a-a|Pairs], keysort(Pairs, _).");
assert_prolog_success!(&mut wam, "?- Pairs = [a-a|Pairs], catch(keysort(Pairs, _), error(E, _), true).",
- [["E = type_error(list, [a-a | _26])", "Pairs = [a-a | Pairs]"]]);
+ [["E = type_error(list, [a-a | _22])", "Pairs = [a-a | Pairs]"]]);
assert_prolog_success!(&mut wam, "?- keysort([], L).",
[["L = []"]]);
assert_prolog_success!(&mut wam, "?- catch(keysort([],[a|a]),error(Pat, _),true).",
[["Pat = type_error(list, [a | a])"]]);
assert_prolog_success!(&mut wam, "?- catch(keysort(_, _), error(E, _), true).",
- [["E = type_error(list, _17)"]]);
+ [["E = type_error(list, _13)"]]);
assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [_|b]), error(E, _), true).",
- [["E = type_error(list, [_28 | b])"]]);
+ [["E = type_error(list, [_24 | b])"]]);
assert_prolog_success!(&mut wam, "?- catch(keysort([a-1], [a-b,c-d,a]), error(E, _), true).",
[["E = type_error(pair, a)"]]);
assert_prolog_success!(&mut wam, "?- catch(keysort([a], [a-b]), error(E, _), true).",
assert_prolog_success!(&mut wam, "?- sort([], L).",
[["L = []"]]);
assert_prolog_success!(&mut wam, "?- catch(sort(_, []), error(E, _), true).",
- [["E = type_error(list, _17)"]]);
+ [["E = type_error(list, _13)"]]);
assert_prolog_success!(&mut wam, "?- catch(sort([a,b,c], not_a_list), error(E, _), true).",
[["E = type_error(list, not_a_list)"]]);