From 1d2c02e9afcfb2d0c022afabb21cdb69046ead5b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 14 Aug 2017 22:49:41 -0600 Subject: [PATCH] adjust for nested throws. --- src/main.rs | 4 +- src/prolog/ast.rs | 17 ++- src/prolog/builtins.rs | 71 +++++----- src/prolog/codegen.rs | 12 +- src/prolog/copier.rs | 102 +++++++++++++++ src/prolog/io.rs | 21 ++- src/prolog/machine.rs | 286 ++++++++++++++++++++++++----------------- src/prolog/macros.rs | 22 +++- src/prolog/mod.rs | 1 + 9 files changed, 362 insertions(+), 174 deletions(-) create mode 100644 src/prolog/copier.rs diff --git a/src/main.rs b/src/main.rs index 9562f572..ae87f924 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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); diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index ebcff750..0737ef14 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -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 } } diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 976263fb..636bf3e3 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -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) } diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index bbbadbf1..3e3acabb 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -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 index 00000000..774e7ee3 --- /dev/null +++ b/src/prolog/copier.rs @@ -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 + { + 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) + } + } + } +} + diff --git a/src/prolog/io.rs b/src/prolog/io.rs index fc3a746c..5d59a2fb 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -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::::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::::new(); let compiled_query = cg.compile_query(query); + print_code(&compiled_query); wam.submit_query(compiled_query, cg.take_vars()) } } diff --git a/src/prolog/machine.rs b/src/prolog/machine.rs index 67c77469..90878363 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -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 for DuplicateTerm<'a> { + type Output = HeapCellValue; + + fn index(&self, index: usize) -> &Self::Output { + &self.state.heap[index] + } +} + +impl<'a> IndexMut 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 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 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); } }; } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 557fa871..4b6e2951 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -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) ) } diff --git a/src/prolog/mod.rs b/src/prolog/mod.rs index 86a697bd..857496a1 100644 --- a/src/prolog/mod.rs +++ b/src/prolog/mod.rs @@ -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; -- 2.54.0