]> Repositorios git - scryer-prolog.git/commitdiff
adjust for nested throws.
authorMark Thom <[email protected]>
Tue, 15 Aug 2017 04:49:41 +0000 (22:49 -0600)
committerMark Thom <[email protected]>
Tue, 15 Aug 2017 04:49:41 +0000 (22:49 -0600)
src/main.rs
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/copier.rs [new file with mode: 0644]
src/prolog/io.rs
src/prolog/machine.rs
src/prolog/macros.rs
src/prolog/mod.rs

index 9562f5722904f21732f2549796fb61d580c10ba8..ae87f9243b716082889a6c933541bfbbb1f6e464 100644 (file)
@@ -698,10 +698,10 @@ mod tests {
         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, "f(X) :- throw(stuff).");
         submit(&mut wam, "handle(stuff). handle(other_stuff).");
 
-        // this should deterministically succeed with Exception = stuff.
+        // the first 3 cases should deterministically succeed.
         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);
index ebcff75099c08a0d8159ee91443dfdb2522685ec..0737ef14cf2185692f54a3276210cbee867d4f31 100644 (file)
@@ -145,7 +145,7 @@ impl Default for VarReg {
 #[derive(Clone, Hash, PartialEq, Eq)]
 pub enum Constant {
     Atom(Atom),
-    UInt64(usize),
+    BlockNum(usize),
     EmptyList
 }
 
@@ -292,7 +292,8 @@ impl IndexedChoiceInstruction {
 
 pub enum BuiltInInstruction {
     CleanUpBlock,
-    CopyTerm,
+    DuplicateTerm,
+    EraseBall,
     Fail,
     GetBall,
     GetCurrentBlock,
@@ -311,23 +312,27 @@ pub enum ControlInstruction {
     Allocate(usize),
     Call(Atom, usize, usize),
     CallN(usize),
-    Catch,
+    CatchCall,
+    CatchExecute,
     Deallocate,
     Execute(Atom, usize),
     ExecuteN(usize),
     Proceed,
-    Throw
+    ThrowCall,
+    ThrowExecute
 }
 
 impl ControlInstruction {
     pub fn is_jump_instr(&self) -> bool {
         match self {
             &ControlInstruction::Call(_, _, _)  => true,
-            &ControlInstruction::Catch => true,
+            &ControlInstruction::CatchCall => true,
+            &ControlInstruction::CatchExecute => true,
             &ControlInstruction::Execute(_, _)  => true,
             &ControlInstruction::CallN(_) => true,
             &ControlInstruction::ExecuteN(_) => true,
-            &ControlInstruction::Throw => true,
+            &ControlInstruction::ThrowCall => true,
+            &ControlInstruction::ThrowExecute => true,
             _ => false
         }
     }
index 976263fb285d12e2a9af806170f3cd4ea8f721be..636bf3e38061ff82bd2ae0c4e8fd7c32d4fa8d1f 100644 (file)
@@ -19,87 +19,84 @@ fn get_builtins() -> Code {
          is_var!(),    // var/1, 3.
          proceed!(),
          allocate!(4), // catch/3, 5.
-         query![get_var_in_query!(perm_v!(2), 1),
-                get_var_in_query!(perm_v!(3), 2),
-                get_var_in_query!(perm_v!(1), 3),
-                put_var!(perm_v!(4), 1)],
+         fact![get_var_in_fact!(perm_v!(2), 1),
+               get_var_in_fact!(perm_v!(3), 2),
+               get_var_in_fact!(perm_v!(1), 3)],
+         query![put_var!(perm_v!(4), 1)],
          get_current_block!(),
          query![put_value!(perm_v!(2), 1),
                 put_value!(perm_v!(3), 2),
                 put_value!(perm_v!(1), 3),
                 put_unsafe_value!(4, 4)],
          deallocate!(),
-         goto!(11, 4),
-         try_me_else!(9), // catch/4, 11.
+         goto!(12, 4), // goto catch/4.
+         try_me_else!(10), // catch/4, 12.
          allocate!(3),
-         query![get_var_in_query!(perm_v!(3), 1),
-                get_var_in_query!(perm_v!(2), 4),
-                put_var!(perm_v!(1), 1)],
+         fact![get_var_in_fact!(perm_v!(3), 1),
+               get_var_in_fact!(perm_v!(2), 4)],
+         query![put_var!(perm_v!(1), 1)],
          install_new_block!(),
          query![put_value!(perm_v!(3), 1)],
          call_n!(1),
          query![put_value!(perm_v!(2), 1),
                 put_unsafe_value!(1, 2)],
          deallocate!(),
-         goto!(42, 2), // goto end_block/2 at 42.
+         goto!(44, 2), //21: goto end_block/2.
          trust_me!(),
-         allocate!(4),
-         query![get_var_in_query!(perm_v!(2), 2),
-                get_var_in_query!(perm_v!(1), 3),
-                get_var_in_query!(temp_v!(2), 1),
+         allocate!(3),
+         fact![get_var_in_fact!(perm_v!(2), 2),
+               get_var_in_fact!(perm_v!(1), 3)],
+         query![get_var_in_query!(temp_v!(2), 1),
                 put_value!(temp_v!(4), 1)],
          reset_block!(),
-         query![put_var!(perm_v!(4), 1)],
+         query![put_var!(perm_v!(3), 1)],
          get_ball!(),
-         query![put_value!(perm_v!(4), 1),
-                put_var!(perm_v!(3), 2)],
-         copy_term!(),
          query![put_unsafe_value!(3, 1),
                 put_value!(perm_v!(2), 2),
                 put_value!(perm_v!(1), 3)],
          deallocate!(),
-         goto!(31, 2), // goto handle_ball/2.
-         try_me_else!(10), // handle_ball/2, 31.
+         goto!(32, 2), // goto handle_ball/2.
+         try_me_else!(10), // handle_ball/2, 32.
          allocate!(2),
          get_level!(),
-         query![get_var_in_query!(perm_v!(2), 3)],
+         fact![get_var_in_fact!(perm_v!(2), 3)],
          unify!(),
          cut!(non_terminal!()),
+         erase_ball!(),
          query![put_value!(perm_v!(2), 1)],
          deallocate!(),
          execute_n!(1),
          trust_me!(),
          unwind_stack!(),
-         try_me_else!(8), // end_block/2, 42.
+         try_me_else!(9), // end_block/2, 44.
          allocate!(1),
-         query![get_var_in_query!(perm_v!(1), 1),
-                put_value!(temp_v!(2), 1)],
+         fact![get_var_in_fact!(perm_v!(1), 1)],
+         query![put_value!(temp_v!(2), 1)],
          clean_up_block!(),
          query![put_value!(perm_v!(1), 1)],
          deallocate!(),
          reset_block!(),
          proceed!(),
-         trust_me!(),
-         allocate!(0),
+         trust_me!(), // 53.
+         allocate!(0),   
          query![get_var_in_query!(temp_v!(3), 1),
                 put_value!(temp_v!(2), 1)],
          reset_block!(),
          deallocate!(),
-         goto!(58, 0), // goto false.
-         set_ball!(), // throw/1, 56.
+         goto!(61, 0),
+         set_ball!(), // throw/1, 59.
          unwind_stack!(),
-         fail!(), // false/0, 58.
-         proceed!(),
-         try_me_else!(7), // not/1, 60.
+         fail!(), // false/0, 61.         
+         try_me_else!(7), // not/1, 62.
          allocate!(1),
          get_level!(),
          call_n!(1),
          cut!(non_terminal!()),
          deallocate!(),
-         goto!(58, 0), // goto false.
+         goto!(61, 0),
          trust_me!(),
          proceed!(),
-         copy_term!(), // copy_term/2, 69.
+         duplicate_term!(), // duplicate_term/2, 71.
          proceed!()]
 }
 
@@ -115,11 +112,11 @@ pub fn build_code_dir() -> (Code, CodeDir) {
 
     code_dir.insert((String::from("atomic"), 1), (PredicateKeyType::BuiltIn, 1));
     code_dir.insert((String::from("var"), 1), (PredicateKeyType::BuiltIn, 3));
-    code_dir.insert((String::from("false"), 0), (PredicateKeyType::BuiltIn, 58));
-    code_dir.insert((String::from("not"), 1), (PredicateKeyType::BuiltIn, 60));
-    code_dir.insert((String::from("copy_term"), 2), (PredicateKeyType::BuiltIn, 69));
+    code_dir.insert((String::from("false"), 0), (PredicateKeyType::BuiltIn, 61));
+    code_dir.insert((String::from("not"), 1), (PredicateKeyType::BuiltIn, 62));
+    code_dir.insert((String::from("duplicate_term"), 2), (PredicateKeyType::BuiltIn, 71));
     code_dir.insert((String::from("catch"), 3), (PredicateKeyType::BuiltIn, 5));
-    code_dir.insert((String::from("throw"), 1), (PredicateKeyType::BuiltIn, 56));
+    code_dir.insert((String::from("throw"), 1), (PredicateKeyType::BuiltIn, 59));
 
     (builtin_code, code_dir)
 }
index bbbadbf1bbfd27c3656e7a8b69129e035e2b3d9d..3e3acabb0076c7e4aa179f11159674f9771a2ea3 100644 (file)
@@ -212,7 +212,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                 compiled_query.push(Line::Control(call));
             },
             QueryTermRef::Catch(_) =>
-                compiled_query.push(Line::Control(ControlInstruction::Catch)),            
+                compiled_query.push(Line::Control(ControlInstruction::CatchCall)),            
             QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
                 let call = ControlInstruction::Call(atom.clone(), 0, pvs);
                 compiled_query.push(Line::Control(call));
@@ -222,7 +222,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                 compiled_query.push(Line::Control(call));
             },
             QueryTermRef::Throw(_) =>
-                compiled_query.push(Line::Control(ControlInstruction::Throw)),
+                compiled_query.push(Line::Control(ControlInstruction::ThrowCall)),
             _ => {}
         }
     }
