adjust for nested throws.

This commit is contained in:
Mark Thom
2017-08-14 22:49:41 -06:00
parent aa3bee5db9
commit 1d2c02e9af
9 changed files with 362 additions and 174 deletions

View 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(y))."), true);
assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(z))."), false); 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)."); 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(Exception))."), true);
assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(stuff))."), 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(other_stuff))."), true);

View File

@@ -145,7 +145,7 @@ impl Default for VarReg {
#[derive(Clone, Hash, PartialEq, Eq)] #[derive(Clone, Hash, PartialEq, Eq)]
pub enum Constant { pub enum Constant {
Atom(Atom), Atom(Atom),
UInt64(usize), BlockNum(usize),
EmptyList EmptyList
} }
@@ -292,7 +292,8 @@ impl IndexedChoiceInstruction {
pub enum BuiltInInstruction { pub enum BuiltInInstruction {
CleanUpBlock, CleanUpBlock,
CopyTerm, DuplicateTerm,
EraseBall,
Fail, Fail,
GetBall, GetBall,
GetCurrentBlock, GetCurrentBlock,
@@ -311,23 +312,27 @@ pub enum ControlInstruction {
Allocate(usize), Allocate(usize),
Call(Atom, usize, usize), Call(Atom, usize, usize),
CallN(usize), CallN(usize),
Catch, CatchCall,
CatchExecute,
Deallocate, Deallocate,
Execute(Atom, usize), Execute(Atom, usize),
ExecuteN(usize), ExecuteN(usize),
Proceed, Proceed,
Throw ThrowCall,
ThrowExecute
} }
impl ControlInstruction { impl ControlInstruction {
pub fn is_jump_instr(&self) -> bool { pub fn is_jump_instr(&self) -> bool {
match self { match self {
&ControlInstruction::Call(_, _, _) => true, &ControlInstruction::Call(_, _, _) => true,
&ControlInstruction::Catch => true, &ControlInstruction::CatchCall => true,
&ControlInstruction::CatchExecute => true,
&ControlInstruction::Execute(_, _) => true, &ControlInstruction::Execute(_, _) => true,
&ControlInstruction::CallN(_) => true, &ControlInstruction::CallN(_) => true,
&ControlInstruction::ExecuteN(_) => true, &ControlInstruction::ExecuteN(_) => true,
&ControlInstruction::Throw => true, &ControlInstruction::ThrowCall => true,
&ControlInstruction::ThrowExecute => true,
_ => false _ => false
} }
} }

View File

@@ -19,87 +19,84 @@ fn get_builtins() -> Code {
is_var!(), // var/1, 3. is_var!(), // var/1, 3.
proceed!(), proceed!(),
allocate!(4), // catch/3, 5. allocate!(4), // catch/3, 5.
query![get_var_in_query!(perm_v!(2), 1), fact![get_var_in_fact!(perm_v!(2), 1),
get_var_in_query!(perm_v!(3), 2), get_var_in_fact!(perm_v!(3), 2),
get_var_in_query!(perm_v!(1), 3), get_var_in_fact!(perm_v!(1), 3)],
put_var!(perm_v!(4), 1)], query![put_var!(perm_v!(4), 1)],
get_current_block!(), get_current_block!(),
query![put_value!(perm_v!(2), 1), query![put_value!(perm_v!(2), 1),
put_value!(perm_v!(3), 2), put_value!(perm_v!(3), 2),
put_value!(perm_v!(1), 3), put_value!(perm_v!(1), 3),
put_unsafe_value!(4, 4)], put_unsafe_value!(4, 4)],
deallocate!(), deallocate!(),
goto!(11, 4), goto!(12, 4), // goto catch/4.
try_me_else!(9), // catch/4, 11. try_me_else!(10), // catch/4, 12.
allocate!(3), allocate!(3),
query![get_var_in_query!(perm_v!(3), 1), fact![get_var_in_fact!(perm_v!(3), 1),
get_var_in_query!(perm_v!(2), 4), get_var_in_fact!(perm_v!(2), 4)],
put_var!(perm_v!(1), 1)], query![put_var!(perm_v!(1), 1)],
install_new_block!(), install_new_block!(),
query![put_value!(perm_v!(3), 1)], query![put_value!(perm_v!(3), 1)],
call_n!(1), call_n!(1),
query![put_value!(perm_v!(2), 1), query![put_value!(perm_v!(2), 1),
put_unsafe_value!(1, 2)], put_unsafe_value!(1, 2)],
deallocate!(), deallocate!(),
goto!(42, 2), // goto end_block/2 at 42. goto!(44, 2), //21: goto end_block/2.
trust_me!(), trust_me!(),
allocate!(4), allocate!(3),
query![get_var_in_query!(perm_v!(2), 2), fact![get_var_in_fact!(perm_v!(2), 2),
get_var_in_query!(perm_v!(1), 3), get_var_in_fact!(perm_v!(1), 3)],
get_var_in_query!(temp_v!(2), 1), query![get_var_in_query!(temp_v!(2), 1),
put_value!(temp_v!(4), 1)], put_value!(temp_v!(4), 1)],
reset_block!(), reset_block!(),
query![put_var!(perm_v!(4), 1)], query![put_var!(perm_v!(3), 1)],
get_ball!(), get_ball!(),
query![put_value!(perm_v!(4), 1),
put_var!(perm_v!(3), 2)],
copy_term!(),
query![put_unsafe_value!(3, 1), query![put_unsafe_value!(3, 1),
put_value!(perm_v!(2), 2), put_value!(perm_v!(2), 2),
put_value!(perm_v!(1), 3)], put_value!(perm_v!(1), 3)],
deallocate!(), deallocate!(),
goto!(31, 2), // goto handle_ball/2. goto!(32, 2), // goto handle_ball/2.
try_me_else!(10), // handle_ball/2, 31. try_me_else!(10), // handle_ball/2, 32.
allocate!(2), allocate!(2),
get_level!(), get_level!(),
query![get_var_in_query!(perm_v!(2), 3)], fact![get_var_in_fact!(perm_v!(2), 3)],
unify!(), unify!(),
cut!(non_terminal!()), cut!(non_terminal!()),
erase_ball!(),
query![put_value!(perm_v!(2), 1)], query![put_value!(perm_v!(2), 1)],
deallocate!(), deallocate!(),
execute_n!(1), execute_n!(1),
trust_me!(), trust_me!(),
unwind_stack!(), unwind_stack!(),
try_me_else!(8), // end_block/2, 42. try_me_else!(9), // end_block/2, 44.
allocate!(1), allocate!(1),
query![get_var_in_query!(perm_v!(1), 1), fact![get_var_in_fact!(perm_v!(1), 1)],
put_value!(temp_v!(2), 1)], query![put_value!(temp_v!(2), 1)],
clean_up_block!(), clean_up_block!(),
query![put_value!(perm_v!(1), 1)], query![put_value!(perm_v!(1), 1)],
deallocate!(), deallocate!(),
reset_block!(), reset_block!(),
proceed!(), proceed!(),
trust_me!(), trust_me!(), // 53.
allocate!(0), allocate!(0),
query![get_var_in_query!(temp_v!(3), 1), query![get_var_in_query!(temp_v!(3), 1),
put_value!(temp_v!(2), 1)], put_value!(temp_v!(2), 1)],
reset_block!(), reset_block!(),
deallocate!(), deallocate!(),
goto!(58, 0), // goto false. goto!(61, 0),
set_ball!(), // throw/1, 56. set_ball!(), // throw/1, 59.
unwind_stack!(), unwind_stack!(),
fail!(), // false/0, 58. fail!(), // false/0, 61.
proceed!(), try_me_else!(7), // not/1, 62.
try_me_else!(7), // not/1, 60.
allocate!(1), allocate!(1),
get_level!(), get_level!(),
call_n!(1), call_n!(1),
cut!(non_terminal!()), cut!(non_terminal!()),
deallocate!(), deallocate!(),
goto!(58, 0), // goto false. goto!(61, 0),
trust_me!(), trust_me!(),
proceed!(), proceed!(),
copy_term!(), // copy_term/2, 69. duplicate_term!(), // duplicate_term/2, 71.
proceed!()] 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("atomic"), 1), (PredicateKeyType::BuiltIn, 1));
code_dir.insert((String::from("var"), 1), (PredicateKeyType::BuiltIn, 3)); 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("false"), 0), (PredicateKeyType::BuiltIn, 61));
code_dir.insert((String::from("not"), 1), (PredicateKeyType::BuiltIn, 60)); code_dir.insert((String::from("not"), 1), (PredicateKeyType::BuiltIn, 62));
code_dir.insert((String::from("copy_term"), 2), (PredicateKeyType::BuiltIn, 69)); 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("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) (builtin_code, code_dir)
} }

