add support for callable if-then and disjunct

This commit is contained in:
Mark Thom
2018-05-12 00:30:34 -06:00
parent ba7e7ac895
commit 7455c2e9db
12 changed files with 252 additions and 295 deletions

View File

@@ -30,9 +30,9 @@ fn prolog_repl() {
let mut wam = Machine::new(); let mut wam = Machine::new();
load_init_str_and_include(&mut wam, BUILTINS, "builtins"); load_init_str_and_include(&mut wam, BUILTINS, "builtins");
// load_init_str(&mut wam, LISTS); load_init_str(&mut wam, LISTS);
// load_init_str(&mut wam, CONTROL); // load_init_str(&mut wam, CONTROL);
// load_init_str(&mut wam, QUEUES); // load_init_str(&mut wam, QUEUES);
loop { loop {
print!("prolog> "); print!("prolog> ");

View File

@@ -715,14 +715,20 @@ pub struct Rule {
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub enum SystemClauseType { pub enum SystemClauseType {
InstallCleaner,
InstallInferenceCounter,
RemoveCallPolicyCheck,
RemoveInferenceCounter,
RestoreCutPolicy,
SetCutPoint(RegType),
GetArg, GetArg,
InferenceLevel(RegType, RegType), InferenceLevel,
CleanUpBlock, CleanUpBlock,
EraseBall, EraseBall,
Fail, Fail,
GetBall, GetBall,
GetCurrentBlock, GetCurrentBlock,
GetCutPoint(RegType), GetCutPoint,
InstallNewBlock, InstallNewBlock,
ResetBlock, ResetBlock,
SetBall, SetBall,
@@ -734,14 +740,20 @@ pub enum SystemClauseType {
impl SystemClauseType { impl SystemClauseType {
pub fn arity(&self) -> usize { pub fn arity(&self) -> usize {
match self { match self {
&SystemClauseType::InstallCleaner => 1,
&SystemClauseType::InstallInferenceCounter => 3,
&SystemClauseType::RemoveCallPolicyCheck => 1,
&SystemClauseType::RemoveInferenceCounter => 2,
&SystemClauseType::RestoreCutPolicy => 0,
&SystemClauseType::SetCutPoint(_) => 1,
&SystemClauseType::GetArg => 3, &SystemClauseType::GetArg => 3,
&SystemClauseType::InferenceLevel(..) => 2, &SystemClauseType::InferenceLevel => 2,
&SystemClauseType::CleanUpBlock => 1, &SystemClauseType::CleanUpBlock => 1,
&SystemClauseType::EraseBall => 0, &SystemClauseType::EraseBall => 0,
&SystemClauseType::Fail => 0, &SystemClauseType::Fail => 0,
&SystemClauseType::GetBall => 1, &SystemClauseType::GetBall => 1,
&SystemClauseType::GetCurrentBlock => 1, &SystemClauseType::GetCurrentBlock => 1,
&SystemClauseType::GetCutPoint(_) => 1, &SystemClauseType::GetCutPoint => 1,
&SystemClauseType::InstallNewBlock => 1, &SystemClauseType::InstallNewBlock => 1,
&SystemClauseType::ResetBlock => 1, &SystemClauseType::ResetBlock => 1,
&SystemClauseType::SetBall => 1, &SystemClauseType::SetBall => 1,
@@ -757,13 +769,22 @@ impl SystemClauseType {
pub fn name(&self) -> ClauseName { pub fn name(&self) -> ClauseName {
match self { match self {
&SystemClauseType::InstallCleaner => clause_name!("$install_cleaner"),
&SystemClauseType::InstallInferenceCounter =>
clause_name!("$install_inference_counter"),
&SystemClauseType::RemoveCallPolicyCheck =>
clause_name!("$remove_call_policy_check"),
&SystemClauseType::RemoveInferenceCounter =>
clause_name!("$remove_inference_counter"),
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
&SystemClauseType::GetArg => clause_name!("$get_arg"), &SystemClauseType::GetArg => clause_name!("$get_arg"),
&SystemClauseType::InferenceLevel(..) => clause_name!("$inference_level"), &SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
&SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"), &SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
&SystemClauseType::EraseBall => clause_name!("$erase_ball"), &SystemClauseType::EraseBall => clause_name!("$erase_ball"),
&SystemClauseType::Fail => clause_name!("$fail"), &SystemClauseType::Fail => clause_name!("$fail"),
&SystemClauseType::GetBall => clause_name!("$get_ball"), &SystemClauseType::GetBall => clause_name!("$get_ball"),
&SystemClauseType::GetCutPoint(_) => clause_name!("$get_cp"), &SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"), &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"), &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"), &SystemClauseType::ResetBlock => clause_name!("$reset_block"),
@@ -776,14 +797,24 @@ impl SystemClauseType {
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> { pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
match (name, arity) { match (name, arity) {
("$install_cleaner", 1) =>
Some(SystemClauseType::InstallCleaner),
("$install_inference_counter", 3) =>
Some(SystemClauseType::InstallInferenceCounter),
("$remove_call_policy_check", 1) =>
Some(SystemClauseType::RemoveCallPolicyCheck),
("$remove_inference_counter", 1) =>
Some(SystemClauseType::RemoveInferenceCounter),
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
("$get_arg", 3) => Some(SystemClauseType::GetArg), ("$get_arg", 3) => Some(SystemClauseType::GetArg),
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel(temp_v!(0), temp_v!(0))), ("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock), ("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
("$erase_ball", 0) => Some(SystemClauseType::EraseBall), ("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
("$fail", 0) => Some(SystemClauseType::Fail), ("$fail", 0) => Some(SystemClauseType::Fail),
("$get_ball", 1) => Some(SystemClauseType::GetBall), ("$get_ball", 1) => Some(SystemClauseType::GetBall),
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock), ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint(temp_v!(0))), ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
("$set_ball", 1) => Some(SystemClauseType::SetBall), ("$set_ball", 1) => Some(SystemClauseType::SetBall),
@@ -1371,12 +1402,6 @@ pub enum ArithmeticInstruction {
// call and cut policy exempt instructions. // call and cut policy exempt instructions.
#[derive(Clone)] #[derive(Clone)]
pub enum PEInstruction { pub enum PEInstruction {
InstallCleaner,
InstallInferenceCounter(RegType, RegType, RegType),
RemoveCallPolicyCheck,
RemoveInferenceCounter(RegType, RegType),
RestoreCutPolicy,
SetCutPoint(RegType),
} }
#[derive(Clone)] #[derive(Clone)]
@@ -1453,7 +1478,6 @@ pub type CompiledQuery = Vec<QueryInstruction>;
#[derive(Clone)] #[derive(Clone)]
pub enum Line { pub enum Line {
Arithmetic(ArithmeticInstruction), Arithmetic(ArithmeticInstruction),
PolicyExempt(PEInstruction),
Choice(ChoiceInstruction), Choice(ChoiceInstruction),
Control(ControlInstruction), Control(ControlInstruction),
Cut(CutInstruction), Cut(CutInstruction),
@@ -1590,6 +1614,7 @@ impl From<(usize, ClauseName)> for CodeIndex {
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum CodePtr { pub enum CodePtr {
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
CallN(usize, LocalCodePtr), // arity, local.
Local(LocalCodePtr) Local(LocalCodePtr)
} }
@@ -1597,6 +1622,7 @@ impl CodePtr {
pub fn local(&self) -> LocalCodePtr { pub fn local(&self) -> LocalCodePtr {
match self { match self {
&CodePtr::BuiltInClause(_, ref local) &CodePtr::BuiltInClause(_, ref local)
| &CodePtr::CallN(_, ref local)
| &CodePtr::Local(ref local) => local.clone() | &CodePtr::Local(ref local) => local.clone()
} }
} }
@@ -1685,7 +1711,8 @@ impl Add<usize> for CodePtr {
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self { match self {
CodePtr::Local(local) => CodePtr::Local(local + rhs), CodePtr::Local(local) => CodePtr::Local(local + rhs),
CodePtr::BuiltInClause(_, local) => CodePtr::Local(local + rhs), CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) =>
CodePtr::Local(local + rhs),
} }
} }
} }

View File

@@ -658,7 +658,7 @@ pub fn default_op_dir() -> OpDir
op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200, module_name.clone())); op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200, module_name.clone()));
op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200, module_name.clone())); op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200, module_name.clone()));
op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200, module_name.clone())); op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200, module_name.clone()));
// op_dir.insert((clause_name!("/"), Fixity::In), (YFX, 400, module_name.clone())); op_dir.insert((clause_name!("/"), Fixity::In), (YFX, 400, module_name.clone()));
/* /*
// control operators. // control operators.

View File

@@ -166,25 +166,6 @@ impl fmt::Display for IndexedChoiceInstruction {
} }
} }
impl fmt::Display for PEInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&PEInstruction::InstallInferenceCounter(r1, r2, r3) =>
write!(f, "install_inference_counter {}, {}, {}", r1, r2, r3),
&PEInstruction::InstallCleaner =>
write!(f, "install_cleaner"),
&PEInstruction::RemoveCallPolicyCheck =>
write!(f, "remove_call_policy_check"),
&PEInstruction::RemoveInferenceCounter(r1, r2) =>
write!(f, "remove_inference_counter {}, {}", r1, r2),
&PEInstruction::RestoreCutPolicy =>
write!(f, "restore_cut_point"),
&PEInstruction::SetCutPoint(r) =>
write!(f, "set_cp {}", r),
}
}
}
impl fmt::Display for ChoiceInstruction { impl fmt::Display for ChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -328,8 +309,6 @@ pub fn print_code(code: &Code) {
for fact_instr in fact { for fact_instr in fact {
println!("{}", fact_instr); println!("{}", fact_instr);
}, },
&Line::PolicyExempt(ref instr) =>
println!("{}", instr),
&Line::Cut(ref cut) => &Line::Cut(ref cut) =>
println!("{}", cut), println!("{}", cut),
&Line::Choice(ref choice) => &Line::Choice(ref choice) =>
@@ -537,6 +516,8 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSe
decl_info.label_clauses(wam.code_size(), &mut wam.code_dir, &mut code); decl_info.label_clauses(wam.code_size(), &mut wam.code_dir, &mut code);
print_code(&code);
if !code.is_empty() { if !code.is_empty() {
wam.add_user_code(name, tl.arity(), code, tl.as_predicate().ok().unwrap()) wam.add_user_code(name, tl.arity(), code, tl.as_predicate().ok().unwrap())
} else { } else {

View File

@@ -2,8 +2,9 @@
:- module(builtins, [(=)/2, (+)/2, (*)/2, (-)/2, (/)/2, (/\)/2, :- module(builtins, [(=)/2, (+)/2, (*)/2, (-)/2, (/)/2, (/\)/2,
(\/)/2, (is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2, (\/)/2, (is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2,
(>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2, (-)/1, (>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2,
(>=)/2, (=<)/2, (->)/2, (;)/2, catch/3, throw/1, true/0, false/0]). (-)/1, (>=)/2, (=<)/2, (->)/2, (;)/2, (==)/2, catch/3,
throw/1, true/0, false/0]).
% arithmetic operators. % arithmetic operators.
:- op(700, xfx, is). :- op(700, xfx, is).
@@ -30,12 +31,15 @@
:- op(700, xfx, >=). :- op(700, xfx, >=).
:- op(700, xfx, =<). :- op(700, xfx, =<).
% unify.
:- op(700, xfx, =).
% conditional operators. % conditional operators.
:- op(1050, xfy, ->). :- op(1050, xfy, ->).
:- op(1100, xfy, ;). :- op(1100, xfy, ;).
% unify. % term comparison.
:- op(700, xfx, =). :- op(700, xfx, ==).
% unify. % unify.
X = X. X = X.
@@ -44,33 +48,32 @@ true.
false :- '$fail'. false :- '$fail'.
% conditions. % control operators.
/*
','(G1, G2) :- get_cp(B), ','(G1, G2, B).
','(!, ','(G1, G2), B) :- set_cp(B), ','(G1, G2, B). ','(G1, G2) :- '$get_cp'(B), ','(G1, G2, B).
','(!, !, B) :- set_cp(B).
','(!, G, B) :- set_cp(B), G. ','(!, ','(G1, G2), B) :- '$set_cp'(B), ','(G1, G2, B).
','(!, !, B) :- '$set_cp'(B).
','(!, G, B) :- '$set_cp'(B), G.
','(G, ','(G2, G3), B) :- !, G, ','(G2, G3, B). ','(G, ','(G2, G3), B) :- !, G, ','(G2, G3, B).
','(G, !, B) :- !, G, set_cp(B). ','(G, !, B) :- !, G, '$set_cp'(B).
','(G1, G2, _) :- G1, G2. ','(G1, G2, _) :- G1, G2.
;(G1, G2) :- get_cp(B), ;(G1, G2, B). ;(G1, G2) :- '$get_cp'(B), ;(G1, G2, B).
;(G1 -> G2, _, B) :- ->(G1, G2, B). ;(G1, G4, B) :- compound(G1), G1 = ->(G2, G3), (G2 -> G3 ; '$set_cp'(B), G4).
;(_ -> _ , G, B) :- set_cp(B), G. ;(G1, G2, B) :- G1 == !, '$set_cp'(B), call(G2).
;(!, _, B) :- set_cp(B). ;(G1, G2, B) :- G2 == !, call(G2), '$set_cp'(B).
;(_, !, B) :- set_cp(B).
;(G, _, _) :- G. ;(G, _, _) :- G.
;(_, G, _) :- G. ;(_, G, _) :- G.
G1 -> G2 :- get_cp(B), ->(G1, G2, B). G1 -> G2 :- '$get_cp'(B), ->(G1, G2, B).
->(G1, !, B) :- call(G1), set_cp(B). ->(G1, G2, B) :- G2 == !, call(G1), !, '$set_cp'(B).
->(G1, G2, B) :- call(G1), set_cp(B), call(G2). ->(G1, G2, B) :- call(G1), '$set_cp'(B), call(G2).
*/
% exception handling.
% exceptions.
catch(G,C,R) :- '$get_current_block'(Bb), catch(G,C,R,Bb). catch(G,C,R) :- '$get_current_block'(Bb), catch(G,C,R,Bb).
catch(G,C,R,Bb) :- '$install_new_block'(NBb), call(G), end_block(Bb, NBb). catch(G,C,R,Bb) :- '$install_new_block'(NBb), call(G), end_block(Bb, NBb).

View File

@@ -324,6 +324,7 @@ pub(crate) trait CallPolicy: Any {
let n = machine_st.or_stack[b].num_args(); let n = machine_st.or_stack[b].num_args();
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
let addr = machine_st.store(machine_st.deref(machine_st.or_stack[b][i].clone()));
machine_st.registers[i] = machine_st.or_stack[b][i].clone(); machine_st.registers[i] = machine_st.or_stack[b][i].clone();
} }
@@ -517,40 +518,37 @@ pub(crate) trait CallPolicy: Any {
} }
} }
fn call_n<'a>(&mut self, machine_st: &mut MachineState, mut arity: usize, fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize,
code_dirs: CodeDirs<'a>, lco: bool) code_dirs: CodeDirs<'a>, lco: bool)
-> CallResult -> CallResult
{ {
while let Some((name, inner_arity)) = machine_st.setup_call_n(arity) { if let Some((name, arity)) = machine_st.setup_call_n(arity) {
let user = clause_name!("user"); let user = clause_name!("user");
match ClauseType::from(name.clone(), inner_arity, None) { match ClauseType::from(name.clone(), arity, None) {
ClauseType::CallN => { ClauseType::CallN => {
machine_st.handle_internal_call_n(inner_arity); machine_st.handle_internal_call_n(arity);
if machine_st.fail { if machine_st.fail {
return Ok(()); return Ok(());
} }
arity = inner_arity; machine_st.p = CodePtr::CallN(arity, machine_st.p.local());
continue;
}, },
ClauseType::BuiltIn(built_in) => ClauseType::BuiltIn(built_in) =>
machine_st.setup_built_in_call(built_in), machine_st.setup_built_in_call(built_in),
ClauseType::Inlined(inlined) => ClauseType::Inlined(inlined) =>
machine_st.execute_inlined(&inlined), machine_st.execute_inlined(&inlined),
ClauseType::Op(..) | ClauseType::Named(..) => ClauseType::Op(..) | ClauseType::Named(..) =>
if let Some(idx) = code_dirs.get(name.clone(), inner_arity, user) { if let Some(idx) = code_dirs.get(name.clone(), arity, user) {
self.context_call(machine_st, name, inner_arity, idx, lco)?; self.context_call(machine_st, name, arity, idx, lco)?;
} else { } else {
return Err(machine_st.existence_error(name, inner_arity)); return Err(machine_st.existence_error(name, arity));
}, },
ClauseType::System(ct) => ClauseType::System(ct) =>
return Err(machine_st.type_error(ValidType::Callable, return Err(machine_st.type_error(ValidType::Callable,
Addr::Con(Constant::Atom(name)))) Addr::Con(Constant::Atom(name))))
}; };
break;
} }
Ok(()) Ok(())
@@ -700,8 +698,6 @@ impl CutPolicy for DefaultCutPolicy {
machine_st.fail = true; machine_st.fail = true;
return; return;
} }
machine_st.p += 1;
} }
} }
@@ -743,8 +739,6 @@ impl CutPolicy for SetupCallCleanupCutPolicy {
return; return;
} }
machine_st.p += 1;
if !self.out_of_cont_pts() { if !self.out_of_cont_pts() {
machine_st.cp.assign_if_local(machine_st.p.clone()); machine_st.cp.assign_if_local(machine_st.p.clone());
machine_st.num_of_args = 0; machine_st.num_of_args = 0;

View File

@@ -1,6 +1,5 @@
use prolog::and_stack::*; use prolog::and_stack::*;
use prolog::ast::*; use prolog::ast::*;
use prolog::builtins::*;
use prolog::copier::*; use prolog::copier::*;
use prolog::heap_iter::*; use prolog::heap_iter::*;
use prolog::heap_print::*; use prolog::heap_print::*;
@@ -956,8 +955,10 @@ impl MachineState {
self.registers[arg] = self.heap[h].as_addr(h); self.registers[arg] = self.heap[h].as_addr(h);
} }
}, },
&QueryInstruction::PutValue(norm, arg) => &QueryInstruction::PutValue(norm, arg) => {
self.registers[arg] = self[norm].clone(), let addr = self.store(self.deref(self[norm].clone()));
self.registers[arg] = self[norm].clone();
},
&QueryInstruction::PutVariable(norm, arg) => { &QueryInstruction::PutVariable(norm, arg) => {
match norm { match norm {
RegType::Perm(n) => { RegType::Perm(n) => {
@@ -1400,121 +1401,6 @@ impl MachineState {
} }
} }
pub(super)
fn execute_pe_instr<'a>(&mut self, code_dirs: CodeDirs<'a>, call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>, instr: &PEInstruction)
{
match instr {
&PEInstruction::InstallCleaner => {
let addr = self[temp_v!(1)].clone();
let b = self.b;
let block = self.block;
if cut_policy.downcast_ref::<SetupCallCleanupCutPolicy>().is_err() {
*cut_policy = Box::new(SetupCallCleanupCutPolicy::new());
}
match cut_policy.downcast_mut::<SetupCallCleanupCutPolicy>().ok()
{
Some(cut_policy) => cut_policy.push_cont_pt(addr, b, block),
None => panic!("install_cleaner: should have installed \\
SetupCallCleanupCutPolicy.")
};
self.p += 1;
},
&PEInstruction::InstallInferenceCounter(r1, r2, r3) => { // A1 = B, A2 = L
let a1 = self.store(self.deref(self[r1].clone()));
let a2 = self.store(self.deref(self[r2].clone()));
if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
CallWithInferenceLimitCallPolicy::new_in_place(call_policy);
}
self.p += 1;
match (a1, a2.clone()) {
(Addr::Con(Constant::Usize(bp)),
Addr::Con(Constant::Number(Number::Integer(n)))) =>
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => {
let count = call_policy.add_limit(n, bp);
self[r3] = Addr::Con(Constant::Number(Number::Integer(count)));
},
None => panic!("install_inference_counter: should have installed \\
CallWithInferenceLimitCallPolicy.")
},
_ => {
let stub = self.functor_stub(clause_name!("call_with_inference_limit"), 3);
let type_error = self.error_form(self.type_error(ValidType::Integer, a2),
stub);
self.throw_exception(type_error)
}
};
},
&PEInstruction::RemoveCallPolicyCheck => {
let restore_default =
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => {
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
if let Addr::Con(Constant::Usize(bp)) = a1 {
if call_policy.is_empty() && bp == self.b {
Some(call_policy.into_inner())
} else {
None
}
} else {
panic!("remove_call_policy_check: expected Usize in A1.");
}
},
None => panic!("remove_call_policy_check: requires \\
CallWithInferenceLimitCallPolicy.")
};
if let Some(new_policy) = restore_default {
*call_policy = new_policy;
}
self.p += 1;
},
&PEInstruction::RemoveInferenceCounter(r1, r2) => { // A1 = B
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => {
let a1 = self.store(self.deref(self[r1].clone()));
if let Addr::Con(Constant::Usize(bp)) = a1 {
let count = call_policy.remove_limit(bp);
self[r2] = Addr::Con(Constant::Number(Number::Integer(count)));
} else {
panic!("remove_inference_counter: expected Usize in A1.");
}
},
None => panic!("remove_inference_counters: requires \\
CallWithInferenceLimitCallPolicy.")
};
self.p += 1;
},
&PEInstruction::RestoreCutPolicy => {
let restore_default =
if let Ok(cut_policy) = cut_policy.downcast_ref::<SetupCallCleanupCutPolicy>() {
cut_policy.out_of_cont_pts()
} else {
false
};
if restore_default {
*cut_policy = Box::new(DefaultCutPolicy {});
}
self.p += 1;
},
&PEInstruction::SetCutPoint(r) =>
cut_policy.cut(self, r),
};
}
pub(super) fn try_functor(&mut self) -> Result<(), MachineError> { pub(super) fn try_functor(&mut self) -> Result<(), MachineError> {
let stub = self.functor_stub(clause_name!("functor"), 3); let stub = self.functor_stub(clause_name!("functor"), 3);
let a1 = self.store(self.deref(self[temp_v!(1)].clone())); let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
@@ -1849,7 +1735,7 @@ impl MachineState {
try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(), try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
lco)), lco)),
&ControlInstruction::CallClause(ClauseType::System(ref ct), arity, _, lco) => { &ControlInstruction::CallClause(ClauseType::System(ref ct), arity, _, lco) => {
try_or_fail!(self, self.system_call(ct)); try_or_fail!(self, self.system_call(ct, call_policy, cut_policy));
if lco { if lco {
self.p = CodePtr::Local(self.cp.clone()); self.p = CodePtr::Local(self.cp.clone());
@@ -2011,8 +1897,10 @@ impl MachineState {
self[r] = Addr::Con(Constant::Usize(b0)); self[r] = Addr::Con(Constant::Usize(b0));
self.p += 1; self.p += 1;
}, },
&CutInstruction::Cut(r) => &CutInstruction::Cut(r) => {
cut_policy.cut(self, r), cut_policy.cut(self, r);
self.p += 1;
}
} }
} }

