From: Mark Thom Date: Sat, 21 Dec 2019 05:27:49 +0000 (-0700) Subject: push of preliminary delimited continuations library cont.pl (#136) X-Git-Tag: v0.8.118~28^2~2 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=3bf1cbbe6ccd2ada0e595bae872af34f6cacb1c9;p=scryer-prolog.git push of preliminary delimited continuations library cont.pl (#136) --- diff --git a/Cargo.lock b/Cargo.lock index dd192cb7..19d316e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,8 +311,7 @@ dependencies = [ [[package]] name = "prolog_parser" -version = "0.8.36" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.8.37" dependencies = [ "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -447,7 +446,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "prolog_parser 0.8.36 (registry+https://github.com/rust-lang/crates.io-index)", + "prolog_parser 0.8.37", "ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -590,7 +589,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6" "checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum prolog_parser 0.8.36 (registry+https://github.com/rust-lang/crates.io-index)" = "fea0ae985b51f28cb3582469fbe9318e238d504a7358d90eb671f0d772fb5061" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" diff --git a/Cargo.toml b/Cargo.toml index 30099863..f26c3b3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ libc = "0.2.62" nix = "0.15.0" num-rug-adapter = { optional = true, version = "0.1.1" } ordered-float = "0.5.0" -prolog_parser = { version = "0.8.36", default-features = false } +prolog_parser = { version = "0.8.37", default-features = false } ref_thread_local = "0.0.0" rug = { version = "1.4.0", optional = true } rustyline = "5.0.3" diff --git a/README.md b/README.md index 2d060807..44238464 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,9 @@ Extend Scryer Prolog to include the following, among other features: `retract/1`, `abolish/1`) with logical update semantics. - [x] Backtrackable and non-backtrackable global variables via `bb_get/2` `bb_put/2` (non-backtrackable) and `bb_b_put/2` - (backtrackable). + (backtrackable). +- [ ] Delimited continuations based on reset/3, shift/1 (documented in + "Delimited Continuations for Prolog") (_in progress_). - [ ] clp(B) and clp(ℤ) as builtin libraries (_in progress_). - [ ] Streams and predicates for stream control (_in progress_). - [ ] An incremental compacting garbage collector satisfying the five @@ -79,15 +81,12 @@ Programming?" unum implementation or an ad hoc one. Unums are described in Gustafson's book "The End of Error." -3. Add support for shift/reset delimited continuations, see "Delimited -Continuations for Prolog." - -4. Add concurrent tables to manage shared references to atoms and +3. Add concurrent tables to manage shared references to atoms and strings. -5. Add optional SLG resolution for fast memoization of predicates. +4. Add optional SLG resolution for fast memoization of predicates. -6. Add some form of JIT predicate indexing. +5. Add some form of JIT predicate indexing. ## Installing Scryer Prolog diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index a829b7d0..78670b65 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -165,6 +165,7 @@ pub enum SystemClauseType { AtomLength, BindFromRegister, CallAttributeGoals, + CallContinuation, CharCode, CharsToNumber, ClearAttrVarBindings, @@ -193,6 +194,7 @@ pub enum SystemClauseType { GetAttrVarQueueBeyond, GetBValue, GetClause, + GetContinuationChunk, GetModuleClause, GetNextDBRef, GetNextOpDBRef, @@ -212,10 +214,12 @@ pub enum SystemClauseType { ModuleExists, ModuleOf, ModuleRetractClause, + NextEP, NoSuchPredicate, NumberToChars, NumberToCodes, OpDeclaration, + PointsToContinuationResetMarker, REPL(REPLCodePtr), ReadQueryTerm, ReadTerm, @@ -252,6 +256,7 @@ pub enum SystemClauseType { TermVariables, TruncateLiftedHeapTo, UnifyWithOccursCheck, + UnwindEnvironments, UnwindStack, Variant, WAMInstructions, @@ -271,6 +276,7 @@ impl SystemClauseType { &SystemClauseType::AtomLength => clause_name!("$atom_length"), &SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"), &SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"), + &SystemClauseType::CallContinuation => clause_name!("$call_continuation"), &SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), &SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"), @@ -316,6 +322,7 @@ impl SystemClauseType { clause_name!("$get_attr_var_queue_delim") } &SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"), + &SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"), &SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"), &SystemClauseType::GetLiftedHeapFromOffsetDiff => { clause_name!("$get_lh_from_offset_diff") @@ -350,6 +357,9 @@ impl SystemClauseType { &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"), &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"), &SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"), + &SystemClauseType::PointsToContinuationResetMarker => { + clause_name!("$points_to_cont_reset_marker") + } &SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"), &SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"), &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), @@ -370,6 +380,7 @@ impl SystemClauseType { &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"), &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"), &SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"), + &SystemClauseType::NextEP => clause_name!("$nextEP"), &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"), &SystemClauseType::ReadTerm => clause_name!("$read_term"), &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"), @@ -386,6 +397,7 @@ impl SystemClauseType { &SystemClauseType::TermVariables => clause_name!("$term_variables"), &SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"), &SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"), + &SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"), &SystemClauseType::UnwindStack => clause_name!("$unwind_stack"), &SystemClauseType::Variant => clause_name!("$variant"), &SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"), @@ -407,6 +419,7 @@ impl SystemClauseType { ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront), ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack), ("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals), + ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation), ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), ("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings), @@ -432,6 +445,9 @@ impl SystemClauseType { ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$get_char", 1) => Some(SystemClauseType::GetChar), + ("$points_to_cont_reset_marker", 1) => { + Some(SystemClauseType::PointsToContinuationResetMarker) + } ("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState), ("$truncate_if_no_lh_growth", 1) => { Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth) @@ -473,10 +489,12 @@ impl SystemClauseType { ("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond), ("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter), ("$get_ball", 1) => Some(SystemClauseType::GetBall), + ("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk), ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock), ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar), + ("$nextEP", 3) => Some(SystemClauseType::NextEP), ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm), ("$read_term", 2) => Some(SystemClauseType::ReadTerm), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock), @@ -494,6 +512,7 @@ impl SystemClauseType { ("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset), ("$term_variables", 2) => Some(SystemClauseType::TermVariables), ("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo), + ("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments), ("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack), ("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck), ("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 8db9ff43..76df2798 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -809,6 +809,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }); } Constant::CharCode(c) => self.append_str(&format!("{}", c)), + Constant::CutPoint(b) => self.append_str(&format!("{}", b)), Constant::EmptyList => self.append_str("[]"), Constant::Integer(n) => self.print_number(Number::Integer(n), op), Constant::Float(n) => self.print_number(Number::Float(n), op), diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index ef919e55..31d9dc4a 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -364,6 +364,17 @@ pub enum ControlInstruction { } impl ControlInstruction { + pub fn perm_vars(&self) -> Option { + match self { + ControlInstruction::CallClause(_, _, num_cells, ..) => + Some(*num_cells), + ControlInstruction::JmpBy(_, _, num_cells, ..) => + Some(*num_cells), + _ => + None + } + } + pub fn to_functor(&self) -> MachineStub { match self { &ControlInstruction::Allocate(num_frames) => { diff --git a/src/prolog/lib/cont.pl b/src/prolog/lib/cont.pl index 6fc0118b..630519a7 100644 --- a/src/prolog/lib/cont.pl +++ b/src/prolog/lib/cont.pl @@ -17,7 +17,7 @@ shift(Term) :- get_chunks(E, P, L) :- ( '$points_to_cont_reset_marker'(P) -> L = [] - ; '$get_chunk'(E,P,TB), + ; '$get_cont_chunk'(E,P,TB), L = [TB|Rest], '$nextEP'(E, NextE, NextP), get_chunks(NextE, NextP, Rest) @@ -26,4 +26,3 @@ get_chunks(E, P, L) :- call_continuation(L) :- '$call_continuation'(L). '$write_cont_and_term'(_, _, _, _). - diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index 1edc240d..eb0fbbb5 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -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(); diff --git a/src/prolog/machine/heap.rs b/src/prolog/machine/heap.rs index 5277b130..da3cc218 100644 --- a/src/prolog/machine/heap.rs +++ b/src/prolog/machine/heap.rs @@ -82,6 +82,50 @@ impl Heap { self.push(hcv); } } + + pub fn to_local_code_ptr(&self, addr: &Addr) -> Option { + let extract_integer = |s: usize| -> Option { + 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 for Heap { diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index 41d7a553..0a7a35af 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -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 for CodePtr { @@ -399,6 +466,25 @@ impl Add for LocalCodePtr { } } +impl Sub for LocalCodePtr { + type Output = Option; + + 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 for LocalCodePtr { fn add_assign(&mut self, rhs: usize) { match self { diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index fef46e6b..84af7ccb 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -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) diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 6588c270..d56cd17b 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -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) => { diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 0158c65e..3d575b93 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -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::().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 => {