View File

@@ -212,7 +212,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
compiled_query.push(Line::Control(call)); compiled_query.push(Line::Control(call));
}, },
QueryTermRef::Catch(_) => QueryTermRef::Catch(_) =>
compiled_query.push(Line::Control(ControlInstruction::Catch)), compiled_query.push(Line::Control(ControlInstruction::CatchCall)),
QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => { QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
let call = ControlInstruction::Call(atom.clone(), 0, pvs); let call = ControlInstruction::Call(atom.clone(), 0, pvs);
compiled_query.push(Line::Control(call)); compiled_query.push(Line::Control(call));
@@ -222,7 +222,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
compiled_query.push(Line::Control(call)); compiled_query.push(Line::Control(call));
}, },
QueryTermRef::Throw(_) => 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() { if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
*ctrl = ControlInstruction::ExecuteN(terms.len()); *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() _ => dealloc_index = body.len()
}; };

102
src/prolog/copier.rs Normal file
View File

@@ -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)
}
}
}
}

View File

@@ -19,7 +19,7 @@ impl fmt::Display for Constant {
write!(f, "{}", atom), write!(f, "{}", atom),
&Constant::EmptyList => &Constant::EmptyList =>
write!(f, "[]"), write!(f, "[]"),
&Constant::UInt64(integer) => &Constant::BlockNum(integer) =>
write!(f, "u{}", integer) write!(f, "u{}", integer)
} }
} }
@@ -43,7 +43,7 @@ impl fmt::Display for FactInstruction {
&FactInstruction::GetValue(ref x, ref a) => &FactInstruction::GetValue(ref x, ref a) =>
write!(f, "get_value {}, A{}", x, a), write!(f, "get_value {}, A{}", x, a),
&FactInstruction::GetVariable(ref x, ref 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) => &FactInstruction::UnifyConstant(ref constant) =>
write!(f, "unify_constant {}", constant), write!(f, "unify_constant {}", constant),
&FactInstruction::UnifyVariable(ref r) => &FactInstruction::UnifyVariable(ref r) =>
@@ -62,7 +62,7 @@ impl fmt::Display for QueryInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&QueryInstruction::GetVariable(ref x, ref a) => &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) => &QueryInstruction::PutConstant(Level::Shallow, ref constant, ref r) =>
write!(f, "put_constant {}, A{}", constant, r.reg_num()), write!(f, "put_constant {}, A{}", constant, r.reg_num()),
&QueryInstruction::PutConstant(Level::Deep, ref constant, ref r) => &QueryInstruction::PutConstant(Level::Deep, ref constant, ref r) =>
@@ -104,8 +104,10 @@ impl fmt::Display for ControlInstruction {
write!(f, "call {}/{}, {}", name, arity, pvs), write!(f, "call {}/{}, {}", name, arity, pvs),
&ControlInstruction::CallN(arity) => &ControlInstruction::CallN(arity) =>
write!(f, "call_N {}", arity), write!(f, "call_N {}", arity),
&ControlInstruction::Catch => &ControlInstruction::CatchCall =>
write!(f, "catch"), write!(f, "call_catch"),
&ControlInstruction::CatchExecute =>
write!(f, "execute_catch"),
&ControlInstruction::ExecuteN(arity) => &ControlInstruction::ExecuteN(arity) =>
write!(f, "execute_N {}", arity), write!(f, "execute_N {}", arity),
&ControlInstruction::Deallocate => &ControlInstruction::Deallocate =>
@@ -114,8 +116,10 @@ impl fmt::Display for ControlInstruction {
write!(f, "execute {}/{}", name, arity), write!(f, "execute {}/{}", name, arity),
&ControlInstruction::Proceed => &ControlInstruction::Proceed =>
write!(f, "proceed"), write!(f, "proceed"),
&ControlInstruction::Throw => &ControlInstruction::ThrowCall =>
write!(f, "throw") 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) { if is_consistent(clauses) {
let compiled_pred = cg.compile_predicate(clauses); let compiled_pred = cg.compile_predicate(clauses);
print_code(&compiled_pred);
wam.add_predicate(clauses, compiled_pred) wam.add_predicate(clauses, compiled_pred)
} else { } else {
let msg = r"Error: predicate is inconsistent. 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 mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_rule = cg.compile_rule(rule); let compiled_rule = cg.compile_rule(rule);
print_code(&compiled_rule);
wam.add_rule(rule, compiled_rule) wam.add_rule(rule, compiled_rule)
}, },
&TopLevel::Query(ref query) => { &TopLevel::Query(ref query) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new(); let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_query = cg.compile_query(query); let compiled_query = cg.compile_query(query);
print_code(&compiled_query);
wam.submit_query(compiled_query, cg.take_vars()) wam.submit_query(compiled_query, cg.take_vars())
} }
} }

