implement logical update semantics for dynamic database predicates

This commit is contained in:
Mark Thom
2021-02-27 22:51:32 -07:00
parent adb96710bf
commit 064d261357
16 changed files with 1904 additions and 418 deletions

View File

@@ -37,6 +37,9 @@ impl CodeRepo {
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
}
&IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[i]))
}
_ => {
unreachable!()
}
@@ -86,11 +89,98 @@ impl CodeRepo {
&CodePtr::VerifyAttrInterrupt(p) => {
Some(RefOrOwned::Borrowed(&self.code[p]))
}
/*
&CodePtr::DynamicTransaction(..) => {
None
}
}
pub(super)
fn find_living_dynamic_else(&self, mut p: usize, cc: usize) -> Option<(usize, usize)> {
loop {
match &self.code[p] {
&Line::Choice(ChoiceInstruction::DynamicElse(birth, death, NextOrFail::Next(i))) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, i));
} else if i > 0 {
p += i;
} else {
return None;
}
}
&Line::Choice(ChoiceInstruction::DynamicElse(birth, death, NextOrFail::Fail(_))) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, 0));
} else {
return None;
}
}
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
birth,
death,
NextOrFail::Next(i),
)) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, i));
} else if i > 0 {
p += i;
} else {
return None;
}
}
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
birth,
death,
NextOrFail::Fail(_)),
) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((p, 0));
} else {
return None;
}
}
&Line::Control(ControlInstruction::RevJmpBy(i)) => {
p -= i;
}
_ => {
unreachable!();
}
}
}
}
pub(super)
fn find_living_dynamic(&self, p: LocalCodePtr, cc: usize) -> Option<(usize, usize, usize, bool)> {
let (p, oi, mut ii) = match p {
LocalCodePtr::IndexingBuf(p, oi, ii) => (p, oi, ii),
_ => unreachable!(),
};
let indexed_choice_instrs = match &self.code[p] {
Line::IndexingCode(ref indexing_code) => match &indexing_code[oi] {
IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
indexed_choice_instrs
}
_ => unreachable!()
}
_ => unreachable!()
};
loop {
match &indexed_choice_instrs.get(ii) {
Some(&offset) => {
match &self.code[p + offset - 1] {
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
birth, death, next_or_fail,
)) => {
if birth < cc && Death::Finite(cc) <= death {
return Some((offset, oi, ii, next_or_fail.is_next()));
} else {
ii += 1;
}
}
_ => unreachable!(),
}
}
None => return None,
}
*/
}
}
}

View File