@@ -242,6 +242,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                 if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
                     *ctrl = ControlInstruction::ExecuteN(terms.len());
                 },
+            QueryTermRef::Catch(_) =>
+                if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
+                    *ctrl = ControlInstruction::CatchExecute;
+                },
+            QueryTermRef::Throw(_) =>
+                if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
+                    *ctrl = ControlInstruction::ThrowExecute;
+                },
             _ => dealloc_index = body.len()
         };
 
diff --git a/src/prolog/copier.rs b/src/prolog/copier.rs
new file mode 100644 (file)
index 0000000..774e7ee
--- /dev/null
@@ -0,0 +1,102 @@
+use prolog::and_stack::*;
+use prolog::ast::*;
+
+use std::ops::IndexMut;
+
+pub trait CopierTarget
+{
+    fn source(&self) -> usize;
+    fn threshold(&self) -> usize;
+    fn push(&mut self, HeapCellValue);
+    fn store(&self, Addr) -> Addr;
+    fn deref(&self, Addr) -> Addr;
+    fn stack(&mut self) -> &mut AndStack;
+
+    // duplicate_term(L1, L2) uses Cheney's algorithm to copy the term at
+    // L1 to L2. forwarding_terms is kept to restore the innards of L1
+    // after it's been copied to L2.
+    fn duplicate_term(&mut self, a: Addr) where Self: IndexMut<usize, Output=HeapCellValue>
+    {
+        let mut forward_trail: Vec<(Ref, HeapCellValue)>= Vec::new();
+        let mut scan = self.source();
+        let old_h = self.threshold();
+
+        self.push(HeapCellValue::from(a));
+
+        while scan < self.threshold() {
+            match self[scan].clone() {
+                HeapCellValue::Con(_) | HeapCellValue::NamedStr(_, _) =>
+                    scan += 1,
+                HeapCellValue::Lis(a) => {
+                    self[scan] = HeapCellValue::Lis(self.threshold());
+
+                    let hcv = self[a].clone();
+                    self.push(hcv);
+
+                    let hcv = self[a+1].clone();
+                    self.push(hcv);
+
+                    scan += 1;
+                },
+                HeapCellValue::Ref(r) => {
+                    let ra = Addr::from(r);
+                    let rd = self.store(self.deref(ra.clone()));
+
+                    match rd {
+                        Addr::HeapCell(hc) if hc >= old_h => {
+                            self[scan] = HeapCellValue::Ref(Ref::HeapCell(hc));
+                            scan += 1;
+                        },
+                        _ if ra == rd => {
+                            self[scan] = HeapCellValue::Ref(Ref::HeapCell(scan));
+
+                            match r {
+                                Ref::HeapCell(hc) =>
+                                    self[hc] = HeapCellValue::Ref(Ref::HeapCell(scan)),
+                                Ref::StackCell(fr, sc) =>
+                                    self.stack()[fr][sc] = Addr::HeapCell(scan)
+                            };
+
+                            forward_trail.push((r, HeapCellValue::Ref(r)));
+                            scan += 1;
+                        },
+                        _ => self[scan] = HeapCellValue::from(rd)
+                    }
+                },
+                HeapCellValue::Str(s) => {
+                    match self[s].clone() {
+                        HeapCellValue::NamedStr(arity, name) => {
+                            let threshold = self.threshold();
+                            
+                            self[scan] = HeapCellValue::Str(threshold);
+                            self[s] = HeapCellValue::Str(threshold);
+
+                            forward_trail.push((Ref::HeapCell(s),
+                                                HeapCellValue::NamedStr(arity, name.clone())));
+
+                            self.push(HeapCellValue::NamedStr(arity, name));
+
+                            for i in 0 .. arity {
+                                let hcv = self[s + 1 + i].clone();
+                                self.push(hcv);
+                            }
+                        },
+                        HeapCellValue::Str(o) =>
+                            self[scan] = HeapCellValue::Str(o),
+                        _ => {}
+                    };
+
+                    scan += 1;
+                }
+            };
+        }   
+        
+        for (r, hcv) in forward_trail {
+            match r {
+                Ref::HeapCell(hc) => self[hc] = hcv,
+                Ref::StackCell(fr, sc) => self.stack()[fr][sc] = hcv.as_addr(0)
+            }
+        }
+    }
+}
+    
index fc3a746cfb59e0385b7eb8e8e87f83cb75461236..5d59a2fb4b309ac5e66107f9eee0b33a9ea59bf6 100644 (file)
@@ -19,7 +19,7 @@ impl fmt::Display for Constant {
                 write!(f, "{}", atom),
             &Constant::EmptyList =>
                 write!(f, "[]"),
-            &Constant::UInt64(integer) =>
+            &Constant::BlockNum(integer) =>
                 write!(f, "u{}", integer)
         }
     }