View File

@@ -1,6 +1,7 @@
use prolog::ast::*; use prolog::ast::*;
use prolog::builtins::*; use prolog::builtins::*;
use prolog::codegen::*; use prolog::codegen::*;
use prolog::copier::*;
use prolog::heapview::*; use prolog::heapview::*;
use prolog::and_stack::*; use prolog::and_stack::*;
use prolog::or_stack::*; use prolog::or_stack::*;
@@ -35,7 +36,122 @@ struct MachineState {
tr: usize, tr: usize,
hb: usize, hb: usize,
block: usize, // an offset into the OR stack. 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 { pub struct Machine {
@@ -368,7 +484,7 @@ impl Machine {
while let Some(view) = viewer.next() { while let Some(view) = viewer.next() {
match view { match view {
CellView::Con(&Constant::UInt64(integer)) => CellView::Con(&Constant::BlockNum(integer)) =>
result += integer.to_string().as_str(), result += integer.to_string().as_str(),
CellView::Con(&Constant::EmptyList) => CellView::Con(&Constant::EmptyList) =>
result += "[]", result += "[]",
@@ -442,7 +558,7 @@ impl MachineState {
tr: 0, tr: 0,
hb: 0, hb: 0,
block: 0, block: 0,
ball: Addr::Con(Constant::UInt64(0)) ball: Vec::new()
} }
} }
@@ -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) fn handle_internal_call_n(&mut self, code_dir: &CodeDir)
{ {
let arity = self.num_of_args + 1; let arity = self.num_of_args + 1;
@@ -1146,30 +1172,28 @@ impl MachineState {
Some((name, arity + narity - 1)) 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) fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
{ {
match instr { match instr {
&BuiltInInstruction::CopyTerm => { &BuiltInInstruction::DuplicateTerm => {
let old_h = self.h; 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(); 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.unify(Addr::HeapCell(old_h), a2);
self.p += 1; self.p += 1;
}, },
&BuiltInInstruction::GetCurrentBlock => { &BuiltInInstruction::GetCurrentBlock => {
let c = Constant::UInt64(self.block); let c = Constant::BlockNum(self.block);
let addr = self[temp_v!(1)].clone(); let addr = self[temp_v!(1)].clone();
self.write_constant_to_var(addr, &c); self.write_constant_to_var(addr, &c);
@@ -1182,15 +1206,25 @@ impl MachineState {
self.unify(a1, a2); self.unify(a1, a2);
self.p += 1; self.p += 1;
}, },
&BuiltInInstruction::EraseBall => {
self.ball.truncate(0);
self.p += 1;
},
&BuiltInInstruction::GetBall => { &BuiltInInstruction::GetBall => {
let addr = self.store(self.deref(self[temp_v!(1)].clone())); let addr = self.store(self.deref(self[temp_v!(1)].clone()));
let ball = self.ball.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; self.fail = true;
return; return;
} }
let ball = self.heap[h].as_addr(h);
match addr.as_ref() { match addr.as_ref() {
Some(r) => { Some(r) => {
self.bind(r, ball); self.bind(r, ball);
@@ -1200,14 +1234,20 @@ impl MachineState {
}; };
}, },
&BuiltInInstruction::SetBall => { &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; self.p += 1;
}, },
&BuiltInInstruction::CleanUpBlock => { &BuiltInInstruction::CleanUpBlock => {
let nb = self.store(self.deref(self[temp_v!(1)].clone())); let nb = self.store(self.deref(self[temp_v!(1)].clone()));
match nb { match nb {
Addr::Con(Constant::UInt64(nb)) => { Addr::Con(Constant::BlockNum(nb)) => {
let b = self.b - 1; let b = self.b - 1;
if nb > 0 && self.or_stack[b].b == nb { if nb > 0 && self.or_stack[b].b == nb {
@@ -1221,7 +1261,7 @@ impl MachineState {
}, },
&BuiltInInstruction::InstallNewBlock => { &BuiltInInstruction::InstallNewBlock => {
self.block = self.b; self.block = self.b;
let c = Constant::UInt64(self.block); let c = Constant::BlockNum(self.block);
let addr = self[temp_v!(1)].clone(); let addr = self[temp_v!(1)].clone();
self.write_constant_to_var(addr, &c); self.write_constant_to_var(addr, &c);
@@ -1231,7 +1271,7 @@ impl MachineState {
let addr = self.deref(self[temp_v!(1)].clone()); let addr = self.deref(self[temp_v!(1)].clone());
match self.store(addr) { match self.store(addr) {
Addr::Con(Constant::UInt64(b)) => { Addr::Con(Constant::BlockNum(b)) => {
self.block = b; self.block = b;
self.p += 1; self.p += 1;
}, },
@@ -1286,12 +1326,17 @@ impl MachineState {
}, },
&ControlInstruction::Call(ref name, arity, _) => &ControlInstruction::Call(ref name, arity, _) =>
self.try_call_predicate(code_dir, name.clone(), arity), self.try_call_predicate(code_dir, name.clone(), arity),
&ControlInstruction::Catch => { &ControlInstruction::CatchCall => {
self.cp = self.p + 1; self.cp = self.p + 1;
self.num_of_args = 3; self.num_of_args = 3;
self.b0 = self.b; self.b0 = self.b;
self.p = CodePtr::DirEntry(5); self.p = CodePtr::DirEntry(5);
}, },
&ControlInstruction::CatchExecute => {
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(5);
},
&ControlInstruction::CallN(arity) => &ControlInstruction::CallN(arity) =>
if let Some((name, arity)) = self.setup_call_n(arity) { if let Some((name, arity)) = self.setup_call_n(arity) {
self.try_call_predicate(code_dir, name, arity); self.try_call_predicate(code_dir, name, arity);
@@ -1312,11 +1357,16 @@ impl MachineState {
}, },
&ControlInstruction::Proceed => &ControlInstruction::Proceed =>
self.p = self.cp, self.p = self.cp,
&ControlInstruction::Throw => { &ControlInstruction::ThrowCall => {
self.cp = self.p + 1; self.cp = self.p + 1;
self.num_of_args = 1; self.num_of_args = 1;
self.b0 = self.b; 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);
} }
}; };
} }

View File

@@ -22,6 +22,12 @@ macro_rules! query {
) )
} }
macro_rules! fact {
[$($x:expr),+] => (
Line::Fact(vec![$($x),+])
)
}
macro_rules! temp_v { macro_rules! temp_v {
($x:expr) => ( ($x:expr) => (
RegType::Temp($x) 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 { macro_rules! put_var {
($r:expr, $arg:expr) => ( ($r:expr, $arg:expr) => (
QueryInstruction::PutVariable($r, $arg) QueryInstruction::PutVariable($r, $arg)
@@ -150,6 +162,12 @@ macro_rules! get_ball {
) )
} }
macro_rules! erase_ball {
() => (
Line::BuiltIn(BuiltInInstruction::EraseBall)
)
}
macro_rules! unify { macro_rules! unify {
() => ( () => (
Line::BuiltIn(BuiltInInstruction::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)
) )
} }

View File

@@ -2,6 +2,7 @@ pub mod allocator;
pub mod and_stack; pub mod and_stack;
pub mod ast; pub mod ast;
pub mod codegen; pub mod codegen;
pub mod copier;
pub mod debray_allocator; pub mod debray_allocator;
pub mod fixtures; pub mod fixtures;
pub mod heapview; pub mod heapview;