View File

@@ -234,6 +234,8 @@ impl Machine {
Some(self.code[p].clone()), Some(self.code[p].clone()),
CodePtr::BuiltInClause(built_in, _) => CodePtr::BuiltInClause(built_in, _) =>
Some(call_clause!(ClauseType::BuiltIn(built_in), built_in.arity(), 0)), Some(call_clause!(ClauseType::BuiltIn(built_in), built_in.arity(), 0)),
CodePtr::CallN(arity, _) =>
Some(call_clause!(ClauseType::CallN, arity, 0))
} }
} }
@@ -247,11 +249,6 @@ impl Machine {
match instr { match instr {
Line::Arithmetic(ref arith_instr) => Line::Arithmetic(ref arith_instr) =>
self.ms.execute_arith_instr(arith_instr), self.ms.execute_arith_instr(arith_instr),
Line::PolicyExempt(ref built_in_instr) => {
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
self.ms.execute_pe_instr(code_dirs, &mut self.call_policy,
&mut self.cut_policy, built_in_instr);
},
Line::Choice(ref choice_instr) => Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(choice_instr, &mut self.call_policy), self.ms.execute_choice_instr(choice_instr, &mut self.call_policy),
Line::Cut(ref cut_instr) => Line::Cut(ref cut_instr) =>

View File

@@ -3,7 +3,6 @@ use prolog::machine::machine_errors::*;
use prolog::machine::machine_state::*; use prolog::machine::machine_state::*;
use prolog::num::{ToPrimitive, Zero}; use prolog::num::{ToPrimitive, Zero};
use prolog::num::bigint::BigInt; use prolog::num::bigint::BigInt;
use prolog::tabled_rc::*;
use std::rc::Rc; use std::rc::Rc;
@@ -153,14 +152,113 @@ impl MachineState {
Ok(()) Ok(())
} }
pub(super) fn system_call(&mut self, ct: &SystemClauseType) -> CallResult pub(super) fn system_call(&mut self, ct: &SystemClauseType, call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,)
-> CallResult
{ {
match ct { match ct {
&SystemClauseType::InstallCleaner => {
let addr = self[temp_v!(1)].clone();
let b = self.b;
let block = self.block;
if cut_policy.downcast_ref::<SetupCallCleanupCutPolicy>().is_err() {
*cut_policy = Box::new(SetupCallCleanupCutPolicy::new());
}
match cut_policy.downcast_mut::<SetupCallCleanupCutPolicy>().ok()
{
Some(cut_policy) => cut_policy.push_cont_pt(addr, b, block),
None => panic!("install_cleaner: should have installed \\
SetupCallCleanupCutPolicy.")
};
},
&SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
CallWithInferenceLimitCallPolicy::new_in_place(call_policy);
}
match (a1, a2.clone()) {
(Addr::Con(Constant::Usize(bp)),
Addr::Con(Constant::Number(Number::Integer(n)))) =>
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => {
let count = call_policy.add_limit(n, bp);
self[temp_v!(3)] = Addr::Con(Constant::Number(Number::Integer(count)));
},
None => panic!("install_inference_counter: should have installed \\
CallWithInferenceLimitCallPolicy.")
},
_ => {
let stub = self.functor_stub(clause_name!("call_with_inference_limit"), 3);
let type_error = self.error_form(self.type_error(ValidType::Integer, a2),
stub);
self.throw_exception(type_error)
}
};
},
&SystemClauseType::RemoveCallPolicyCheck => {
let restore_default =
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => {
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
if let Addr::Con(Constant::Usize(bp)) = a1 {
if call_policy.is_empty() && bp == self.b {
Some(call_policy.into_inner())
} else {
None
}
} else {
panic!("remove_call_policy_check: expected Usize in A1.");
}
},
None => panic!("remove_call_policy_check: requires \\
CallWithInferenceLimitCallPolicy.")
};
if let Some(new_policy) = restore_default {
*call_policy = new_policy;
}
},
&SystemClauseType::RemoveInferenceCounter => {
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
Some(call_policy) => {
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
if let Addr::Con(Constant::Usize(bp)) = a1 {
let count = call_policy.remove_limit(bp);
self[temp_v!(2)] = Addr::Con(Constant::Number(Number::Integer(count)));
} else {
panic!("remove_inference_counter: expected Usize in A1.");
}
},
None => panic!("remove_inference_counters: requires \\
CallWithInferenceLimitCallPolicy.")
};
},
&SystemClauseType::RestoreCutPolicy => {
let restore_default =
if let Ok(cut_policy) = cut_policy.downcast_ref::<SetupCallCleanupCutPolicy>() {
cut_policy.out_of_cont_pts()
} else {
false
};
if restore_default {
*cut_policy = Box::new(DefaultCutPolicy {});
}
},
&SystemClauseType::SetCutPoint(r) =>
cut_policy.cut(self, r),
&SystemClauseType::GetArg => &SystemClauseType::GetArg =>
self.try_get_arg(), return self.try_get_arg(),
&SystemClauseType::InferenceLevel(r1, r2) => { &SystemClauseType::InferenceLevel => {
let a1 = self[r1].clone(); let a1 = self[temp_v!(1)].clone();
let a2 = self.store(self.deref(self[r2].clone())); let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
match a2 { match a2 {
Addr::Con(Constant::Usize(bp)) => Addr::Con(Constant::Usize(bp)) =>
@@ -173,8 +271,6 @@ impl MachineState {
}, },
_ => self.fail = true _ => self.fail = true
}; };
Ok(())
}, },
&SystemClauseType::CleanUpBlock => { &SystemClauseType::CleanUpBlock => {
let nb = self.store(self.deref(self[temp_v!(1)].clone())); let nb = self.store(self.deref(self[temp_v!(1)].clone()));
@@ -190,17 +286,9 @@ impl MachineState {
}, },
_ => self.fail = true _ => self.fail = true
}; };
Ok(())
},
&SystemClauseType::EraseBall => {
self.ball.reset();
Ok(())
},
&SystemClauseType::Fail => {
self.fail = true;
Ok(())
}, },
&SystemClauseType::EraseBall => self.ball.reset(),
&SystemClauseType::Fail => self.fail = true,
&SystemClauseType::GetBall => { &SystemClauseType::GetBall => {
let addr = self.store(self.deref(self[temp_v!(1)].clone())); let addr = self.store(self.deref(self[temp_v!(1)].clone()));
let h = self.heap.h; let h = self.heap.h;
@@ -218,20 +306,18 @@ impl MachineState {
Some(r) => self.bind(r, ball), Some(r) => self.bind(r, ball),
_ => self.fail = true _ => self.fail = true
}; };
Ok(())
}, },
&SystemClauseType::GetCurrentBlock => { &SystemClauseType::GetCurrentBlock => {
let c = Constant::Usize(self.block); let c = Constant::Usize(self.block);
let addr = self[temp_v!(1)].clone(); let addr = self[temp_v!(1)].clone();
self.write_constant_to_var(addr, c); self.write_constant_to_var(addr, c);
Ok(())
}, },
&SystemClauseType::GetCutPoint(r) => { &SystemClauseType::GetCutPoint => {
let c = Constant::Usize(self.b); let a1 = self[temp_v!(1)].clone();
self[r] = Addr::Con(c); let a2 = Addr::Con(Constant::Usize(self.b));
Ok(())
self.unify(a1, a2);
}, },
&SystemClauseType::InstallNewBlock => { &SystemClauseType::InstallNewBlock => {
self.block = self.b; self.block = self.b;
@@ -240,28 +326,17 @@ impl MachineState {
let addr = self[temp_v!(1)].clone(); let addr = self[temp_v!(1)].clone();
self.write_constant_to_var(addr, c); self.write_constant_to_var(addr, c);
Ok(())
}, },
&SystemClauseType::ResetBlock => { &SystemClauseType::ResetBlock => {
let addr = self.deref(self[temp_v!(1)].clone()); let addr = self.deref(self[temp_v!(1)].clone());
self.reset_block(addr); self.reset_block(addr);
Ok(())
}, },
&SystemClauseType::SetBall => { &SystemClauseType::SetBall => self.set_ball(),
self.set_ball(); &SystemClauseType::SkipMaxList => return self.skip_max_list(),
Ok(()) &SystemClauseType::Succeed => {},
}, &SystemClauseType::UnwindStack => self.unwind_stack()
&SystemClauseType::SkipMaxList => { };
self.skip_max_list()?;
Ok(()) Ok(())
},
&SystemClauseType::Succeed => {
Ok(())
},
&SystemClauseType::UnwindStack => {
self.unwind_stack();
Ok(())
}
}
} }
} }