@@ -43,7 +43,7 @@ impl fmt::Display for FactInstruction {
             &FactInstruction::GetValue(ref x, ref a) =>
                 write!(f, "get_value {}, A{}", x, a),
             &FactInstruction::GetVariable(ref x, ref a) =>
-                write!(f, "get_variable {}, A{}", x, a),
+                write!(f, "fact:get_variable {}, A{}", x, a),
             &FactInstruction::UnifyConstant(ref constant) =>
                 write!(f, "unify_constant {}", constant),
             &FactInstruction::UnifyVariable(ref r) =>
@@ -62,7 +62,7 @@ impl fmt::Display for QueryInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             &QueryInstruction::GetVariable(ref x, ref a) =>
-                write!(f, "get_variable {}, A{}", x, a),
+                write!(f, "query:get_variable {}, A{}", x, a),
             &QueryInstruction::PutConstant(Level::Shallow, ref constant, ref r) =>
                 write!(f, "put_constant {}, A{}", constant, r.reg_num()),
             &QueryInstruction::PutConstant(Level::Deep, ref constant, ref r) =>
@@ -104,8 +104,10 @@ 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::CatchCall =>
+                write!(f, "call_catch"),
+            &ControlInstruction::CatchExecute =>
+                write!(f, "execute_catch"),
             &ControlInstruction::ExecuteN(arity) =>
                 write!(f, "execute_N {}", arity),
             &ControlInstruction::Deallocate =>
@@ -114,8 +116,10 @@ impl fmt::Display for ControlInstruction {
                 write!(f, "execute {}/{}", name, arity),
             &ControlInstruction::Proceed =>
                 write!(f, "proceed"),
-            &ControlInstruction::Throw =>
-                write!(f, "throw")
+            &ControlInstruction::ThrowCall =>
+                write!(f, "call_throw"),
+            &ControlInstruction::ThrowExecute =>
+                write!(f, "execute_throw")
         }
     }
 }
