push of preliminary delimited continuations library cont.pl (#136)

This commit is contained in:
Mark Thom
2019-12-20 22:27:49 -07:00
parent 4ef8ab6e76
commit 3bf1cbbe6c
13 changed files with 422 additions and 56 deletions

View File

@@ -117,7 +117,7 @@ impl MachineState {
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone();
}
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::Con(Constant::Usize(self.b0));
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::Con(Constant::CutPoint(self.b0));
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Con(Constant::Usize(self.num_of_args));
self.verify_attributes();

View File

@@ -82,6 +82,50 @@ impl Heap {
self.push(hcv);
}
}
pub fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
let extract_integer = |s: usize| -> Option<usize> {
match self.heap[s].as_addr(s) {
Addr::Con(Constant::Integer(n)) => n.to_usize(),
_ => None
}
};
match addr {
Addr::Str(s) => {
match &self.heap[*s] {
HeapCellValue::NamedStr(arity, ref name, _) => {
match (name.as_str(), *arity) {
("dir_entry", 1) => {
extract_integer(s+1).map(LocalCodePtr::DirEntry)
}
("in_situ_dir_entry", 1) => {
extract_integer(s+1).map(LocalCodePtr::InSituDirEntry)
}
("top_level", 2) => {
if let Some(chunk_num) = extract_integer(s+1) {
if let Some(p) = extract_integer(s+2) {
return Some(LocalCodePtr::TopLevel(chunk_num, p));
}
}
None
}
("user_goal_expansion", 1) => {
extract_integer(s+1).map(LocalCodePtr::UserGoalExpansion)
}
("user_term_expansion", 1) => {
extract_integer(s+1).map(LocalCodePtr::UserTermExpansion)
}
_ => None
}
}
_ => unreachable!()
}
}
_ => None
}
}
}
impl Index<usize> for Heap {

View File

@@ -4,7 +4,11 @@ use prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::Ball;
use crate::prolog::machine::heap::Heap;
use crate::prolog::instructions::*;
use crate::prolog::rug::Integer;
use indexmap::IndexMap;
@@ -346,6 +350,69 @@ impl LocalCodePtr {
_ => {}
}
}
pub fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool {
match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) {
Some(line) => {
match line.as_ref() {
Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
return true;
}
}
_ => {}
}
}
None => {}
}
false
}
pub fn as_functor(&self, heap: &mut Heap) -> Addr {
let addr = Addr::HeapCell(heap.h);
match self {
LocalCodePtr::DirEntry(p) => {
heap.append(functor!(
"dir_entry",
1,
[heap_integer!(Integer::from(*p))]
));
}
LocalCodePtr::InSituDirEntry(p) => {
heap.append(functor!(
"in_situ_dir_entry",
1,
[heap_integer!(Integer::from(*p))]
));
}
LocalCodePtr::TopLevel(chunk_num, offset) => {
heap.append(functor!(
"top_level",
2,
[heap_integer!(Integer::from(*chunk_num)),
heap_integer!(Integer::from(*offset))]
));
}
LocalCodePtr::UserGoalExpansion(p) => {
heap.append(functor!(
"user_goal_expansion",
1,
[heap_integer!(Integer::from(*p))]
));
}
LocalCodePtr::UserTermExpansion(p) => {
heap.append(functor!(
"user_term_expansion",
1,
[heap_integer!(Integer::from(*p))]
));
}
}
addr
}
}
impl PartialOrd<CodePtr> for CodePtr {
@@ -399,6 +466,25 @@ impl Add<usize> for LocalCodePtr {
}
}
impl Sub<usize> for LocalCodePtr {
type Output = Option<LocalCodePtr>;
fn sub(self, rhs: usize) -> Self::Output {
match self {
LocalCodePtr::InSituDirEntry(p) =>
p.checked_sub(rhs).map(LocalCodePtr::InSituDirEntry),
LocalCodePtr::DirEntry(p) =>
p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
LocalCodePtr::TopLevel(cn, p) =>
p.checked_sub(rhs).map(|r| LocalCodePtr::TopLevel(cn, r)),
LocalCodePtr::UserTermExpansion(p) =>
p.checked_sub(rhs).map(LocalCodePtr::UserTermExpansion),
LocalCodePtr::UserGoalExpansion(p) =>
p.checked_sub(rhs).map(LocalCodePtr::UserGoalExpansion),
}
}
}
impl AddAssign<usize> for LocalCodePtr {
fn add_assign(&mut self, rhs: usize) {
match self {

View File

@@ -1063,17 +1063,20 @@ downcast!(dyn CutPolicy);
fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
let b = machine_st.b;
if let Addr::Con(Constant::Usize(b0)) = addr {
if b > b0 {
machine_st.b = b0;
machine_st.tidy_trail();
machine_st.tidy_pstr_trail();
machine_st.truncate_stack();
match addr {
Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => {
if b > b0 {
machine_st.b = b0;
machine_st.tidy_trail();
machine_st.tidy_pstr_trail();
machine_st.truncate_stack();
}
}
} else {
machine_st.fail = true;
return true;
}
_ => {
machine_st.fail = true;
return true;
}
};
false
}
@@ -1148,15 +1151,19 @@ impl CutPolicy for SCCCutPolicy {
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
let b = machine_st.b;
if let Addr::Con(Constant::Usize(b0)) = machine_st[r].clone() {
if b > b0 {
machine_st.b = b0;
machine_st.tidy_trail();
machine_st.tidy_pstr_trail();
match machine_st[r].clone() {
Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => {
if b > b0 {
machine_st.b = b0;
machine_st.tidy_trail();
machine_st.tidy_pstr_trail();
machine_st.truncate_stack();
}
}
_ => {
machine_st.fail = true;
return true;
}
} else {
machine_st.fail = true;
return true;
}
self.run_cleaners(machine_st)

View File

@@ -3337,7 +3337,7 @@ impl MachineState {
&CutInstruction::GetLevel(r) => {
let b0 = self.b0;
self[r] = Addr::Con(Constant::Usize(b0));
self[r] = Addr::Con(Constant::CutPoint(b0));
self.p += 1;
}
&CutInstruction::GetLevelAndUnify(r) => {

View File

@@ -580,6 +580,51 @@ impl MachineState {
functors
}
fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr {
let chunk = self.store(self.deref(chunk));
match chunk {
Addr::Str(s) => {
match &self.heap[s] {
HeapCellValue::NamedStr(arity, ..) => {
let num_cells = arity - 1;
let p_functor = self.heap[s+1].as_addr(s+1);
let cp = self.heap.to_local_code_ptr(&p_functor).unwrap();
let prev_e = self.e;
let e = self.stack.allocate_and_frame(num_cells);
let and_frame = self.stack.index_and_frame_mut(e);
and_frame.prelude.e = prev_e;
and_frame.prelude.cp = return_p;
self.p = CodePtr::Local(cp + 1);
// adjust cut point to occur after call_continuation.
if num_cells > 0 {
if let Addr::Con(Constant::CutPoint(_)) = self.heap[s+2].as_addr(s+2) {
and_frame[1] = Addr::Con(Constant::CutPoint(self.b));
} else {
and_frame[1] = self.heap[s+2].as_addr(s+2);
}
}
for index in s+3 .. s+2+num_cells {
and_frame[index - (s+1)] = self.heap[index].as_addr(index);
}
self.e = e;
self.p.local()
}
_ => unreachable!()
}
}
_ => unreachable!()
}
}
pub(super) fn system_call(
&mut self,
ct: &SystemClauseType,
@@ -610,17 +655,17 @@ impl MachineState {
Addr::Con(Constant::Integer(n)) => n.to_usize(),
_ => unreachable!()
};
if let Some(n) = n {
if n <= MAX_ARITY {
let target = self[temp_v!(n)].clone();
let addr = self[temp_v!(1)].clone();
self.unify(addr, target);
return return_from_clause!(self.last_call, self);
}
}
self.fail = true;
}
&SystemClauseType::AssertDynamicPredicateToFront => {
@@ -784,6 +829,28 @@ impl MachineState {
return Ok(());
}
&SystemClauseType::CallContinuation => {
let stub = MachineError::functor_stub(clause_name!("call_continuation"), 1);
match self.try_from_list(temp_v!(1), stub) {
Err(e) => return Err(e),
Ok(cont_chunks) => {
let mut return_p = if self.last_call {
self.cp
} else {
self.p.local() + 1
};
self.p = CodePtr::Local(return_p);
for chunk in cont_chunks.into_iter().rev() {
return_p = self.call_continuation_chunk(chunk, return_p);
}
}
}
return Ok(());
}
&SystemClauseType::CharsToNumber => {
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
@@ -897,7 +964,7 @@ impl MachineState {
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
match addr {
Addr::Con(Constant::Usize(old_b)) => {
Addr::Con(Constant::Usize(old_b)) | Addr::Con(Constant::CutPoint(old_b)) => {
let prev_b = self.stack.index_or_frame(self.b).prelude.b;
let prev_b = self.stack.index_or_frame(prev_b).prelude.b;
@@ -1477,6 +1544,50 @@ impl MachineState {
_ => self.fail = true,
}
}
&SystemClauseType::GetContinuationChunk => {
let e = self.store(self.deref(self[temp_v!(1)].clone()));
let e = if let Addr::Con(Constant::Usize(e)) = e {
e
} else {
self.fail = true;
return Ok(());
};
let p_functor = self.store(self.deref(self[temp_v!(2)].clone()));
let p = self.heap.to_local_code_ptr(&p_functor).unwrap();
let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) {
Some(line) => {
let perm_vars = match line.as_ref() {
Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(),
_ => None
};
perm_vars.unwrap()
}
_ => unreachable!()
};
let mut addrs = vec![];
for index in 1 .. num_cells + 1 {
addrs.push(self.stack.index_and_frame(e)[index].clone());
}
let chunk = Addr::HeapCell(self.heap.h);
self.heap.push(HeapCellValue::NamedStr(
1 + num_cells,
clause_name!("cont_chunk"),
None,
));
self.heap.push(HeapCellValue::Addr(p_functor));
self.heap.extend(addrs.into_iter().map(HeapCellValue::Addr));
self.unify(self[temp_v!(3)].clone(), chunk);
}
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
let lh_offset = self[temp_v!(1)].clone();
@@ -1609,7 +1720,8 @@ impl MachineState {
}
match (a1, a2.clone()) {
(Addr::Con(Constant::Usize(bp)), Addr::Con(Constant::Integer(n))) => {
(Addr::Con(Constant::Usize(bp)), Addr::Con(Constant::Integer(n)))
| (Addr::Con(Constant::CutPoint(bp)), Addr::Con(Constant::Integer(n))) => {
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
Some(call_policy) => {
let count = call_policy.add_limit(n, bp);
@@ -1771,14 +1883,17 @@ impl MachineState {
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
match a1 {
Addr::Con(Constant::Usize(bp)) | Addr::Con(Constant::CutPoint(bp)) => {
if call_policy.is_empty() && bp == self.b {
Some(call_policy.into_inner())
} else {
None
}
}
_ => {
panic!("remove_call_policy_check: expected Usize in A1.");
}
} else {
panic!("remove_call_policy_check: expected Usize in A1.");
}
}
None => panic!(
@@ -1796,15 +1911,18 @@ impl MachineState {
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);
let count = Addr::Con(Constant::Integer(count.clone()));
match a1 {
Addr::Con(Constant::Usize(bp)) | Addr::Con(Constant::CutPoint(bp)) => {
let count = call_policy.remove_limit(bp);
let count = Addr::Con(Constant::Integer(count.clone()));
let a2 = self[temp_v!(2)].clone();
let a2 = self[temp_v!(2)].clone();
self.unify(a2, count);
} else {
panic!("remove_inference_counter: expected Usize in A1.");
self.unify(a2, count);
}
_ => {
panic!("remove_inference_counter: expected Usize in A1.");
}
}
}
None => panic!(
@@ -1836,7 +1954,7 @@ impl MachineState {
self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i].clone();
}
if let &Addr::Con(Constant::Usize(b0)) = &self.stack.index_and_frame(e)[frame_len - 1] {
if let &Addr::Con(Constant::CutPoint(b0)) = &self.stack.index_and_frame(e)[frame_len - 1] {
self.b0 = b0;
}
@@ -1884,7 +2002,7 @@ impl MachineState {
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
match a2 {
Addr::Con(Constant::Usize(bp)) => {
Addr::Con(Constant::CutPoint(bp)) | Addr::Con(Constant::Usize(bp)) => {
let prev_b = self.stack.index_or_frame(self.b).prelude.b;
if prev_b <= bp {
@@ -1975,7 +2093,7 @@ impl MachineState {
}
&SystemClauseType::GetCutPoint => {
let a1 = self[temp_v!(1)].clone();
let a2 = Addr::Con(Constant::Usize(self.b0));
let a2 = Addr::Con(Constant::CutPoint(self.b0));
self.unify(a1, a2);
}
@@ -1997,6 +2115,72 @@ impl MachineState {
let target = self[temp_v!(1)].clone();
self.unify(Addr::Con(Constant::Char(c)), target);
}
&SystemClauseType::NextEP => {
let first_arg = self.store(self.deref(self[temp_v!(1)].clone()));
match first_arg {
Addr::Con(Constant::Atom(ref name, _))
if name.as_str() == "first" => {
if self.e == 0 {
self.fail = true;
return Ok(());
}
let cp = (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap();
let e = self.stack.index_and_frame(self.e).prelude.e;
let e = Addr::Con(Constant::Usize(e));
let p = cp.as_functor(&mut self.heap);
self.unify(self[temp_v!(2)].clone(), e);
if !self.fail {
self.unify(self[temp_v!(3)].clone(), p);
}
},
Addr::Con(Constant::Usize(e)) => {
if e == 0 {
self.fail = true;
return Ok(());
}
// get the call site so that the number of active permanent variables can be read
// from it later.
let cp = (self.stack.index_and_frame(e).prelude.cp - 1).unwrap();
let p = cp.as_functor(&mut self.heap);
let e = self.stack.index_and_frame(e).prelude.e;
let e = Addr::Con(Constant::Usize(e));
self.unify(self[temp_v!(2)].clone(), e);
if !self.fail {
self.unify(self[temp_v!(3)].clone(), p);
}
}
_ => unreachable!()
}
}
&SystemClauseType::PointsToContinuationResetMarker => {
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
let p = match self.heap.to_local_code_ptr(&addr) {
Some(p) => p + 1,
None => {
self.fail = true;
return Ok(());
}
};
if p.is_reset_cont_marker(code_repo, self.last_call) {
return return_from_clause!(self.last_call, self);
}
self.fail = true;
return Ok(());
}
&SystemClauseType::ReadQueryTerm => {
readline::set_prompt(true);
let result = self.read_term(current_input_stream, indices);
@@ -2013,6 +2197,8 @@ impl MachineState {
self.reset_block(addr);
}
&SystemClauseType::ResetContinuationMarker => {
self[temp_v!(3)] = Addr::Con(Constant::Integer(Integer::from(0)));
self[temp_v!(4)] = Addr::Con(Constant::Integer(Integer::from(0)));
}
&SystemClauseType::SetBall =>
self.set_ball(),
@@ -2123,6 +2309,22 @@ impl MachineState {
self.unify_with_occurs_check(a1, a2);
}
&SystemClauseType::UnwindEnvironments => {
let mut e = self.e;
let mut cp = self.cp;
while e > 0 {
if cp.is_reset_cont_marker(code_repo, self.last_call) {
self.e = e;
self.p = CodePtr::Local(cp + 1); // skip the reset marker.
return Ok(());
}
cp = self.stack.index_and_frame(e).prelude.cp;
e = self.stack.index_and_frame(e).prelude.e;
}
}
&SystemClauseType::UnwindStack => self.unwind_stack(),
&SystemClauseType::Variant => self.fail = self.structural_eq_test(),
&SystemClauseType::WAMInstructions => {