]> Repositorios git - scryer-prolog.git/commitdiff
add tests, update status.
authorMark Thom <[email protected]>
Mon, 14 Aug 2017 19:21:45 +0000 (13:21 -0600)
committerMark Thom <[email protected]>
Mon, 14 Aug 2017 19:21:45 +0000 (13:21 -0600)
README.md
src/main.rs
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/fixtures.rs
src/prolog/io.rs
src/prolog/iterators.rs
src/prolog/machine.rs

index 90a5b0e71dc08f776380aad252ce4b983ba259c0..4e19b5ef8b97cf8fcec0eafc41572780940bc8db 100644 (file)
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ argument indexing, and conjunctive queries.
 Extend rusty-wam to include the following, among other features:
 
 * call/N as a built-in meta-predicate (_done_).
-* ISO Prolog compliant throw/catch (_done_).
+* ISO Prolog compliant throw/catch (_in progress_).
 * Built-in and user-defined operators of all fixities,
   with custom associativity and precedence.
 * Bignum and floating point arithmetic.
index 23d713386d81db46cfb451cf26b3633f143b94d4..9562f5722904f21732f2549796fb61d580c10ba8 100644 (file)
@@ -504,15 +504,15 @@ mod tests {
         assert_eq!(submit(&mut wam, "?- member(X, [a,b,c,d]), !, member(X, [a,d])."), true);
         assert_eq!(submit(&mut wam, "?- member(X, [a,b,c,d]), !, member(X, [e])."), false);
         assert_eq!(submit(&mut wam, "?- member([X,X],[a,b,c,[d,d],[e,d]]),
-                                        member(X, [a,b,c,d,e,f,g]), 
+                                        member(X, [a,b,c,d,e,f,g]),
                                         member(Y, [X, a, b, c, d])."),
                           true);
         assert_eq!(submit(&mut wam, "?- member([X,X],[a,b,c,[d,d],[e,d]]),
-                                        member(X, [a,b,c,d,e,f,g]), 
+                                        member(X, [a,b,c,d,e,f,g]),
                                         !,
                                         member(Y, [X, a, b, c, d])."),
                           true);
-        
+
         submit(&mut wam, "p(a, [f(g(X))]).");
         submit(&mut wam, "q(Y, c).");
 
@@ -545,11 +545,11 @@ mod tests {
     fn test_queries_on_call_n()
     {
         let mut wam = Machine::new();
-        
+
         submit(&mut wam, "maplist(Pred, []).
                           maplist(Pred, [X|Xs]) :- call(Pred, X), maplist(Pred, Xs).");
         submit(&mut wam, "f(a). f(b). f(c).");
-        
+
         assert_eq!(submit(&mut wam, "?- maplist(f, [X,Y,Z])."), true);
         assert_eq!(submit(&mut wam, "?- maplist(f, [a,Y,Z])."), true);
         assert_eq!(submit(&mut wam, "?- maplist(f, [X,a,b])."), true);
@@ -580,7 +580,7 @@ mod tests {
         assert_eq!(submit(&mut wam, "?- f(p, x, y)."), true);
         assert_eq!(submit(&mut wam, "?- f(p, X, z)."), false);
         assert_eq!(submit(&mut wam, "?- f(p, z, Y)."), false);
-        
+
         assert_eq!(submit(&mut wam, "?- call(p, X)."), true);
         assert_eq!(submit(&mut wam, "?- call(p, x)."), true);
         assert_eq!(submit(&mut wam, "?- call(p, y)."), true);
@@ -639,7 +639,7 @@ mod tests {
         assert_eq!(submit(&mut wam, "?- call(david_lynch, kyle(Film), _)."), false);
 
         submit(&mut wam, "call_mult(P, X) :- call(call(P), X).");
-        
+
         assert_eq!(submit(&mut wam, "?- call_mult(p(X), Y)."), true);
         assert_eq!(submit(&mut wam, "?- call_mult(p(X), X)."), true);
         assert_eq!(submit(&mut wam, "?- call_mult(p(one), X)."), true);
@@ -656,10 +656,10 @@ mod tests {
         assert_eq!(submit(&mut wam, "?- call(call(p), X, Y), call(call(call(p(X))), Y)."), true);
         assert_eq!(submit(&mut wam, "?- call(call(p), X, Y), call(call(call(p(X))), X, Y)."), false);
         assert_eq!(submit(&mut wam, "?- call(call(p), X, Y), call(call(call(p(X))), X)."), true);
-        
+
         submit(&mut wam, "f(call(f, undefined)). f(undefined).");
         submit(&mut wam, "call_var(P) :- P.");
-                
+
         assert_eq!(submit(&mut wam, "?- f(X), call_var(X)."), true);
         assert_eq!(submit(&mut wam, "?- f(call(f, Q)), call_var(call(f, Q))."), true);
         assert_eq!(submit(&mut wam, "?- call_var(call(undefined, Q))."), false);
@@ -681,25 +681,49 @@ mod tests {
         submit(&mut wam, "handle(stuff).");
 
         assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(Exception))."), true);
-        
+
         submit(&mut wam, "f(a). f(X) :- g(X).");
         submit(&mut wam, "g(x). g(y). g(z).");
         submit(&mut wam, "handle(x). handle(y).");
-        
+
         assert_eq!(submit(&mut wam, "?- catch(f(X), X, handle(X))."), true);
         assert_eq!(submit(&mut wam, "?- catch(f(a), _, handle(X))."), true);
         assert_eq!(submit(&mut wam, "?- catch(f(b), _, handle(X))."), false);
 
         submit(&mut wam, "g(x). g(X) :- throw(x).");
-        
+
         assert_eq!(submit(&mut wam, "?- catch(f(X), x, handle(X))."), true);
         assert_eq!(submit(&mut wam, "?- catch(f(X), x, handle(z))."), true);
         assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(x))."), true);
         assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(y))."), true);
         assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(z))."), false);
+
+        submit(&mut wam, "f(X) :- throw(stuff). f(X) :- throw(other_stuff).");
+        submit(&mut wam, "handle(stuff). handle(other_stuff).");
+
+        // this should deterministically succeed with Exception = stuff.
+        assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(Exception))."), true);
+        assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(stuff))."), true);
+        assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(other_stuff))."), true);
+        assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(not_stuff))."), false);
+
+        submit(&mut wam, "f(success). f(X) :- catch(g(X), E, handle(E)).");
+        submit(&mut wam, "g(g_success). g(g_success_2). g(X) :- throw(X).");
+        submit(&mut wam, "handle(x). handle(y). handle(z).");
+
+        assert_eq!(submit(&mut wam, "?- catch(f(X), E, E)."), true);
+        assert_eq!(submit(&mut wam, "?- catch(f(fail), _, _)."), false);
+        assert_eq!(submit(&mut wam, "?- catch(f(x), _, _)."), true);
+        assert_eq!(submit(&mut wam, "?- catch(f(y), _, _)."), true);
+        assert_eq!(submit(&mut wam, "?- catch(f(z), _, _)."), true);
         
-        //TODO: write more tests: multi-layered throw/catch, catch
-        // within catch, throw within catch, etc.
+        submit(&mut wam, "f(success). f(E) :- catch(g(E), E, handle(E)).");
+        submit(&mut wam, "g(g_success). g(g_success_2). g(X) :- throw(X).");
+        submit(&mut wam, "handle(x). handle(y). handle(z). handle(v) :- throw(X).");
+
+        //TODO: fix this test. record the ball properly. currently it
+        // is unwound when the heap is truncated.
+        assert_eq!(submit(&mut wam, "?- catch(f(X), E, E)."), true);
     }
 }
 
