]> Repositorios git - scryer-prolog.git/commitdiff
push of preliminary delimited continuations library cont.pl (#136)
authorMark Thom <[email protected]>
Sat, 21 Dec 2019 05:27:49 +0000 (22:27 -0700)
committerMark Thom <[email protected]>
Sat, 21 Dec 2019 05:27:49 +0000 (22:27 -0700)
13 files changed:
Cargo.lock
Cargo.toml
README.md
src/prolog/clause_types.rs
src/prolog/heap_print.rs
src/prolog/instructions.rs
src/prolog/lib/cont.pl
src/prolog/machine/attributed_variables.rs
src/prolog/machine/heap.rs
src/prolog/machine/machine_indices.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/system_calls.rs

index dd192cb7d2a93bb8f6e9b2e230ddd46ebd394165..19d316e981f21610f297e9c39363a98a0235de13 100644 (file)
@@ -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"
index 30099863b6b44e6547521b8e8b67058f7d26d008..f26c3b3a13661fc7fba09b07668ce0d889d069f6 100644 (file)
@@ -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"
index 2d060807dfe11829c2fe70ccd2c3c6022f538316..442384640c2d1c9172dbce0629df7a67e3f30d72 100644 (file)
--- 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
 
index a829b7d00d8b3ee7b5d54f03f0ae9c2d4fa6d429..78670b655c37253d8d4ecbac2ab1f65102ef42a8 100644 (file)
@@ -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)),
index 8db9ff4308040eb2a5bb0c8bd7bd39d70fba5b97..76df279818613660a0f9615b05851681a07710e5 100644 (file)
@@ -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),
index ef919e55e6a3337712a5b91cdfce1e06fcc584d5..31d9dc4ac173945660c3d26e2882c87a29ce9e31 100644 (file)
@@ -364,6 +364,17 @@ pub enum ControlInstruction {
 }
 
 impl ControlInstruction {
+    pub fn perm_vars(&self) -> Option<usize> {
+        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) => {
index 6fc0118bd88d4f3c786df7f8506f7e617176e91d..630519a7f646277c0a798ad1dd1c1088af78300f 100644 (file)
@@ -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'(_, _, _, _).
-
index 1edc240d2b0a4ef420fd60ccd770be64b67dd89f..eb0fbbb5619a994013471c63b2f8b17d3d5035eb 100644 (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();
index 5277b130268c594f46121d4425af4bab038e3a2b..da3cc2182655a76d6c6fb4819868491431409b2f 100644 (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 {
index 41d7a55327f6e2a072f87eb819491fbbcc0d03c5..0a7a35afe94e86ba121834aa8463757e023f0b53 100644 (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 {
index fef46e6b57c008713a60f90e6126597bd7e2b4f0..84af7ccbae41be465f29029eb7fa0a51ac2af97b 100644 (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)
index 6588c27033baa1cfbb674df1f7d71e142901c53c..d56cd17b688a53dd2ef9cf6c36ef576ef158b730 100644 (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) => {
index 0158c65e9d34c151ab0982ef3700f9f5bf0bc08b..3d575b93707d13538a6bab62e3ef9be2e03dc546 100644 (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 => {