View File

@@ -152,7 +152,7 @@ macro_rules! is_call {
macro_rules! set_cp { macro_rules! set_cp {
($r:expr) => ( ($r:expr) => (
Line::PolicyExempt(PEInstruction::SetCutPoint($r)) call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
) )
} }

View File

@@ -398,27 +398,20 @@ impl RelationWorker {
Term::Var(_, ref v) if v.as_str() == "!" => Term::Var(_, ref v) if v.as_str() == "!" =>
Ok(QueryTerm::UnblockedCut(Cell::default())), Ok(QueryTerm::UnblockedCut(Cell::default())),
Term::Clause(r, name, mut terms, fixity) => Term::Clause(r, name, mut terms, fixity) =>
if name.as_str() == ";" { if name.as_str() == ";" && terms.len() == 2 {
if terms.len() == 2 { let term = Term::Clause(r, name.clone(), terms, fixity);
let term = Term::Clause(r, name.clone(), terms, fixity); let (stub, clauses) = self.fabricate_disjunct(term);
let (stub, clauses) = self.fabricate_disjunct(term);
self.queue.push_back(clauses); self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
} else {
Err(ParserError::BuiltInArityMismatch(";"))
}
} else if name.as_str() == "->" && terms.len() == 2 { } else if name.as_str() == "->" && terms.len() == 2 {
if terms.len() == 2 { let conq = *terms.pop().unwrap();
let conq = *terms.pop().unwrap(); let prec = *terms.pop().unwrap();
let prec = *terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq);
self.queue.push_back(clauses); let (stub, clauses) = self.fabricate_if_then(prec, conq);
Ok(QueryTerm::Jump(stub))
} else { self.queue.push_back(clauses);
Err(ParserError::BuiltInArityMismatch("->")) Ok(QueryTerm::Jump(stub))
}
} else { } else {
Ok(QueryTerm::Clause(Cell::default(), Ok(QueryTerm::Clause(Cell::default(),
ClauseType::from(name, terms.len(), fixity), ClauseType::from(name, terms.len(), fixity),

View File

@@ -1201,16 +1201,14 @@ fn test_queries_on_skip_max_list() {
[["Xs = non_list", "N = 0"]]); [["Xs = non_list", "N = 0"]]);
} }
/*
#[test] #[test]
fn test_queries_on_conditionals() fn test_queries_on_conditionals()
{ {
let mut wam = Machine::new(); let mut wam = Machine::new();
load_init_str_and_include(&mut wam, BUILTINS, "builtins");
submit(&mut wam, "test(A) :- ( A =:= 2 -> submit(&mut wam, "test(A) :- ( A =:= 2 -> display(\"A is 2\")
display(\"A is 2\") ; A =:= 3 -> display(\"A is 3\")
; A =:= 3 ->
display(\"A is 3\")
; A = \"not 2 or 3\" ; A = \"not 2 or 3\"
)."); ).");
@@ -1268,6 +1266,7 @@ fn test_queries_on_conditionals()
[["X = a"], ["X = b"]]); [["X = a"], ["X = b"]]);
} }
/*
#[test] #[test]
fn test_queries_on_builtins() fn test_queries_on_builtins()
{ {