use std::collections::VecDeque;
use std::rc::Rc;
-#[inline]
-pub fn trust_me(non_counted_bt: bool) -> ChoiceInstruction {
- if non_counted_bt {
- ChoiceInstruction::DefaultTrustMe(0)
- } else {
- ChoiceInstruction::TrustMe(0)
- }
-}
-
-#[inline]
-pub fn retry_me_else(offset: usize, non_counted_bt: bool) -> ChoiceInstruction {
- if non_counted_bt {
- ChoiceInstruction::DefaultRetryMeElse(offset)
- } else {
- ChoiceInstruction::RetryMeElse(offset)
- }
-}
-
#[derive(Debug)]
pub struct ConjunctInfo<'a> {
pub perm_vs: VariableFixtures<'a>,
#[derive(Clone, Copy, Debug)]
pub struct CodeGenSettings {
+ pub global_clock_tick: Option<usize>,
pub is_extensible: bool,
pub non_counted_bt: bool,
}
impl CodeGenSettings {
#[inline]
- pub fn new(is_extensible: bool, non_counted_bt: bool) -> Self {
- CodeGenSettings {
- is_extensible,
- non_counted_bt,
+ pub fn is_dynamic(&self) -> bool {
+ self.global_clock_tick.is_some()
+ }
+
+ #[inline]
+ pub fn internal_try_me_else(&self, offset: usize) -> ChoiceInstruction {
+ if let Some(global_clock_time) = self.global_clock_tick {
+ ChoiceInstruction::DynamicInternalElse(
+ global_clock_time,
+ Death::Infinity,
+ if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ )
+ } else {
+ ChoiceInstruction::TryMeElse(offset)
+ }
+ }
+
+ pub fn try_me_else(&self, offset: usize) -> ChoiceInstruction {
+ if let Some(global_clock_tick) = self.global_clock_tick {
+ ChoiceInstruction::DynamicElse(
+ global_clock_tick,
+ Death::Infinity,
+ if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ )
+ } else {
+ ChoiceInstruction::TryMeElse(offset)
+ }
+ }
+
+ pub fn internal_retry_me_else(&self, offset: usize) -> ChoiceInstruction {
+ if let Some(global_clock_tick) = self.global_clock_tick {
+ ChoiceInstruction::DynamicInternalElse(
+ global_clock_tick,
+ Death::Infinity,
+ if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ )
+ } else {
+ ChoiceInstruction::RetryMeElse(offset)
+ }
+ }
+
+ pub fn retry_me_else(&self, offset: usize) -> ChoiceInstruction {
+ if let Some(global_clock_tick) = self.global_clock_tick {
+ ChoiceInstruction::DynamicElse(
+ global_clock_tick,
+ Death::Infinity,
+ if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) },
+ )
+ } else if self.non_counted_bt {
+ ChoiceInstruction::DefaultRetryMeElse(offset)
+ } else {
+ ChoiceInstruction::RetryMeElse(offset)
+ }
+ }
+
+ pub fn internal_trust_me(&self) -> ChoiceInstruction {
+ if let Some(global_clock_tick) = self.global_clock_tick {
+ ChoiceInstruction::DynamicInternalElse(
+ global_clock_tick,
+ Death::Infinity,
+ NextOrFail::Fail(0),
+ )
+ } else if self.non_counted_bt {
+ ChoiceInstruction::DefaultTrustMe(0)
+ } else {
+ ChoiceInstruction::TrustMe(0)
+ }
+ }
+
+ pub fn trust_me(&self) -> ChoiceInstruction {
+ if let Some(global_clock_tick) = self.global_clock_tick {
+ ChoiceInstruction::DynamicElse(
+ global_clock_tick,
+ Death::Infinity,
+ NextOrFail::Fail(0),
+ )
+ } else if self.non_counted_bt {
+ ChoiceInstruction::DefaultTrustMe(0)
+ } else {
+ ChoiceInstruction::TrustMe(0)
}
}
}
atom_tbl: TabledData<Atom>,
marker: TermMarker,
pub var_count: IndexMap<Rc<Var>, usize>,
- non_counted_bt: bool,
- is_extensible: bool,
+ settings: CodeGenSettings,
pub skeleton: PredicateSkeleton,
pub jmp_by_locs: Vec<usize>,
global_jmp_by_locs_offset: usize,
atom_tbl,
marker: Allocator::new(),
var_count: IndexMap::new(),
- non_counted_bt: settings.non_counted_bt,
- is_extensible: settings.is_extensible,
+ settings,
skeleton: PredicateSkeleton::new(),
jmp_by_locs: vec![],
global_jmp_by_locs_offset: 0,
self.add_conditional_call(code, term, num_perm_vars_left);
}
- /*
- pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Result<Code, CompilationError> {
- let iter = ChunkedIterator::from_term_sequence(query);
- let conjunct_info = self.collect_var_data(iter);
-
- let mut code = Vec::new();
- self.compile_seq_prelude(&conjunct_info, &mut code);
-
- let iter = ChunkedIterator::from_term_sequence(query);
- self.compile_seq(iter, &conjunct_info, &mut code, true)?;
-
- conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code);
-
- if let Some(query_term) = query.last() {
- Self::compile_cleanup(&mut code, &conjunct_info, query_term);
- }
-
- Ok(code)
- }
- */
-
#[inline]
fn increment_jmp_by_locs_by(&mut self, incr: usize) {
let offset = self.global_jmp_by_locs_offset;
subseqs
}
- fn compile_pred_subseq<'b: 'a>(
+ fn compile_pred_subseq<'b: 'a, I: Indexer>(
&mut self,
clauses: &'b [PredicateClause],
optimal_index: usize,
) -> Result<Code, CompilationError> {
let mut code = VecDeque::new();
- let mut code_offsets = CodeOffsets::new(self.atom_tbl.clone(), optimal_index + 1);
- let mut skip_stub_try_me_else = false;
+ let mut code_offsets = CodeOffsets::new(
+ self.atom_tbl.clone(),
+ I::new(),
+ optimal_index + 1,
+ );
+ let mut skip_stub_try_me_else = false;
let jmp_by_locs_len = self.jmp_by_locs.len();
for (i, clause) in clauses.iter().enumerate() {
if clauses.len() > 1 {
let choice = match i {
- 0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
- _ if i == clauses.len() - 1 => trust_me(self.non_counted_bt),
- _ => retry_me_else(clause_code.len() + 1, self.non_counted_bt),
+ 0 => self.settings.internal_try_me_else(clause_code.len() + 1),
+ //ChoiceInstruction::TryMeElse(clause_code.len() + 1),
+ _ if i == clauses.len() - 1 => self.settings.internal_trust_me(),
+ _ => self.settings.internal_retry_me_else(clause_code.len() + 1),
};
code.push_back(Line::Choice(choice));
- } else if self.is_extensible {
+ } else if self.settings.is_extensible {
/*
generate stub choice instructions for extensible
predicates. if predicates are added to either the
over them.
*/
- code.push_front(Line::Choice(ChoiceInstruction::TryMeElse(0)));
- skip_stub_try_me_else = true;
+ code.push_front(Line::Choice(self.settings.internal_try_me_else(0)));
+ //Line::Choice(ChoiceInstruction::TryMeElse(0)));
+ skip_stub_try_me_else = !self.settings.is_dynamic(); //true;
}
let arg = match clause.args() {
code_offsets.index_term(arg, index, &mut clause_index_info);
}
- if !skip_stub_try_me_else {
+ if !(clauses.len() == 1 && self.settings.is_extensible) {
self.increment_jmp_by_locs_by(code.len());
}
} else {
self.increment_jmp_by_locs_by(1);
}
- } else if skip_stub_try_me_else {
+ } else if clauses.len() == 1 && self.settings.is_extensible {
+ // the condition is the value of skip_stub_try_me_else, which is
+ // true if the predicate is not dynamic. This operation must apply
+ // to dynamic predicates also, though.
+
// remove the TryMeElse(0).
code.pop_front();
}
for (l, r) in split_pred {
let skel_lower_bound = self.skeleton.clauses.len();
- let code_segment = self.compile_pred_subseq(&clauses[l..r], optimal_index)?;
+ let code_segment = if self.settings.is_dynamic() {
+ self.compile_pred_subseq::<DynamicCodeIndices>(&clauses[l..r], optimal_index)?
+ } else {
+ self.compile_pred_subseq::<StaticCodeIndices>(&clauses[l..r], optimal_index)?
+ };
+
let clause_start_offset = code.len();
if multi_seq {
let choice = match l {
- 0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1),
- _ if r == clauses.len() => trust_me(self.non_counted_bt),
- _ => retry_me_else(code_segment.len() + 1, self.non_counted_bt),
+ 0 => self.settings.try_me_else(code_segment.len() + 1),
+ _ if r == clauses.len() => self.settings.trust_me(),
+ _ => self.settings.retry_me_else(code_segment.len() + 1),
};
code.push(Line::Choice(choice));
- } else if self.is_extensible {
- code.push(Line::Choice(ChoiceInstruction::TryMeElse(0)));
+ } else if self.settings.is_extensible {
+ code.push(Line::Choice(self.settings.try_me_else(0)));
}
- if self.is_extensible {
+ if self.settings.is_extensible {
let segment_is_indexed = to_indexing_line(&code_segment[0]).is_some();
for clause_index_info in self.skeleton.clauses[skel_lower_bound..].iter_mut() {
use std::convert::TryFrom;
use std::hash::Hash;
use std::iter::once;
+use std::mem;
use std::rc::Rc;
#[derive(Debug, Clone, Copy)]
pub enum IndexingCodePtr {
External(usize), // the index points past the indexing instruction prelude.
+ DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction.
Fail,
Internal(usize), // the index points into the indexing instruction prelude.
}
struct IndexingCodeMergingPtr<'a> {
skeleton: &'a mut [ClauseIndexInfo],
- // merged_clause_index: usize,
indexing_code: &'a mut Vec<IndexingLine>,
offset: usize,
append_or_prepend: AppendOrPrepend,
+ is_dynamic: bool,
}
impl<'a> IndexingCodeMergingPtr<'a> {
indexing_code: &'a mut Vec<IndexingLine>,
append_or_prepend: AppendOrPrepend,
) -> Self {
+ let is_dynamic = match &indexing_code[0] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
+ match v {
+ IndexingCodePtr::External(_) => false,
+ IndexingCodePtr::DynamicExternal(_) => true,
+ _ => unreachable!()
+ }
+ }
+ _ => unreachable!()
+ };
+
Self {
skeleton,
indexing_code,
offset: 0,
append_or_prepend,
+ is_dynamic,
}
}
}
if let IndexingCodePtr::Internal(_) = constant_ptr {
+ let last_index = self.indexing_code.len();
+
self.indexing_code.push(IndexingLine::Indexing(
IndexingInstruction::SwitchOnConstant(constants),
));
- let last_index = self.indexing_code.len() - 1;
self.indexing_code.swap(self.offset, last_index);
} else {
self.offset = self.indexing_code.len();
}
}
- fn add_indexed_choice_for_constant(
+ fn add_static_indexed_choice_for_constant(
&mut self,
external: usize,
constant: Constant,
};
let indexing_code_len = self.indexing_code.len();
- self.indexing_code
- .push(IndexingLine::IndexedChoice(third_level_index));
+ self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index));
+
+ match &mut self.indexing_code[self.offset] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => {
+ constants.insert(
+ constant,
+ IndexingCodePtr::Internal(indexing_code_len - self.offset),
+ );
+ }
+ _ => {
+ unreachable!()
+ }
+ }
+ }
+
+ fn add_dynamic_indexed_choice_for_constant(
+ &mut self,
+ external: usize,
+ constant: Constant,
+ index: usize,
+ ) {
+ let third_level_index = if self.append_or_prepend.is_append() {
+ sdeq![external, index]
+ } else {
+ sdeq![index, external]
+ };
+
+ let indexing_code_len = self.indexing_code.len();
+ self.indexing_code.push(IndexingLine::DynamicIndexedChoice(third_level_index));
match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref mut constants)) => {
uncap_choice_seq_with_try(indexed_choice_instrs);
indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index));
}
+ IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs)
+ if self.append_or_prepend.is_append() =>
+ {
+ indexed_choice_instrs.push_back(index);
+ }
+ IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => {
+ indexed_choice_instrs.push_front(index);
+ }
_ => {
unreachable!()
}
match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => {
match *c {
+ IndexingCodePtr::Fail if self.is_dynamic => {
+ *c = IndexingCodePtr::DynamicExternal(index);
+ break;
+ }
IndexingCodePtr::Fail => {
*c = IndexingCodePtr::External(index);
break;
}
- IndexingCodePtr::External(_) => {
+ IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
let mut constants = IndexMap::new();
constants.insert(orig_constant.clone(), *c);
}
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => {
match constants.get(&overlapping_constant).cloned() {
+ None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
+ constants.insert(
+ overlapping_constant,
+ IndexingCodePtr::DynamicExternal(index),
+ );
+ }
None | Some(IndexingCodePtr::Fail) => {
- constants
- .insert(overlapping_constant, IndexingCodePtr::External(index));
+ constants.insert(
+ overlapping_constant,
+ IndexingCodePtr::External(index),
+ );
+ }
+ Some(IndexingCodePtr::DynamicExternal(o)) => {
+ self.add_dynamic_indexed_choice_for_constant(o, overlapping_constant, index);
}
Some(IndexingCodePtr::External(o)) => {
- self.add_indexed_choice_for_constant(o, overlapping_constant, index);
+ self.add_static_indexed_choice_for_constant(o, overlapping_constant, index);
}
Some(IndexingCodePtr::Internal(o)) => {
self.offset += o;
break;
}
- IndexingLine::IndexedChoice(_) => {
+ IndexingLine::IndexedChoice(_) | IndexingLine::DynamicIndexedChoice(_) => {
self.internalize_constant(IndexingCodePtr::Internal(
indexing_code_len - self.offset,
));
match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => {
match *c {
+ IndexingCodePtr::Fail if self.is_dynamic => {
+ *c = IndexingCodePtr::DynamicExternal(index);
+ break;
+ }
IndexingCodePtr::Fail => {
*c = IndexingCodePtr::External(index);
break;
*c = IndexingCodePtr::Internal(indexing_code_len - self.offset);
self.internalize_constant(IndexingCodePtr::External(o));
}
+ IndexingCodePtr::DynamicExternal(o) => {
+ *c = IndexingCodePtr::Internal(indexing_code_len - self.offset);
+ self.internalize_constant(IndexingCodePtr::DynamicExternal(o));
+ }
IndexingCodePtr::Internal(o) => {
self.offset += o;
}
}
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => {
match constants.get(&constant).cloned() {
+ None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
+ constants.insert(constant, IndexingCodePtr::DynamicExternal(index));
+ }
None | Some(IndexingCodePtr::Fail) => {
constants.insert(constant, IndexingCodePtr::External(index));
}
+ Some(IndexingCodePtr::DynamicExternal(o)) => {
+ self.add_dynamic_indexed_choice_for_constant(o, constant, index);
+ }
Some(IndexingCodePtr::External(o)) => {
- self.add_indexed_choice_for_constant(o, constant, index);
+ self.add_static_indexed_choice_for_constant(o, constant, index);
}
Some(IndexingCodePtr::Internal(o)) => {
self.offset += o;
break;
}
- IndexingLine::IndexedChoice(_) => {
+ IndexingLine::IndexedChoice(_) | IndexingLine::DynamicIndexedChoice(_) => {
self.internalize_constant(IndexingCodePtr::Internal(
indexing_code_len - self.offset,
));
}
if let IndexingCodePtr::Internal(_) = structure_ptr {
+ let last_index = self.indexing_code.len();
+
self.indexing_code.push(IndexingLine::Indexing(
IndexingInstruction::SwitchOnStructure(structures),
));
- let last_index = self.indexing_code.len() - 1;
self.indexing_code.swap(self.offset, last_index);
} else {
self.offset = self.indexing_code.len();
}
}
- fn add_indexed_choice_for_structure(
+ fn add_static_indexed_choice_for_structure(
&mut self,
external: usize,
key: PredicateKey,
}
}
+ fn add_dynamic_indexed_choice_for_structure(
+ &mut self,
+ external: usize,
+ key: PredicateKey,
+ index: usize,
+ ) {
+ let third_level_index = if self.append_or_prepend.is_append() {
+ sdeq![external, index]
+ } else {
+ sdeq![index, external]
+ };
+
+ let indexing_code_len = self.indexing_code.len();
+ self.indexing_code.push(IndexingLine::DynamicIndexedChoice(third_level_index));
+
+ match &mut self.indexing_code[self.offset] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => {
+ structures.insert(
+ key,
+ IndexingCodePtr::Internal(indexing_code_len - self.offset),
+ );
+ }
+ _ => {
+ unreachable!()
+ }
+ }
+ }
+
fn index_structure(&mut self, key: PredicateKey, index: usize) {
loop {
let indexing_code_len = self.indexing_code.len();
_,
ref mut s,
)) => match *s {
+ IndexingCodePtr::Fail if self.is_dynamic => {
+ *s = IndexingCodePtr::DynamicExternal(index);
+ break;
+ }
IndexingCodePtr::Fail => {
*s = IndexingCodePtr::External(index);
break;
}
+ IndexingCodePtr::DynamicExternal(o) => {
+ *s = IndexingCodePtr::Internal(indexing_code_len - self.offset);
+ self.internalize_structure(IndexingCodePtr::DynamicExternal(o));
+ }
IndexingCodePtr::External(o) => {
*s = IndexingCodePtr::Internal(indexing_code_len - self.offset);
self.internalize_structure(IndexingCodePtr::External(o));
},
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(structures)) => {
match structures.get(&key).cloned() {
+ None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
+ structures.insert(key, IndexingCodePtr::DynamicExternal(index));
+ }
None | Some(IndexingCodePtr::Fail) => {
structures.insert(key, IndexingCodePtr::External(index));
}
+ Some(IndexingCodePtr::DynamicExternal(o)) => {
+ self.add_dynamic_indexed_choice_for_structure(o, key, index);
+ }
Some(IndexingCodePtr::External(o)) => {
- self.add_indexed_choice_for_structure(o, key, index);
+ self.add_static_indexed_choice_for_structure(o, key, index);
}
Some(IndexingCodePtr::Internal(o)) => {
self.offset += o;
break;
}
- IndexingLine::IndexedChoice(_) => {
+ IndexingLine::IndexedChoice(_) | IndexingLine::DynamicIndexedChoice(_) => {
// replace this value, at self.offset, with
// SwitchOnStructures, and swap this IndexedChoice
// vector to the end of self.indexing_code.
match &mut self.indexing_code[self.offset] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _)) => {
match *l {
+ IndexingCodePtr::Fail if self.is_dynamic => {
+ *l = IndexingCodePtr::DynamicExternal(index);
+ }
IndexingCodePtr::Fail => {
*l = IndexingCodePtr::External(index);
}
+ IndexingCodePtr::DynamicExternal(o) => {
+ *l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
+
+ let third_level_index = if self.append_or_prepend.is_append() {
+ sdeq![o, index]
+ } else {
+ sdeq![index, o]
+ };
+
+ self.indexing_code
+ .push(IndexingLine::DynamicIndexedChoice(third_level_index));
+ }
IndexingCodePtr::External(o) => {
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
AppendOrPrepend::Prepend => skeleton.first_mut().unwrap().opt_arg_index_key.take(),
};
- let mut merging_ptr =
- IndexingCodeMergingPtr::new(skeleton, target_indexing_code, append_or_prepend);
+ let mut merging_ptr = IndexingCodeMergingPtr::new(
+ skeleton,
+ target_indexing_code,
+ append_or_prepend,
+ );
match &opt_arg_index_key {
OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => {
}
}
-#[inline]
-fn remove_instruction_with_offset(code: &mut SliceDeque<IndexedChoiceInstruction>, offset: usize) {
- for (index, line) in code.iter().enumerate() {
- if offset == line.offset() {
- code.remove(index);
- cap_choice_seq(code);
- return;
- }
- }
-}
-
pub fn remove_constant_indices(
constant: &Constant,
overlapping_constants: &[Constant],
match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => {
match *c {
- IndexingCodePtr::External(_) => {
+ IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
*c = IndexingCodePtr::Fail;
return;
}
let mut constants_index = 0;
for constant in iter {
- // (constant, index_loc) in iter.zip(index_locs.iter()) {
loop {
match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
constants_index = index;
match constants.get(constant).cloned() {
- Some(IndexingCodePtr::External(_)) | Some(IndexingCodePtr::Fail) => {
+ Some(IndexingCodePtr::DynamicExternal(_)) |
+ Some(IndexingCodePtr::External(_)) |
+ Some(IndexingCodePtr::Fail) => {
constants.remove(constant);
break;
}
}
}
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
- remove_instruction_with_offset(indexed_choice_instrs, offset);
+ StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
if indexed_choice_instrs.len() == 1 {
- let ext = IndexingCodePtr::External(
- indexed_choice_instrs.pop_back().unwrap().offset(),
- );
-
- match &mut indexing_code[constants_index] {
- IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
- _,
- _,
- ref mut c,
- ..,
- )) => {
- *c = ext;
- }
- IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
- ref mut constants,
- )) => {
- constants.insert(constant.clone(), ext);
+ if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
+ let ext = IndexingCodePtr::External(
+ indexed_choice_instr.offset()
+ );
+
+ match &mut indexing_code[constants_index] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
+ _,
+ _,
+ ref mut c,
+ ..,
+ )) => {
+ *c = ext;
+ }
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
+ ref mut constants,
+ )) => {
+ constants.insert(constant.clone(), ext);
+ }
+ _ => {
+ unreachable!()
+ }
}
- _ => {
- unreachable!()
+ }
+ }
+
+ break;
+ }
+ IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => {
+ DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
+
+ if indexed_choice_instrs.len() == 1 {
+ if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
+ let ext = IndexingCodePtr::DynamicExternal(indexed_choice_instr);
+
+ match &mut indexing_code[constants_index] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
+ _,
+ _,
+ ref mut c,
+ ..,
+ )) => {
+ *c = ext;
+ }
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
+ ref mut constants,
+ )) => {
+ constants.insert(constant.clone(), ext);
+ }
+ _ => {
+ unreachable!()
+ }
}
}
}
match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s)) => {
match *s {
- IndexingCodePtr::External(_) => {
+ IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
*s = IndexingCodePtr::Fail;
return;
}
structures_index = index;
match structures.get(&(name.clone(), arity)).cloned() {
- Some(IndexingCodePtr::External(_)) => {
+ Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => {
structures.remove(&(name.clone(), arity));
break;
}
}
}
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
- remove_instruction_with_offset(indexed_choice_instrs, offset);
+ StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
if indexed_choice_instrs.len() == 1 {
- let ext = IndexingCodePtr::External(
- indexed_choice_instrs.pop_back().unwrap().offset(),
- );
+ if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
+ let ext = IndexingCodePtr::External(indexed_choice_instr.offset());
- match &mut indexing_code[structures_index] {
- IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
- _,
- _,
- _,
- _,
- ref mut s,
- )) => {
- *s = ext;
- }
- IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(
- ref mut structures,
- )) => {
- structures.insert((name.clone(), arity), ext);
+ match &mut indexing_code[structures_index] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
+ _,
+ _,
+ _,
+ _,
+ ref mut s,
+ )) => {
+ *s = ext;
+ }
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(
+ ref mut structures,
+ )) => {
+ structures.insert((name.clone(), arity), ext);
+ }
+ _ => {
+ unreachable!()
+ }
}
- _ => {
- unreachable!()
+ }
+ }
+
+ break;
+ }
+ IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => {
+ DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
+
+ if indexed_choice_instrs.len() == 1 {
+ if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
+ let ext = IndexingCodePtr::DynamicExternal(indexed_choice_instr);
+
+ match &mut indexing_code[structures_index] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
+ _,
+ _,
+ _,
+ _,
+ ref mut s,
+ )) => {
+ *s = ext;
+ }
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(
+ ref mut structures,
+ )) => {
+ structures.insert((name.clone(), arity), ext);
+ }
+ _ => {
+ unreachable!()
+ }
}
}
}
match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _)) => {
match *l {
- IndexingCodePtr::External(_) => {
+ IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
*l = IndexingCodePtr::Fail;
return;
}
match &mut indexing_code[index] {
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
- remove_instruction_with_offset(indexed_choice_instrs, offset);
+ StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
if indexed_choice_instrs.len() == 1 {
- let ext =
- IndexingCodePtr::External(indexed_choice_instrs.pop_back().unwrap().offset());
-
- match &mut indexing_code[0] {
- IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
- _,
- _,
- _,
- ref mut l,
- _,
- )) => {
- *l = ext;
+ if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
+ let ext = IndexingCodePtr::External(indexed_choice_instr.offset());
+
+ match &mut indexing_code[0] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
+ _,
+ _,
+ _,
+ ref mut l,
+ _,
+ )) => {
+ *l = ext;
+ }
+ _ => {
+ unreachable!()
+ }
}
- _ => {
- unreachable!()
+ }
+ }
+ }
+ IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => {
+ DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
+
+ if indexed_choice_instrs.len() == 1 {
+ if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
+ let ext = IndexingCodePtr::DynamicExternal(indexed_choice_instr);
+
+ match &mut indexing_code[0] {
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
+ _,
+ _,
+ _,
+ ref mut l,
+ _,
+ )) => {
+ *l = ext;
+ }
+ _ => {
+ unreachable!()
+ }
}
}
}
}
pub fn remove_index(
- //skeleton: &[ClauseIndexInfo],
opt_arg_index_key: &OptArgIndexKey,
indexing_code: &mut Vec<IndexingLine>,
clause_loc: usize,
overlapping_constants,
indexing_code,
clause_loc,
- //&skeleton[index].index_locs,
);
}
OptArgIndexKey::Structure(_, _, ref name, ref arity) => {
*arity,
indexing_code,
clause_loc,
- //&skeleton[index].index_locs,
);
}
OptArgIndexKey::List(..) => {
remove_list_index(
indexing_code,
clause_loc,
- //&skeleton[index].index_locs,
);
}
OptArgIndexKey::None => {
}
}
-fn second_level_index<IndexKey: Eq + Hash>(
- indices: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
- prelude: &mut SliceDeque<IndexingLine>,
-) -> IndexMap<IndexKey, IndexingCodePtr> {
- let mut index_locs = IndexMap::new();
-
- for (key, mut code) in indices.into_iter() {
- if code.len() > 1 {
- index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
- cap_choice_seq_with_trust(&mut code);
- prelude.push_back(IndexingLine::from(code));
- } else {
- code.first().map(|i| {
- index_locs.insert(key, IndexingCodePtr::External(i.offset()));
- });
- }
- }
-
- index_locs
-}
-
-fn switch_on<IndexKey: Eq + Hash>(
- mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
- index: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
- prelude: &mut SliceDeque<IndexingLine>,
-) -> IndexingCodePtr {
- let index = second_level_index(index, prelude);
-
- if index.len() > 1 {
- let instr = instr_fn(index);
- prelude.push_front(IndexingLine::from(instr));
-
- IndexingCodePtr::Internal(1)
- } else {
- index
- .into_iter()
- .next()
- .map(|(_, v)| v)
- .unwrap_or(IndexingCodePtr::Fail)
- }
-}
-
-fn switch_on_list(
- mut lists: SliceDeque<IndexedChoiceInstruction>,
- prelude: &mut SliceDeque<IndexingLine>,
-) -> IndexingCodePtr {
- if lists.len() > 1 {
- cap_choice_seq_with_trust(&mut lists);
- prelude.push_back(IndexingLine::from(lists));
- IndexingCodePtr::Internal(1)
- } else {
- lists
- .first()
- .map(|i| IndexingCodePtr::External(i.offset()))
- .unwrap_or(IndexingCodePtr::Fail)
- }
-}
-
#[inline]
fn cap_choice_seq(prelude: &mut [IndexedChoiceInstruction]) {
prelude.first_mut().map(|instr| {
});
}
-fn compute_index(is_first_index: bool, index: usize) -> IndexedChoiceInstruction {
- // in either case, increment index to skip the IndexingLine vector.
- if is_first_index {
- IndexedChoiceInstruction::Try(index + 1)
- } else {
- IndexedChoiceInstruction::Retry(index + 1)
- }
-}
-
pub fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData<Atom>) -> Vec<Constant> {
let mut constants = vec![];
}
#[derive(Debug)]
-pub struct CodeOffsets {
+pub(crate) struct StaticCodeIndices {
+ constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>,
+ lists: SliceDeque<IndexedChoiceInstruction>,
+ structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>,
+}
+
+#[derive(Debug)]
+pub(crate) struct DynamicCodeIndices {
+ constants: IndexMap<Constant, SliceDeque<usize>>,
+ lists: SliceDeque<usize>,
+ structures: IndexMap<(ClauseName, usize), SliceDeque<usize>>,
+}
+
+pub trait Indexer {
+ type ThirdLevelIndex;
+
+ fn new() -> Self;
+
+ fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<Self::ThirdLevelIndex>>;
+ fn lists(&mut self) -> &mut SliceDeque<Self::ThirdLevelIndex>;
+ fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<Self::ThirdLevelIndex>>;
+
+ fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
+
+ fn second_level_index<IndexKey: Eq + Hash>(
+ indices: IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexMap<IndexKey, IndexingCodePtr>;
+
+ fn switch_on<IndexKey: Eq + Hash>(
+ instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
+ index: &mut IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexingCodePtr;
+
+ fn switch_on_list(
+ lists: &mut SliceDeque<Self::ThirdLevelIndex>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexingCodePtr;
+
+ fn remove_instruction_with_offset(
+ code: &mut SliceDeque<Self::ThirdLevelIndex>,
+ offset: usize,
+ );
+
+ fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
+}
+
+impl Indexer for StaticCodeIndices {
+ type ThirdLevelIndex = IndexedChoiceInstruction;
+
+ #[inline]
+ fn new() -> Self {
+ Self {
+ constants: IndexMap::new(),
+ lists: sdeq![],
+ structures: IndexMap::new(),
+ }
+ }
+
+ #[inline]
+ fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>> {
+ &mut self.constants
+ }
+
+ #[inline]
+ fn lists(&mut self) -> &mut SliceDeque<IndexedChoiceInstruction> {
+ &mut self.lists
+ }
+
+ #[inline]
+ fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>> {
+ &mut self.structures
+ }
+
+ fn compute_index(is_initial_index: bool, index: usize) -> IndexedChoiceInstruction {
+ if is_initial_index {
+ IndexedChoiceInstruction::Try(index + 1)
+ } else {
+ IndexedChoiceInstruction::Retry(index + 1)
+ }
+ }
+
+ fn second_level_index<IndexKey: Eq + Hash>(
+ indices: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexMap<IndexKey, IndexingCodePtr> {
+ let mut index_locs = IndexMap::new();
+
+ for (key, mut code) in indices.into_iter() {
+ if code.len() > 1 {
+ index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
+ cap_choice_seq_with_trust(&mut code);
+ prelude.push_back(IndexingLine::from(code));
+ } else {
+ code.first().map(|i| {
+ index_locs.insert(key, IndexingCodePtr::External(i.offset()));
+ });
+ }
+ }
+
+ index_locs
+ }
+
+ fn switch_on<IndexKey: Eq + Hash>(
+ mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
+ index: &mut IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexingCodePtr {
+ let index = mem::replace(index, IndexMap::new());
+ let index = Self::second_level_index(index, prelude);
+
+ if index.len() > 1 {
+ let instr = instr_fn(index);
+ prelude.push_front(IndexingLine::from(instr));
+
+ IndexingCodePtr::Internal(1)
+ } else {
+ index
+ .into_iter()
+ .next()
+ .map(|(_, v)| v)
+ .unwrap_or(IndexingCodePtr::Fail)
+ }
+ }
+
+ fn switch_on_list(
+ lists: &mut SliceDeque<IndexedChoiceInstruction>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexingCodePtr {
+ if lists.len() > 1 {
+ cap_choice_seq_with_trust(lists);
+ let lists = mem::replace(lists, sdeq![]);
+ prelude.push_back(IndexingLine::from(lists));
+
+ IndexingCodePtr::Internal(1)
+ } else {
+ lists
+ .first()
+ .map(|i| IndexingCodePtr::External(i.offset()))
+ .unwrap_or(IndexingCodePtr::Fail)
+ }
+ }
+
+ #[inline]
+ fn remove_instruction_with_offset(code: &mut SliceDeque<IndexedChoiceInstruction>, offset: usize) {
+ for (index, line) in code.iter().enumerate() {
+ if offset == line.offset() {
+ code.remove(index);
+ cap_choice_seq(code);
+ return;
+ }
+ }
+ }
+
+ #[inline]
+ fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr {
+ IndexingCodePtr::External(var_offset)
+ }
+}
+
+impl Indexer for DynamicCodeIndices {
+ type ThirdLevelIndex = usize;
+
+ #[inline]
+ fn new() -> Self {
+ Self {
+ constants: IndexMap::new(),
+ lists: sdeq![],
+ structures: IndexMap::new(),
+ }
+ }
+
+ #[inline]
+ fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<usize>> {
+ &mut self.constants
+ }
+
+ #[inline]
+ fn lists(&mut self) -> &mut SliceDeque<usize> {
+ &mut self.lists
+ }
+
+ #[inline]
+ fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<usize>> {
+ &mut self.structures
+ }
+
+ #[inline]
+ fn compute_index(_: bool, index: usize) -> usize {
+ index + 1
+ }
+
+ fn second_level_index<IndexKey: Eq + Hash>(
+ indices: IndexMap<IndexKey, SliceDeque<usize>>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexMap<IndexKey, IndexingCodePtr> {
+ let mut index_locs = IndexMap::new();
+
+ for (key, code) in indices.into_iter() {
+ if code.len() > 1 {
+ index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
+ prelude.push_back(IndexingLine::DynamicIndexedChoice(code));
+ } else {
+ code.first().map(|i| {
+ index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i));
+ });
+ }
+ }
+
+ index_locs
+ }
+
+ fn switch_on<IndexKey: Eq + Hash>(
+ mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
+ index: &mut IndexMap<IndexKey, SliceDeque<usize>>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexingCodePtr {
+ let index = mem::replace(index, IndexMap::new());
+ let index = Self::second_level_index(index, prelude);
+
+ if index.len() > 1 {
+ let instr = instr_fn(index);
+ prelude.push_front(IndexingLine::from(instr));
+
+ IndexingCodePtr::Internal(1)
+ } else {
+ index
+ .into_iter()
+ .next()
+ .map(|(_, v)| v)
+ .unwrap_or(IndexingCodePtr::Fail)
+ }
+ }
+
+ fn switch_on_list(
+ lists: &mut SliceDeque<usize>,
+ prelude: &mut SliceDeque<IndexingLine>,
+ ) -> IndexingCodePtr {
+ if lists.len() > 1 {
+ let lists = mem::replace(lists, sdeq![]);
+ prelude.push_back(IndexingLine::DynamicIndexedChoice(lists));
+ IndexingCodePtr::Internal(1)
+ } else {
+ lists
+ .first()
+ .map(|i| IndexingCodePtr::DynamicExternal(*i))
+ .unwrap_or(IndexingCodePtr::Fail)
+ }
+ }
+
+ #[inline]
+ fn remove_instruction_with_offset(code: &mut SliceDeque<usize>, offset: usize) {
+ for (index, line) in code.iter().enumerate() {
+ if offset == *line {
+ code.remove(index);
+ return;
+ }
+ }
+ }
+
+ #[inline]
+ fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr {
+ IndexingCodePtr::DynamicExternal(var_offset)
+ }
+}
+
+#[derive(Debug)]
+pub struct CodeOffsets<I: Indexer> {
atom_tbl: TabledData<Atom>,
- pub constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>,
- pub lists: SliceDeque<IndexedChoiceInstruction>,
- pub structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>,
+ indices: I,
optimal_index: usize,
}
-impl CodeOffsets {
- pub fn new(atom_tbl: TabledData<Atom>, optimal_index: usize) -> Self {
+impl<I: Indexer> CodeOffsets<I> {
+ pub fn new(
+ atom_tbl: TabledData<Atom>,
+ indices: I,
+ optimal_index: usize,
+ ) -> Self {
CodeOffsets {
atom_tbl,
- constants: IndexMap::new(),
- lists: sdeq![],
- structures: IndexMap::new(),
+ indices,
optimal_index,
}
}
fn index_list(&mut self, index: usize) {
- let is_initial_index = self.lists.is_empty();
- self.lists.push_back(compute_index(is_initial_index, index));
+ let is_initial_index = self.indices.lists().is_empty();
+ let index = I::compute_index(is_initial_index, index);
+ self.indices.lists().push_back(index);
}
fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec<Constant> {
let overlapping_constants = constant_key_alternatives(constant, self.atom_tbl.clone());
-
- let code = self.constants.entry(constant.clone()).or_insert(sdeq![]);
+ let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
let is_initial_index = code.is_empty();
- code.push_back(compute_index(is_initial_index, index));
+ code.push_back(I::compute_index(is_initial_index, index));
for constant in &overlapping_constants {
- let code = self.constants.entry(constant.clone()).or_insert(sdeq![]);
+ let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
let is_initial_index = code.is_empty();
- let index = compute_index(is_initial_index, index);
+ let index = I::compute_index(is_initial_index, index);
code.push_back(index);
}
}
fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize {
- let code = self
- .structures
+ let code = self.indices
+ .structures()
.entry((name.clone(), arity))
.or_insert(sdeq![]);
let code_len = code.len();
let is_initial_index = code.is_empty();
- code.push_back(compute_index(is_initial_index, index));
+ code.push_back(I::compute_index(is_initial_index, index));
code_len
}
}
}
- pub fn no_indices(&self) -> bool {
- let no_constants = self.constants.is_empty();
- let no_structures = self.structures.is_empty();
- let no_lists = self.lists.is_empty();
+ pub fn no_indices(&mut self) -> bool {
+ let no_constants = self.indices.constants().is_empty();
+ let no_structures = self.indices.structures().is_empty();
+ let no_lists = self.indices.lists().is_empty();
no_constants && no_structures && no_lists
}
- pub fn compute_indices(self, skip_stub_try_me_else: bool) -> Vec<IndexingLine> {
+ pub fn compute_indices(mut self, skip_stub_try_me_else: bool) -> Vec<IndexingLine> {
if self.no_indices() {
return vec![];
}
let mut emitted_switch_on_structure = false;
let mut emitted_switch_on_constant = false;
- let mut lst_loc = switch_on_list(self.lists, &mut prelude);
+ let mut lst_loc = I::switch_on_list(self.indices.lists(), &mut prelude);
- let mut str_loc = switch_on(
+ let mut str_loc = I::switch_on(
|index| {
emitted_switch_on_structure = true;
IndexingInstruction::SwitchOnStructure(index)
},
- self.structures,
+ self.indices.structures(),
&mut prelude,
);
- let con_loc = switch_on(
+ let con_loc = I::switch_on(
|index| {
emitted_switch_on_constant = true;
IndexingInstruction::SwitchOnConstant(index)
},
- self.constants,
+ self.indices.constants(),
&mut prelude,
);
prelude.push_front(IndexingLine::from(IndexingInstruction::SwitchOnTerm(
self.optimal_index,
- var_offset,
+ I::var_offset_wrapper(var_offset),
con_loc,
lst_loc,
str_loc,
}
}
+#[derive(Debug, Clone, Copy)]
+pub enum NextOrFail {
+ Next(usize),
+ Fail(usize),
+}
+
+impl NextOrFail {
+ #[inline]
+ pub fn is_next(&self) -> bool {
+ if let NextOrFail::Next(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum Death {
+ Finite(usize),
+ Infinity,
+}
+
#[derive(Debug)]
pub enum ChoiceInstruction {
+ DynamicElse(usize, Death, NextOrFail),
+ DynamicInternalElse(usize, Death, NextOrFail),
DefaultRetryMeElse(usize),
DefaultTrustMe(usize),
RetryMeElse(usize),
}
impl ChoiceInstruction {
- pub fn to_functor(&self) -> MachineStub {
+ pub fn to_functor(&self, h: usize) -> MachineStub {
match self {
+ &ChoiceInstruction::DynamicElse(birth, death, next_or_fail) => {
+ match (death, next_or_fail) {
+ (Death::Infinity, NextOrFail::Next(i)) => {
+ functor!(
+ "dynamic_else",
+ [integer(birth), atom("inf"), integer(i)]
+ )
+ }
+ (Death::Infinity, NextOrFail::Fail(i)) => {
+ let next_functor = functor!("fail", [integer(i)]);
+
+ functor!(
+ "dynamic_else",
+ [integer(birth), atom("inf"), aux(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Fail(i)) => {
+ let next_functor = functor!("fail", [integer(i)]);
+
+ functor!(
+ "dynamic_else",
+ [integer(birth), integer(d), aux(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Next(i)) => {
+ functor!(
+ "dynamic_else",
+ [integer(birth), integer(d), integer(i)]
+ )
+ }
+ }
+ }
+ &ChoiceInstruction::DynamicInternalElse(birth, death, next_or_fail) => {
+ match (death, next_or_fail) {
+ (Death::Infinity, NextOrFail::Next(i)) => {
+ functor!(
+ "dynamic_internal_else",
+ [integer(birth), atom("inf"), integer(i)]
+ )
+ }
+ (Death::Infinity, NextOrFail::Fail(i)) => {
+ let next_functor = functor!("fail", [integer(i)]);
+
+ functor!(
+ "dynamic_internal_else",
+ [integer(birth), atom("inf"), aux(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Fail(i)) => {
+ let next_functor = functor!("fail", [integer(i)]);
+
+ functor!(
+ "dynamic_internal_else",
+ [integer(birth), integer(d), aux(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Next(i)) => {
+ functor!(
+ "dynamic_internal_else",
+ [integer(birth), integer(d), integer(i)]
+ )
+ }
+ }
+ }
&ChoiceInstruction::TryMeElse(offset) => {
functor!("try_me_else", [integer(offset)])
}
pub enum IndexingLine {
Indexing(IndexingInstruction),
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
+ DynamicIndexedChoice(SliceDeque<usize>),
}
impl From<IndexingInstruction> for IndexingLine {
Fact(FactInstruction),
IndexingCode(Vec<IndexingLine>),
IndexedChoice(IndexedChoiceInstruction),
+ DynamicIndexedChoice(usize),
Query(QueryInstruction),
}
pub fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
match self {
&Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
- &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor()),
+ &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)),
&Line::Control(ref control_instr) => functors.push(control_instr.to_functor()),
&Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
&Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
functors.push(section);
}
}
+ IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
+ for indexed_choice_instr in indexed_choice_instrs {
+ let section = functor!("dynamic", [integer(*indexed_choice_instr)]);
+ h += section.len();
+ functors.push(section);
+ }
+ }
}
}
}
&Line::IndexedChoice(ref indexed_choice_instr) => {
functors.push(indexed_choice_instr.to_functor())
}
+ &Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
+ functors.push(functor!("dynamic", [integer(*indexed_choice_instr)]));
+ }
&Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
}
}
// The first index is the optimal argument being indexed.
SwitchOnTerm(
usize,
- usize,
+ IndexingCodePtr,
IndexingCodePtr,
IndexingCodePtr,
IndexingCodePtr,
"switch_on_term",
[
integer(arg),
- integer(vars),
+ indexing_code_ptr(h, vars),
indexing_code_ptr(h, constants),
indexing_code_ptr(h, lists),
indexing_code_ptr(h, structures)
; functor(H, Name, Arity) ->
( Name == '.' ->
throw(error(type_error(callable, H), clause/2))
- ; '$no_such_predicate'(Module, H) ->
- '$fail'
; '$head_is_dynamic'(Module, H) ->
'$clause_body_is_valid'(B),
Module:'$clause'(H, B)
+ ; '$no_such_predicate'(Module, H) ->
+ '$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2))
)
arg(1, H, Module),
arg(2, H, F),
'$module_clause'(F, B, Module)
- ; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if
- %% H is not callable.
- '$fail'
; '$head_is_dynamic'(user, H) ->
'$clause_body_is_valid'(B),
'$clause'(H, B)
+ ; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if
+ %% H is not callable.
+ '$fail'
; throw(error(permission_error(access, private_procedure, Name/Arity),
clause/2))
)
arg(1, Head, Module),
arg(2, Head, F),
module_asserta_clause(F, Body, Module)
- ; '$no_such_predicate'(user, Head) ->
- call_asserta(Head, Body, Name, Arity, user)
; '$head_is_dynamic'(user, Head) ->
call_asserta(Head, Body, Name, Arity, user)
+ ; '$no_such_predicate'(user, Head) ->
+ call_asserta(Head, Body, Name, Arity, user)
; throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1))
)
; throw(error(type_error(callable, Head), asserta/1))
; functor(Head, Name, Arity),
atom(Name),
Name \== '.' ->
- ( '$no_such_predicate'(Module, Head) ->
- call_assertz(Head, Body, Name, Arity, Module)
- ; '$head_is_dynamic'(Module, Head) ->
+ ( '$head_is_dynamic'(Module, Head) ->
call_assertz(Head, Body, Name, Arity, Module)
+ ; '$no_such_predicate'(Module, Head) ->
+ call_assertz(Head, Body, Name, Arity, Module)
; throw(error(permission_error(modify, static_procedure, Name/Arity),
assertz/1))
)
arg(1, Head, Module),
arg(2, Head, F),
module_assertz_clause(F, Body, Module)
- ; '$no_such_predicate'(user, Head) ->
- call_assertz(Head, Body, Name, Arity, user)
; '$head_is_dynamic'(user, Head) ->
call_assertz(Head, Body, Name, Arity, user)
+ ; '$no_such_predicate'(user, Head) ->
+ call_assertz(Head, Body, Name, Arity, user)
; throw(error(permission_error(modify, static_procedure, Name/Arity),
assertz/1))
)
module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :-
functor(VarHead, Name, Arity),
findall((VarHead :- VarBody), Module:'$clause'(VarHead, VarBody), Clauses1),
- first_match_index(Clauses1, (Head :- Body), 0, N),
+ ( first_match_index(Clauses1, (Head :- Body), 0, N) ->
+ '$retract_clause'(Name, Arity, N, Module)
+ ; Clause = (Head :- Body)
+ ),
( Clauses0 == [] -> !
; true
- ),
- '$retract_clause'(Name, Arity, N, Module).
+ ).
module_retract_clauses([_|Clauses0], Head, Body, Name, Arity, Module) :-
module_retract_clauses(Clauses0, Head, Body, Name, Arity, Module).
).
-first_match_index([Clause0 | Clauses], Clause1, N0, N) :-
- ( Clause0 \= Clause1 ->
- N1 is N0 + 1,
- first_match_index(Clauses, Clause1, N1, N)
- ; N0 = N,
- Clause0 = Clause1
- ).
+first_match_index([Clause | Clauses], Clause, N, N) :-
+ !.
+first_match_index([_ | Clauses], Clause, N0, N) :-
+ N1 is N0 + 1,
+ first_match_index(Clauses, Clause, N1, N).
retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :-
functor(VarHead, Name, Arity),
findall((VarHead :- VarBody), builtins:'$clause'(VarHead, VarBody), Clauses1),
- first_match_index(Clauses1, (Head :- Body), 0, N),
+ ( first_match_index(Clauses1, (Head :- Body), 0, N) ->
+ '$retract_clause'(Name, Arity, N, user)
+ ; Clause = (Head :- Body)
+ ),
( Clauses0 == [] -> !
; true
- ),
- '$retract_clause'(Name, Arity, N, user).
+ ).
retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :-
retract_clauses(Clauses0, Head, Body, Name, Arity).
; max_arity(N), Arity > N ->
throw(error(representation_error(max_arity), abolish/1))
; functor(Head, Name, Arity) ->
- ( '$no_such_predicate'(user, Head) ->
- true
- ; '$head_is_dynamic'(user, Head) ->
+ ( '$head_is_dynamic'(user, Head) ->
'$abolish_clause'(user, Name, Arity)
+ ; '$no_such_predicate'(user, Head) ->
+ true
; throw(error(permission_error(modify, static_procedure, Pred), abolish/1))
)
)
&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!()
}
&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,
}
-*/
}
}
}
&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);
}
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::*;
}
// 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();
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!()
}
}
-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!();
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,
));
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;
) {
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);
}
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!()
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));
) {
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));
*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 => {
*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),
}
}
+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,
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()
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,
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
}
};
- 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
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..));
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;
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!();
}
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)
}
} 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;
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)
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)
// 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)
}
}
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;
.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
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,
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..));
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 {
// 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)
}
}
}
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]
&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());
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;
}
};
- let settings = CodeGenSettings::new(true, non_counted_bt);
let atom_tbl = self.wam.machine_st.atom_tbl.clone();
let StandaloneCompileResult {
clause_code,
skeleton,
&mut self.retraction_info,
+ self.wam.machine_st.global_clock,
);
match self
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,
);
}
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
&compilation_target,
key,
&code_index,
- IndexPtr::Index(threaded_choice_instr_loc),
+ new_code_ptr,
);
Ok(())
}
}
+ 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(),
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;
}
}
- 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();
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,
);
}
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,
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);
}
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),
SliceDeque<usize>,
),
RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton),
+ ReplacedDynamicElseOffset(usize, usize),
+ AppendedNextOrFail(usize, NextOrFail),
}
/*
}
}
}
+ 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;
+ }
+ _ => {}
+ }
+ }
}
}
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,
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,
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,
#[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,
}
pub fn local(&self) -> Option<usize> {
match self.0.get() {
IndexPtr::Index(i) => Some(i),
+ IndexPtr::DynamicIndex(i) => Some(i),
_ => None,
}
}
}
}
-/*
-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 {
}
}
+#[derive(Debug)]
+pub enum FirstOrNext {
+ First,
+ Next,
+}
+
#[derive(Debug)]
pub struct MachineState {
pub(crate) atom_tbl: TabledData<Atom>,
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 {
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));
}
}
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))
}
last_call: false,
heap_locs: HeapVarDict::new(),
flags: MachineFlags::default(),
- at_end_of_expansion: false,
+ cc: 0,
+ global_clock: 0,
+ dynamic_mode: FirstOrNext::First,
}
}
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, ..)) => {
IndexingCodePtr::Fail
}
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
- IndexingCodePtr::External(v)
+ v
}
Addr::PStrLocation(..) => l,
Addr::Char(_)
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;
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;
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;
}
}
}
- &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;
}
};
}
+ 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,
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);
&Line::Choice(ref choice_instr) => {
self.execute_choice_instr(
choice_instr,
+ code_repo,
&mut policies.call_policy,
&mut indices.global_variables,
)
&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) => {
&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;
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!()
}
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!()
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let stub =
match $e {
+ IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]),
IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
match self {
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
&IndexPtr::Undefined => write!(f, "undefined"),
- &IndexPtr::Index(i) => write!(f, "{}", i),
+ &IndexPtr::DynamicIndex(i) | &IndexPtr::Index(i) => write!(f, "{}", i),
}
}
}
impl fmt::Display for ChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
+ &ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
+ write!(f, "dynamic_else {}, {}, {}", offset, "inf", i)
+ }
+ &ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
+ write!(f, "dynamic_else {}, {}, fail({})", offset, "inf", i)
+ }
+ &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
+ write!(f, "dynamic_else {}, {}, {}", offset, d, i)
+ }
+ &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
+ write!(f, "dynamic_else {}, {}, fail({})", offset, d, i)
+ }
+ &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
+ write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i)
+ }
+ &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
+ write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i)
+ }
+ &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
+ write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i)
+ }
+ &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
+ write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i)
+ }
&ChoiceInstruction::TryMeElse(offset) =>
write!(f, "try_me_else {}", offset),
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
impl fmt::Display for IndexingCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
+ &IndexingCodePtr::DynamicExternal(o) => {
+ write!(f, "IndexingCodePtr::DynamicExternal({})", o)
+ }
&IndexingCodePtr::External(o) => {
write!(f, "IndexingCodePtr::External({})", o)
}
write!(f, "{}", indexed_choice_instr)?;
}
+ Ok(())
+ }
+ &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
+ for indexed_choice_instr in indexed_choice_instrs {
+ write!(f, "dynamic({})", indexed_choice_instr)?;
+ }
+
Ok(())
}
}
Ok(())
}
&Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
+ &Line::DynamicIndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
&Line::Query(ref query_instr) => write!(f, "{}", query_instr),
}
}