@@ -368,6 +372,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
 
             if is_consistent(clauses) {
                 let compiled_pred = cg.compile_predicate(clauses);
+                print_code(&compiled_pred);
                 wam.add_predicate(clauses, compiled_pred)
             } else {
                 let msg = r"Error: predicate is inconsistent.
@@ -386,12 +391,14 @@ Each predicate must have the same name and arity.";
             let mut cg = CodeGenerator::<DebrayAllocator>::new();
 
             let compiled_rule = cg.compile_rule(rule);
+            print_code(&compiled_rule);
             wam.add_rule(rule, compiled_rule)
         },
         &TopLevel::Query(ref query) => {
             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 67c7746950712120b210845b0e96e1da6fa5efef..908783633bf9921dbed2d520220939a0845c07ea 100644 (file)
@@ -1,6 +1,7 @@
 use prolog::ast::*;
 use prolog::builtins::*;
 use prolog::codegen::*;
+use prolog::copier::*;
 use prolog::heapview::*;
 use prolog::and_stack::*;
 use prolog::or_stack::*;
@@ -35,7 +36,122 @@ struct MachineState {
     tr: usize,
     hb: usize,
     block: usize, // an offset into the OR stack.
-    ball: Addr
+    ball: Heap
+}
+
+struct DuplicateTerm<'a> {
+    state: &'a mut MachineState
+}
+
+impl<'a> DuplicateTerm<'a> {
+    fn new(state: &'a mut MachineState) -> Self {
+        DuplicateTerm { state: state }
+    }
+}
+
+impl<'a> Index<usize> for DuplicateTerm<'a> {
+    type Output = HeapCellValue;
+    
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.state.heap[index]
+    }
+}
+
+impl<'a> IndexMut<usize> for DuplicateTerm<'a> {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        &mut self.state.heap[index]
+    }
+}
+
+// the ordinary, heap term copier, used by duplicate_term.
+impl<'a> CopierTarget for DuplicateTerm<'a> {
+    fn source(&self) -> usize {
+        self.state.h
+    }
+
+    fn threshold(&self) -> usize {
+        self.state.h
+    }
+    
+    fn push(&mut self, hcv: HeapCellValue) {
+        self.state.heap.push(hcv);
+        self.state.h += 1;
+    }
+
+    fn store(&self, a: Addr) -> Addr {
+        self.state.store(a)
+    }
+
+    fn deref(&self, a: Addr) -> Addr {
+        self.state.deref(a)
+    }
+
+    fn stack(&mut self) -> &mut AndStack {
+        &mut self.state.and_stack
+    }
+}
+
+struct DuplicateBallTerm<'a> {
+    state: &'a mut MachineState,
+    heap_boundary: usize
+}
+
+impl<'a> DuplicateBallTerm<'a> {
+    fn new(state: &'a mut MachineState) -> Self {
+        let hb = state.heap.len();
+        DuplicateBallTerm { state: state, heap_boundary: hb }
+    }
+}
+
+impl<'a> Index<usize> for DuplicateBallTerm<'a> {
+    type Output = HeapCellValue;
+    
+    fn index(&self, index: usize) -> &Self::Output {
+        if index < self.heap_boundary {
+            &self.state.heap[index]
+        } else {
+            let index = index - self.heap_boundary;
+            &self.state.ball[index]
+        }
+    }
+}
+
+impl<'a> IndexMut<usize> for DuplicateBallTerm<'a> {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        if index < self.heap_boundary {
+            &mut self.state.heap[index]
+        } else {
+            let index = index - self.heap_boundary;
+            &mut self.state.ball[index]
+        }
+    }
+}
+
+// the ordinary, heap term copier, used by duplicate_term.
+impl<'a> CopierTarget for DuplicateBallTerm<'a> {
+    fn source(&self) -> usize {
+        self.heap_boundary
+    }
+
+    fn threshold(&self) -> usize {
+        self.heap_boundary + self.state.ball.len()
+    }
+    
+    fn push(&mut self, hcv: HeapCellValue) {
+        self.state.ball.push(hcv);        
+    }
+
+    fn store(&self, a: Addr) -> Addr {
+        self.state.store(a)
+    }
+
+    fn deref(&self, a: Addr) -> Addr {
+        self.state.deref(a)
+    }
+
+    fn stack(&mut self) -> &mut AndStack {
+        &mut self.state.and_stack
+    }
 }
 
 pub struct Machine {
@@ -368,7 +484,7 @@ impl Machine {
 
             while let Some(view) = viewer.next() {
                 match view {
-                    CellView::Con(&Constant::UInt64(integer)) =>
+                    CellView::Con(&Constant::BlockNum(integer)) =>
                         result += integer.to_string().as_str(),
                     CellView::Con(&Constant::EmptyList) =>
                         result += "[]",
@@ -442,10 +558,10 @@ impl MachineState {
                        tr: 0,
                        hb: 0,
                        block: 0,
-                       ball: Addr::Con(Constant::UInt64(0))
+                       ball: Vec::new()
         }
     }
-
+    
     fn num_frames(&self) -> usize {
         self.and_stack.len() + self.or_stack.len()
     }
@@ -1003,96 +1119,6 @@ impl MachineState {
         };
     }
 
-    // copy_term(L1, L2) uses Cheney's algorithm to copy the term at
-    // L1 to L2. forwarding_terms is kept to restore the innards of L1
-    // after it's been copied to L2.
-    fn copy_term(&mut self, a: Addr)
-    {
-        let mut forward_trail = Vec::new(); // list of (Ref, HeapCellValue) items.
-        let mut scan  = self.h;
-        let old_h = self.h;
-
-        self.heap.push(HeapCellValue::from(a));
-        self.h += 1;
-
-        while scan < self.h {
-            match self.heap[scan].clone() {
-                HeapCellValue::Con(_) | HeapCellValue::NamedStr(_, _) =>
-                    scan += 1,
-                HeapCellValue::Lis(a) => {
-                    let hcv = self.heap[a].clone();
-                    self.heap.push(hcv);
-
-                    let hcv = self.heap[a+1].clone();
-                    self.heap.push(hcv);
-
-                    self.heap[scan] = HeapCellValue::Lis(self.h);
-
-                    self.h += 2;
-                    scan += 1;
-                },
-                HeapCellValue::Ref(r) => {
-                    let ra = Addr::from(r);
-                    let rd = self.store(self.deref(ra.clone()));
-
-                    match rd {
-                        Addr::HeapCell(hc) if hc >= old_h => {
-                            self.heap[scan] = HeapCellValue::Ref(Ref::HeapCell(hc));
-                            scan += 1;
-                        },
-                        _ if ra == rd => {
-                            self.heap[scan] = HeapCellValue::Ref(Ref::HeapCell(scan));
-
-                            match r {
-                                Ref::HeapCell(hc) =>
-                                    self.heap[hc] = HeapCellValue::Ref(Ref::HeapCell(scan)),
-                                Ref::StackCell(fr, sc) =>
-                                    self.and_stack[fr][sc] = Addr::HeapCell(scan),
-                            };
-
-                            forward_trail.push((r, HeapCellValue::Ref(r)));
-                            scan += 1;
-                        },
-                        _ => self.heap[scan] = HeapCellValue::from(rd)
-                    }
-                },
-                HeapCellValue::Str(s) => {
-                    match self.heap[s].clone() {
-                        HeapCellValue::NamedStr(arity, name) => {
-                            self.heap[scan] = HeapCellValue::Str(self.h);
-                            self.heap[s] = HeapCellValue::Str(self.h);
-
-                            forward_trail.push((Ref::HeapCell(s),
-                                                HeapCellValue::NamedStr(arity, name.clone())));
-
-                            self.heap.push(HeapCellValue::NamedStr(arity, name));
-                            self.h += 1;
-
-                            for i in 0 .. arity {
-                                let hcv = self.heap[s + 1 + i].clone();
-                                self.heap.push(hcv);
-                                self.h += 1;
-                            }
-
-                        },
-                        HeapCellValue::Str(o) =>
-                            self.heap[scan] = HeapCellValue::Str(o),
-                        _ => {}
-                    }
-
-                    scan += 1;
-                }
-            };
-        }
-
-        for (r, hcv) in forward_trail {
-            match r {
-                Ref::HeapCell(hc) => self.heap[hc] = hcv,
-                Ref::StackCell(fr, sc) => self.and_stack[fr][sc] = hcv.as_addr(0)
-            }
-        }
-    }
-
     fn handle_internal_call_n(&mut self, code_dir: &CodeDir)
     {
         let arity = self.num_of_args + 1;
@@ -1146,30 +1172,28 @@ impl MachineState {
         Some((name, arity + narity - 1))
     }
 
-    fn has_null_ball(&self) -> bool
-    {
-        if let &Addr::Con(Constant::UInt64(_)) = &self.ball {
-            true
-        } else {
-            false
-        }
-    }
-
     fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
     {
         match instr {
-            &BuiltInInstruction::CopyTerm => {
+            &BuiltInInstruction::DuplicateTerm => {
                 let old_h = self.h;
-                let a = self[temp_v!(1)].clone();
-                self.copy_term(a);
-
+                
+                let a1 = self[temp_v!(1)].clone();
                 let a2 = self[temp_v!(2)].clone();
+
+                // drop the mutable references contained in gadget
+                // once the term has been duplicated.
+                {   
+                    let mut gadget = DuplicateTerm::new(self);                    
+                    gadget.duplicate_term(a1);
+                }
+                
                 self.unify(Addr::HeapCell(old_h), a2);
 
                 self.p += 1;
             },
             &BuiltInInstruction::GetCurrentBlock => {
-                let c = Constant::UInt64(self.block);
+                let c = Constant::BlockNum(self.block);
                 let addr = self[temp_v!(1)].clone();
 
                 self.write_constant_to_var(addr, &c);
@@ -1182,15 +1206,25 @@ impl MachineState {
                 self.unify(a1, a2);
                 self.p += 1;
             },
+            &BuiltInInstruction::EraseBall => {
+                self.ball.truncate(0);
+                self.p += 1;
+            },
             &BuiltInInstruction::GetBall => {
-                let addr = self.store(self.deref(self[temp_v!(1)].clone()));
-                let ball = self.ball.clone();
+                let addr = self.store(self.deref(self[temp_v!(1)].clone()));                
+                let h = self.h;
 
-                if self.has_null_ball() {
+                if self.ball.len() > 0 {
+                    let copied_ball_iter = self.ball.iter().cloned();
+                    self.heap.extend(copied_ball_iter);
+                    self.h += self.ball.len();
+                } else {
                     self.fail = true;
                     return;
                 }
 
+                let ball = self.heap[h].as_addr(h);
+                
                 match addr.as_ref() {
                     Some(r) => {
                         self.bind(r, ball);
@@ -1200,14 +1234,20 @@ impl MachineState {
                 };
             },
             &BuiltInInstruction::SetBall => {
-                self.ball = self[temp_v!(1)].clone();
+                let addr = self[temp_v!(1)].clone();
+
+                {
+                    let mut duplicator = DuplicateBallTerm::new(self);                
+                    duplicator.duplicate_term(addr);
+                }
+                
                 self.p += 1;
             },
             &BuiltInInstruction::CleanUpBlock => {
                 let nb = self.store(self.deref(self[temp_v!(1)].clone()));
 
                 match nb {
-                    Addr::Con(Constant::UInt64(nb)) => {
+                    Addr::Con(Constant::BlockNum(nb)) => {
                         let b = self.b - 1;
 
                         if nb > 0 && self.or_stack[b].b == nb {
@@ -1221,7 +1261,7 @@ impl MachineState {
             },
             &BuiltInInstruction::InstallNewBlock => {
                 self.block = self.b;
-                let c = Constant::UInt64(self.block);
+                let c = Constant::BlockNum(self.block);
                 let addr = self[temp_v!(1)].clone();
 
                 self.write_constant_to_var(addr, &c);
@@ -1231,7 +1271,7 @@ impl MachineState {
                 let addr = self.deref(self[temp_v!(1)].clone());
 
                 match self.store(addr) {
-                    Addr::Con(Constant::UInt64(b)) => {
+                    Addr::Con(Constant::BlockNum(b)) => {
                         self.block = b;
                         self.p += 1;
                     },
@@ -1286,12 +1326,17 @@ impl MachineState {
             },
             &ControlInstruction::Call(ref name, arity, _) =>
                 self.try_call_predicate(code_dir, name.clone(), arity),
-            &ControlInstruction::Catch => {
+            &ControlInstruction::CatchCall => {
                 self.cp = self.p + 1;
                 self.num_of_args = 3;
                 self.b0 = self.b;
                 self.p  = CodePtr::DirEntry(5);
             },
+            &ControlInstruction::CatchExecute => {
+                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);
@@ -1312,11 +1357,16 @@ impl MachineState {
                 },
             &ControlInstruction::Proceed =>
                 self.p = self.cp,
-            &ControlInstruction::Throw => {
+            &ControlInstruction::ThrowCall => {
                 self.cp = self.p + 1;
                 self.num_of_args = 1;
                 self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(56);
+                self.p  = CodePtr::DirEntry(59);
+            },
+            &ControlInstruction::ThrowExecute => {
+                self.num_of_args = 1;
+                self.b0 = self.b;
+                self.p  = CodePtr::DirEntry(59);
             }
         };
     }
index 557fa871180b6e9c1a827ea792ac830d8e054a9b..4b6e2951683cc244a3c2bb19e1e5c448e805c005 100644 (file)
@@ -22,6 +22,12 @@ macro_rules! query {
     )
 }
 
+macro_rules! fact {
+    [$($x:expr),+] => (
+        Line::Fact(vec![$($x),+])
+    )
+}
+
 macro_rules! temp_v {
     ($x:expr) => (
         RegType::Temp($x)
@@ -40,6 +46,12 @@ macro_rules! get_var_in_query {
     )
 }
 
+macro_rules! get_var_in_fact {
+    ($r:expr, $arg:expr) => (
+        FactInstruction::GetVariable($r, $arg)
+    )
+}
+
 macro_rules! put_var {
     ($r:expr, $arg:expr) => (
         QueryInstruction::PutVariable($r, $arg)
@@ -150,6 +162,12 @@ macro_rules! get_ball {
     )
 }
 
+macro_rules! erase_ball {
+    () => (
+        Line::BuiltIn(BuiltInInstruction::EraseBall)
+    )
+}
+
 macro_rules! unify {
     () => (
         Line::BuiltIn(BuiltInInstruction::Unify)
@@ -180,9 +198,9 @@ macro_rules! fail {
     )
 }
 
-macro_rules! copy_term {
+macro_rules! duplicate_term {
     () => (
-        Line::BuiltIn(BuiltInInstruction::CopyTerm)
+        Line::BuiltIn(BuiltInInstruction::DuplicateTerm)
     )
 }
 
index 86a697bdfc25c5f54b2ae23648a0d12642fe07c9..857496a1237790b6bb4b0a2dee76c49d40e8575c 100644 (file)
@@ -2,6 +2,7 @@ pub mod allocator;
 pub mod and_stack;
 pub mod ast;
 pub mod codegen;
+pub mod copier;
 pub mod debray_allocator;
 pub mod fixtures;
 pub mod heapview;