Merge branch 'develop'
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::machine::machine_state::*;
|
||||
use prolog::num::bigint::BigInt;
|
||||
|
||||
@@ -8,6 +7,107 @@ use std::rc::Rc;
|
||||
pub(super) type MachineError = Vec<HeapCellValue>;
|
||||
pub(super) type MachineStub = Vec<HeapCellValue>;
|
||||
|
||||
// from 7.12.2 b) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ValidType {
|
||||
Atom,
|
||||
Atomic,
|
||||
// Byte,
|
||||
Callable,
|
||||
// Character,
|
||||
Compound,
|
||||
// Evaluable,
|
||||
// InByte,
|
||||
// InCharacter,
|
||||
Integer,
|
||||
List,
|
||||
// Number,
|
||||
Pair,
|
||||
// PredicateIndicator,
|
||||
// Variable
|
||||
}
|
||||
|
||||
impl ValidType {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
ValidType::Atom => "atom",
|
||||
ValidType::Atomic => "atomic",
|
||||
// ValidType::Byte => "byte",
|
||||
ValidType::Callable => "callable",
|
||||
// ValidType::Character => "character",
|
||||
ValidType::Compound => "compound",
|
||||
// ValidType::Evaluable => "evaluable",
|
||||
// ValidType::InByte => "in_byte",
|
||||
// ValidType::InCharacter => "in_character",
|
||||
ValidType::Integer => "integer",
|
||||
ValidType::List => "list",
|
||||
// ValidType::Number => "number",
|
||||
ValidType::Pair => "pair",
|
||||
// ValidType::PredicateIndicator => "predicate_indicator",
|
||||
// ValidType::Variable => "variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum DomainError {
|
||||
NotLessThanZero
|
||||
}
|
||||
|
||||
impl DomainError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
DomainError::NotLessThanZero => "not_less_than_zero"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 f) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RepFlag {
|
||||
// Character,
|
||||
// CharacterCode,
|
||||
// InCharacterCode,
|
||||
MaxArity,
|
||||
// MaxInteger,
|
||||
// MinInteger
|
||||
}
|
||||
|
||||
impl RepFlag {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
// RepFlag::Character => "character",
|
||||
// RepFlag::CharacterCode => "character_code",
|
||||
// RepFlag::InCharacterCode => "in_character_code",
|
||||
RepFlag::MaxArity => "max_arity",
|
||||
// RepFlag::MaxInteger => "max_integer",
|
||||
// RepFlag::MinInteger => "min_integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 g) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum EvalError {
|
||||
// FloatOverflow,
|
||||
// IntOverflow,
|
||||
// Undefined,
|
||||
// Underflow,
|
||||
ZeroDivisor
|
||||
}
|
||||
|
||||
impl EvalError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
// EvalError::FloatOverflow => "float_overflow",
|
||||
// EvalError::IntOverflow => "int_overflow",
|
||||
// EvalError::Undefined => "undefined",
|
||||
// EvalError::Underflow => "underflow",
|
||||
EvalError::ZeroDivisor => "zero_divisor"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// used by '$skip_max_list'.
|
||||
pub(super) enum CycleSearchResult {
|
||||
EmptyList,
|
||||
@@ -111,6 +211,10 @@ impl MachineState {
|
||||
error
|
||||
}
|
||||
|
||||
pub(super) fn domain_error(&self, error: DomainError, culprit: Addr) -> MachineError {
|
||||
functor!("domain_error", 2, [heap_atom!(error.as_str()), HeapCellValue::Addr(culprit)])
|
||||
}
|
||||
|
||||
pub(super) fn instantiation_error(&self) -> MachineError {
|
||||
functor!("instantiation_error")
|
||||
}
|
||||
@@ -125,7 +229,7 @@ impl MachineState {
|
||||
let mut error_form = vec![HeapCellValue::NamedStr(2, clause_name!("error"), None),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3 + err.len()))];
|
||||
|
||||
|
||||
error_form.extend(err.into_iter());
|
||||
error_form.extend(src.into_iter());
|
||||
|
||||
@@ -141,6 +245,8 @@ impl MachineState {
|
||||
self.heap.append(err);
|
||||
|
||||
self.registers[1] = Addr::HeapCell(h);
|
||||
self.goto_throw();
|
||||
|
||||
self.set_ball();
|
||||
self.unwind_stack();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use prolog::and_stack::*;
|
||||
use prolog::ast::*;
|
||||
use prolog::copier::*;
|
||||
use prolog::machine::machine_errors::MachineStub;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::num::{BigInt, BigUint, Zero, One};
|
||||
use prolog::or_stack::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::tabled_rc::*;
|
||||
|
||||
use downcast::Any;
|
||||
@@ -17,14 +17,14 @@ use std::rc::Rc;
|
||||
|
||||
pub(super) struct Ball {
|
||||
pub(super) boundary: usize, // ball.0
|
||||
pub(super) stub: MachineStub, // ball.1
|
||||
pub(super) stub: MachineStub, // ball.1
|
||||
}
|
||||
|
||||
impl Ball {
|
||||
pub(super) fn new() -> Self {
|
||||
Ball { boundary: 0, stub: MachineStub::new() }
|
||||
}
|
||||
|
||||
|
||||
pub(super) fn reset(&mut self) {
|
||||
self.boundary = 0;
|
||||
self.stub.clear();
|
||||
@@ -209,7 +209,7 @@ pub struct MachineState {
|
||||
pub(super) b0: usize,
|
||||
pub(super) e: usize,
|
||||
pub(super) num_of_args: usize,
|
||||
pub(super) cp: CodePtr,
|
||||
pub(super) cp: LocalCodePtr,
|
||||
pub(super) fail: bool,
|
||||
pub(crate) heap: Heap,
|
||||
pub(super) mode: MachineMode,
|
||||
@@ -222,61 +222,12 @@ pub struct MachineState {
|
||||
pub(super) block: usize, // an offset into the OR stack.
|
||||
pub(super) ball: Ball,
|
||||
pub(super) interms: Vec<Number>, // intermediate numbers.
|
||||
pub(super) last_call: bool
|
||||
}
|
||||
|
||||
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
|
||||
|
||||
pub(crate) trait CallPolicy: Any {
|
||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex, lco: bool)
|
||||
-> CallResult
|
||||
{
|
||||
if lco {
|
||||
self.try_execute(machine_st, name, arity, idx)
|
||||
} else {
|
||||
self.try_call(machine_st, name, arity, idx)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
let b = machine_st.b - 1;
|
||||
@@ -400,49 +351,70 @@ pub(crate) trait CallPolicy: Any {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_call_clause<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
ct: &ClauseType, arity: usize, lco: bool)
|
||||
-> CallResult
|
||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
|
||||
idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
if machine_st.last_call {
|
||||
self.try_execute(machine_st, name, arity, idx)
|
||||
} else {
|
||||
self.try_call(machine_st, name, arity, idx)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.cp.assign_if_local(machine_st.p.clone() + 1);
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = dir_entry!(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = dir_entry!(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType)
|
||||
-> CallResult
|
||||
{
|
||||
match ct {
|
||||
&ClauseType::AcyclicTerm => {
|
||||
&BuiltInClauseType::AcyclicTerm => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
machine_st.fail = machine_st.is_cyclic_term(addr);
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Arg => {
|
||||
if !lco {
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
}
|
||||
|
||||
machine_st.num_of_args = 3;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(166, clause_name!("builtin"));
|
||||
|
||||
Ok(())
|
||||
&BuiltInClauseType::Arg => {
|
||||
machine_st.try_arg()?;
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Catch => {
|
||||
if !lco {
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
}
|
||||
|
||||
machine_st.num_of_args = 3;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(5, clause_name!("builtin"));
|
||||
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::CallN =>
|
||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||
if let Some(idx) = code_dirs.get(name.clone(), arity, clause_name!("user")) {
|
||||
self.context_call(machine_st, name, arity, idx, lco)
|
||||
} else {
|
||||
Err(machine_st.existence_error(name, arity))
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::Compare => {
|
||||
&BuiltInClauseType::Compare => {
|
||||
let a1 = machine_st[temp_v!(1)].clone();
|
||||
let a2 = machine_st[temp_v!(2)].clone();
|
||||
let a3 = machine_st[temp_v!(3)].clone();
|
||||
@@ -454,9 +426,9 @@ pub(crate) trait CallPolicy: Any {
|
||||
});
|
||||
|
||||
machine_st.unify(a1, c);
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::CompareTerm(qt) => {
|
||||
&BuiltInClauseType::CompareTerm(qt) => {
|
||||
match qt {
|
||||
CompareTermQT::Equal =>
|
||||
machine_st.fail = machine_st.structural_eq_test(),
|
||||
@@ -465,47 +437,47 @@ pub(crate) trait CallPolicy: Any {
|
||||
_ => machine_st.compare_term(qt)
|
||||
};
|
||||
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::CyclicTerm => {
|
||||
&BuiltInClauseType::CyclicTerm => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
machine_st.fail = !machine_st.is_cyclic_term(addr);
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Display => {
|
||||
&BuiltInClauseType::Display => {
|
||||
let output = machine_st.print_term(machine_st[temp_v!(1)].clone(),
|
||||
DisplayFormatter {},
|
||||
PrinterOutputter::new());
|
||||
|
||||
println!("{}", output.result());
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::DuplicateTerm => {
|
||||
&BuiltInClauseType::DuplicateTerm => {
|
||||
machine_st.duplicate_term();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Eq => {
|
||||
&BuiltInClauseType::Eq => {
|
||||
machine_st.fail = machine_st.eq_test();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Ground => {
|
||||
&BuiltInClauseType::Ground => {
|
||||
machine_st.fail = machine_st.ground_test();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Functor => {
|
||||
&BuiltInClauseType::Functor => {
|
||||
machine_st.try_functor()?;
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::NotEq => {
|
||||
&BuiltInClauseType::NotEq => {
|
||||
machine_st.fail = !machine_st.eq_test();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Sort => {
|
||||
&BuiltInClauseType::Sort => {
|
||||
machine_st.check_sort_errors()?;
|
||||
|
||||
|
||||
let stub = machine_st.functor_stub(clause_name!("sort"), 2);
|
||||
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
|
||||
|
||||
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
|
||||
|
||||
list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2));
|
||||
machine_st.term_dedup(&mut list);
|
||||
|
||||
@@ -514,15 +486,15 @@ pub(crate) trait CallPolicy: Any {
|
||||
let r2 = machine_st[temp_v!(2)].clone();
|
||||
machine_st.unify(r2, heap_addr);
|
||||
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::KeySort => {
|
||||
&BuiltInClauseType::KeySort => {
|
||||
machine_st.check_keysort_errors()?;
|
||||
|
||||
|
||||
let stub = machine_st.functor_stub(clause_name!("keysort"), 2);
|
||||
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
|
||||
let mut key_pairs = Vec::new();
|
||||
|
||||
let mut key_pairs = Vec::new();
|
||||
|
||||
for val in list {
|
||||
let key = machine_st.project_onto_key(val.clone())?;
|
||||
key_pairs.push((key, val.clone()));
|
||||
@@ -536,47 +508,100 @@ pub(crate) trait CallPolicy: Any {
|
||||
let r2 = machine_st[temp_v!(2)].clone();
|
||||
machine_st.unify(r2, heap_addr);
|
||||
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Throw => {
|
||||
if !lco {
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
}
|
||||
&BuiltInClauseType::Is(r, ref at) => {
|
||||
let a1 = machine_st[r].clone();
|
||||
let a2 = machine_st.get_number(at)?;
|
||||
|
||||
machine_st.goto_throw();
|
||||
Ok(())
|
||||
machine_st.unify(a1, Addr::Con(Constant::Number(a2)));
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Named(ref name, ref idx) | &ClauseType::Op(ref name, _, ref idx) =>
|
||||
self.context_call(machine_st, name.clone(), arity, idx.clone(), lco),
|
||||
&ClauseType::CallWithInferenceLimit => {
|
||||
machine_st.goto_ptr(CodePtr::DirEntry(409, clause_name!("builtin")), 3, lco);
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::SetupCallCleanup => {
|
||||
machine_st.goto_ptr(CodePtr::DirEntry(310, clause_name!("builtin")), 3, lco);
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::Is => {
|
||||
let a = machine_st[temp_v!(1)].clone();
|
||||
let result = machine_st.arith_eval_by_metacall(temp_v!(2))?;
|
||||
|
||||
machine_st.unify(a, Addr::Con(Constant::Number(result)));
|
||||
machine_st.p += 1;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::Inlined(ref inlined) => {
|
||||
machine_st.execute_inlined(inlined, &vec![temp_v!(1), temp_v!(2)]);
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::SkipMaxList => {
|
||||
machine_st.skip_max_list()?;
|
||||
machine_st.p += 1;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize, code_dirs: CodeDirs<'a>)
|
||||
-> CallResult
|
||||
{
|
||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||
let user = clause_name!("user");
|
||||
|
||||
match ClauseType::from(name.clone(), arity, None) {
|
||||
ClauseType::CallN => {
|
||||
machine_st.handle_internal_call_n(arity);
|
||||
|
||||
if machine_st.fail {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
machine_st.p = CodePtr::CallN(arity, machine_st.p.local());
|
||||
},
|
||||
ClauseType::BuiltIn(built_in) =>
|
||||
machine_st.setup_built_in_call(built_in),
|
||||
ClauseType::Inlined(inlined) =>
|
||||
machine_st.execute_inlined(&inlined),
|
||||
ClauseType::Op(..) | ClauseType::Named(..) =>
|
||||
if let Some(idx) = code_dirs.get(name.clone(), arity, user) {
|
||||
self.context_call(machine_st, name, arity, idx)?;
|
||||
} else {
|
||||
return Err(machine_st.existence_error(name, arity));
|
||||
},
|
||||
ClauseType::System(_) =>
|
||||
return Err(machine_st.type_error(ValidType::Callable,
|
||||
Addr::Con(Constant::Atom(name))))
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CallPolicy for CallWithInferenceLimitCallPolicy {
|
||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.context_call(machine_st, name, arity, idx)?;
|
||||
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()
|
||||
}
|
||||
|
||||
fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.call_builtin(machine_st, ct)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize, code_dirs: CodeDirs<'a>)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.call_n(machine_st, arity, code_dirs)?;
|
||||
self.increment()
|
||||
}
|
||||
}
|
||||
|
||||
downcast!(CallPolicy);
|
||||
@@ -651,40 +676,6 @@ impl CallWithInferenceLimitCallPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
impl CallPolicy for CallWithInferenceLimitCallPolicy {
|
||||
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()
|
||||
}
|
||||
|
||||
fn try_call_clause<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
ct: &ClauseType, arity: usize, lco: bool)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.try_call_clause(machine_st, code_dirs, ct, arity, lco)?;
|
||||
self.increment()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait CutPolicy: Any {
|
||||
fn cut(&mut self, &mut MachineState, RegType);
|
||||
}
|
||||
@@ -707,27 +698,25 @@ impl CutPolicy for DefaultCutPolicy {
|
||||
machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
|
||||
machine_st.p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SetupCallCleanupCutPolicy {
|
||||
pub(crate) struct SCCCutPolicy {
|
||||
// locations of cleaners, cut points, the previous block
|
||||
cont_pts: Vec<(Addr, usize, usize)>
|
||||
}
|
||||
|
||||
impl SetupCallCleanupCutPolicy {
|
||||
impl SCCCutPolicy {
|
||||
pub(crate) fn new() -> Self {
|
||||
SetupCallCleanupCutPolicy { cont_pts: vec![] }
|
||||
SCCCutPolicy { cont_pts: vec![] }
|
||||
}
|
||||
|
||||
pub(crate) fn out_of_cont_pts(&self) -> bool {
|
||||
self.cont_pts.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn push_cont_pt(&mut self, addr: Addr, b: usize, block: usize) {
|
||||
self.cont_pts.push((addr, b, block));
|
||||
pub(crate) fn push_cont_pt(&mut self, addr: Addr, b: usize, prev_b: usize) {
|
||||
self.cont_pts.push((addr, b, prev_b));
|
||||
}
|
||||
|
||||
pub(crate) fn pop_cont_pt(&mut self) -> Option<(Addr, usize, usize)> {
|
||||
@@ -735,12 +724,12 @@ impl SetupCallCleanupCutPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
impl CutPolicy for SetupCallCleanupCutPolicy {
|
||||
impl CutPolicy for SCCCutPolicy {
|
||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) {
|
||||
let b = machine_st.b;
|
||||
|
||||
if let Addr::Con(Constant::Usize(b0)) = machine_st[r].clone() {
|
||||
if b > b0 {
|
||||
if b > b0 {
|
||||
machine_st.b = b0;
|
||||
machine_st.tidy_trail();
|
||||
machine_st.or_stack.truncate(machine_st.b);
|
||||
@@ -748,16 +737,13 @@ impl CutPolicy for SetupCallCleanupCutPolicy {
|
||||
} else {
|
||||
machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
|
||||
machine_st.p += 1;
|
||||
|
||||
if !self.out_of_cont_pts() {
|
||||
machine_st.cp = machine_st.p.clone();
|
||||
machine_st.num_of_args = 0;
|
||||
machine_st.b0 = machine_st.b;
|
||||
// goto_call run_cleaners_without_handling/0, 370.
|
||||
machine_st.p = CodePtr::DirEntry(370, clause_name!("builtin"));
|
||||
}
|
||||
|
||||
if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
|
||||
if machine_st.b < b_cutoff {
|
||||
machine_st.block = prev_block;
|
||||
machine_st.unwind_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::compile::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::tabled_rc::*;
|
||||
|
||||
@@ -7,6 +7,7 @@ mod machine_errors;
|
||||
pub(super) mod machine_state;
|
||||
#[macro_use]
|
||||
mod machine_state_impl;
|
||||
mod system_calls;
|
||||
|
||||
use prolog::machine::machine_state::*;
|
||||
|
||||
@@ -16,9 +17,9 @@ use std::mem::swap;
|
||||
use std::ops::Index;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(super) struct MachineCodeIndex<'a> {
|
||||
pub(super) code_dir: &'a mut CodeDir,
|
||||
pub(super) op_dir: &'a mut OpDir,
|
||||
pub struct MachineCodeIndex<'a> {
|
||||
pub code_dir: &'a mut CodeDir,
|
||||
pub op_dir: &'a mut OpDir,
|
||||
}
|
||||
|
||||
pub struct Machine {
|
||||
@@ -33,18 +34,18 @@ pub struct Machine {
|
||||
cached_query: Option<Code>
|
||||
}
|
||||
|
||||
impl Index<CodePtr> for Machine {
|
||||
impl Index<LocalCodePtr> for Machine {
|
||||
type Output = Line;
|
||||
|
||||
fn index(&self, ptr: CodePtr) -> &Self::Output {
|
||||
fn index(&self, ptr: LocalCodePtr) -> &Self::Output {
|
||||
match ptr {
|
||||
CodePtr::TopLevel(_, p) => {
|
||||
LocalCodePtr::TopLevel(_, p) => {
|
||||
match &self.cached_query {
|
||||
&Some(ref cq) => &cq[p],
|
||||
&None => panic!("Out-of-bounds top level index.")
|
||||
}
|
||||
},
|
||||
CodePtr::DirEntry(p, _) => &self.code[p]
|
||||
LocalCodePtr::DirEntry(p, _) => &self.code[p]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,23 +66,33 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> {
|
||||
self.code_dir.insert((name, arity), CodeIndex::from(idx));
|
||||
}
|
||||
}
|
||||
|
||||
static LISTS: &str = include_str!("../lib/lists.pl");
|
||||
static CONTROL: &str = include_str!("../lib/control.pl");
|
||||
static QUEUES: &str = include_str!("../lib/queues.pl");
|
||||
|
||||
impl Machine {
|
||||
pub fn new() -> Self {
|
||||
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
|
||||
let (code, code_dir, op_dir) = default_build();
|
||||
|
||||
Machine {
|
||||
ms: MachineState::new(atom_tbl),
|
||||
let mut wam = Machine {
|
||||
ms: MachineState::new(Rc::new(RefCell::new(HashSet::new()))),
|
||||
call_policy: Box::new(DefaultCallPolicy {}),
|
||||
cut_policy: Box::new(DefaultCutPolicy {}),
|
||||
code,
|
||||
code_dir,
|
||||
code: Code::new(),
|
||||
code_dir: CodeDir::new(),
|
||||
term_dir: TermDir::new(),
|
||||
op_dir,
|
||||
op_dir: default_op_dir(),
|
||||
modules: HashMap::new(),
|
||||
cached_query: None
|
||||
}
|
||||
};
|
||||
|
||||
compile_listing(&mut wam, BUILTINS);
|
||||
wam.use_module_in_toplevel(clause_name!("builtins"));
|
||||
|
||||
compile_listing(&mut wam, LISTS);
|
||||
compile_listing(&mut wam, CONTROL);
|
||||
compile_listing(&mut wam, QUEUES);
|
||||
|
||||
wam
|
||||
}
|
||||
|
||||
fn remove_module(&mut self, module_name: ClauseName) {
|
||||
@@ -221,36 +232,43 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_instr(&self, p: CodePtr) -> Option<Line> {
|
||||
match p {
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) =>
|
||||
match &self.cached_query {
|
||||
&Some(ref cq) => Some(cq[p].clone()),
|
||||
&None => None
|
||||
},
|
||||
CodePtr::Local(LocalCodePtr::DirEntry(p, _)) =>
|
||||
Some(self.code[p].clone()),
|
||||
CodePtr::BuiltInClause(built_in, _) =>
|
||||
Some(call_clause!(ClauseType::BuiltIn(built_in.clone()), built_in.arity(),
|
||||
0, self.ms.last_call)),
|
||||
CodePtr::CallN(arity, _) =>
|
||||
Some(call_clause!(ClauseType::CallN, arity, 0, self.ms.last_call))
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_instr(&mut self)
|
||||
{
|
||||
let instr = match self.ms.p {
|
||||
CodePtr::TopLevel(_, p) => {
|
||||
match &self.cached_query {
|
||||
&Some(ref cq) => &cq[p],
|
||||
&None => return
|
||||
}
|
||||
},
|
||||
CodePtr::DirEntry(p, _) => &self.code[p]
|
||||
let instr = match self.lookup_instr(self.ms.p.clone()) {
|
||||
Some(instr) => instr,
|
||||
None => return
|
||||
};
|
||||
|
||||
match instr {
|
||||
&Line::Arithmetic(ref arith_instr) =>
|
||||
Line::Arithmetic(ref arith_instr) =>
|
||||
self.ms.execute_arith_instr(arith_instr),
|
||||
&Line::BuiltIn(ref built_in_instr) => {
|
||||
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
|
||||
self.ms.execute_built_in_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),
|
||||
&Line::Cut(ref cut_instr) =>
|
||||
Line::Cut(ref cut_instr) =>
|
||||
self.ms.execute_cut_instr(cut_instr, &mut self.cut_policy),
|
||||
&Line::Control(ref control_instr) => {
|
||||
Line::Control(ref control_instr) => {
|
||||
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
|
||||
self.ms.execute_ctrl_instr(code_dirs, &mut self.call_policy,
|
||||
&mut self.cut_policy, control_instr)
|
||||
},
|
||||
&Line::Fact(ref fact) => {
|
||||
Line::Fact(ref fact) => {
|
||||
for fact_instr in fact {
|
||||
if self.failed() {
|
||||
break;
|
||||
@@ -261,11 +279,11 @@ impl Machine {
|
||||
|
||||
self.ms.p += 1;
|
||||
},
|
||||
&Line::Indexing(ref indexing_instr) =>
|
||||
Line::Indexing(ref indexing_instr) =>
|
||||
self.ms.execute_indexing_instr(&indexing_instr),
|
||||
&Line::IndexedChoice(ref choice_instr) =>
|
||||
Line::IndexedChoice(ref choice_instr) =>
|
||||
self.ms.execute_indexed_choice_instr(choice_instr, &mut self.call_policy),
|
||||
&Line::Query(ref query) => {
|
||||
Line::Query(ref query) => {
|
||||
for query_instr in query {
|
||||
if self.failed() {
|
||||
break;
|
||||
@@ -287,13 +305,13 @@ impl Machine {
|
||||
self.ms.b0 = self.ms.or_stack[b].b0;
|
||||
self.ms.p = self.ms.or_stack[b].bp.clone();
|
||||
|
||||
if let CodePtr::TopLevel(_, p) = self.ms.p {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.ms.p {
|
||||
self.ms.fail = p == 0;
|
||||
} else {
|
||||
self.ms.fail = false;
|
||||
}
|
||||
} else {
|
||||
self.ms.p = CodePtr::TopLevel(0, 0);
|
||||
self.ms.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,8 +325,9 @@ impl Machine {
|
||||
}
|
||||
|
||||
match self.ms.p {
|
||||
CodePtr::DirEntry(p, _) if p < self.code.len() => {},
|
||||
_ => break
|
||||
CodePtr::Local(LocalCodePtr::DirEntry(p, _)) if p < self.code.len() => {},
|
||||
CodePtr::Local(_) => break,
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -340,11 +359,11 @@ impl Machine {
|
||||
|
||||
fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());
|
||||
let end_ptr = top_level_code_ptr!(0, self.cached_query_size());
|
||||
|
||||
while self.ms.p < end_ptr {
|
||||
if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
|
||||
match &self[CodePtr::TopLevel(cn, p)] {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.ms.p {
|
||||
match &self[LocalCodePtr::TopLevel(cn, p)] {
|
||||
&Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
|
||||
self.record_var_places(cn, alloc_locs, heap_locs);
|
||||
cn += 1;
|
||||
@@ -352,13 +371,13 @@ impl Machine {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.ms.p = CodePtr::TopLevel(cn, p);
|
||||
self.ms.p = top_level_code_ptr!(cn, p);
|
||||
}
|
||||
|
||||
self.query_stepper();
|
||||
|
||||
match self.ms.p {
|
||||
CodePtr::TopLevel(_, p) if p > 0 => {},
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {},
|
||||
_ => {
|
||||
if heap_locs.is_empty() {
|
||||
self.record_var_places(0, alloc_locs, heap_locs);
|
||||
@@ -375,7 +394,7 @@ impl Machine {
|
||||
if self.ms.ball.stub.len() > 0 {
|
||||
let h = self.ms.heap.h;
|
||||
self.ms.copy_and_align_ball_to_heap();
|
||||
|
||||
|
||||
let error_str = self.ms.print_exception(Addr::HeapCell(h),
|
||||
&heap_locs,
|
||||
TermFormatter {},
|
||||
@@ -408,7 +427,7 @@ impl Machine {
|
||||
let b = self.ms.b - 1;
|
||||
self.ms.p = self.ms.or_stack[b].bp.clone();
|
||||
|
||||
if let CodePtr::TopLevel(_, 0) = self.ms.p {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.ms.p {
|
||||
return EvalSession::from(SessionError::QueryFailure);
|
||||
}
|
||||
|
||||
|
||||
379
src/prolog/machine/system_calls.rs
Normal file
379
src/prolog/machine/system_calls.rs
Normal file
@@ -0,0 +1,379 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::machine_state::*;
|
||||
use prolog::num::{ToPrimitive, Zero};
|
||||
use prolog::num::bigint::BigInt;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
struct BrentAlgState {
|
||||
hare: usize,
|
||||
tortoise: usize,
|
||||
power: usize,
|
||||
steps: usize
|
||||
}
|
||||
|
||||
impl BrentAlgState {
|
||||
fn new(hare: usize) -> Self {
|
||||
BrentAlgState { hare, tortoise: hare, power: 2, steps: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
// a step in Brent's algorithm.
|
||||
fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
|
||||
{
|
||||
match self.heap[brent_st.hare].clone() {
|
||||
HeapCellValue::Addr(Addr::Lis(l)) => {
|
||||
brent_st.hare = l + 1;
|
||||
brent_st.steps += 1;
|
||||
|
||||
if brent_st.tortoise == brent_st.hare {
|
||||
return Some(CycleSearchResult::NotList);
|
||||
} else if brent_st.steps == brent_st.power {
|
||||
brent_st.tortoise = brent_st.hare;
|
||||
brent_st.power <<= 1;
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
HeapCellValue::NamedStr(..) =>
|
||||
Some(CycleSearchResult::NotList),
|
||||
HeapCellValue::Addr(addr) =>
|
||||
match self.store(self.deref(addr)) {
|
||||
Addr::Con(Constant::EmptyList) =>
|
||||
Some(CycleSearchResult::ProperList(brent_st.steps)),
|
||||
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||
Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)),
|
||||
_ =>
|
||||
Some(CycleSearchResult::NotList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult
|
||||
{
|
||||
let addr = self.store(self.deref(addr));
|
||||
let hare = match addr {
|
||||
Addr::Lis(offset) if max_steps > 0 => offset + 1,
|
||||
Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
|
||||
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
||||
_ => return CycleSearchResult::NotList
|
||||
};
|
||||
|
||||
let mut brent_st = BrentAlgState::new(hare);
|
||||
|
||||
loop {
|
||||
if brent_st.steps == max_steps {
|
||||
return CycleSearchResult::PartialList(brent_st.steps, brent_st.hare);
|
||||
}
|
||||
|
||||
if let Some(result) = self.brents_alg_step(&mut brent_st) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult
|
||||
{
|
||||
let addr = self.store(self.deref(addr));
|
||||
let hare = match addr {
|
||||
Addr::Lis(offset) => offset + 1,
|
||||
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
||||
_ => return CycleSearchResult::NotList
|
||||
};
|
||||
|
||||
let mut brent_st = BrentAlgState::new(hare);
|
||||
|
||||
loop {
|
||||
if let Some(result) = self.brents_alg_step(&mut brent_st) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) {
|
||||
let target_n = self[temp_v!(1)].clone();
|
||||
self.unify(Addr::Con(integer!(n)), target_n);
|
||||
|
||||
if !self.fail {
|
||||
let xs = self[temp_v!(4)].clone();
|
||||
self.unify(addr, xs);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn skip_max_list(&mut self) -> Result<(), MachineError> {
|
||||
let max_steps = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
match max_steps {
|
||||
Addr::Con(Constant::Number(Number::Integer(ref max_steps)))
|
||||
if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) => {
|
||||
let n = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
match n {
|
||||
Addr::Con(Constant::Number(Number::Integer(ref n))) if n.is_zero() => {
|
||||
let xs0 = self[temp_v!(3)].clone();
|
||||
let xs = self[temp_v!(4)].clone();
|
||||
|
||||
self.unify(xs0, xs);
|
||||
},
|
||||
_ => {
|
||||
let search_result = if let Some(max_steps) = max_steps.to_isize() {
|
||||
if max_steps == -1 {
|
||||
self.detect_cycles(self[temp_v!(3)].clone())
|
||||
} else {
|
||||
self.detect_cycles_with_max(max_steps as usize,
|
||||
self[temp_v!(3)].clone())
|
||||
}
|
||||
} else {
|
||||
self.detect_cycles(self[temp_v!(3)].clone())
|
||||
};
|
||||
|
||||
match search_result {
|
||||
CycleSearchResult::UntouchedList(l) =>
|
||||
self.finalize_skip_max_list(0, Addr::Lis(l)),
|
||||
CycleSearchResult::EmptyList =>
|
||||
self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)),
|
||||
CycleSearchResult::PartialList(n, hc) =>
|
||||
self.finalize_skip_max_list(n, Addr::HeapCell(hc)),
|
||||
CycleSearchResult::ProperList(n) =>
|
||||
self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)),
|
||||
CycleSearchResult::NotList => {
|
||||
let xs0 = self[temp_v!(3)].clone();
|
||||
self.finalize_skip_max_list(0, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => self.fail = true
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn install_new_block(&mut self, r: RegType) -> usize {
|
||||
self.block = self.b;
|
||||
|
||||
let c = Constant::Usize(self.block);
|
||||
let addr = self[r].clone();
|
||||
|
||||
self.write_constant_to_var(addr, c);
|
||||
self.block
|
||||
}
|
||||
|
||||
pub(super) fn system_call(&mut self, ct: &SystemClauseType,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,)
|
||||
-> CallResult
|
||||
{
|
||||
match ct {
|
||||
&SystemClauseType::CheckCutPoint => {
|
||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
match addr {
|
||||
Addr::Con(Constant::Usize(old_b)) if self.b <= old_b + 2 => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::GetSCCCleaner => {
|
||||
let dest = self[temp_v!(1)].clone();
|
||||
|
||||
match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
|
||||
Some(sgc_policy) =>
|
||||
if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() {
|
||||
if self.b <= b_cutoff + 1 {
|
||||
self.block = prev_b;
|
||||
|
||||
if let Some(r) = dest.as_var() {
|
||||
self.bind(r, addr.clone());
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
sgc_policy.push_cont_pt(addr, b_cutoff, prev_b);
|
||||
}
|
||||
},
|
||||
None => panic!("expected SCCCutPolicy trait object.")
|
||||
};
|
||||
|
||||
self.fail = true;
|
||||
},
|
||||
&SystemClauseType::InstallSCCCleaner => {
|
||||
let addr = self[temp_v!(1)].clone();
|
||||
let b = self.b;
|
||||
let prev_block = self.block;
|
||||
|
||||
if cut_policy.downcast_ref::<SCCCutPolicy>().is_err() {
|
||||
*cut_policy = Box::new(SCCCutPolicy::new());
|
||||
}
|
||||
|
||||
match cut_policy.downcast_mut::<SCCCutPolicy>().ok()
|
||||
{
|
||||
Some(cut_policy) => {
|
||||
self.install_new_block(temp_v!(2));
|
||||
cut_policy.push_cont_pt(addr, b, prev_block);
|
||||
},
|
||||
None => panic!("install_cleaner: should have installed \\
|
||||
SCCCutPolicy.")
|
||||
};
|
||||
},
|
||||
&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::<SCCCutPolicy>() {
|
||||
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::InferenceLevel => {
|
||||
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 + 1 {
|
||||
let a2 = Addr::Con(atom!("!"));
|
||||
self.unify(a1, a2);
|
||||
} else {
|
||||
let a2 = Addr::Con(atom!("true"));
|
||||
self.unify(a1, a2);
|
||||
},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::CleanUpBlock => {
|
||||
let nb = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
match nb {
|
||||
Addr::Con(Constant::Usize(nb)) => {
|
||||
let b = self.b - 1;
|
||||
|
||||
if nb > 0 && self.or_stack[b].b == nb {
|
||||
self.b = self.or_stack[nb - 1].b;
|
||||
self.or_stack.truncate(self.b);
|
||||
}
|
||||
},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::EraseBall => self.ball.reset(),
|
||||
&SystemClauseType::Fail => self.fail = true,
|
||||
&SystemClauseType::GetBall => {
|
||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let h = self.heap.h;
|
||||
|
||||
if self.ball.stub.len() > 0 {
|
||||
self.copy_and_align_ball_to_heap();
|
||||
} else {
|
||||
self.fail = true;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ball = self.heap[h].as_addr(h);
|
||||
|
||||
match addr.as_var() {
|
||||
Some(r) => self.bind(r, ball),
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::GetCurrentBlock => {
|
||||
let c = Constant::Usize(self.block);
|
||||
let addr = self[temp_v!(1)].clone();
|
||||
|
||||
self.write_constant_to_var(addr, c);
|
||||
},
|
||||
&SystemClauseType::GetCutPoint => {
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
let a2 = Addr::Con(Constant::Usize(self.b));
|
||||
|
||||
self.unify(a1, a2);
|
||||
},
|
||||
&SystemClauseType::InstallNewBlock => {
|
||||
self.install_new_block(temp_v!(1));
|
||||
},
|
||||
&SystemClauseType::ResetBlock => {
|
||||
let addr = self.deref(self[temp_v!(1)].clone());
|
||||
self.reset_block(addr);
|
||||
},
|
||||
&SystemClauseType::SetBall => self.set_ball(),
|
||||
&SystemClauseType::SkipMaxList => return self.skip_max_list(),
|
||||
&SystemClauseType::Succeed => {},
|
||||
&SystemClauseType::UnwindStack => self.unwind_stack()
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user