correct inlined calling bug in last call, add dynamic database manipulation predicates
This commit is contained in:
@@ -8,9 +8,9 @@ use prolog::machine::machine_errors::*;
|
||||
use prolog::num::ToPrimitive;
|
||||
|
||||
impl Machine {
|
||||
fn get_dynamic_predicate_key(&self) -> PredicateKey {
|
||||
let name = self.machine_st[temp_v!(3)].clone();
|
||||
let arity = self.machine_st[temp_v!(4)].clone();
|
||||
fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey {
|
||||
let name = self.machine_st[name].clone();
|
||||
let arity = self.machine_st[arity].clone();
|
||||
|
||||
let name = match self.machine_st.store(self.machine_st.deref(name)) {
|
||||
Addr::Con(Constant::Atom(name, _)) => name,
|
||||
@@ -26,13 +26,13 @@ impl Machine {
|
||||
(name, arity)
|
||||
}
|
||||
|
||||
fn print_new_dynamic_clause(&self, addrs: VecDeque<Addr>) -> String
|
||||
fn print_new_dynamic_clause(&self, addrs: VecDeque<Addr>, name: RegType, arity: RegType)
|
||||
-> String
|
||||
{
|
||||
let mut output = PrinterOutputter::new();
|
||||
let (name, arity) = self.get_dynamic_predicate_key();
|
||||
let (name, arity) = self.get_predicate_key(name, arity);
|
||||
|
||||
output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity)
|
||||
.as_str());
|
||||
output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
|
||||
|
||||
for addr in addrs {
|
||||
let mut printer = HCPrinter::new(&self.machine_st, output);
|
||||
@@ -45,46 +45,90 @@ impl Machine {
|
||||
output.result()
|
||||
}
|
||||
|
||||
fn handle_eval_result_from_dynamic_compile(&mut self, result: EvalSession)
|
||||
fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType)
|
||||
{
|
||||
if let EvalSession::Error(e) = result {
|
||||
println!("{}\r", e);
|
||||
self.machine_st.fail = true;
|
||||
let (name, arity) = self.get_predicate_key(name, arity);
|
||||
|
||||
if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) {
|
||||
set_code_index!(idx, IndexPtr::Undefined, clause_name!("user"));
|
||||
}
|
||||
|
||||
self.indices.code_dir.remove(&(name.clone(), arity));
|
||||
self.indices.dynamic_code_dir.remove(&(name, arity));
|
||||
}
|
||||
|
||||
fn handle_eval_result_from_dynamic_compile(&mut self, pred_str: String, src: ClauseName)
|
||||
{
|
||||
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
|
||||
let result = compile_user_module(self, pred_str.as_bytes());
|
||||
|
||||
self.machine_st = machine_st;
|
||||
|
||||
if let EvalSession::Error(err) = result {
|
||||
let h = self.machine_st.heap.h;
|
||||
let stub = MachineError::functor_stub(src, 1);
|
||||
let err = MachineError::session_error(h, err);
|
||||
let err = self.machine_st.error_form(err, stub);
|
||||
|
||||
self.machine_st.throw_exception(err);
|
||||
}
|
||||
}
|
||||
|
||||
fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace)
|
||||
{
|
||||
let stub = MachineError::functor_stub(place.predicate_name(), 1);
|
||||
|
||||
let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) {
|
||||
Ok(addrs) => {
|
||||
let mut addrs = VecDeque::from(addrs);
|
||||
let added_clause = self.machine_st[temp_v!(1)].clone();
|
||||
|
||||
place.push_to_queue(&mut addrs, added_clause);
|
||||
self.print_new_dynamic_clause(addrs)
|
||||
self.print_new_dynamic_clause(addrs, temp_v!(3), temp_v!(4))
|
||||
},
|
||||
Err(err) =>
|
||||
return self.machine_st.throw_exception(err)
|
||||
};
|
||||
|
||||
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
|
||||
self.handle_eval_result_from_dynamic_compile(pred_str, place.predicate_name());
|
||||
}
|
||||
|
||||
let result = compile_user_module(self, pred_str.as_bytes());
|
||||
self.machine_st = machine_st;
|
||||
fn retract_from_dynamic_predicate(&mut self) {
|
||||
let index = self.machine_st[temp_v!(3)].clone();
|
||||
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
||||
Addr::Con(Constant::Number(Number::Integer(n))) => n.to_usize().unwrap(),
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(result);
|
||||
let stub = MachineError::functor_stub(clause_name!("retract"), 1);
|
||||
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
|
||||
Ok(addrs) => {
|
||||
let mut addrs = VecDeque::from(addrs);
|
||||
addrs.remove(index);
|
||||
|
||||
if addrs.is_empty() {
|
||||
self.abolish_dynamic_clause(temp_v!(1), temp_v!(2));
|
||||
return;
|
||||
}
|
||||
|
||||
self.print_new_dynamic_clause(addrs, temp_v!(1), temp_v!(2))
|
||||
},
|
||||
Err(err) =>
|
||||
return self.machine_st.throw_exception(err)
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(pred_str, clause_name!("retract"));
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn dynamic_transaction(&mut self, trans_type: DynamicTransactionType, p: LocalCodePtr)
|
||||
{
|
||||
match trans_type {
|
||||
DynamicTransactionType::Abolish => {},
|
||||
DynamicTransactionType::Abolish =>
|
||||
self.abolish_dynamic_clause(temp_v!(1), temp_v!(2)),
|
||||
DynamicTransactionType::Assert(place) =>
|
||||
self.recompile_dynamic_predicate(place),
|
||||
DynamicTransactionType::Retract(idx) => {}
|
||||
DynamicTransactionType::Retract =>
|
||||
self.retract_from_dynamic_predicate()
|
||||
}
|
||||
|
||||
self.machine_st.p = CodePtr::Local(p);
|
||||
|
||||
@@ -60,6 +60,36 @@ impl MachineError {
|
||||
MachineError { stub, from: ErrorProvenance::Constructed }
|
||||
}
|
||||
|
||||
// so far, this function is only called wrt dynamic database
|
||||
// transactions. their inapplicable error cases have been left
|
||||
// unhandled.
|
||||
pub(super) fn session_error(h: usize, err: SessionError) -> Self {
|
||||
match err {
|
||||
SessionError::ParserError(err) => Self::syntax_error(h, err),
|
||||
SessionError::CannotOverwriteBuiltIn(pred_str)
|
||||
| SessionError::CannotOverwriteImport(pred_str) =>
|
||||
Self::permission_error(PermissionError::Modify, pred_str),
|
||||
SessionError::ModuleDoesNotContainExport =>
|
||||
Self::permission_error(PermissionError::Access,
|
||||
clause_name!("module_does_not_contain_claimed_export")),
|
||||
SessionError::ModuleNotFound =>
|
||||
Self::permission_error(PermissionError::Access,
|
||||
clause_name!("module_does_not_exist")),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn permission_error(err: PermissionError, pred_str: ClauseName) -> Self {
|
||||
let pred_str = HeapCellValue::Addr(Addr::Con(Constant::Atom(pred_str, None)));
|
||||
|
||||
let err = vec![heap_atom!(err.as_str()), pred_str];
|
||||
let mut stub = functor!("permission_error", 2);
|
||||
|
||||
stub.extend(err.into_iter());
|
||||
|
||||
MachineError { stub, from: ErrorProvenance::Constructed }
|
||||
}
|
||||
|
||||
pub(super) fn syntax_error(h: usize, err: ParserError) -> Self {
|
||||
let err = vec![heap_atom!(err.as_str())];
|
||||
|
||||
@@ -109,6 +139,21 @@ impl MachineError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PermissionError {
|
||||
Access,
|
||||
Modify,
|
||||
}
|
||||
|
||||
impl PermissionError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
PermissionError::Access => "access",
|
||||
PermissionError::Modify => "modify"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 b) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ValidType {
|
||||
|
||||
@@ -1423,7 +1423,7 @@ impl MachineState {
|
||||
|
||||
for index in from .. self.ball.stub.len() {
|
||||
let heap_value = self.ball.stub[index].clone();
|
||||
|
||||
|
||||
self.heap.push(match heap_value {
|
||||
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
|
||||
_ => heap_value
|
||||
@@ -1768,7 +1768,7 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Con(Constant::Atom(..)) | Addr::Con(Constant::Char(_)) => self.p += 1,
|
||||
Addr::Con(Constant::Atom(..)) | Addr::Con(Constant::Char(_)) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1776,7 +1776,7 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Con(_) => self.p += 1,
|
||||
Addr::Con(_) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1784,7 +1784,7 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Con(Constant::Number(Number::Integer(_))) => self.p += 1,
|
||||
Addr::Con(Constant::Number(Number::Integer(_))) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1792,7 +1792,7 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Str(_) | Addr::Lis(_) => self.p += 1,
|
||||
Addr::Str(_) | Addr::Lis(_) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1800,7 +1800,7 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Con(Constant::Number(Number::Float(_))) => self.p += 1,
|
||||
Addr::Con(Constant::Number(Number::Float(_))) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1808,7 +1808,7 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Con(Constant::Number(Number::Rational(_))) => self.p += 1,
|
||||
Addr::Con(Constant::Number(Number::Rational(_))) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1816,7 +1816,7 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Con(Constant::String(_)) => self.p += 1,
|
||||
Addr::Con(Constant::String(_)) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1825,14 +1825,14 @@ impl MachineState {
|
||||
|
||||
match d {
|
||||
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => self.fail = true,
|
||||
_ => self.p += 1
|
||||
_ => {}
|
||||
};
|
||||
},
|
||||
&InlinedClauseType::IsVar(r1) => {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_,_) => self.p += 1,
|
||||
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_,_) => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
@@ -1840,11 +1840,13 @@ impl MachineState {
|
||||
let d = self.store(self.deref(self[r1].clone()));
|
||||
|
||||
match d {
|
||||
Addr::Con(Constant::String(ref s)) if s.is_expandable() => self.p += 1,
|
||||
Addr::Con(Constant::String(ref s)) if s.is_expandable() => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
self.set_p();
|
||||
}
|
||||
|
||||
fn try_functor_unify_components(&mut self, name: Addr, arity: Addr) {
|
||||
|
||||
@@ -24,12 +24,10 @@ use std::mem;
|
||||
use std::ops::Index;
|
||||
use std::rc::Rc;
|
||||
|
||||
//pub type DynamicPredicateClauses = VecDeque<(PredicateClause, VecDeque<TopLevel>)>;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct DynamicPredicateInfo {
|
||||
pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value.
|
||||
// clauses: DynamicPredicateClauses
|
||||
}
|
||||
|
||||
impl Default for DynamicPredicateInfo {
|
||||
@@ -424,6 +422,8 @@ impl Machine {
|
||||
_ => {
|
||||
// ensure we don't try to overwrite the name/arity of a builtin.
|
||||
let err_str = format!("{}/{}", key.0, key.1);
|
||||
let err_str = clause_name!(err_str, self.indices.atom_tbl());
|
||||
|
||||
return Err(SessionError::CannotOverwriteBuiltIn(err_str));
|
||||
}
|
||||
};
|
||||
@@ -439,6 +439,7 @@ impl Machine {
|
||||
if existing_idx.module_name() != idx.module_name() {
|
||||
let err_str = format!("{}/{} from module {}", key.0, key.1,
|
||||
existing_idx.module_name().as_str());
|
||||
let err_str = clause_name!(err_str, self.indices.atom_tbl());
|
||||
return Err(SessionError::CannotOverwriteImport(err_str));
|
||||
}
|
||||
}
|
||||
@@ -479,18 +480,19 @@ impl Machine {
|
||||
self.code_repo.code.len()
|
||||
}
|
||||
|
||||
fn fail(&mut self, heap_locs: &HeapVarDict) -> EvalSession
|
||||
fn fail(&mut self) -> EvalSession
|
||||
{
|
||||
if self.machine_st.ball.stub.len() > 0 {
|
||||
let h = self.machine_st.heap.h;
|
||||
self.machine_st.copy_and_align_ball_to_heap(0);
|
||||
|
||||
let error_str = self.machine_st.print_exception(Addr::HeapCell(h),
|
||||
&heap_locs,
|
||||
PrinterOutputter::new())
|
||||
.result();
|
||||
let err_str = self.machine_st.print_exception(Addr::HeapCell(h),
|
||||
&HeapVarDict::new(),
|
||||
PrinterOutputter::new())
|
||||
.result();
|
||||
|
||||
EvalSession::from(SessionError::QueryFailureWithException(error_str))
|
||||
let err_str = clause_name!(err_str, self.indices.atom_tbl());
|
||||
EvalSession::from(SessionError::QueryFailureWithException(err_str))
|
||||
} else {
|
||||
EvalSession::from(SessionError::QueryFailure)
|
||||
}
|
||||
@@ -504,7 +506,7 @@ impl Machine {
|
||||
self.run_query(&alloc_locs, &mut heap_locs);
|
||||
|
||||
if self.machine_st.fail {
|
||||
self.fail(&heap_locs)
|
||||
self.fail()
|
||||
} else {
|
||||
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
|
||||
}
|
||||
@@ -599,7 +601,7 @@ impl Machine {
|
||||
self.run_query(alloc_l, heap_l);
|
||||
|
||||
if self.machine_st.fail {
|
||||
self.fail(&heap_l)
|
||||
self.fail()
|
||||
} else {
|
||||
EvalSession::SubsequentQuerySuccess
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ impl MachineState {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn set_p(&mut self) {
|
||||
if self.last_call {
|
||||
self.p = CodePtr::Local(self.cp.clone());
|
||||
@@ -230,6 +231,13 @@ impl MachineState {
|
||||
-> CallResult
|
||||
{
|
||||
match ct {
|
||||
&SystemClauseType::AbolishClause => {
|
||||
let p = self.cp;
|
||||
let trans_type = DynamicTransactionType::Abolish;
|
||||
|
||||
self.p = CodePtr::DynamicTransaction(trans_type, p);
|
||||
return Ok(());
|
||||
},
|
||||
&SystemClauseType::AssertDynamicPredicateToFront => {
|
||||
let p = self.cp;
|
||||
let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front);
|
||||
@@ -370,6 +378,24 @@ impl MachineState {
|
||||
self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0));
|
||||
return Ok(());
|
||||
},
|
||||
&SystemClauseType::GetCurrentPredicateList => {
|
||||
let mut addrs = vec![];
|
||||
|
||||
for (name, arity) in indices.code_dir.keys().cloned() {
|
||||
let h = self.heap.h;
|
||||
|
||||
self.heap.push(HeapCellValue::NamedStr(2, clause_name!("/"), Some((400, YFX))));
|
||||
self.heap.push(HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None))));
|
||||
self.heap.push(heap_integer!(arity));
|
||||
|
||||
addrs.push(Addr::Str(h));
|
||||
}
|
||||
|
||||
let list_addr = Addr::HeapCell(self.heap.to_list(addrs.into_iter()));
|
||||
let target_addr = self[temp_v!(1)].clone();
|
||||
|
||||
self.unify(list_addr, target_addr);
|
||||
},
|
||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff =>
|
||||
self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)),
|
||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowth =>
|
||||
@@ -660,6 +686,13 @@ impl MachineState {
|
||||
None => panic!("remove_inference_counter: requires \\
|
||||
CWILCallPolicy.")
|
||||
},
|
||||
&SystemClauseType::RetractClause => {
|
||||
let p = self.cp;
|
||||
let trans_type = DynamicTransactionType::Retract;
|
||||
|
||||
self.p = CodePtr::DynamicTransaction(trans_type, p);
|
||||
return Ok(());
|
||||
},
|
||||
&SystemClauseType::ReturnFromAttributeGoals => {
|
||||
self.deallocate();
|
||||
self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0));
|
||||
|
||||
Reference in New Issue
Block a user