@@ -11,6 +11,14 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
&Line::Choice(ChoiceInstruction::RetryMeElse(offset)) if offset > 0 => {
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
if offset > 0 => {
stack.push(index + offset);
}
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
if offset > 0 => {
stack.push(index + offset);
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
stack.push(index + offset);
}

View File

@@ -2,7 +2,7 @@ use prolog_parser::clause_name;
use crate::codegen::*;
use crate::debray_allocator::*;
use crate::indexing::{merge_clause_index, remove_index};
use crate::indexing::{IndexingCodePtr, merge_clause_index, remove_index};
use crate::machine::load_state::*;
use crate::machine::loader::*;
use crate::machine::preprocessor::*;
@@ -74,7 +74,12 @@ pub(super) fn compile_appendix(
}
// false because the inner predicate is a one-off, hence not extensible.
let settings = CodeGenSettings::new(false, non_counted_bt);
let settings = CodeGenSettings {
global_clock_tick: None,
is_extensible: false,
non_counted_bt,
};
let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
let tl = queue.pop_front().unwrap();
@@ -115,11 +120,22 @@ fn derelictize_try_me_else(
retraction_info: &mut RetractionInfo,
) -> Option<usize> {
match &mut code[index] {
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(0))) => None,
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o));
Some(mem::replace(o, 0))
}
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(0))) => None,
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o));
Some(mem::replace(o, 0))
}
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_))) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => None,
Line::Choice(ChoiceInstruction::TryMeElse(0)) => None,
Line::Choice(ChoiceInstruction::TryMeElse(ref mut offset)) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *offset));
Some(mem::replace(offset, 0))
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o));
Some(mem::replace(o, 0))
}
_ => {
unreachable!()
@@ -165,23 +181,80 @@ fn merge_indices(
}
}
fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> usize {
fn find_outer_choice_instr(
code: &Code,
mut index: usize,
) -> usize {
loop {
match &code[index] {
Line::Choice(ChoiceInstruction::TryMeElse(o))
| Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(i))) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(i)))
if *i > 0 =>
{
index += i;
}
_ => {
return index;
}
}
}
}
fn find_inner_choice_instr(
code: &Code,
mut index: usize,
index_loc: usize,
) -> usize {
loop {
match &code[index] {
Line::Choice(ChoiceInstruction::TryMeElse(o)) |
Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
if *o > 0 {
return index;
} else {
index = index_loc;
}
}
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, next_or_fail)) |
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, next_or_fail)) => {
match next_or_fail {
NextOrFail::Next(i) => {
if i == 0 {
index = index_loc;
} else {
return index;
}
}
NextOrFail::Fail(_) => {
return index;
}
}
}
Line::Choice(ChoiceInstruction::TrustMe(_)) => {
return index;
}
Line::IndexingCode(indexing_code) => match &indexing_code[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
index += v;
match v {
IndexingCodePtr::External(v) => {
index += v;
}
IndexingCodePtr::DynamicExternal(v) => {
match &code[index + v] {
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
_,
_,
NextOrFail::Next(0),
)) => {
return index + v;
}
_ => {
index += v;
}
}
}
_ => unreachable!()
}
}
_ => {
unreachable!();
@@ -253,7 +326,7 @@ fn merge_indexed_subsequences(
match &mut code[inner_try_me_else_loc] {
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
skeleton.clauses[upper_lower_bound].clause_start,
inner_try_me_else_loc,
*o,
));
@@ -357,9 +430,35 @@ fn blunt_leading_choice_instr(
return instr_loc;
}
Line::Choice(ChoiceInstruction::TrustMe(offset)) => {
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(_))) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(_))) => {
return instr_loc;
}
&mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o))) => {
retraction_info.push_record(
RetractionRecord::AppendedNextOrFail(instr_loc, NextOrFail::Fail(o)),
);
code[instr_loc] = Line::Choice(
ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(0)),
);
return instr_loc;
}
&mut Line::Choice(ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Fail(o))) => {
retraction_info.push_record(
RetractionRecord::AppendedNextOrFail(instr_loc, NextOrFail::Fail(o)),
);
code[instr_loc] = Line::Choice(
ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(0)),
);
return instr_loc;
}
Line::Choice(ChoiceInstruction::TrustMe(o)) => {
retraction_info
.push_record(RetractionRecord::AppendedTrustMe(instr_loc, *offset, false));
.push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false));
code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0));
return instr_loc + 1;
@@ -388,15 +487,22 @@ fn set_switch_var_offset_to_choice_instr(
) {
let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
let v = match &mut target_indexing_line[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => *v,
let v = match &target_indexing_line[0] {
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
match v {
IndexingCodePtr::External(v) | IndexingCodePtr::DynamicExternal(v) => v,
_ => unreachable!()
}
}
_ => {
unreachable!();
}
};
match &code[index_loc + v] {
Line::Choice(ChoiceInstruction::TryMeElse(_)) => {}
Line::Choice(ChoiceInstruction::TryMeElse(_)) |
Line::Choice(ChoiceInstruction::DynamicElse(..)) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {}
_ => {
set_switch_var_offset(code, index_loc, offset, retraction_info);
}
@@ -414,7 +520,15 @@ fn set_switch_var_offset(
let old_v = match &mut target_indexing_line[0] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => {
mem::replace(v, offset)
match *v {
IndexingCodePtr::DynamicExternal(_) => {
mem::replace(v, IndexingCodePtr::DynamicExternal(offset))
}
IndexingCodePtr::External(_) => {
mem::replace(v, IndexingCodePtr::External(offset))
}
_ => unreachable!()
}
}
_ => {
unreachable!()
@@ -432,6 +546,53 @@ fn internalize_choice_instr_at(
retraction_info: &mut RetractionInfo,
) {
match &mut code[instr_loc] {
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_))) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => {
}
Line::Choice(ChoiceInstruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0))) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0));
*o = NextOrFail::Fail(0);
}
&mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o))) => {
retraction_info.push_record(
RetractionRecord::AppendedNextOrFail(instr_loc, NextOrFail::Next(o)),
);
match &mut code[instr_loc + o] {
Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
code[instr_loc] = Line::Choice(
ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o)),
);
}
_ => {
code[instr_loc] = Line::Choice(
ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o)),
);
}
}
}
Line::Choice(ChoiceInstruction::DynamicInternalElse(
_, _, ref mut o @ NextOrFail::Next(0),
)) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0));
*o = NextOrFail::Fail(0);
}
&mut Line::Choice(ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(o))) => {
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, o));
match &mut code[instr_loc + o] {
Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
code[instr_loc] = Line::Choice(
ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Fail(o)),
);
}
_ => {
code[instr_loc] = Line::Choice(
ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(o)),
);
}
}
}
Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0));
@@ -465,8 +626,8 @@ fn thread_choice_instr_at_to(
) {
loop {
match &mut code[instr_loc] {
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
| Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) |
Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
if target_loc >= instr_loc =>
{
retraction_info.push_record(RetractionRecord::ReplacedChoiceOffset(instr_loc, *o));
@@ -474,8 +635,20 @@ fn thread_choice_instr_at_to(
*o = target_loc - instr_loc;
return;
}
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
| Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => {
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o)))
if target_loc >= instr_loc =>
{
retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, *o));
*o = target_loc - instr_loc;
return;
}
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) => {
instr_loc += *o;
}
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) |
Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => {
instr_loc += *o;
}
Line::Control(ControlInstruction::RevJmpBy(ref mut o)) if instr_loc >= target_loc => {
@@ -484,6 +657,44 @@ fn thread_choice_instr_at_to(
*o = instr_loc - target_loc;
return;
}
&mut Line::Choice(ChoiceInstruction::DynamicElse(birth, death, ref mut fail))
if target_loc >= instr_loc =>
{
retraction_info.push_record(
RetractionRecord::AppendedNextOrFail(instr_loc, *fail),
);
code[instr_loc] =
Line::Choice(ChoiceInstruction::DynamicElse(
birth, death, NextOrFail::Next(target_loc - instr_loc),
));
return;
}
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(o)))
if *o > 0 =>
{
instr_loc += *o;
}
&mut Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, ref mut fail))
if target_loc >= instr_loc =>
{
retraction_info.push_record(
RetractionRecord::AppendedNextOrFail(instr_loc, *fail),
);
code[instr_loc] =
Line::Choice(ChoiceInstruction::DynamicInternalElse(
birth, death, NextOrFail::Next(target_loc - instr_loc),
));
return;
}
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(o)))
if *o > 0 =>
{
instr_loc += *o;
}
Line::Choice(ChoiceInstruction::TrustMe(ref mut o)) if target_loc >= instr_loc => {
retraction_info.push_record(
RetractionRecord::AppendedTrustMe(instr_loc, *o, false),
@@ -619,6 +830,29 @@ fn remove_leading_unindexed_clause(
}
}
fn find_dynamic_outer_choice_instr(
code: &Code,
index_loc: usize,
) -> usize {
match &code[index_loc] {
Line::IndexingCode(indexing_code) => {
match &indexing_code[0] {
&IndexingLine::Indexing(
IndexingInstruction::SwitchOnTerm(
_,
IndexingCodePtr::DynamicExternal(v),
..,
)
) => {
index_loc + v - 2
}
_ => unreachable!()
}
}
_ => unreachable!()
}
}
fn prepend_compiled_clause(
code: &mut Code,
compilation_target: CompilationTarget,
@@ -626,14 +860,25 @@ fn prepend_compiled_clause(
mut clause_code: Code,
skeleton: &mut PredicateSkeleton,
retraction_info: &mut RetractionInfo,
) -> usize {
global_clock_tick: usize,
) -> IndexPtr {
let clause_loc = code.len();
let mut prepend_queue = sdeq![];
let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num();
let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num();
let settings = CodeGenSettings {
global_clock_tick: if skeleton.is_dynamic {
Some(global_clock_tick)
} else {
None
},
is_extensible: true,
non_counted_bt: false,
};
if skeleton.clauses[0]
let clause_loc = if skeleton.clauses[0]
.opt_arg_index_key
.switch_on_term_loc()
.is_some()
@@ -650,7 +895,11 @@ fn prepend_compiled_clause(
skeleton.clauses[0].clause_start,
));
let outer_thread_choice_loc = skeleton.clauses[1].clause_start - 2;
let outer_thread_choice_loc = if skeleton.is_dynamic {
find_dynamic_outer_choice_instr(code, index_loc)
} else {
skeleton.clauses[1].clause_start - 2
};
retraction_info.push_record(RetractionRecord::SkeletonClauseStartReplaced(
compilation_target,
@@ -669,9 +918,9 @@ fn prepend_compiled_clause(
inner_thread_rev_offset,
)));
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
prepend_queue.len(),
)));
prepend_queue.push_front(Line::Choice(
settings.internal_try_me_else(prepend_queue.len()),
));
// prepend_queue is now:
// | TryMeElse N_2
@@ -716,9 +965,9 @@ fn prepend_compiled_clause(
}
};
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
outer_thread_choice_offset,
)));
prepend_queue.push_front(Line::Choice(
settings.try_me_else(outer_thread_choice_offset),
));
// prepend_queue is now:
// | TryMeElse N_3
@@ -747,7 +996,11 @@ fn prepend_compiled_clause(
code.extend(prepend_queue.into_iter());
clause_loc + (outer_thread_choice_offset == 0) as usize
if skeleton.is_dynamic {
clause_loc
} else {
clause_loc + (outer_thread_choice_offset == 0) as usize
}
}
_ => {
prepend_queue.extend(clause_code.drain(1..));
@@ -755,7 +1008,18 @@ fn prepend_compiled_clause(
skeleton.clauses[0].opt_arg_index_key += clause_loc;
skeleton.clauses[0].clause_start = clause_loc + 2;
let old_clause_start = skeleton.clauses[1].clause_start;
let old_clause_start =
match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() {
Some(index_loc) if skeleton.is_dynamic => {
find_dynamic_outer_choice_instr(code, index_loc)
}
Some(_) => {
skeleton.clauses[1].clause_start - 2
}
None => {
skeleton.clauses[1].clause_start
}
};
let inner_thread_rev_offset =
2 + prepend_queue.len() + clause_loc - old_clause_start;
@@ -770,6 +1034,11 @@ fn prepend_compiled_clause(
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) if *o == 0 => {
*o = prepend_queue_len - 2;
}
Line::Choice(ChoiceInstruction::DynamicInternalElse(
_, _, ref mut o @ NextOrFail::Next(0),
)) => {
*o = NextOrFail::Fail(prepend_queue_len - 2);
}
_ => {
unreachable!();
}
@@ -779,9 +1048,9 @@ fn prepend_compiled_clause(
inner_thread_rev_offset,
)));
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
prepend_queue.len(),
)));
prepend_queue.push_front(Line::Choice(
settings.try_me_else(prepend_queue.len()),
));
// prepend_queue is now:
// | TryMeElse(N_2)
@@ -799,10 +1068,14 @@ fn prepend_compiled_clause(
}
} else {
match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() {
Some(_) => {
Some(index_loc) => {
prepend_queue.extend(clause_code.drain(1..));
let old_clause_start = skeleton.clauses[1].clause_start - 2;
let old_clause_start = if skeleton.is_dynamic {
find_dynamic_outer_choice_instr(code, index_loc)
} else {
skeleton.clauses[1].clause_start - 2
};
let inner_thread_rev_offset =
1 + prepend_queue.len() + clause_loc - old_clause_start;
@@ -811,9 +1084,9 @@ fn prepend_compiled_clause(
inner_thread_rev_offset,
)));
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
prepend_queue.len(),
)));
prepend_queue.push_front(Line::Choice(
settings.try_me_else(prepend_queue.len()),
));
// prepend_queue is now:
// | TryMeElse(N_2)
@@ -841,9 +1114,9 @@ fn prepend_compiled_clause(
inner_thread_rev_offset,
)));
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
prepend_queue.len(),
)));
prepend_queue.push_front(Line::Choice(
settings.try_me_else(prepend_queue.len()),
));
// prepend_queue is now:
// | TryMeElse(N_2)
@@ -857,9 +1130,15 @@ fn prepend_compiled_clause(
// skeleton.clauses[0].opt_arg_index_key += clause_loc;
skeleton.clauses[0].clause_start = clause_loc;
clause_loc // + (outer_thread_choice_offset == 0 as usize)
clause_loc
}
}
};
if skeleton.is_dynamic {
IndexPtr::DynamicIndex(clause_loc)
} else {
IndexPtr::Index(clause_loc)
}
}
@@ -868,12 +1147,22 @@ fn append_compiled_clause(
mut clause_code: Code,
skeleton: &mut PredicateSkeleton,
retraction_info: &mut RetractionInfo,
) -> Option<usize> {
global_clock_tick: usize,
) -> Option<IndexPtr> {
let clause_loc = code.len();
let target_pos = skeleton.clauses.len() - 1;
let lower_bound = lower_bound_of_target_clause(skeleton, target_pos);
code.push(Line::Choice(ChoiceInstruction::TrustMe(0)));
let settings = CodeGenSettings {
global_clock_tick: if skeleton.is_dynamic {
Some(global_clock_tick)
} else {
None
},
is_extensible: true,
non_counted_bt: false,
};
skeleton.clauses[target_pos].clause_start = clause_loc;
let mut code_ptr_opt = None;
@@ -886,6 +1175,8 @@ fn append_compiled_clause(
.switch_on_term_loc()
{
Some(index_loc) if lower_bound_arg_num == target_arg_num => {
code.push(Line::Choice(settings.internal_trust_me()));
code.extend(clause_code.drain(3..)); // skip the indexing code
// set skeleton[target_pos].opt_arg_index_key to
@@ -912,8 +1203,13 @@ fn append_compiled_clause(
index_loc,
);
let target_pos_clause_start = find_outer_choice_instr(
code,
target_pos_clause_start,
);
if lower_bound + 1 == target_pos {
set_switch_var_offset(
set_switch_var_offset_to_choice_instr(
code,
index_loc,
target_pos_clause_start - index_loc,
@@ -924,6 +1220,8 @@ fn append_compiled_clause(
target_pos_clause_start // skeleton.clauses[target_pos - 1].clause_start
}
_ => {
code.push(Line::Choice(settings.trust_me()));
skeleton.clauses[target_pos].opt_arg_index_key += clause_loc;
code.extend(clause_code.drain(1..));
@@ -936,7 +1234,7 @@ fn append_compiled_clause(
code_ptr_opt = Some(skeleton.clauses[lower_bound].clause_start - 2);
}
skeleton.clauses[lower_bound].clause_start - 2
find_outer_choice_instr(code, skeleton.clauses[lower_bound].clause_start - 2)
}
None => {
if lower_bound == 0 {
@@ -953,12 +1251,14 @@ fn append_compiled_clause(
// its variable offset.
skeleton.clauses[target_pos].clause_start += 2;
set_switch_var_offset(code, index_loc, 2, retraction_info);
if !skeleton.is_dynamic {
set_switch_var_offset(code, index_loc, 2, retraction_info);
}
}
None => {}
}
skeleton.clauses[lower_bound].clause_start
find_outer_choice_instr(code, skeleton.clauses[lower_bound].clause_start)
}
}
}
@@ -966,7 +1266,13 @@ fn append_compiled_clause(
thread_choice_instr_at_to(code, threaded_choice_instr_loc, clause_loc, retraction_info);
code_ptr_opt
code_ptr_opt.map(|p| {
if skeleton.is_dynamic {
IndexPtr::DynamicIndex(p)
} else {
IndexPtr::Index(p)
}
})
}
#[inline]
@@ -1139,7 +1445,11 @@ impl<'a> LoadState<'a> {
&predicates.compilation_target,
key,
&code_index,
IndexPtr::Index(code_ptr),
if settings.is_dynamic() {
IndexPtr::DynamicIndex(code_ptr)
} else {
IndexPtr::Index(code_ptr)
},
);
self.wam.code_repo.code.extend(code.into_iter());
@@ -1191,15 +1501,36 @@ impl<'a> LoadState<'a> {
append_or_prepend,
);
match self
let settings = match self
.wam
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
Some(skeleton) if !skeleton.clauses.is_empty() => {},
_ => {
// true because this predicate is extensible.
let settings = CodeGenSettings::new(true, non_counted_bt);
Some(skeleton) if !skeleton.clauses.is_empty() => {
CodeGenSettings {
global_clock_tick: if skeleton.is_dynamic {
Some(self.wam.machine_st.global_clock)
} else {
None
},
is_extensible: true,
non_counted_bt,
}
},
skeleton_opt => {
let settings = CodeGenSettings {
global_clock_tick: if let Some(skeleton) = skeleton_opt {
if skeleton.is_dynamic {
Some(self.wam.machine_st.global_clock)
} else {
None
}
} else {
None
},
is_extensible: true,
non_counted_bt,
};
let mut predicate_queue = predicate_queue![clause];
predicate_queue.compilation_target = compilation_target;
@@ -1208,7 +1539,6 @@ impl<'a> LoadState<'a> {
}
};
let settings = CodeGenSettings::new(true, non_counted_bt);
let atom_tbl = self.wam.machine_st.atom_tbl.clone();
let StandaloneCompileResult {
@@ -1245,6 +1575,7 @@ impl<'a> LoadState<'a> {
clause_code,
skeleton,
&mut self.retraction_info,
self.wam.machine_st.global_clock,
);
match self
@@ -1284,13 +1615,13 @@ impl<'a> LoadState<'a> {
compilation_target.clone(),
);
if let Some(new_code_index) = result {
if let Some(new_code_ptr) = result {
set_code_index(
&mut self.retraction_info,
&compilation_target,
key,
&code_index,
IndexPtr::Index(new_code_index),
new_code_ptr,
);
}
@@ -1309,13 +1640,14 @@ impl<'a> LoadState<'a> {
key.clone(),
));
let threaded_choice_instr_loc = prepend_compiled_clause(
let new_code_ptr = prepend_compiled_clause(
&mut self.wam.code_repo.code,
compilation_target.clone(),
key.clone(),
clause_code,
skeleton,
&mut self.retraction_info,
self.wam.machine_st.global_clock,
);
match self
@@ -1360,7 +1692,7 @@ impl<'a> LoadState<'a> {
&compilation_target,
key,
&code_index,
IndexPtr::Index(threaded_choice_instr_loc),
new_code_ptr,
);
Ok(())
@@ -1368,6 +1700,51 @@ impl<'a> LoadState<'a> {
}
}
pub(super) fn retract_dynamic_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
let skeleton = match self
.wam
.indices
.get_predicate_skeleton_mut(&self.compilation_target, &key)
{
Some(skeleton) => skeleton,
None => {
unreachable!();
}
};
let clause_loc = match skeleton.clauses[target_pos]
.opt_arg_index_key
.switch_on_term_loc()
{
Some(index_loc) => {
find_inner_choice_instr(
&self.wam.code_repo.code,
skeleton.clauses[target_pos].clause_start,
index_loc,
)
}
None => {
skeleton.clauses[target_pos].clause_start
}
};
match &mut self.wam.code_repo.code[clause_loc] {
Line::Choice(ChoiceInstruction::DynamicElse(_, ref mut d, _)) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(_, ref mut d, _)) => {
*d = Death::Finite(self.wam.machine_st.global_clock);
}
_ => unreachable!()
}
delete_from_skeleton(
self.compilation_target.clone(),
key,
skeleton,
target_pos,
&mut self.retraction_info,
)
}
pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
let code_index = self.get_or_insert_code_index(
key.clone(),
@@ -1835,6 +2212,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
clause_clause_compilation_target,
(clause_name!("$clause"), 2),
(0 .. skeleton.clauses.len()).map(Some).collect(),
false, // the builtin M:'$clause'/2 is never dynamic.
);
predicate_info.is_dynamic = false;
@@ -1851,11 +2229,22 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
}
let settings = CodeGenSettings::new(predicate_info.is_extensible, non_counted_bt);
let settings = CodeGenSettings {
global_clock_tick: if predicate_info.is_dynamic {
Some(self.load_state.wam.machine_st.global_clock)
} else {
None
},
is_extensible: predicate_info.is_extensible,
non_counted_bt,
};
self.load_state.compile(key.clone(), &mut self.predicates, settings)?;
}
if predicate_info.is_dynamic {
self.load_state.wam.machine_st.global_clock += 1;
let clauses_vec: Vec<_> = self.clause_clauses
.drain(0 .. predicates_len)
.collect();

View File

@@ -346,25 +346,27 @@ impl<'a> LoadState<'a> {
key: PredicateKey,
clause_locs: &SliceDeque<usize>,
) {
let clause_target_poses: Vec<_> = self
let (clause_target_poses, is_dynamic) = self
.wam
.indices
.get_predicate_skeleton(&compilation_target, &key)
.map(|skeleton| {
clause_locs
(clause_locs
.iter()
.map(|clause_clause_loc| {
skeleton.target_pos_of_clause_clause_loc(
*clause_clause_loc,
)
})
.collect()
.collect(),
skeleton.is_dynamic)
}).unwrap();
self.retract_local_clauses_by_locs(
compilation_target,
key,
clause_target_poses,
is_dynamic,
);
}
@@ -373,6 +375,7 @@ impl<'a> LoadState<'a> {
compilation_target: CompilationTarget,
key: PredicateKey,
mut clause_target_poses: Vec<Option<usize>>,
is_dynamic: bool,
) {
let old_compilation_target = mem::replace(
&mut self.compilation_target,
@@ -381,6 +384,9 @@ impl<'a> LoadState<'a> {
while let Some(target_pos_opt) = clause_target_poses.pop() {
match target_pos_opt {
Some(target_pos) if is_dynamic => {
self.retract_dynamic_clause(key.clone(), target_pos);
}
Some(target_pos) => {
self.retract_clause(key.clone(), target_pos);
}

View File

@@ -68,7 +68,7 @@ pub(crate) enum RetractionRecord {
RemovedIndex(usize, OptArgIndexKey, usize),
ReplacedChoiceOffset(usize, usize),
AppendedTrustMe(usize, usize, bool),
ReplacedSwitchOnTermVarIndex(usize, usize),
ReplacedSwitchOnTermVarIndex(usize, IndexingCodePtr),
ModifiedTryMeElse(usize, usize),
ModifiedRetryMeElse(usize, usize),
ModifiedRevJmpBy(usize, usize),
@@ -94,6 +94,8 @@ pub(crate) enum RetractionRecord {
SliceDeque<usize>,
),
RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton),
ReplacedDynamicElseOffset(usize, usize),
AppendedNextOrFail(usize, NextOrFail),
}
/*
@@ -626,6 +628,32 @@ impl<'a> Drop for LoadState<'a> {
}
}
}
RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => {
match &mut self.wam.code_repo.code[instr_loc] {
Line::Choice(ChoiceInstruction::DynamicElse(
_, _, NextOrFail::Next(ref mut o),
)) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(
_, _, NextOrFail::Next(ref mut o),
)) => {
*o = next;
}
_ => {}
}
}
RetractionRecord::AppendedNextOrFail(instr_loc, fail) => {
match &mut self.wam.code_repo.code[instr_loc] {
Line::Choice(ChoiceInstruction::DynamicElse(
_, _, ref mut next_or_fail,
)) |
Line::Choice(ChoiceInstruction::DynamicInternalElse(
_, _, ref mut next_or_fail,
)) => {
*next_or_fail = fail;
}
_ => {}
}
}
}
}
@@ -1720,6 +1748,13 @@ impl Machine {
fetch_op_spec(clause_name!(":-"), 2, &loader.load_state.wam.indices.op_dir),
);
// if a new predicate was just created, make it dynamic.
loader.add_dynamic_predicate(
compilation_target.clone(),
key.0.clone(),
key.1,
)?;
loader.load_state.incremental_compile_clause(
key.clone(),
asserted_clause,
@@ -1728,13 +1763,8 @@ impl Machine {
append_or_prepend,
)?;
// if a new predicate was just created, make it dynamic.
loader
.load_state
.wam
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
.map(|skeleton| skeleton.is_dynamic = true);
// the global clock is incremented after each assertion.
loader.load_state.wam.machine_st.global_clock += 1;
loader.compile_clause_clauses(
key,
@@ -1883,7 +1913,10 @@ impl Machine {
let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
loader.load_state.compilation_target = compilation_target;
let clause_clause_loc = loader.load_state.retract_clause(key, target_pos);
let clause_clause_loc = loader.load_state.retract_dynamic_clause(key, target_pos);
// the global clock is incremented after each retraction.
loader.load_state.wam.machine_st.global_clock += 1;
let target_pos = match loader.load_state.wam.indices.get_predicate_skeleton(
&clause_clause_compilation_target,

View File

@@ -372,6 +372,7 @@ impl From<Addr> for HeapCellValue {
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
DynamicIndex(usize),
Index(usize),
Undefined,
}
@@ -405,6 +406,7 @@ impl CodeIndex {
pub fn local(&self) -> Option<usize> {
match self.0.get() {
IndexPtr::Index(i) => Some(i),
IndexPtr::DynamicIndex(i) => Some(i),
_ => None,
}
}
@@ -555,38 +557,6 @@ impl LocalCodePtr {
}
}
/*
impl PartialOrd<CodePtr> for CodePtr {
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
match (self, other) {
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => {
l1.partial_cmp(l2)
}
_ => {
Some(Ordering::Greater)
}
}
}
}
impl PartialOrd<LocalCodePtr> for LocalCodePtr {
fn partial_cmp(&self, other: &LocalCodePtr) -> Option<Ordering> {
match (self, other) {
(&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2)) |
(&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
p1.partial_cmp(p2)
}
(_, &LocalCodePtr::TopLevel(_, _)) => {
Some(Ordering::Less)
}
_ => {
Some(Ordering::Greater)
}
}
}
}
*/
impl Default for CodePtr {
#[inline]
fn default() -> Self {

View File

@@ -269,6 +269,12 @@ impl Default for HeapPtr {
}
}
#[derive(Debug)]
pub enum FirstOrNext {
First,
Next,
}
#[derive(Debug)]
pub struct MachineState {
pub(crate) atom_tbl: TabledData<Atom>,
@@ -295,7 +301,9 @@ pub struct MachineState {
pub(super) last_call: bool,
pub(crate) heap_locs: HeapVarDict,
pub(crate) flags: MachineFlags,
pub(crate) at_end_of_expansion: bool,
pub(crate) cc: usize,
pub(crate) global_clock: usize,
pub(crate) dynamic_mode: FirstOrNext,
}
impl MachineState {
@@ -911,8 +919,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
IndexPtr::Undefined => {
return Err(machine_st.throw_undefined_error(name, arity));
}
IndexPtr::DynamicIndex(compiled_tl_index) => {
machine_st.dynamic_mode = FirstOrNext::First;
machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
}
IndexPtr::Index(compiled_tl_index) => {
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index));
machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
}
}
@@ -934,6 +946,10 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
IndexPtr::Undefined => {
return Err(machine_st.throw_undefined_error(name, arity));
}
IndexPtr::DynamicIndex(compiled_tl_index) => {
machine_st.dynamic_mode = FirstOrNext::First;
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index));
}
IndexPtr::Index(compiled_tl_index) => {
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
}

View File

@@ -54,7 +54,9 @@ impl MachineState {
last_call: false,
heap_locs: HeapVarDict::new(),
flags: MachineFlags::default(),
at_end_of_expansion: false,
cc: 0,
global_clock: 0,
dynamic_mode: FirstOrNext::First,
}
}
@@ -1302,9 +1304,35 @@ impl MachineState {
pub(super) fn execute_indexing_instr(
&mut self,
indexing_lines: &Vec<IndexingLine>,
call_policy: &mut Box<dyn CallPolicy>,
global_variables: &mut GlobalVarDir,
code_repo: &CodeRepo,
) {
fn dynamic_external_of_clause_is_valid(
machine_st: &mut MachineState,
code: &Code,
p: usize,
) -> bool {
match &code[p] {
Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {
machine_st.dynamic_mode = FirstOrNext::First;
return true;
}
_ => {}
}
match &code[p-1] {
&Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => {
if birth < machine_st.cc && Death::Finite(machine_st.cc) <= death {
return true;
} else {
return false;
}
}
_ => {}
}
true
}
let mut index = 0;
let addr = match &indexing_lines[0] {
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
@@ -1323,7 +1351,7 @@ impl MachineState {
IndexingCodePtr::Fail
}
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
IndexingCodePtr::External(v)
v
}
Addr::PStrLocation(..) => l,
Addr::Char(_)
@@ -1342,6 +1370,20 @@ impl MachineState {
self.fail = true;
break;
}
IndexingCodePtr::DynamicExternal(o) => {
// either points directly to a
// DynamicInternalElse, or just ahead of
// one. Or neither!
let p = self.p.local().abs_loc();
if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
self.fail = true;
} else {
self.p += o;
}
break;
}
IndexingCodePtr::External(o) => {
self.p += o;
break;
@@ -1365,6 +1407,20 @@ impl MachineState {
self.fail = true;
break;
}
IndexingCodePtr::DynamicExternal(o) => {
// either points directly to a
// DynamicInternalElse, or just ahead of
// one. Or neither!
let p = self.p.local().abs_loc();
if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
self.fail = true;
} else {
self.p += o;
}
break;
}
IndexingCodePtr::External(o) => {
self.p += o;
break;
@@ -1394,6 +1450,17 @@ impl MachineState {
self.fail = true;
break;
}
IndexingCodePtr::DynamicExternal(o) => {
let p = self.p.local().abs_loc();
if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) {
self.fail = true;
} else {
self.p += o;
}
break;
}
IndexingCodePtr::External(o) => {
self.p += o;
break;
@@ -1403,18 +1470,23 @@ impl MachineState {
}
}
}
&IndexingLine::IndexedChoice(ref instrs) => {
&IndexingLine::IndexedChoice(_) => {
if let LocalCodePtr::DirEntry(p) = self.p.local() {
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
} else {
unreachable!()
}
self.execute_indexed_choice_instr(
instrs.first().unwrap(),
call_policy,
global_variables,
);
break;
}
&IndexingLine::DynamicIndexedChoice(_) => {
self.dynamic_mode = FirstOrNext::First;
if let LocalCodePtr::DirEntry(p) = self.p.local() {
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
} else {
unreachable!()
}
break;
}
@@ -3028,6 +3100,113 @@ impl MachineState {
};
}
pub(super) fn execute_dynamic_indexed_choice_instr(
&mut self,
code_repo: &CodeRepo,
call_policy: &mut Box<dyn CallPolicy>,
global_variables: &mut GlobalVarDir,
) {
let p = self.p.local();
match code_repo.find_living_dynamic(p, self.cc) {
Some((offset, oi, ii, is_next_clause)) => {
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(
p.abs_loc(), oi, ii,
));
match self.dynamic_mode {
FirstOrNext::First if !is_next_clause => {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(
p.abs_loc() + offset,
));
}
FirstOrNext::First => {
// there's a leading DynamicElse that sets self.cc.
// self.cc = self.global_clock;
match code_repo.find_living_dynamic(
LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1),
self.cc,
) {
Some(_) => {
self.registers[self.num_of_args + 1] = Addr::Usize(self.cc);
self.num_of_args += 1;
self.execute_indexed_choice_instr(
&IndexedChoiceInstruction::Try(offset),
call_policy,
global_variables,
);
self.num_of_args -= 1;
}
None => {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(
p.abs_loc() + offset,
));
}
}
}
FirstOrNext::Next => {
let n = self
.stack
.index_or_frame(self.b)
.prelude
.univ_prelude
.num_cells;
self.cc = match self.stack.index_or_frame(self.b)[n - 1] {
Addr::Usize(cc) => cc,
_ => unreachable!(),
};
if is_next_clause {
match code_repo.find_living_dynamic(
LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1),
self.cc,
) {
Some(_) => {
try_or_fail!(
self,
call_policy.retry(
self,
offset,
global_variables,
)
)
}
None => {
try_or_fail!(
self,
call_policy.trust(
self,
offset,
global_variables,
)
)
}
}
} else {
try_or_fail!(
self,
call_policy.trust(
self,
offset,
global_variables,
)
)
}
}
}
self.dynamic_mode = FirstOrNext::Next;
}
None => {
self.fail = true;
}
}
}
pub(super) fn execute_indexed_choice_instr(
&mut self,
instr: &IndexedChoiceInstruction,
@@ -3073,10 +3252,187 @@ impl MachineState {
pub(super) fn execute_choice_instr(
&mut self,
instr: &ChoiceInstruction,
code_repo: &CodeRepo,
call_policy: &mut Box<dyn CallPolicy>,
global_variables: &mut GlobalVarDir,
) {
match instr {
&ChoiceInstruction::DynamicElse(..) => {
if let FirstOrNext::First = self.dynamic_mode {
self.cc = self.global_clock;
}
let p = self.p.local().abs_loc();
match code_repo.find_living_dynamic_else(p, self.cc) {
Some((p, next_i)) => {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
match self.dynamic_mode {
FirstOrNext::First if next_i == 0 => {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
}
FirstOrNext::First => {
self.cc = self.global_clock;
match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
Some(_) => {
self.registers[self.num_of_args + 1] = Addr::Usize(self.cc);
self.num_of_args += 1;
self.execute_choice_instr(
&ChoiceInstruction::TryMeElse(next_i),
code_repo,
call_policy,
global_variables,
);
self.num_of_args -= 1;
}
None => {
self.p += 1;
}
}
}
FirstOrNext::Next => {
let n = self
.stack
.index_or_frame(self.b)
.prelude
.univ_prelude
.num_cells;
self.cc = match self.stack.index_or_frame(self.b)[n - 1] {
Addr::Usize(cc) => cc,
_ => unreachable!(),
};
if next_i > 0 {
match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
Some(_) => {
try_or_fail!(
self,
call_policy.retry_me_else(
self,
next_i,
global_variables,
)
)
}
None => {
try_or_fail!(
self,
call_policy.trust_me(
self,
global_variables,
)
)
}
}
} else {
try_or_fail!(
self,
call_policy.trust_me(
self,
global_variables,
)
)
}
}
}
}
None => {
self.fail = true;
}
}
self.dynamic_mode = FirstOrNext::Next;
}
&ChoiceInstruction::DynamicInternalElse(..) => {
let p = self.p.local().abs_loc();
match code_repo.find_living_dynamic_else(p, self.cc) {
Some((p, next_i)) => {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
match self.dynamic_mode {
FirstOrNext::First if next_i == 0 => {
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
}
FirstOrNext::First => {
match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
Some(_) => {
self.registers[self.num_of_args + 1] = Addr::Usize(self.cc);
self.num_of_args += 1;
self.execute_choice_instr(
&ChoiceInstruction::TryMeElse(next_i),
code_repo,
call_policy,
global_variables,
);
self.num_of_args -= 1;
}
None => {
self.p += 1;
}
}
}
FirstOrNext::Next => {
let n = self
.stack
.index_or_frame(self.b)
.prelude
.univ_prelude
.num_cells;
self.cc = match self.stack.index_or_frame(self.b)[n - 1] {
Addr::Usize(cc) => cc,
_ => unreachable!(),
};
if next_i > 0 {
match code_repo.find_living_dynamic_else(p + next_i, self.cc) {
Some(_) => {
try_or_fail!(
self,
call_policy.retry_me_else(
self,
next_i,
global_variables,
)
)
}
None => {
try_or_fail!(
self,
call_policy.trust_me(
self,
global_variables,
)
)
}
}
} else {
try_or_fail!(
self,
call_policy.trust_me(
self,
global_variables,
)
)
}
}
}
}
None => {
self.fail = true;
}
}
self.dynamic_mode = FirstOrNext::Next;
}
&ChoiceInstruction::TryMeElse(offset) => {
let n = self.num_of_args;
let b = self.stack.allocate_or_frame(n);

View File

@@ -562,6 +562,7 @@ impl MachineState {
&Line::Choice(ref choice_instr) => {
self.execute_choice_instr(
choice_instr,
code_repo,
&mut policies.call_policy,
&mut indices.global_variables,
)
@@ -585,8 +586,7 @@ impl MachineState {
&Line::IndexingCode(ref indexing_lines) => {
self.execute_indexing_instr(
indexing_lines,
&mut policies.call_policy,
&mut indices.global_variables,
code_repo,
)
}
&Line::IndexedChoice(ref choice_instr) => {
@@ -596,6 +596,13 @@ impl MachineState {
&mut indices.global_variables,
)
}
&Line::DynamicIndexedChoice(_) => {
self.execute_dynamic_indexed_choice_instr(
code_repo,
&mut policies.call_policy,
&mut indices.global_variables,
)
}
&Line::Query(ref query_instr) => {
self.execute_query_instr(&query_instr);
self.p += 1;

View File

@@ -3496,14 +3496,16 @@ impl MachineState {
self.fail = match self.store(self.deref(self[temp_v!(2)])) {
Addr::Str(s) => match &self.heap[s] {
&HeapCellValue::NamedStr(arity, ref name, ref spec) => indices
.get_predicate_code_index(
&HeapCellValue::NamedStr(arity, ref name, ref spec) => {
CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), arity)).is_some() ||
indices.get_predicate_code_index(
name.clone(),
arity,
module_name,
spec.clone(),
)
.is_some(),
.is_some()
}
_ => {
unreachable!()
}
@@ -3513,8 +3515,8 @@ impl MachineState {
let spec =
fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir);
indices
.get_predicate_code_index(name.clone(), 0, module_name, spec)
CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), 0)).is_some() ||
indices.get_predicate_code_index(name.clone(), 0, module_name, spec)
.is_some()
} else {
unreachable!()