add support for setup_call_cleanup
This commit is contained in:
@@ -100,6 +100,7 @@ The following predicates are built-in to rusty-wam.
|
||||
* `once/1`
|
||||
* `reverse/2`
|
||||
* `select/3`
|
||||
* `setup_call_cleanup/3`
|
||||
* `throw/1`
|
||||
* `true/0`
|
||||
* `var/1`
|
||||
|
||||
@@ -18,7 +18,7 @@ pub trait Allocator<'a>
|
||||
fn reset(&mut self);
|
||||
fn reset_contents(&mut self) {}
|
||||
fn reset_arg(&mut self, usize);
|
||||
fn reset_arg_at_head(&mut self, &Term);
|
||||
fn reset_arg_at_head(&mut self, &'a Term);
|
||||
|
||||
fn advance_arg(&mut self);
|
||||
|
||||
|
||||
@@ -381,6 +381,7 @@ pub enum QueryTerm {
|
||||
Inlined(InlinedQueryTerm),
|
||||
Is(Vec<Box<Term>>),
|
||||
Jump(JumpStub),
|
||||
SetupCallCleanup(Vec<Box<Term>>),
|
||||
Term(Term),
|
||||
Throw(Vec<Box<Term>>)
|
||||
}
|
||||
@@ -399,6 +400,7 @@ impl QueryTerm {
|
||||
&QueryTerm::Jump(ref vars) => vars.len(),
|
||||
&QueryTerm::CallN(ref terms) => terms.len(),
|
||||
&QueryTerm::Cut => 0,
|
||||
&QueryTerm::SetupCallCleanup(_) => 3,
|
||||
&QueryTerm::Term(ref term) => term.arity(),
|
||||
}
|
||||
}
|
||||
@@ -422,6 +424,7 @@ pub enum ClauseType<'a> {
|
||||
Functor,
|
||||
Is,
|
||||
Root(&'a TabledRc<Atom>),
|
||||
SetupCallCleanup,
|
||||
Throw,
|
||||
}
|
||||
|
||||
@@ -437,6 +440,7 @@ impl<'a> ClauseType<'a> {
|
||||
&ClauseType::Functor => "functor",
|
||||
&ClauseType::Is => "is",
|
||||
&ClauseType::Root(name) => name.as_str(),
|
||||
&ClauseType::SetupCallCleanup => "setup_call_cleanup",
|
||||
&ClauseType::Throw => "throw"
|
||||
}
|
||||
}
|
||||
@@ -478,8 +482,8 @@ pub enum ChoiceInstruction {
|
||||
}
|
||||
|
||||
pub enum CutInstruction {
|
||||
Cut,
|
||||
GetLevel,
|
||||
Cut(RegType),
|
||||
GetLevel(RegType),
|
||||
NeckCut
|
||||
}
|
||||
|
||||
@@ -792,6 +796,7 @@ pub enum BuiltInInstruction {
|
||||
GetCutPoint(RegType),
|
||||
DynamicCompareNumber(CompareNumberQT),
|
||||
DynamicIs,
|
||||
InstallCleaner,
|
||||
InstallNewBlock,
|
||||
InternalCallN,
|
||||
IsAtomic(RegType),
|
||||
@@ -805,6 +810,7 @@ pub enum BuiltInInstruction {
|
||||
UnwindStack
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ControlInstruction {
|
||||
Allocate(usize), // num_frames.
|
||||
ArgCall,
|
||||
@@ -813,6 +819,7 @@ pub enum ControlInstruction {
|
||||
CallN(usize), // arity.
|
||||
CatchCall,
|
||||
CatchExecute,
|
||||
CheckCpExecute,
|
||||
DisplayCall,
|
||||
DisplayExecute,
|
||||
Deallocate,
|
||||
@@ -822,10 +829,11 @@ pub enum ControlInstruction {
|
||||
ExecuteN(usize),
|
||||
FunctorCall,
|
||||
FunctorExecute,
|
||||
JmpByCall(usize, usize), // arity, global_offset.
|
||||
JmpByExecute(usize, usize),
|
||||
GetCleanerCall,
|
||||
GotoCall(usize, usize), // p, arity.
|
||||
GotoExecute(usize, usize), // p, arity.
|
||||
JmpByCall(usize, usize), // arity, global_offset.
|
||||
JmpByExecute(usize, usize),
|
||||
IsCall(RegType, ArithmeticTerm),
|
||||
IsExecute(RegType, ArithmeticTerm),
|
||||
Proceed,
|
||||
@@ -852,6 +860,7 @@ impl ControlInstruction {
|
||||
&ControlInstruction::FunctorExecute => true,
|
||||
&ControlInstruction::ThrowCall => true,
|
||||
&ControlInstruction::ThrowExecute => true,
|
||||
&ControlInstruction::GetCleanerCall => true,
|
||||
&ControlInstruction::GotoCall(..) => true,
|
||||
&ControlInstruction::GotoExecute(..) => true,
|
||||
&ControlInstruction::Proceed => true,
|
||||
|
||||
@@ -65,10 +65,10 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
goto_execute!(32, 2), // goto handle_ball/2.
|
||||
try_me_else!(10), // handle_ball/2, 32.
|
||||
allocate!(2),
|
||||
get_level!(),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(2), 3)],
|
||||
unify!(),
|
||||
cut!(),
|
||||
cut!(perm_v!(1)),
|
||||
erase_ball!(),
|
||||
query![put_value!(perm_v!(2), 1)],
|
||||
deallocate!(),
|
||||
@@ -96,9 +96,9 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
fail!(), // false/0, 61.
|
||||
try_me_else!(7), // not/1, 62.
|
||||
allocate!(1),
|
||||
get_level!(),
|
||||
get_level!(perm_v!(1)),
|
||||
call_n!(1),
|
||||
cut!(),
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
goto_execute!(61, 0),
|
||||
trust_me!(),
|
||||
@@ -145,8 +145,8 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
deallocate!(),
|
||||
goto_execute!(83, 3),
|
||||
retry_me_else!(10),
|
||||
allocate!(1),
|
||||
get_level!(),
|
||||
allocate!(2),
|
||||
get_level!(perm_v!(2)),
|
||||
fact![get_constant!(atom!("!", atom_tbl), temp_v!(2)),
|
||||
get_var_in_fact!(perm_v!(1), 3)],
|
||||
neck_cut!(),
|
||||
@@ -300,7 +300,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
proceed!(),
|
||||
retry_me_else!(11),
|
||||
allocate!(4),
|
||||
get_level!(),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(3), 1),
|
||||
get_list!(Level::Shallow, temp_v!(2)),
|
||||
unify_variable!(temp_v!(2)),
|
||||
@@ -309,7 +309,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
query![put_value!(perm_v!(3), 1),
|
||||
put_var!(perm_v!(2), 3)],
|
||||
functor_call!(),
|
||||
cut!(),
|
||||
cut!(perm_v!(1)),
|
||||
query![put_unsafe_value!(4, 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_constant!(Level::Shallow, integer!(1), temp_v!(3)),
|
||||
@@ -318,7 +318,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
goto_execute!(236, 4), // goto get_args/4.
|
||||
trust_me!(),
|
||||
allocate!(5),
|
||||
get_level!(),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(3), 1),
|
||||
get_list!(Level::Shallow, temp_v!(2)),
|
||||
unify_variable!(perm_v!(5)),
|
||||
@@ -330,7 +330,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
put_value!(perm_v!(5), 2),
|
||||
put_value!(perm_v!(2), 3)],
|
||||
functor_call!(),
|
||||
cut!(),
|
||||
cut!(perm_v!(1)),
|
||||
query![put_unsafe_value!(4, 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_constant!(Level::Shallow, integer!(1), temp_v!(3)),
|
||||
@@ -370,7 +370,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
query![put_value!(perm_v!(5), 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_value!(temp_v!(5), 3)],
|
||||
get_arg_call!(),
|
||||
get_arg_call!(),
|
||||
add!(ArithmeticTerm::Reg(perm_v!(5)),
|
||||
ArithmeticTerm::Number(rc_integer!(1)),
|
||||
1),
|
||||
@@ -389,17 +389,17 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
neck_cut!(),
|
||||
query![put_value!(temp_v!(4), 1),
|
||||
put_constant!(Level::Shallow, integer!(0), temp_v!(2))],
|
||||
goto_execute!(281, 3), // goto length/3, 281.
|
||||
goto_execute!(281, 3), // goto length/3, 281.
|
||||
retry_me_else!(10),
|
||||
allocate!(1),
|
||||
get_level!(),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(temp_v!(4), 1),
|
||||
get_var_in_fact!(temp_v!(3), 2)],
|
||||
is_integer!(temp_v!(3)),
|
||||
is_integer!(temp_v!(3)),
|
||||
query![put_value!(temp_v!(4), 1),
|
||||
put_constant!(Level::Shallow, integer!(0), temp_v!(2))],
|
||||
goto_call!(281, 3), // goto length/3, 281.
|
||||
cut!(),
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
proceed!(),
|
||||
trust_me!(),
|
||||
@@ -413,9 +413,9 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
None),
|
||||
set_constant!(atom!("integer_expected", atom_tbl)),
|
||||
set_value!(temp_v!(4))],
|
||||
goto_execute!(59, 1), // goto throw/1, 59.
|
||||
goto_execute!(59, 1), // goto throw/1, 59.
|
||||
switch_on_term!(1,2,5,0), // length/3, 281.
|
||||
try_me_else!(3),
|
||||
try_me_else!(3),
|
||||
fact![get_constant!(Constant::EmptyList, temp_v!(1)),
|
||||
get_var_in_fact!(temp_v!(4), 2),
|
||||
get_value!(temp_v!(4), 3)],
|
||||
@@ -436,7 +436,92 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
|
||||
put_unsafe_value!(2, 2),
|
||||
put_value!(perm_v!(3), 3)],
|
||||
deallocate!(),
|
||||
goto_execute!(281, 3) // goto length/3, 281.
|
||||
goto_execute!(281, 3), // goto length/3, 281.
|
||||
allocate!(4), // setup_call_cleanup/3, 294.
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(2), 2),
|
||||
get_var_in_fact!(perm_v!(3), 3)],
|
||||
call_n!(1),
|
||||
cut!(perm_v!(1)),
|
||||
query![put_var!(perm_v!(4), 1)],
|
||||
get_current_block!(),
|
||||
query![put_value!(perm_v!(3), 1),
|
||||
put_unsafe_value!(4, 2),
|
||||
put_value!(perm_v!(2), 3)],
|
||||
deallocate!(),
|
||||
jmp_execute!(3, 1),
|
||||
try_me_else!(5), // 304.
|
||||
is_var!(temp_v!(1)),
|
||||
neck_cut!(),
|
||||
query![put_constant!(Level::Shallow, atom!("instantiation_error", atom_tbl),
|
||||
temp_v!(1))],
|
||||
goto_execute!(59, 1),
|
||||
trust_me!(),
|
||||
query![get_var_in_query!(temp_v!(4), 2),
|
||||
put_value!(temp_v!(3), 2),
|
||||
get_var_in_query!(temp_v!(5), 3),
|
||||
put_value!(temp_v!(4), 3)],
|
||||
goto_execute!(312, 3),
|
||||
try_me_else!(13), // sgc_helper/3, 312.
|
||||
allocate!(4),
|
||||
fact![get_var_in_fact!(perm_v!(4), 1),
|
||||
get_var_in_fact!(perm_v!(3), 2),
|
||||
get_var_in_fact!(perm_v!(2), 3)],
|
||||
get_level!(perm_v!(1)),
|
||||
query![put_value!(perm_v!(4), 1)],
|
||||
install_cleaner!(),
|
||||
query![put_var!(temp_v!(2), 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!(),
|
||||
check_cp_execute!(),
|
||||
retry_me_else!(10),
|
||||
allocate!(1),
|
||||
query![put_value!(temp_v!(3), 1)],
|
||||
reset_block!(),
|
||||
query![put_var!(perm_v!(1), 1)],
|
||||
get_ball!(),
|
||||
goto_call!(337, 0), // goto run_cleaners_with_handling/0, 337.
|
||||
query![put_value!(perm_v!(1), 1)],
|
||||
deallocate!(),
|
||||
goto_execute!(59, 1),
|
||||
trust_me!(),
|
||||
goto_execute!(349, 0), // goto run_cleaners_without_handling/0, 349.
|
||||
try_me_else!(10), // run_cleaners_with_handling/0, 337.
|
||||
allocate!(2),
|
||||
get_level!(perm_v!(1)),
|
||||
query![put_var!(perm_v!(2), 1)],
|
||||
get_cleaner_call!(),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_var!(temp_v!(4), 2),
|
||||
put_constant!(Level::Shallow, atom!("true", atom_tbl), temp_v!(3))],
|
||||
goto_call!(5, 3), // goto catch/3, 5.
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
goto_execute!(337, 0), // goto run_cleaners_with_handling/0, 337.
|
||||
trust_me!(),
|
||||
proceed!(),
|
||||
try_me_else!(10), // run_cleaners_without_handling/1, 349.
|
||||
allocate!(2),
|
||||
get_level!(perm_v!(1)),
|
||||
query![put_var!(perm_v!(2), 1)],
|
||||
get_cleaner_call!(),
|
||||
query![put_value!(perm_v!(2), 1)],
|
||||
call_n!(1),
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
goto_execute!(349, 0), // goto run_cleaners_without_handling/1, 349.
|
||||
trust_me!(),
|
||||
proceed!(),
|
||||
allocate!(1), // sgc_on_success/2, 361.
|
||||
fact![get_var_in_fact!(perm_v!(1), 2)],
|
||||
reset_block!(),
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
proceed!()
|
||||
]
|
||||
}
|
||||
|
||||
@@ -486,7 +571,7 @@ pub fn build_code_dir(atom_tbl: TabledData<Atom>) -> (Code, CodeDir, OpDir)
|
||||
op_dir.insert((tabled_rc!("->", atom_tbl), Fixity::In), (XFY, 1050));
|
||||
|
||||
op_dir.insert((tabled_rc!("=..", atom_tbl), Fixity::In), (XFX, 700));
|
||||
|
||||
|
||||
// there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
|
||||
// (an extra register is needed for the predicate name)
|
||||
for arity in 0 .. 63 {
|
||||
@@ -522,6 +607,7 @@ pub fn build_code_dir(atom_tbl: TabledData<Atom>) -> (Code, CodeDir, OpDir)
|
||||
code_dir.insert((tabled_rc!("=..", atom_tbl), 2), (PredicateKeyType::BuiltIn, 208));
|
||||
|
||||
code_dir.insert((tabled_rc!("length", atom_tbl), 2), (PredicateKeyType::BuiltIn, 261));
|
||||
|
||||
code_dir.insert((tabled_rc!("setup_call_cleanup", atom_tbl), 3), (PredicateKeyType::BuiltIn, 294));
|
||||
|
||||
(builtin_code, code_dir, op_dir)
|
||||
}
|
||||
|
||||
@@ -245,6 +245,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize)
|
||||
{
|
||||
match qt {
|
||||
&QueryTerm::SetupCallCleanup(_) =>
|
||||
code.push(goto_call!(294, 3)),
|
||||
&QueryTerm::Arg(_) => {
|
||||
let call = ControlInstruction::ArgCall;
|
||||
code.push(Line::Control(call));
|
||||
@@ -287,6 +289,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
match code.last_mut() {
|
||||
Some(&mut Line::Control(ref mut ctrl)) =>
|
||||
match ctrl.clone() {
|
||||
ControlInstruction::GotoCall(p, arity) =>
|
||||
*ctrl = ControlInstruction::GotoExecute(p, arity),
|
||||
ControlInstruction::ArgCall =>
|
||||
*ctrl = ControlInstruction::ArgExecute,
|
||||
ControlInstruction::Call(name, arity, _) =>
|
||||
@@ -310,7 +314,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
ControlInstruction::Proceed => {},
|
||||
_ => dealloc_index += 1 // = code.len()
|
||||
},
|
||||
Some(&mut Line::Cut(CutInstruction::Cut)) =>
|
||||
Some(&mut Line::Cut(CutInstruction::Cut(_))) =>
|
||||
dealloc_index += 1,
|
||||
_ => {}
|
||||
};
|
||||
@@ -402,7 +406,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
code.push(if chunk_num == 0 {
|
||||
Line::Cut(CutInstruction::NeckCut)
|
||||
} else {
|
||||
Line::Cut(CutInstruction::Cut)
|
||||
Line::Cut(CutInstruction::Cut(perm_v!(1)))
|
||||
});
|
||||
},
|
||||
&QueryTerm::Is(ref terms) => {
|
||||
@@ -460,7 +464,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
||||
|
||||
if conjunct_info.has_deep_cut {
|
||||
body.push(Line::Cut(CutInstruction::GetLevel));
|
||||
body.push(Line::Cut(CutInstruction::GetLevel(perm_v!(1))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,7 +495,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
let mut code = Vec::new();
|
||||
|
||||
if let &QueryTerm::Term(ref term) = p0 {
|
||||
self.marker.reset_arg_at_head(term);
|
||||
self.marker.reset_arg(term.arity());
|
||||
self.compile_seq_prelude(&conjunct_info, &mut code);
|
||||
|
||||
if let &Term::Clause(..) = term {
|
||||
@@ -503,6 +507,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
}
|
||||
}
|
||||
|
||||
self.marker.reset_arg_at_head(term);
|
||||
|
||||
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
||||
try!(self.compile_seq(iter, &conjunct_info, &mut code, false));
|
||||
|
||||
@@ -562,7 +568,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
vs.populate_restricting_sets();
|
||||
|
||||
self.marker.drain_var_data(vs);
|
||||
self.marker.reset_arg_at_head(term);
|
||||
self.marker.reset_arg(term.arity());
|
||||
|
||||
let mut code = Vec::new();
|
||||
|
||||
|
||||
@@ -346,7 +346,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
|
||||
self.temp_lb = arity + 1;
|
||||
}
|
||||
|
||||
fn reset_arg_at_head(&mut self, term: &Term) {
|
||||
fn reset_arg_at_head(&mut self, term: &'a Term) {
|
||||
self.arg_c = 1;
|
||||
self.temp_lb = term.arity() + 1;
|
||||
|
||||
|
||||
@@ -110,9 +110,11 @@ impl fmt::Display for ControlInstruction {
|
||||
&ControlInstruction::CallN(arity) =>
|
||||
write!(f, "call_N {}", arity),
|
||||
&ControlInstruction::CatchCall =>
|
||||
write!(f, "call_catch"),
|
||||
write!(f, "catch_call"),
|
||||
&ControlInstruction::CatchExecute =>
|
||||
write!(f, "execute_catch"),
|
||||
write!(f, "catch_execute"),
|
||||
&ControlInstruction::CheckCpExecute =>
|
||||
write!(f, "check_cp_execute"),
|
||||
&ControlInstruction::DisplayCall =>
|
||||
write!(f, "display_call"),
|
||||
&ControlInstruction::DisplayExecute =>
|
||||
@@ -131,6 +133,8 @@ impl fmt::Display for ControlInstruction {
|
||||
write!(f, "deallocate"),
|
||||
&ControlInstruction::Execute(ref name, arity) =>
|
||||
write!(f, "execute {}/{}", name, arity),
|
||||
&ControlInstruction::GetCleanerCall =>
|
||||
write!(f, "get_cleaner_call"),
|
||||
&ControlInstruction::GotoCall(p, arity) =>
|
||||
write!(f, "goto_call {}/{}", p, arity),
|
||||
&ControlInstruction::GotoExecute(p, arity) =>
|
||||
@@ -189,6 +193,8 @@ impl fmt::Display for BuiltInInstruction {
|
||||
write!(f, "get_current_block X1"),
|
||||
&BuiltInInstruction::GetCutPoint(r) =>
|
||||
write!(f, "get_cp {}", r),
|
||||
&BuiltInInstruction::InstallCleaner =>
|
||||
write!(f, "install_cleaner"),
|
||||
&BuiltInInstruction::InstallNewBlock =>
|
||||
write!(f, "install_new_block"),
|
||||
&BuiltInInstruction::InternalCallN =>
|
||||
@@ -307,12 +313,12 @@ impl fmt::Display for ArithmeticInstruction {
|
||||
impl fmt::Display for CutInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&CutInstruction::Cut =>
|
||||
write!(f, "cut"),
|
||||
&CutInstruction::Cut(r) =>
|
||||
write!(f, "cut {}", r),
|
||||
&CutInstruction::NeckCut =>
|
||||
write!(f, "neck_cut"),
|
||||
&CutInstruction::GetLevel =>
|
||||
write!(f, "get_level")
|
||||
&CutInstruction::GetLevel(r) =>
|
||||
write!(f, "get_level {}", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ impl<'a> QueryIterator<'a> {
|
||||
&QueryTerm::Catch(ref terms) => {
|
||||
let state = TermIterState::Clause(0, ClauseType::Catch, terms);
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
},
|
||||
},
|
||||
&QueryTerm::DuplicateTerm(ref terms) => {
|
||||
let state = TermIterState::Clause(0, ClauseType::DuplicateTerm, terms);
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
@@ -48,6 +48,10 @@ impl<'a> QueryIterator<'a> {
|
||||
let state = TermIterState::Clause(0, ClauseType::Arg, terms);
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
},
|
||||
&QueryTerm::SetupCallCleanup(ref terms) => {
|
||||
let state = TermIterState::Clause(0, ClauseType::SetupCallCleanup, terms);
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
},
|
||||
&QueryTerm::Functor(ref terms) => {
|
||||
let state = TermIterState::Clause(0, ClauseType::Functor, terms);
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
@@ -60,7 +64,7 @@ impl<'a> QueryIterator<'a> {
|
||||
| &QueryTerm::Is(ref terms) => {
|
||||
let state = TermIterState::Clause(0, ClauseType::Is, terms);
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
},
|
||||
},
|
||||
&QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(ref terms))
|
||||
| &QueryTerm::Inlined(InlinedQueryTerm::IsInteger(ref terms))
|
||||
| &QueryTerm::Inlined(InlinedQueryTerm::IsVar(ref terms)) =>
|
||||
@@ -290,6 +294,11 @@ impl<'a> ChunkedIterator<'a>
|
||||
break;
|
||||
}
|
||||
},
|
||||
&QueryTerm::SetupCallCleanup(_) => {
|
||||
result.push(term);
|
||||
arity = 3;
|
||||
break;
|
||||
},
|
||||
&QueryTerm::CallN(ref child_terms) => {
|
||||
result.push(term);
|
||||
arity = child_terms.len() + 1;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1827
src/prolog/machine/machine_state_impl.rs
Normal file
1827
src/prolog/machine/machine_state_impl.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,8 @@ use prolog::fixtures::*;
|
||||
use prolog::tabled_rc::*;
|
||||
|
||||
pub(crate) mod machine_state;
|
||||
#[macro_use]
|
||||
mod machine_state_impl;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
@@ -199,8 +199,8 @@ macro_rules! proceed {
|
||||
}
|
||||
|
||||
macro_rules! cut {
|
||||
() => (
|
||||
Line::Cut(CutInstruction::Cut)
|
||||
($r:expr) => (
|
||||
Line::Cut(CutInstruction::Cut($r))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -301,8 +301,8 @@ macro_rules! duplicate_term {
|
||||
}
|
||||
|
||||
macro_rules! get_level {
|
||||
() => (
|
||||
Line::Cut(CutInstruction::GetLevel)
|
||||
($r:expr) => (
|
||||
Line::Cut(CutInstruction::GetLevel($r))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -490,6 +490,12 @@ macro_rules! jmp_call {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! jmp_execute {
|
||||
($arity:expr, $offset:expr) => (
|
||||
Line::Control(ControlInstruction::JmpByExecute($arity, $offset))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_list {
|
||||
($lvl:expr, $r:expr) => (
|
||||
FactInstruction::GetList($lvl, $r)
|
||||
@@ -501,3 +507,21 @@ macro_rules! unify_constant {
|
||||
FactInstruction::UnifyConstant($c)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! install_cleaner {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::InstallCleaner)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! check_cp_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CheckCpExecute)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_cleaner_call {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::GetCleanerCall)
|
||||
)
|
||||
}
|
||||
|
||||
Submodule src/prolog/parser updated: 2579afe5fd...5d8398b4e6
57
src/tests.rs
57
src/tests.rs
@@ -1168,7 +1168,7 @@ fn test_queries_on_conditionals()
|
||||
|
||||
submit(&mut wam, "test(X, [X]) :- (atomic(X) -> true ; throw(type_error(atomic_expected, X))).
|
||||
test(_, _).");
|
||||
|
||||
|
||||
assert_prolog_success!(&mut wam, "?- catch(test(a, [a]), type_error(E), true).",
|
||||
[["E = _6"], ["E = _6"]]);
|
||||
|
||||
@@ -1291,3 +1291,58 @@ fn test_queries_on_builtins()
|
||||
assert_prolog_success!(&mut wam, "?- duplicate_term(f(X), f(X)).",
|
||||
[["X = _1"]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queries_on_setup_call_cleanup()
|
||||
{
|
||||
let mut wam = Machine::new();
|
||||
|
||||
// Test examples from the ISO Prolog page for setup_call_catch.
|
||||
assert_prolog_failure!(&mut wam, "?- setup_call_cleanup(false, _, _).");
|
||||
assert_prolog_success!(&mut wam, "?- catch(setup_call_cleanup(true, throw(unthrown), _), instantiation_error, true).");
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(true, true, (true ; throw(x))).");
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(true, X = 1, X = 2).",
|
||||
[["X = 1"]]);
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(true, true, X = 2).",
|
||||
[["X = 2"]]);
|
||||
assert_prolog_success!(&mut wam, "?- catch(setup_call_cleanup(true, X=true, X), E, true).",
|
||||
[["E = instantiation_error", "X = _1"]]);
|
||||
assert_prolog_success!(&mut wam, "?- catch(setup_call_cleanup(X=throw(ex), true, X), E, true).",
|
||||
[["E = ex", "X = _3"]]);
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(true, true, false).");
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(S = 1, G = 2, C = 3).",
|
||||
[["S = 1", "G = 2", "C = 3"]]);
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup((S=1;S=2), G=3, C=4).",
|
||||
[["S = 1", "G = 3", "C = 4"]]);
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(S=1, G=2, display(S+G)).",
|
||||
[["S = 1", "G = 2"]]);
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(S=1, (G=2;G=3), display(S+G)).",
|
||||
[["S = 1", "G = 2"],
|
||||
["S = 1", "G = 3"]]);
|
||||
assert_prolog_success!(&mut wam, "?- setup_call_cleanup(S=1, G=2, display(S+G>A+B)), A=3, B=4.",
|
||||
[["S = 1", "G = 2", "A = 3", "B = 4"]]);
|
||||
assert_prolog_success!(&mut wam,
|
||||
"?- catch(setup_call_cleanup(S=1, (G=2;G=3,throw(x)), display(S+G)), E, true).",
|
||||
[["S = 1", "G = 2", "E = _26"], ["G = _4", "E = x", "S = _1"]]);
|
||||
assert_prolog_success!(&mut wam,
|
||||
"?- setup_call_cleanup(S=1, (G=2;G=3),display(S+G>B)), B=4, !.",
|
||||
[["S = 1", "B = 4", "G = 2"]]);
|
||||
assert_prolog_success!(&mut wam,
|
||||
"?- setup_call_cleanup(S=1,G=2,display(S+G>B)),B=3,!.",
|
||||
[["S = 1", "G = 2", "B = 3"]]);
|
||||
assert_prolog_success!(&mut wam,
|
||||
"?- setup_call_cleanup(S=1,(G=2;false),display(S+G>B)),B=3,!.",
|
||||
[["S = 1", "G = 2", "B = 3"]]);
|
||||
assert_prolog_success!(&mut wam,
|
||||
"?- setup_call_cleanup(S=1,(G=2;S=2),display(S+G>B)), B=3, !.",
|
||||
[["S = 1", "B = 3", "G = 2"]]);
|
||||
assert_prolog_failure!(&mut wam,
|
||||
"?- setup_call_cleanup(S=1,(G=2;G=3), display(S+G>B)), B=4, !, throw(x).");
|
||||
assert_prolog_success!(&mut wam,
|
||||
"?- setup_call_cleanup(true, (X=1;X=2), display(a)), setup_call_cleanup(true,(Y=1;Y=2),display(b)), !.",
|
||||
[["Y = 1", "X = 1"]]);
|
||||
assert_prolog_success!(&mut wam, "?- catch(setup_call_cleanup(true,throw(goal),throw(cl)), Pat, true).",
|
||||
[["Pat = goal"]]);
|
||||
assert_prolog_success!(&mut wam, "?- catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true).",
|
||||
[["Pat = cont", "G = _1"]]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user