index bf1a3fef0ab871e99a7538392e9c1a732a877233..ebcff75099c08a0d8159ee91443dfdb2522685ec 100644 (file)
@@ -159,8 +159,10 @@ pub enum Term {
 
 pub enum QueryTerm {
     CallN(Vec<Box<Term>>),
+    Catch(Vec<Box<Term>>),
     Cut,
-    Term(Term)
+    Term(Term),
+    Throw(Vec<Box<Term>>)
 }
 
 impl QueryTerm {
@@ -168,10 +170,14 @@ impl QueryTerm {
         match self {
             &QueryTerm::CallN(ref terms) =>
                 QueryTermRef::CallN(terms),
+            &QueryTerm::Catch(ref terms) =>
+                QueryTermRef::Catch(terms),
             &QueryTerm::Cut =>
                 QueryTermRef::Cut,
             &QueryTerm::Term(ref term) =>
                 QueryTermRef::Term(term),
+            &QueryTerm::Throw(ref t) =>
+                QueryTermRef::Throw(t)
         }
     }
 }
@@ -184,14 +190,16 @@ pub struct Rule {
 #[derive(Clone, Copy)]
 pub enum ClauseType<'a> {
     CallN,
+    Catch,
     Deep(Level, &'a Cell<RegType>, &'a Atom),
-    Root
+    Root,
+    Throw
 }
 
 impl<'a> ClauseType<'a> {
     pub fn level_of_subterms(self) -> Level {
         match self {
-            ClauseType::CallN => Level::Shallow,
+            ClauseType::CallN | ClauseType::Catch | ClauseType::Throw => Level::Shallow,
             ClauseType::Deep(_, _, _) => Level::Deep,
             ClauseType::Root => Level::Shallow
         }
@@ -216,7 +224,9 @@ impl<'a> TermRef<'a> {
           | TermRef::Var(lvl, _, _) => lvl,
             TermRef::Clause(ClauseType::Root, _) => Level::Shallow,
             TermRef::Clause(ClauseType::Deep(lvl, _, _), _) => lvl,
-            TermRef::Clause(ClauseType::CallN, _) => Level::Shallow
+            TermRef::Clause(ClauseType::CallN, _) => Level::Shallow,
+            TermRef::Clause(ClauseType::Throw, _) => Level::Shallow,
+            TermRef::Clause(ClauseType::Catch, _) => Level::Shallow
         }
     }
 }
@@ -224,13 +234,17 @@ impl<'a> TermRef<'a> {
 #[derive(Clone, Copy)]
 pub enum QueryTermRef<'a> {
     CallN(&'a Vec<Box<Term>>),
+    Catch(&'a Vec<Box<Term>>),
     Cut,
     Term(&'a Term),
+    Throw(&'a Vec<Box<Term>>)
 }
 
 impl<'a> QueryTermRef<'a> {
     pub fn arity(self) -> usize {
         match self {
+            QueryTermRef::Catch(_) => 3,
+            QueryTermRef::Throw(_) => 1,
             QueryTermRef::CallN(terms) => terms.len(),
             QueryTermRef::Cut => 0,
             QueryTermRef::Term(term) => term.arity(),
@@ -276,7 +290,7 @@ impl IndexedChoiceInstruction {
     }
 }
 
-pub enum BuiltInInstruction {    
+pub enum BuiltInInstruction {
     CleanUpBlock,
     CopyTerm,
     Fail,
@@ -297,19 +311,23 @@ pub enum ControlInstruction {
     Allocate(usize),
     Call(Atom, usize, usize),
     CallN(usize),
+    Catch,
     Deallocate,
     Execute(Atom, usize),
     ExecuteN(usize),
-    Proceed
+    Proceed,
+    Throw
 }
 
 impl ControlInstruction {
     pub fn is_jump_instr(&self) -> bool {
         match self {
-            &ControlInstruction::Call(_, _, _) => true,
-            &ControlInstruction::Execute(_, _) => true,
+            &ControlInstruction::Call(_, _, _)  => true,
+            &ControlInstruction::Catch => true,
+            &ControlInstruction::Execute(_, _)  => true,
             &ControlInstruction::CallN(_) => true,
             &ControlInstruction::ExecuteN(_) => true,
+            &ControlInstruction::Throw => true,
             _ => false
         }
     }
index daa339f9f8d85e9f3293ef4c0d95ca8c960306ca..976263fb285d12e2a9af806170f3cd4ea8f721be 100644 (file)
@@ -87,7 +87,7 @@ fn get_builtins() -> Code {
          deallocate!(),
          goto!(58, 0), // goto false.
          set_ball!(), // throw/1, 56.
-         unwind_stack!(),         
+         unwind_stack!(),
          fail!(), // false/0, 58.
          proceed!(),
          try_me_else!(7), // not/1, 60.
index 71b9f4352fe0610443b05ff4dedfafa595d87b90..bbbadbf1bbfd27c3656e7a8b69129e035e2b3d9d 100644 (file)
@@ -24,20 +24,18 @@ pub enum EvalSession<'a> {
 pub struct ConjunctInfo<'a> {
     pub perm_vs: VariableFixtures<'a>,
     pub num_of_chunks: usize,
-    pub has_deep_cut: bool,
-    pub has_catch: bool
+    pub has_deep_cut: bool
 }
 
 impl<'a> ConjunctInfo<'a>
 {
-    fn new(perm_vs: VariableFixtures<'a>, num_of_chunks: usize, has_deep_cut: bool, has_catch: bool)
-        -> Self
+    fn new(perm_vs: VariableFixtures<'a>, num_of_chunks: usize, has_deep_cut: bool) -> Self
     {
-        ConjunctInfo { perm_vs, num_of_chunks, has_deep_cut, has_catch }
+        ConjunctInfo { perm_vs, num_of_chunks, has_deep_cut }
     }
 
     fn allocates(&self) -> bool {
-        self.perm_vs.size() > 0 || self.num_of_chunks > 1 || self.has_deep_cut || self.has_catch
+        self.perm_vs.size() > 0 || self.num_of_chunks > 1 || self.has_deep_cut
     }
 
     fn perm_vars(&self) -> usize {
@@ -45,7 +43,7 @@ impl<'a> ConjunctInfo<'a>
     }
 
     fn perm_var_offset(&self) -> usize {
-        self.has_deep_cut as usize + 2 * (self.has_catch as usize)
+        self.has_deep_cut as usize
     }
 }
 
@@ -197,14 +195,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
 
         let num_of_chunks = iter.chunk_num();
         let has_deep_cut  = iter.encountered_deep_cut();
-        let has_catch     = iter.encountered_catch();
 
         vs.populate_restricting_sets();
-        vs.set_perm_vals(has_deep_cut, has_catch);
+        vs.set_perm_vals(has_deep_cut);
 
         let vs = self.marker.drain_var_data(vs);
 
-        ConjunctInfo::new(vs, num_of_chunks, has_deep_cut, has_catch)
+        ConjunctInfo::new(vs, num_of_chunks, has_deep_cut)
     }
 
     fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize)
@@ -214,6 +211,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                 let call = ControlInstruction::CallN(terms.len());
                 compiled_query.push(Line::Control(call));
             },
+            QueryTermRef::Catch(_) =>
+                compiled_query.push(Line::Control(ControlInstruction::Catch)),            
             QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
                 let call = ControlInstruction::Call(atom.clone(), 0, pvs);
                 compiled_query.push(Line::Control(call));
@@ -222,6 +221,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                 let call = ControlInstruction::Call(atom.clone(), terms.len(), pvs);
                 compiled_query.push(Line::Control(call));
             },
+            QueryTermRef::Throw(_) =>
+                compiled_query.push(Line::Control(ControlInstruction::Throw)),
             _ => {}
         }
     }
index cc2412e405b1993dd22b6c2b1d88892b45ce6cd5..a726835efe3ed677ef1fc372a5516c4446bbf335 100644 (file)
@@ -218,7 +218,7 @@ impl<'a> VariableFixtures<'a>
         self.0.len()
     }
     
-    pub fn set_perm_vals(&self, has_deep_cuts: bool, has_catch: bool)
+    pub fn set_perm_vals(&self, has_deep_cuts: bool)
     {
         let mut values_vec : Vec<_> = self.values()
             .filter_map(|ref v| {
@@ -231,7 +231,7 @@ impl<'a> VariableFixtures<'a>
 
         values_vec.sort_by_key(|ref v| v.0);
 
-        let offset = has_deep_cuts as usize + 2 * has_catch as usize;
+        let offset = has_deep_cuts as usize;
 
         for (i, (_, cells)) in values_vec.into_iter().rev().enumerate() {
             for cell in cells {
index a45718e1a7d31e2ce6b4ee481debd42eba276ee6..7ffbbf87f3a34a8012d9cb288252794629f162b3 100644 (file)
@@ -104,6 +104,8 @@ impl fmt::Display for ControlInstruction {
                 write!(f, "call {}/{}, {}", name, arity, pvs),
             &ControlInstruction::CallN(arity) =>
                 write!(f, "call_N {}", arity),
+            &ControlInstruction::Catch =>
+                write!(f, "catch"),
             &ControlInstruction::ExecuteN(arity) =>
                 write!(f, "execute_N {}", arity),
             &ControlInstruction::Deallocate =>
@@ -111,7 +113,9 @@ impl fmt::Display for ControlInstruction {
             &ControlInstruction::Execute(ref name, arity) =>
                 write!(f, "execute {}/{}", name, arity),
             &ControlInstruction::Proceed =>
-                write!(f, "proceed")
+                write!(f, "proceed"),
+            &ControlInstruction::Throw =>
+                write!(f, "throw")
         }
     }
 }
@@ -239,10 +243,28 @@ fn rewrite_call_n(terms: &mut Vec<Box<Term>>) -> QueryTerm {
     QueryTerm::CallN(new_terms)
 }
 
+fn rewrite_catch(terms: &mut Vec<Box<Term>>) -> QueryTerm {
+    let mut new_terms = Vec::with_capacity(0);
+    swap(&mut new_terms, terms);
+
+    QueryTerm::Catch(new_terms)
+}
+
+fn rewrite_throw(terms: &mut Vec<Box<Term>>) -> QueryTerm {
+    let mut new_terms = Vec::with_capacity(0);
+    swap(&mut new_terms, terms);
+
+    QueryTerm::Throw(new_terms)
+}
+
 fn rewrite_clause(name: &Atom, terms: &mut Vec<Box<Term>>) -> Option<QueryTerm>
 {
     if name == "call" {
         Some(rewrite_call_n(terms))
+    } else if name == "catch" && terms.len() == 3 {
+        Some(rewrite_catch(terms))
+    } else if name == "throw" && terms.len() == 1 {
+        Some(rewrite_throw(terms))
     } else {
         None
     }
@@ -370,6 +392,7 @@ Each predicate must have the same name and arity.";
             let mut cg = CodeGenerator::<DebrayAllocator>::new();
 
             let compiled_query = cg.compile_query(query);
+            print_code(&compiled_query);
             wam.submit_query(compiled_query, cg.take_vars())
         }
     }
index 8230fae9f46df7cf51caa27b9b486e1c0412c32a..78dd0320167b5f74dff095732c977589f9486a65 100644 (file)
@@ -72,11 +72,19 @@ impl<'a> QueryIterator<'a> {
 
     fn new(term: QueryTermRef<'a>) -> Self {
         match term {
-            QueryTermRef::CallN(child_terms) => {
-                let state = IteratorState::Clause(1, ClauseType::CallN, child_terms);
+            QueryTermRef::CallN(terms) => {
+                let state = IteratorState::Clause(1, ClauseType::CallN, terms);
+                QueryIterator { state_stack: vec![state] }
+            },
+            QueryTermRef::Catch(terms) => {
+                let state = IteratorState::Clause(0, ClauseType::Catch, terms);
+                QueryIterator { state_stack: vec![state] }
+            },
+            QueryTermRef::Term(term)  => Self::from_term(term),
+            QueryTermRef::Throw(term) => {
+                let state = IteratorState::Clause(0, ClauseType::Throw, term);
                 QueryIterator { state_stack: vec![state] }
             },
-            QueryTermRef::Term(term) => Self::from_term(term),
             _ => QueryIterator { state_stack: vec![] }
         }
     }
@@ -101,7 +109,7 @@ impl<'a> Iterator for QueryIterator<'a> {
                         match ct {
                             ClauseType::CallN =>
                                 self.push_subterm(Level::Shallow, child_terms[0].as_ref()),
-                            ClauseType::Root =>
+                            ClauseType::Root | ClauseType::Throw | ClauseType::Catch =>
                                 return None,
                             ClauseType::Deep(_, _, _) =>
                                 return Some(TermRef::Clause(ct, child_terms))
@@ -211,8 +219,7 @@ pub struct ChunkedIterator<'a>
 {
     term_loc: GenContext,
     iter: Box<Iterator<Item=QueryTermRef<'a>> + 'a>,
-    deep_cut_encountered: bool,
-    catch_encountered: bool
+    deep_cut_encountered: bool
 }
 
 impl<'a> ChunkedIterator<'a>
@@ -226,7 +233,6 @@ impl<'a> ChunkedIterator<'a>
             term_loc: GenContext::Head,
             iter: inner_iter,
             deep_cut_encountered: false,
-            catch_encountered: false
         }
     }
 
@@ -237,49 +243,34 @@ impl<'a> ChunkedIterator<'a>
         ChunkedIterator {
             term_loc: GenContext::Last(0),
             iter: Box::new(iter),
-            deep_cut_encountered: false,
-            catch_encountered: false
-        }
-    }
-
-    fn iterate_over_query_term(p1: &'a QueryTerm) -> Box<Iterator<Item=QueryTermRef<'a>> + 'a>
-    {
-        match p1 {
-            &QueryTerm::CallN(ref child_terms) =>
-                Box::new(once(QueryTermRef::CallN(child_terms))),
-            &QueryTerm::Term(ref p1) =>
-                Box::new(once(QueryTermRef::Term(p1))),
-            &QueryTerm::Cut =>
-                Box::new(once(QueryTermRef::Cut))
+            deep_cut_encountered: false
         }
     }
 
     pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self
     {
-        let inner_iter = Self::iterate_over_query_term(p1);
+        let inner_iter = Box::new(once(p1.to_ref()));
         let iter = inner_iter.chain(clauses.iter().map(|c| c.to_ref()));
 
         ChunkedIterator {
             term_loc: GenContext::Last(0),
             iter: Box::new(iter),
-            deep_cut_encountered: false,
-            catch_encountered: false
+            deep_cut_encountered: false
         }
     }
 
     pub fn from_rule(rule: &'a Rule) -> Self
     {
         let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
-        let iter = once(QueryTermRef::Term(p0));
 
-        let inner_iter = Self::iterate_over_query_term(p1);
+        let iter = once(QueryTermRef::Term(p0));
+        let inner_iter = Box::new(once(p1.to_ref()));
         let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| c.to_ref())));
 
         ChunkedIterator {
             term_loc: GenContext::Head,
             iter: Box::new(iter),
-            deep_cut_encountered: false,
-            catch_encountered: false
+            deep_cut_encountered: false
         }
     }
 
@@ -287,10 +278,6 @@ impl<'a> ChunkedIterator<'a>
         self.deep_cut_encountered
     }
 
-    pub fn encountered_catch(&self) -> bool {
-        self.catch_encountered
-    }
-
     pub fn at_rule_head(&self) -> bool {
         self.term_loc == GenContext::Head
     }
@@ -307,6 +294,9 @@ impl<'a> ChunkedIterator<'a>
 
         while let Some(term) = item {
             match term {
+                //TODO: This can refer to the term at the head of a
+                // goal, not technically a QueryTerm (ie. a term in a
+                // query).  Think of a better name.
                 QueryTermRef::Term(inner_term) => {
                     if let GenContext::Head = self.term_loc {
                         result.push(term);
@@ -325,6 +315,11 @@ impl<'a> ChunkedIterator<'a>
                     arity = child_terms.len() + 1;
                     break;
                 },
+                QueryTermRef::Catch(child_terms) | QueryTermRef::Throw(child_terms) => {
+                    result.push(term);
+                    arity = child_terms.len();
+                    break;
+                },
                 QueryTermRef::Cut => {
                     result.push(term);
 
index 53cb6ab73e81a004b652bf601d54af77b3a03be5..67c7746950712120b210845b0e96e1da6fa5efef 100644 (file)
@@ -1286,6 +1286,12 @@ impl MachineState {
             },
             &ControlInstruction::Call(ref name, arity, _) =>
                 self.try_call_predicate(code_dir, name.clone(), arity),
+            &ControlInstruction::Catch => {
+                self.cp = self.p + 1;
+                self.num_of_args = 3;
+                self.b0 = self.b;
+                self.p  = CodePtr::DirEntry(5);
+            },
             &ControlInstruction::CallN(arity) =>
                 if let Some((name, arity)) = self.setup_call_n(arity) {
                     self.try_call_predicate(code_dir, name, arity);
@@ -1306,6 +1312,12 @@ impl MachineState {
                 },
             &ControlInstruction::Proceed =>
                 self.p = self.cp,
+            &ControlInstruction::Throw => {
+                self.cp = self.p + 1;
+                self.num_of_args = 1;
+                self.b0 = self.b;
+                self.p  = CodePtr::DirEntry(56);
+            }
         };
     }