implement logical update semantics for dynamic database predicates
This commit is contained in:
181
src/codegen.rs
181
src/codegen.rs
@@ -21,24 +21,6 @@ use std::cell::Cell;
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::rc::Rc;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct ConjunctInfo<'a> {
|
pub struct ConjunctInfo<'a> {
|
||||||
pub perm_vs: VariableFixtures<'a>,
|
pub perm_vs: VariableFixtures<'a>,
|
||||||
@@ -109,16 +91,93 @@ impl<'a> ConjunctInfo<'a> {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct CodeGenSettings {
|
pub struct CodeGenSettings {
|
||||||
|
pub global_clock_tick: Option<usize>,
|
||||||
pub is_extensible: bool,
|
pub is_extensible: bool,
|
||||||
pub non_counted_bt: bool,
|
pub non_counted_bt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeGenSettings {
|
impl CodeGenSettings {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(is_extensible: bool, non_counted_bt: bool) -> Self {
|
pub fn is_dynamic(&self) -> bool {
|
||||||
CodeGenSettings {
|
self.global_clock_tick.is_some()
|
||||||
is_extensible,
|
}
|
||||||
non_counted_bt,
|
|
||||||
|
#[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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,8 +187,7 @@ pub struct CodeGenerator<TermMarker> {
|
|||||||
atom_tbl: TabledData<Atom>,
|
atom_tbl: TabledData<Atom>,
|
||||||
marker: TermMarker,
|
marker: TermMarker,
|
||||||
pub var_count: IndexMap<Rc<Var>, usize>,
|
pub var_count: IndexMap<Rc<Var>, usize>,
|
||||||
non_counted_bt: bool,
|
settings: CodeGenSettings,
|
||||||
is_extensible: bool,
|
|
||||||
pub skeleton: PredicateSkeleton,
|
pub skeleton: PredicateSkeleton,
|
||||||
pub jmp_by_locs: Vec<usize>,
|
pub jmp_by_locs: Vec<usize>,
|
||||||
global_jmp_by_locs_offset: usize,
|
global_jmp_by_locs_offset: usize,
|
||||||
@@ -141,8 +199,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
atom_tbl,
|
atom_tbl,
|
||||||
marker: Allocator::new(),
|
marker: Allocator::new(),
|
||||||
var_count: IndexMap::new(),
|
var_count: IndexMap::new(),
|
||||||
non_counted_bt: settings.non_counted_bt,
|
settings,
|
||||||
is_extensible: settings.is_extensible,
|
|
||||||
skeleton: PredicateSkeleton::new(),
|
skeleton: PredicateSkeleton::new(),
|
||||||
jmp_by_locs: vec![],
|
jmp_by_locs: vec![],
|
||||||
global_jmp_by_locs_offset: 0,
|
global_jmp_by_locs_offset: 0,
|
||||||
@@ -889,27 +946,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
self.add_conditional_call(code, term, num_perm_vars_left);
|
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]
|
#[inline]
|
||||||
fn increment_jmp_by_locs_by(&mut self, incr: usize) {
|
fn increment_jmp_by_locs_by(&mut self, incr: usize) {
|
||||||
let offset = self.global_jmp_by_locs_offset;
|
let offset = self.global_jmp_by_locs_offset;
|
||||||
@@ -986,15 +1022,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
subseqs
|
subseqs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_pred_subseq<'b: 'a>(
|
fn compile_pred_subseq<'b: 'a, I: Indexer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
clauses: &'b [PredicateClause],
|
clauses: &'b [PredicateClause],
|
||||||
optimal_index: usize,
|
optimal_index: usize,
|
||||||
) -> Result<Code, CompilationError> {
|
) -> Result<Code, CompilationError> {
|
||||||
let mut code = VecDeque::new();
|
let mut code = VecDeque::new();
|
||||||
let mut code_offsets = CodeOffsets::new(self.atom_tbl.clone(), optimal_index + 1);
|
let mut code_offsets = CodeOffsets::new(
|
||||||
let mut skip_stub_try_me_else = false;
|
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();
|
let jmp_by_locs_len = self.jmp_by_locs.len();
|
||||||
|
|
||||||
for (i, clause) in clauses.iter().enumerate() {
|
for (i, clause) in clauses.iter().enumerate() {
|
||||||
@@ -1010,13 +1050,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
|
|
||||||
if clauses.len() > 1 {
|
if clauses.len() > 1 {
|
||||||
let choice = match i {
|
let choice = match i {
|
||||||
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
|
0 => self.settings.internal_try_me_else(clause_code.len() + 1),
|
||||||
_ if i == clauses.len() - 1 => trust_me(self.non_counted_bt),
|
//ChoiceInstruction::TryMeElse(clause_code.len() + 1),
|
||||||
_ => retry_me_else(clause_code.len() + 1, self.non_counted_bt),
|
_ 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));
|
code.push_back(Line::Choice(choice));
|
||||||
} else if self.is_extensible {
|
} else if self.settings.is_extensible {
|
||||||
/*
|
/*
|
||||||
generate stub choice instructions for extensible
|
generate stub choice instructions for extensible
|
||||||
predicates. if predicates are added to either the
|
predicates. if predicates are added to either the
|
||||||
@@ -1028,8 +1069,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
over them.
|
over them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
code.push_front(Line::Choice(ChoiceInstruction::TryMeElse(0)));
|
code.push_front(Line::Choice(self.settings.internal_try_me_else(0)));
|
||||||
skip_stub_try_me_else = true;
|
//Line::Choice(ChoiceInstruction::TryMeElse(0)));
|
||||||
|
skip_stub_try_me_else = !self.settings.is_dynamic(); //true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg = match clause.args() {
|
let arg = match clause.args() {
|
||||||
@@ -1045,7 +1087,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code_offsets.index_term(arg, index, &mut clause_index_info);
|
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());
|
self.increment_jmp_by_locs_by(code.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1065,7 +1107,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
} else {
|
} else {
|
||||||
self.increment_jmp_by_locs_by(1);
|
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).
|
// remove the TryMeElse(0).
|
||||||
code.pop_front();
|
code.pop_front();
|
||||||
}
|
}
|
||||||
@@ -1089,22 +1135,27 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
|
|
||||||
for (l, r) in split_pred {
|
for (l, r) in split_pred {
|
||||||
let skel_lower_bound = self.skeleton.clauses.len();
|
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();
|
let clause_start_offset = code.len();
|
||||||
|
|
||||||
if multi_seq {
|
if multi_seq {
|
||||||
let choice = match l {
|
let choice = match l {
|
||||||
0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1),
|
0 => self.settings.try_me_else(code_segment.len() + 1),
|
||||||
_ if r == clauses.len() => trust_me(self.non_counted_bt),
|
_ if r == clauses.len() => self.settings.trust_me(),
|
||||||
_ => retry_me_else(code_segment.len() + 1, self.non_counted_bt),
|
_ => self.settings.retry_me_else(code_segment.len() + 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
code.push(Line::Choice(choice));
|
code.push(Line::Choice(choice));
|
||||||
} else if self.is_extensible {
|
} else if self.settings.is_extensible {
|
||||||
code.push(Line::Choice(ChoiceInstruction::TryMeElse(0)));
|
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();
|
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() {
|
for clause_index_info in self.skeleton.clauses[skel_lower_bound..].iter_mut() {
|
||||||
|
|||||||
795
src/indexing.rs
795
src/indexing.rs
File diff suppressed because it is too large
Load Diff
@@ -46,8 +46,33 @@ impl ArithmeticTerm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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)]
|
#[derive(Debug)]
|
||||||
pub enum ChoiceInstruction {
|
pub enum ChoiceInstruction {
|
||||||
|
DynamicElse(usize, Death, NextOrFail),
|
||||||
|
DynamicInternalElse(usize, Death, NextOrFail),
|
||||||
DefaultRetryMeElse(usize),
|
DefaultRetryMeElse(usize),
|
||||||
DefaultTrustMe(usize),
|
DefaultTrustMe(usize),
|
||||||
RetryMeElse(usize),
|
RetryMeElse(usize),
|
||||||
@@ -56,8 +81,76 @@ pub enum ChoiceInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChoiceInstruction {
|
impl ChoiceInstruction {
|
||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self, h: usize) -> MachineStub {
|
||||||
match self {
|
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) => {
|
&ChoiceInstruction::TryMeElse(offset) => {
|
||||||
functor!("try_me_else", [integer(offset)])
|
functor!("try_me_else", [integer(offset)])
|
||||||
}
|
}
|
||||||
@@ -143,6 +236,7 @@ impl IndexedChoiceInstruction {
|
|||||||
pub enum IndexingLine {
|
pub enum IndexingLine {
|
||||||
Indexing(IndexingInstruction),
|
Indexing(IndexingInstruction),
|
||||||
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
|
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
|
||||||
|
DynamicIndexedChoice(SliceDeque<usize>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IndexingInstruction> for IndexingLine {
|
impl From<IndexingInstruction> for IndexingLine {
|
||||||
@@ -168,6 +262,7 @@ pub enum Line {
|
|||||||
Fact(FactInstruction),
|
Fact(FactInstruction),
|
||||||
IndexingCode(Vec<IndexingLine>),
|
IndexingCode(Vec<IndexingLine>),
|
||||||
IndexedChoice(IndexedChoiceInstruction),
|
IndexedChoice(IndexedChoiceInstruction),
|
||||||
|
DynamicIndexedChoice(usize),
|
||||||
Query(QueryInstruction),
|
Query(QueryInstruction),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +279,7 @@ impl Line {
|
|||||||
pub fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
|
pub fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
|
||||||
match self {
|
match self {
|
||||||
&Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
|
&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::Control(ref control_instr) => functors.push(control_instr.to_functor()),
|
||||||
&Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
|
&Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
|
||||||
&Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
|
&Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
|
||||||
@@ -203,12 +298,22 @@ impl Line {
|
|||||||
functors.push(section);
|
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) => {
|
&Line::IndexedChoice(ref indexed_choice_instr) => {
|
||||||
functors.push(indexed_choice_instr.to_functor())
|
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)),
|
&Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,7 +559,7 @@ pub enum IndexingInstruction {
|
|||||||
// The first index is the optimal argument being indexed.
|
// The first index is the optimal argument being indexed.
|
||||||
SwitchOnTerm(
|
SwitchOnTerm(
|
||||||
usize,
|
usize,
|
||||||
usize,
|
IndexingCodePtr,
|
||||||
IndexingCodePtr,
|
IndexingCodePtr,
|
||||||
IndexingCodePtr,
|
IndexingCodePtr,
|
||||||
IndexingCodePtr,
|
IndexingCodePtr,
|
||||||
@@ -471,7 +576,7 @@ impl IndexingInstruction {
|
|||||||
"switch_on_term",
|
"switch_on_term",
|
||||||
[
|
[
|
||||||
integer(arg),
|
integer(arg),
|
||||||
integer(vars),
|
indexing_code_ptr(h, vars),
|
||||||
indexing_code_ptr(h, constants),
|
indexing_code_ptr(h, constants),
|
||||||
indexing_code_ptr(h, lists),
|
indexing_code_ptr(h, lists),
|
||||||
indexing_code_ptr(h, structures)
|
indexing_code_ptr(h, structures)
|
||||||
|
|||||||
@@ -802,11 +802,11 @@ setof(Template, Goal, Solution) :-
|
|||||||
; functor(H, Name, Arity) ->
|
; functor(H, Name, Arity) ->
|
||||||
( Name == '.' ->
|
( Name == '.' ->
|
||||||
throw(error(type_error(callable, H), clause/2))
|
throw(error(type_error(callable, H), clause/2))
|
||||||
; '$no_such_predicate'(Module, H) ->
|
|
||||||
'$fail'
|
|
||||||
; '$head_is_dynamic'(Module, H) ->
|
; '$head_is_dynamic'(Module, H) ->
|
||||||
'$clause_body_is_valid'(B),
|
'$clause_body_is_valid'(B),
|
||||||
Module:'$clause'(H, B)
|
Module:'$clause'(H, B)
|
||||||
|
; '$no_such_predicate'(Module, H) ->
|
||||||
|
'$fail'
|
||||||
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||||
clause/2))
|
clause/2))
|
||||||
)
|
)
|
||||||
@@ -825,12 +825,12 @@ clause(H, B) :-
|
|||||||
arg(1, H, Module),
|
arg(1, H, Module),
|
||||||
arg(2, H, F),
|
arg(2, H, F),
|
||||||
'$module_clause'(F, B, Module)
|
'$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) ->
|
; '$head_is_dynamic'(user, H) ->
|
||||||
'$clause_body_is_valid'(B),
|
'$clause_body_is_valid'(B),
|
||||||
'$clause'(H, 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),
|
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||||
clause/2))
|
clause/2))
|
||||||
)
|
)
|
||||||
@@ -865,10 +865,10 @@ asserta_clause(Head, Body) :-
|
|||||||
arg(1, Head, Module),
|
arg(1, Head, Module),
|
||||||
arg(2, Head, F),
|
arg(2, Head, F),
|
||||||
module_asserta_clause(F, Body, Module)
|
module_asserta_clause(F, Body, Module)
|
||||||
; '$no_such_predicate'(user, Head) ->
|
|
||||||
call_asserta(Head, Body, Name, Arity, user)
|
|
||||||
; '$head_is_dynamic'(user, Head) ->
|
; '$head_is_dynamic'(user, Head) ->
|
||||||
call_asserta(Head, Body, Name, Arity, user)
|
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(permission_error(modify, static_procedure, Name/Arity), asserta/1))
|
||||||
)
|
)
|
||||||
; throw(error(type_error(callable, Head), asserta/1))
|
; throw(error(type_error(callable, Head), asserta/1))
|
||||||
@@ -889,10 +889,10 @@ module_assertz_clause(Head, Body, Module) :-
|
|||||||
; functor(Head, Name, Arity),
|
; functor(Head, Name, Arity),
|
||||||
atom(Name),
|
atom(Name),
|
||||||
Name \== '.' ->
|
Name \== '.' ->
|
||||||
( '$no_such_predicate'(Module, Head) ->
|
( '$head_is_dynamic'(Module, Head) ->
|
||||||
call_assertz(Head, Body, Name, Arity, Module)
|
|
||||||
; '$head_is_dynamic'(Module, Head) ->
|
|
||||||
call_assertz(Head, Body, Name, Arity, Module)
|
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),
|
; throw(error(permission_error(modify, static_procedure, Name/Arity),
|
||||||
assertz/1))
|
assertz/1))
|
||||||
)
|
)
|
||||||
@@ -916,10 +916,10 @@ assertz_clause(Head, Body) :-
|
|||||||
arg(1, Head, Module),
|
arg(1, Head, Module),
|
||||||
arg(2, Head, F),
|
arg(2, Head, F),
|
||||||
module_assertz_clause(F, Body, Module)
|
module_assertz_clause(F, Body, Module)
|
||||||
; '$no_such_predicate'(user, Head) ->
|
|
||||||
call_assertz(Head, Body, Name, Arity, user)
|
|
||||||
; '$head_is_dynamic'(user, Head) ->
|
; '$head_is_dynamic'(user, Head) ->
|
||||||
call_assertz(Head, Body, Name, Arity, user)
|
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),
|
; throw(error(permission_error(modify, static_procedure, Name/Arity),
|
||||||
assertz/1))
|
assertz/1))
|
||||||
)
|
)
|
||||||
@@ -939,11 +939,13 @@ assertz(Clause) :-
|
|||||||
module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :-
|
module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :-
|
||||||
functor(VarHead, Name, Arity),
|
functor(VarHead, Name, Arity),
|
||||||
findall((VarHead :- VarBody), Module:'$clause'(VarHead, VarBody), Clauses1),
|
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 == [] -> !
|
( Clauses0 == [] -> !
|
||||||
; true
|
; 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) :-
|
||||||
module_retract_clauses(Clauses0, Head, Body, Name, Arity, Module).
|
module_retract_clauses(Clauses0, Head, Body, Name, Arity, Module).
|
||||||
@@ -969,22 +971,22 @@ retract_module_clause(Head, Body, Module) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
first_match_index([Clause0 | Clauses], Clause1, N0, N) :-
|
first_match_index([Clause | Clauses], Clause, N, N) :-
|
||||||
( Clause0 \= Clause1 ->
|
!.
|
||||||
N1 is N0 + 1,
|
first_match_index([_ | Clauses], Clause, N0, N) :-
|
||||||
first_match_index(Clauses, Clause1, N1, N)
|
N1 is N0 + 1,
|
||||||
; N0 = N,
|
first_match_index(Clauses, Clause, N1, N).
|
||||||
Clause0 = Clause1
|
|
||||||
).
|
|
||||||
|
|
||||||
retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :-
|
retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :-
|
||||||
functor(VarHead, Name, Arity),
|
functor(VarHead, Name, Arity),
|
||||||
findall((VarHead :- VarBody), builtins:'$clause'(VarHead, VarBody), Clauses1),
|
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 == [] -> !
|
( Clauses0 == [] -> !
|
||||||
; true
|
; true
|
||||||
),
|
).
|
||||||
'$retract_clause'(Name, Arity, N, user).
|
|
||||||
|
|
||||||
retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :-
|
retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :-
|
||||||
retract_clauses(Clauses0, Head, Body, Name, Arity).
|
retract_clauses(Clauses0, Head, Body, Name, Arity).
|
||||||
@@ -1065,10 +1067,10 @@ abolish(Pred) :-
|
|||||||
; max_arity(N), Arity > N ->
|
; max_arity(N), Arity > N ->
|
||||||
throw(error(representation_error(max_arity), abolish/1))
|
throw(error(representation_error(max_arity), abolish/1))
|
||||||
; functor(Head, Name, Arity) ->
|
; functor(Head, Name, Arity) ->
|
||||||
( '$no_such_predicate'(user, Head) ->
|
( '$head_is_dynamic'(user, Head) ->
|
||||||
true
|
|
||||||
; '$head_is_dynamic'(user, Head) ->
|
|
||||||
'$abolish_clause'(user, Name, Arity)
|
'$abolish_clause'(user, Name, Arity)
|
||||||
|
; '$no_such_predicate'(user, Head) ->
|
||||||
|
true
|
||||||
; throw(error(permission_error(modify, static_procedure, Pred), abolish/1))
|
; throw(error(permission_error(modify, static_procedure, Pred), abolish/1))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ impl CodeRepo {
|
|||||||
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
|
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
|
||||||
RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
|
RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
|
||||||
}
|
}
|
||||||
|
&IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
|
||||||
|
RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[i]))
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -86,11 +89,98 @@ impl CodeRepo {
|
|||||||
&CodePtr::VerifyAttrInterrupt(p) => {
|
&CodePtr::VerifyAttrInterrupt(p) => {
|
||||||
Some(RefOrOwned::Borrowed(&self.code[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,
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
|
|||||||
&Line::Choice(ChoiceInstruction::RetryMeElse(offset)) if offset > 0 => {
|
&Line::Choice(ChoiceInstruction::RetryMeElse(offset)) if offset > 0 => {
|
||||||
stack.push(index + offset);
|
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)) => {
|
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
|
||||||
stack.push(index + offset);
|
stack.push(index + offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use prolog_parser::clause_name;
|
|||||||
|
|
||||||
use crate::codegen::*;
|
use crate::codegen::*;
|
||||||
use crate::debray_allocator::*;
|
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::load_state::*;
|
||||||
use crate::machine::loader::*;
|
use crate::machine::loader::*;
|
||||||
use crate::machine::preprocessor::*;
|
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.
|
// 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 mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
|
||||||
|
|
||||||
let tl = queue.pop_front().unwrap();
|
let tl = queue.pop_front().unwrap();
|
||||||
@@ -115,11 +120,22 @@ fn derelictize_try_me_else(
|
|||||||
retraction_info: &mut RetractionInfo,
|
retraction_info: &mut RetractionInfo,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
match &mut code[index] {
|
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(0)) => None,
|
||||||
Line::Choice(ChoiceInstruction::TryMeElse(ref mut offset)) => {
|
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
|
||||||
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *offset));
|
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o));
|
||||||
|
Some(mem::replace(o, 0))
|
||||||
Some(mem::replace(offset, 0))
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
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 {
|
loop {
|
||||||
match &code[index] {
|
match &code[index] {
|
||||||
Line::Choice(ChoiceInstruction::TryMeElse(o))
|
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(i))) |
|
||||||
| Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
|
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 {
|
if *o > 0 {
|
||||||
return index;
|
return index;
|
||||||
} else {
|
} else {
|
||||||
index = index_loc;
|
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(_)) => {
|
Line::Choice(ChoiceInstruction::TrustMe(_)) => {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
Line::IndexingCode(indexing_code) => match &indexing_code[0] {
|
Line::IndexingCode(indexing_code) => match &indexing_code[0] {
|
||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
|
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!();
|
unreachable!();
|
||||||
@@ -253,7 +326,7 @@ fn merge_indexed_subsequences(
|
|||||||
match &mut code[inner_try_me_else_loc] {
|
match &mut code[inner_try_me_else_loc] {
|
||||||
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
|
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
|
||||||
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
|
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
|
||||||
skeleton.clauses[upper_lower_bound].clause_start,
|
inner_try_me_else_loc,
|
||||||
*o,
|
*o,
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -357,9 +430,35 @@ fn blunt_leading_choice_instr(
|
|||||||
|
|
||||||
return instr_loc;
|
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
|
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));
|
code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0));
|
||||||
return instr_loc + 1;
|
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 target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
|
||||||
|
|
||||||
let v = match &mut target_indexing_line[0] {
|
let v = match &target_indexing_line[0] {
|
||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => *v,
|
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
|
||||||
|
match v {
|
||||||
|
IndexingCodePtr::External(v) | IndexingCodePtr::DynamicExternal(v) => v,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match &code[index_loc + v] {
|
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);
|
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] {
|
let old_v = match &mut target_indexing_line[0] {
|
||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => {
|
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!()
|
unreachable!()
|
||||||
@@ -432,6 +546,53 @@ fn internalize_choice_instr_at(
|
|||||||
retraction_info: &mut RetractionInfo,
|
retraction_info: &mut RetractionInfo,
|
||||||
) {
|
) {
|
||||||
match &mut code[instr_loc] {
|
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)) => {
|
Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
|
||||||
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0));
|
retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0));
|
||||||
|
|
||||||
@@ -465,8 +626,8 @@ fn thread_choice_instr_at_to(
|
|||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
match &mut code[instr_loc] {
|
match &mut code[instr_loc] {
|
||||||
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
|
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) |
|
||||||
| Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
|
Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
|
||||||
if target_loc >= instr_loc =>
|
if target_loc >= instr_loc =>
|
||||||
{
|
{
|
||||||
retraction_info.push_record(RetractionRecord::ReplacedChoiceOffset(instr_loc, *o));
|
retraction_info.push_record(RetractionRecord::ReplacedChoiceOffset(instr_loc, *o));
|
||||||
@@ -474,8 +635,20 @@ fn thread_choice_instr_at_to(
|
|||||||
*o = target_loc - instr_loc;
|
*o = target_loc - instr_loc;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
|
Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) |
|
||||||
| Line::Choice(ChoiceInstruction::RetryMeElse(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;
|
instr_loc += *o;
|
||||||
}
|
}
|
||||||
Line::Control(ControlInstruction::RevJmpBy(ref mut o)) if instr_loc >= target_loc => {
|
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;
|
*o = instr_loc - target_loc;
|
||||||
return;
|
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 => {
|
Line::Choice(ChoiceInstruction::TrustMe(ref mut o)) if target_loc >= instr_loc => {
|
||||||
retraction_info.push_record(
|
retraction_info.push_record(
|
||||||
RetractionRecord::AppendedTrustMe(instr_loc, *o, false),
|
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(
|
fn prepend_compiled_clause(
|
||||||
code: &mut Code,
|
code: &mut Code,
|
||||||
compilation_target: CompilationTarget,
|
compilation_target: CompilationTarget,
|
||||||
@@ -626,14 +860,25 @@ fn prepend_compiled_clause(
|
|||||||
mut clause_code: Code,
|
mut clause_code: Code,
|
||||||
skeleton: &mut PredicateSkeleton,
|
skeleton: &mut PredicateSkeleton,
|
||||||
retraction_info: &mut RetractionInfo,
|
retraction_info: &mut RetractionInfo,
|
||||||
) -> usize {
|
global_clock_tick: usize,
|
||||||
|
) -> IndexPtr {
|
||||||
let clause_loc = code.len();
|
let clause_loc = code.len();
|
||||||
let mut prepend_queue = sdeq![];
|
let mut prepend_queue = sdeq![];
|
||||||
|
|
||||||
let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num();
|
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 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
|
.opt_arg_index_key
|
||||||
.switch_on_term_loc()
|
.switch_on_term_loc()
|
||||||
.is_some()
|
.is_some()
|
||||||
@@ -650,7 +895,11 @@ fn prepend_compiled_clause(
|
|||||||
skeleton.clauses[0].clause_start,
|
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(
|
retraction_info.push_record(RetractionRecord::SkeletonClauseStartReplaced(
|
||||||
compilation_target,
|
compilation_target,
|
||||||
@@ -669,9 +918,9 @@ fn prepend_compiled_clause(
|
|||||||
inner_thread_rev_offset,
|
inner_thread_rev_offset,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
|
prepend_queue.push_front(Line::Choice(
|
||||||
prepend_queue.len(),
|
settings.internal_try_me_else(prepend_queue.len()),
|
||||||
)));
|
));
|
||||||
|
|
||||||
// prepend_queue is now:
|
// prepend_queue is now:
|
||||||
// | TryMeElse N_2
|
// | TryMeElse N_2
|
||||||
@@ -716,9 +965,9 @@ fn prepend_compiled_clause(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
|
prepend_queue.push_front(Line::Choice(
|
||||||
outer_thread_choice_offset,
|
settings.try_me_else(outer_thread_choice_offset),
|
||||||
)));
|
));
|
||||||
|
|
||||||
// prepend_queue is now:
|
// prepend_queue is now:
|
||||||
// | TryMeElse N_3
|
// | TryMeElse N_3
|
||||||
@@ -747,7 +996,11 @@ fn prepend_compiled_clause(
|
|||||||
|
|
||||||
code.extend(prepend_queue.into_iter());
|
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..));
|
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].opt_arg_index_key += clause_loc;
|
||||||
skeleton.clauses[0].clause_start = clause_loc + 2;
|
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 =
|
let inner_thread_rev_offset =
|
||||||
2 + prepend_queue.len() + clause_loc - old_clause_start;
|
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 => {
|
Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) if *o == 0 => {
|
||||||
*o = prepend_queue_len - 2;
|
*o = prepend_queue_len - 2;
|
||||||
}
|
}
|
||||||
|
Line::Choice(ChoiceInstruction::DynamicInternalElse(
|
||||||
|
_, _, ref mut o @ NextOrFail::Next(0),
|
||||||
|
)) => {
|
||||||
|
*o = NextOrFail::Fail(prepend_queue_len - 2);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
@@ -779,9 +1048,9 @@ fn prepend_compiled_clause(
|
|||||||
inner_thread_rev_offset,
|
inner_thread_rev_offset,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
|
prepend_queue.push_front(Line::Choice(
|
||||||
prepend_queue.len(),
|
settings.try_me_else(prepend_queue.len()),
|
||||||
)));
|
));
|
||||||
|
|
||||||
// prepend_queue is now:
|
// prepend_queue is now:
|
||||||
// | TryMeElse(N_2)
|
// | TryMeElse(N_2)
|
||||||
@@ -799,10 +1068,14 @@ fn prepend_compiled_clause(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() {
|
match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() {
|
||||||
Some(_) => {
|
Some(index_loc) => {
|
||||||
prepend_queue.extend(clause_code.drain(1..));
|
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 =
|
let inner_thread_rev_offset =
|
||||||
1 + prepend_queue.len() + clause_loc - old_clause_start;
|
1 + prepend_queue.len() + clause_loc - old_clause_start;
|
||||||
@@ -811,9 +1084,9 @@ fn prepend_compiled_clause(
|
|||||||
inner_thread_rev_offset,
|
inner_thread_rev_offset,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
|
prepend_queue.push_front(Line::Choice(
|
||||||
prepend_queue.len(),
|
settings.try_me_else(prepend_queue.len()),
|
||||||
)));
|
));
|
||||||
|
|
||||||
// prepend_queue is now:
|
// prepend_queue is now:
|
||||||
// | TryMeElse(N_2)
|
// | TryMeElse(N_2)
|
||||||
@@ -841,9 +1114,9 @@ fn prepend_compiled_clause(
|
|||||||
inner_thread_rev_offset,
|
inner_thread_rev_offset,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
prepend_queue.push_front(Line::Choice(ChoiceInstruction::TryMeElse(
|
prepend_queue.push_front(Line::Choice(
|
||||||
prepend_queue.len(),
|
settings.try_me_else(prepend_queue.len()),
|
||||||
)));
|
));
|
||||||
|
|
||||||
// prepend_queue is now:
|
// prepend_queue is now:
|
||||||
// | TryMeElse(N_2)
|
// | TryMeElse(N_2)
|
||||||
@@ -857,9 +1130,15 @@ fn prepend_compiled_clause(
|
|||||||
// skeleton.clauses[0].opt_arg_index_key += clause_loc;
|
// skeleton.clauses[0].opt_arg_index_key += clause_loc;
|
||||||
skeleton.clauses[0].clause_start = 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,
|
mut clause_code: Code,
|
||||||
skeleton: &mut PredicateSkeleton,
|
skeleton: &mut PredicateSkeleton,
|
||||||
retraction_info: &mut RetractionInfo,
|
retraction_info: &mut RetractionInfo,
|
||||||
) -> Option<usize> {
|
global_clock_tick: usize,
|
||||||
|
) -> Option<IndexPtr> {
|
||||||
let clause_loc = code.len();
|
let clause_loc = code.len();
|
||||||
let target_pos = skeleton.clauses.len() - 1;
|
let target_pos = skeleton.clauses.len() - 1;
|
||||||
let lower_bound = lower_bound_of_target_clause(skeleton, target_pos);
|
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;
|
skeleton.clauses[target_pos].clause_start = clause_loc;
|
||||||
|
|
||||||
let mut code_ptr_opt = None;
|
let mut code_ptr_opt = None;
|
||||||
@@ -886,6 +1175,8 @@ fn append_compiled_clause(
|
|||||||
.switch_on_term_loc()
|
.switch_on_term_loc()
|
||||||
{
|
{
|
||||||
Some(index_loc) if lower_bound_arg_num == target_arg_num => {
|
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
|
code.extend(clause_code.drain(3..)); // skip the indexing code
|
||||||
|
|
||||||
// set skeleton[target_pos].opt_arg_index_key to
|
// set skeleton[target_pos].opt_arg_index_key to
|
||||||
@@ -912,8 +1203,13 @@ fn append_compiled_clause(
|
|||||||
index_loc,
|
index_loc,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let target_pos_clause_start = find_outer_choice_instr(
|
||||||
|
code,
|
||||||
|
target_pos_clause_start,
|
||||||
|
);
|
||||||
|
|
||||||
if lower_bound + 1 == target_pos {
|
if lower_bound + 1 == target_pos {
|
||||||
set_switch_var_offset(
|
set_switch_var_offset_to_choice_instr(
|
||||||
code,
|
code,
|
||||||
index_loc,
|
index_loc,
|
||||||
target_pos_clause_start - 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
|
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;
|
skeleton.clauses[target_pos].opt_arg_index_key += clause_loc;
|
||||||
code.extend(clause_code.drain(1..));
|
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);
|
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 => {
|
None => {
|
||||||
if lower_bound == 0 {
|
if lower_bound == 0 {
|
||||||
@@ -953,12 +1251,14 @@ fn append_compiled_clause(
|
|||||||
// its variable offset.
|
// its variable offset.
|
||||||
skeleton.clauses[target_pos].clause_start += 2;
|
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 => {}
|
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);
|
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]
|
#[inline]
|
||||||
@@ -1139,7 +1445,11 @@ impl<'a> LoadState<'a> {
|
|||||||
&predicates.compilation_target,
|
&predicates.compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
&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());
|
self.wam.code_repo.code.extend(code.into_iter());
|
||||||
@@ -1191,15 +1501,36 @@ impl<'a> LoadState<'a> {
|
|||||||
append_or_prepend,
|
append_or_prepend,
|
||||||
);
|
);
|
||||||
|
|
||||||
match self
|
let settings = match self
|
||||||
.wam
|
.wam
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton_mut(&compilation_target, &key)
|
.get_predicate_skeleton_mut(&compilation_target, &key)
|
||||||
{
|
{
|
||||||
Some(skeleton) if !skeleton.clauses.is_empty() => {},
|
Some(skeleton) if !skeleton.clauses.is_empty() => {
|
||||||
_ => {
|
CodeGenSettings {
|
||||||
// true because this predicate is extensible.
|
global_clock_tick: if skeleton.is_dynamic {
|
||||||
let settings = CodeGenSettings::new(true, non_counted_bt);
|
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];
|
let mut predicate_queue = predicate_queue![clause];
|
||||||
predicate_queue.compilation_target = compilation_target;
|
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 atom_tbl = self.wam.machine_st.atom_tbl.clone();
|
||||||
|
|
||||||
let StandaloneCompileResult {
|
let StandaloneCompileResult {
|
||||||
@@ -1245,6 +1575,7 @@ impl<'a> LoadState<'a> {
|
|||||||
clause_code,
|
clause_code,
|
||||||
skeleton,
|
skeleton,
|
||||||
&mut self.retraction_info,
|
&mut self.retraction_info,
|
||||||
|
self.wam.machine_st.global_clock,
|
||||||
);
|
);
|
||||||
|
|
||||||
match self
|
match self
|
||||||
@@ -1284,13 +1615,13 @@ impl<'a> LoadState<'a> {
|
|||||||
compilation_target.clone(),
|
compilation_target.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(new_code_index) = result {
|
if let Some(new_code_ptr) = result {
|
||||||
set_code_index(
|
set_code_index(
|
||||||
&mut self.retraction_info,
|
&mut self.retraction_info,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
&code_index,
|
||||||
IndexPtr::Index(new_code_index),
|
new_code_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1309,13 +1640,14 @@ impl<'a> LoadState<'a> {
|
|||||||
key.clone(),
|
key.clone(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let threaded_choice_instr_loc = prepend_compiled_clause(
|
let new_code_ptr = prepend_compiled_clause(
|
||||||
&mut self.wam.code_repo.code,
|
&mut self.wam.code_repo.code,
|
||||||
compilation_target.clone(),
|
compilation_target.clone(),
|
||||||
key.clone(),
|
key.clone(),
|
||||||
clause_code,
|
clause_code,
|
||||||
skeleton,
|
skeleton,
|
||||||
&mut self.retraction_info,
|
&mut self.retraction_info,
|
||||||
|
self.wam.machine_st.global_clock,
|
||||||
);
|
);
|
||||||
|
|
||||||
match self
|
match self
|
||||||
@@ -1360,7 +1692,7 @@ impl<'a> LoadState<'a> {
|
|||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
&code_index,
|
||||||
IndexPtr::Index(threaded_choice_instr_loc),
|
new_code_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
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 {
|
pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
|
||||||
let code_index = self.get_or_insert_code_index(
|
let code_index = self.get_or_insert_code_index(
|
||||||
key.clone(),
|
key.clone(),
|
||||||
@@ -1835,6 +2212,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
|
|||||||
clause_clause_compilation_target,
|
clause_clause_compilation_target,
|
||||||
(clause_name!("$clause"), 2),
|
(clause_name!("$clause"), 2),
|
||||||
(0 .. skeleton.clauses.len()).map(Some).collect(),
|
(0 .. skeleton.clauses.len()).map(Some).collect(),
|
||||||
|
false, // the builtin M:'$clause'/2 is never dynamic.
|
||||||
);
|
);
|
||||||
|
|
||||||
predicate_info.is_dynamic = false;
|
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)?;
|
self.load_state.compile(key.clone(), &mut self.predicates, settings)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if predicate_info.is_dynamic {
|
if predicate_info.is_dynamic {
|
||||||
|
self.load_state.wam.machine_st.global_clock += 1;
|
||||||
|
|
||||||
let clauses_vec: Vec<_> = self.clause_clauses
|
let clauses_vec: Vec<_> = self.clause_clauses
|
||||||
.drain(0 .. predicates_len)
|
.drain(0 .. predicates_len)
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -346,25 +346,27 @@ impl<'a> LoadState<'a> {
|
|||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
clause_locs: &SliceDeque<usize>,
|
clause_locs: &SliceDeque<usize>,
|
||||||
) {
|
) {
|
||||||
let clause_target_poses: Vec<_> = self
|
let (clause_target_poses, is_dynamic) = self
|
||||||
.wam
|
.wam
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton(&compilation_target, &key)
|
.get_predicate_skeleton(&compilation_target, &key)
|
||||||
.map(|skeleton| {
|
.map(|skeleton| {
|
||||||
clause_locs
|
(clause_locs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|clause_clause_loc| {
|
.map(|clause_clause_loc| {
|
||||||
skeleton.target_pos_of_clause_clause_loc(
|
skeleton.target_pos_of_clause_clause_loc(
|
||||||
*clause_clause_loc,
|
*clause_clause_loc,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect(),
|
||||||
|
skeleton.is_dynamic)
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
self.retract_local_clauses_by_locs(
|
self.retract_local_clauses_by_locs(
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
clause_target_poses,
|
clause_target_poses,
|
||||||
|
is_dynamic,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,6 +375,7 @@ impl<'a> LoadState<'a> {
|
|||||||
compilation_target: CompilationTarget,
|
compilation_target: CompilationTarget,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
mut clause_target_poses: Vec<Option<usize>>,
|
mut clause_target_poses: Vec<Option<usize>>,
|
||||||
|
is_dynamic: bool,
|
||||||
) {
|
) {
|
||||||
let old_compilation_target = mem::replace(
|
let old_compilation_target = mem::replace(
|
||||||
&mut self.compilation_target,
|
&mut self.compilation_target,
|
||||||
@@ -381,6 +384,9 @@ impl<'a> LoadState<'a> {
|
|||||||
|
|
||||||
while let Some(target_pos_opt) = clause_target_poses.pop() {
|
while let Some(target_pos_opt) = clause_target_poses.pop() {
|
||||||
match target_pos_opt {
|
match target_pos_opt {
|
||||||
|
Some(target_pos) if is_dynamic => {
|
||||||
|
self.retract_dynamic_clause(key.clone(), target_pos);
|
||||||
|
}
|
||||||
Some(target_pos) => {
|
Some(target_pos) => {
|
||||||
self.retract_clause(key.clone(), target_pos);
|
self.retract_clause(key.clone(), target_pos);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ pub(crate) enum RetractionRecord {
|
|||||||
RemovedIndex(usize, OptArgIndexKey, usize),
|
RemovedIndex(usize, OptArgIndexKey, usize),
|
||||||
ReplacedChoiceOffset(usize, usize),
|
ReplacedChoiceOffset(usize, usize),
|
||||||
AppendedTrustMe(usize, usize, bool),
|
AppendedTrustMe(usize, usize, bool),
|
||||||
ReplacedSwitchOnTermVarIndex(usize, usize),
|
ReplacedSwitchOnTermVarIndex(usize, IndexingCodePtr),
|
||||||
ModifiedTryMeElse(usize, usize),
|
ModifiedTryMeElse(usize, usize),
|
||||||
ModifiedRetryMeElse(usize, usize),
|
ModifiedRetryMeElse(usize, usize),
|
||||||
ModifiedRevJmpBy(usize, usize),
|
ModifiedRevJmpBy(usize, usize),
|
||||||
@@ -94,6 +94,8 @@ pub(crate) enum RetractionRecord {
|
|||||||
SliceDeque<usize>,
|
SliceDeque<usize>,
|
||||||
),
|
),
|
||||||
RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton),
|
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),
|
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(
|
loader.load_state.incremental_compile_clause(
|
||||||
key.clone(),
|
key.clone(),
|
||||||
asserted_clause,
|
asserted_clause,
|
||||||
@@ -1728,13 +1763,8 @@ impl Machine {
|
|||||||
append_or_prepend,
|
append_or_prepend,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// if a new predicate was just created, make it dynamic.
|
// the global clock is incremented after each assertion.
|
||||||
loader
|
loader.load_state.wam.machine_st.global_clock += 1;
|
||||||
.load_state
|
|
||||||
.wam
|
|
||||||
.indices
|
|
||||||
.get_predicate_skeleton_mut(&compilation_target, &key)
|
|
||||||
.map(|skeleton| skeleton.is_dynamic = true);
|
|
||||||
|
|
||||||
loader.compile_clause_clauses(
|
loader.compile_clause_clauses(
|
||||||
key,
|
key,
|
||||||
@@ -1883,7 +1913,10 @@ impl Machine {
|
|||||||
let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
|
let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self);
|
||||||
loader.load_state.compilation_target = compilation_target;
|
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(
|
let target_pos = match loader.load_state.wam.indices.get_predicate_skeleton(
|
||||||
&clause_clause_compilation_target,
|
&clause_clause_compilation_target,
|
||||||
|
|||||||
@@ -372,6 +372,7 @@ impl From<Addr> for HeapCellValue {
|
|||||||
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
pub enum IndexPtr {
|
pub enum IndexPtr {
|
||||||
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||||
|
DynamicIndex(usize),
|
||||||
Index(usize),
|
Index(usize),
|
||||||
Undefined,
|
Undefined,
|
||||||
}
|
}
|
||||||
@@ -405,6 +406,7 @@ impl CodeIndex {
|
|||||||
pub fn local(&self) -> Option<usize> {
|
pub fn local(&self) -> Option<usize> {
|
||||||
match self.0.get() {
|
match self.0.get() {
|
||||||
IndexPtr::Index(i) => Some(i),
|
IndexPtr::Index(i) => Some(i),
|
||||||
|
IndexPtr::DynamicIndex(i) => Some(i),
|
||||||
_ => None,
|
_ => 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 {
|
impl Default for CodePtr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|||||||
@@ -269,6 +269,12 @@ impl Default for HeapPtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FirstOrNext {
|
||||||
|
First,
|
||||||
|
Next,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MachineState {
|
pub struct MachineState {
|
||||||
pub(crate) atom_tbl: TabledData<Atom>,
|
pub(crate) atom_tbl: TabledData<Atom>,
|
||||||
@@ -295,7 +301,9 @@ pub struct MachineState {
|
|||||||
pub(super) last_call: bool,
|
pub(super) last_call: bool,
|
||||||
pub(crate) heap_locs: HeapVarDict,
|
pub(crate) heap_locs: HeapVarDict,
|
||||||
pub(crate) flags: MachineFlags,
|
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 {
|
impl MachineState {
|
||||||
@@ -911,8 +919,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
|
|||||||
IndexPtr::Undefined => {
|
IndexPtr::Undefined => {
|
||||||
return Err(machine_st.throw_undefined_error(name, arity));
|
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) => {
|
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 => {
|
IndexPtr::Undefined => {
|
||||||
return Err(machine_st.throw_undefined_error(name, arity));
|
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) => {
|
IndexPtr::Index(compiled_tl_index) => {
|
||||||
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
|
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ impl MachineState {
|
|||||||
last_call: false,
|
last_call: false,
|
||||||
heap_locs: HeapVarDict::new(),
|
heap_locs: HeapVarDict::new(),
|
||||||
flags: MachineFlags::default(),
|
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(
|
pub(super) fn execute_indexing_instr(
|
||||||
&mut self,
|
&mut self,
|
||||||
indexing_lines: &Vec<IndexingLine>,
|
indexing_lines: &Vec<IndexingLine>,
|
||||||
call_policy: &mut Box<dyn CallPolicy>,
|
code_repo: &CodeRepo,
|
||||||
global_variables: &mut GlobalVarDir,
|
|
||||||
) {
|
) {
|
||||||
|
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 mut index = 0;
|
||||||
let addr = match &indexing_lines[0] {
|
let addr = match &indexing_lines[0] {
|
||||||
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
|
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
|
||||||
@@ -1323,7 +1351,7 @@ impl MachineState {
|
|||||||
IndexingCodePtr::Fail
|
IndexingCodePtr::Fail
|
||||||
}
|
}
|
||||||
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
|
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
|
||||||
IndexingCodePtr::External(v)
|
v
|
||||||
}
|
}
|
||||||
Addr::PStrLocation(..) => l,
|
Addr::PStrLocation(..) => l,
|
||||||
Addr::Char(_)
|
Addr::Char(_)
|
||||||
@@ -1342,6 +1370,20 @@ impl MachineState {
|
|||||||
self.fail = true;
|
self.fail = true;
|
||||||
break;
|
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) => {
|
IndexingCodePtr::External(o) => {
|
||||||
self.p += o;
|
self.p += o;
|
||||||
break;
|
break;
|
||||||
@@ -1365,6 +1407,20 @@ impl MachineState {
|
|||||||
self.fail = true;
|
self.fail = true;
|
||||||
break;
|
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) => {
|
IndexingCodePtr::External(o) => {
|
||||||
self.p += o;
|
self.p += o;
|
||||||
break;
|
break;
|
||||||
@@ -1394,6 +1450,17 @@ impl MachineState {
|
|||||||
self.fail = true;
|
self.fail = true;
|
||||||
break;
|
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) => {
|
IndexingCodePtr::External(o) => {
|
||||||
self.p += o;
|
self.p += o;
|
||||||
break;
|
break;
|
||||||
@@ -1403,18 +1470,23 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&IndexingLine::IndexedChoice(ref instrs) => {
|
&IndexingLine::IndexedChoice(_) => {
|
||||||
if let LocalCodePtr::DirEntry(p) = self.p.local() {
|
if let LocalCodePtr::DirEntry(p) = self.p.local() {
|
||||||
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
|
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.execute_indexed_choice_instr(
|
break;
|
||||||
instrs.first().unwrap(),
|
}
|
||||||
call_policy,
|
&IndexingLine::DynamicIndexedChoice(_) => {
|
||||||
global_variables,
|
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;
|
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(
|
pub(super) fn execute_indexed_choice_instr(
|
||||||
&mut self,
|
&mut self,
|
||||||
instr: &IndexedChoiceInstruction,
|
instr: &IndexedChoiceInstruction,
|
||||||
@@ -3073,10 +3252,187 @@ impl MachineState {
|
|||||||
pub(super) fn execute_choice_instr(
|
pub(super) fn execute_choice_instr(
|
||||||
&mut self,
|
&mut self,
|
||||||
instr: &ChoiceInstruction,
|
instr: &ChoiceInstruction,
|
||||||
|
code_repo: &CodeRepo,
|
||||||
call_policy: &mut Box<dyn CallPolicy>,
|
call_policy: &mut Box<dyn CallPolicy>,
|
||||||
global_variables: &mut GlobalVarDir,
|
global_variables: &mut GlobalVarDir,
|
||||||
) {
|
) {
|
||||||
match instr {
|
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) => {
|
&ChoiceInstruction::TryMeElse(offset) => {
|
||||||
let n = self.num_of_args;
|
let n = self.num_of_args;
|
||||||
let b = self.stack.allocate_or_frame(n);
|
let b = self.stack.allocate_or_frame(n);
|
||||||
|
|||||||
@@ -562,6 +562,7 @@ impl MachineState {
|
|||||||
&Line::Choice(ref choice_instr) => {
|
&Line::Choice(ref choice_instr) => {
|
||||||
self.execute_choice_instr(
|
self.execute_choice_instr(
|
||||||
choice_instr,
|
choice_instr,
|
||||||
|
code_repo,
|
||||||
&mut policies.call_policy,
|
&mut policies.call_policy,
|
||||||
&mut indices.global_variables,
|
&mut indices.global_variables,
|
||||||
)
|
)
|
||||||
@@ -585,8 +586,7 @@ impl MachineState {
|
|||||||
&Line::IndexingCode(ref indexing_lines) => {
|
&Line::IndexingCode(ref indexing_lines) => {
|
||||||
self.execute_indexing_instr(
|
self.execute_indexing_instr(
|
||||||
indexing_lines,
|
indexing_lines,
|
||||||
&mut policies.call_policy,
|
code_repo,
|
||||||
&mut indices.global_variables,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
&Line::IndexedChoice(ref choice_instr) => {
|
&Line::IndexedChoice(ref choice_instr) => {
|
||||||
@@ -596,6 +596,13 @@ impl MachineState {
|
|||||||
&mut indices.global_variables,
|
&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) => {
|
&Line::Query(ref query_instr) => {
|
||||||
self.execute_query_instr(&query_instr);
|
self.execute_query_instr(&query_instr);
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
|
|||||||
@@ -3496,14 +3496,16 @@ impl MachineState {
|
|||||||
|
|
||||||
self.fail = match self.store(self.deref(self[temp_v!(2)])) {
|
self.fail = match self.store(self.deref(self[temp_v!(2)])) {
|
||||||
Addr::Str(s) => match &self.heap[s] {
|
Addr::Str(s) => match &self.heap[s] {
|
||||||
&HeapCellValue::NamedStr(arity, ref name, ref spec) => indices
|
&HeapCellValue::NamedStr(arity, ref name, ref spec) => {
|
||||||
.get_predicate_code_index(
|
CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), arity)).is_some() ||
|
||||||
|
indices.get_predicate_code_index(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
arity,
|
arity,
|
||||||
module_name,
|
module_name,
|
||||||
spec.clone(),
|
spec.clone(),
|
||||||
)
|
)
|
||||||
.is_some(),
|
.is_some()
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -3513,8 +3515,8 @@ impl MachineState {
|
|||||||
let spec =
|
let spec =
|
||||||
fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir);
|
fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir);
|
||||||
|
|
||||||
indices
|
CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), 0)).is_some() ||
|
||||||
.get_predicate_code_index(name.clone(), 0, module_name, spec)
|
indices.get_predicate_code_index(name.clone(), 0, module_name, spec)
|
||||||
.is_some()
|
.is_some()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ macro_rules! functor_term {
|
|||||||
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||||
let stub =
|
let stub =
|
||||||
match $e {
|
match $e {
|
||||||
|
IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]),
|
||||||
IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
|
IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
|
||||||
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
|
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
|
||||||
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
|
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
|
||||||
|
|||||||
37
src/write.rs
37
src/write.rs
@@ -96,7 +96,7 @@ impl fmt::Display for IndexPtr {
|
|||||||
match self {
|
match self {
|
||||||
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
|
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
|
||||||
&IndexPtr::Undefined => write!(f, "undefined"),
|
&IndexPtr::Undefined => write!(f, "undefined"),
|
||||||
&IndexPtr::Index(i) => write!(f, "{}", i),
|
&IndexPtr::DynamicIndex(i) | &IndexPtr::Index(i) => write!(f, "{}", i),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,6 +339,30 @@ impl fmt::Display for IndexedChoiceInstruction {
|
|||||||
impl fmt::Display for ChoiceInstruction {
|
impl fmt::Display for ChoiceInstruction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
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) =>
|
&ChoiceInstruction::TryMeElse(offset) =>
|
||||||
write!(f, "try_me_else {}", offset),
|
write!(f, "try_me_else {}", offset),
|
||||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
||||||
@@ -357,6 +381,9 @@ impl fmt::Display for ChoiceInstruction {
|
|||||||
impl fmt::Display for IndexingCodePtr {
|
impl fmt::Display for IndexingCodePtr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
&IndexingCodePtr::DynamicExternal(o) => {
|
||||||
|
write!(f, "IndexingCodePtr::DynamicExternal({})", o)
|
||||||
|
}
|
||||||
&IndexingCodePtr::External(o) => {
|
&IndexingCodePtr::External(o) => {
|
||||||
write!(f, "IndexingCodePtr::External({})", o)
|
write!(f, "IndexingCodePtr::External({})", o)
|
||||||
}
|
}
|
||||||
@@ -480,6 +507,13 @@ impl fmt::Display for IndexingLine {
|
|||||||
write!(f, "{}", indexed_choice_instr)?;
|
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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,6 +536,7 @@ impl fmt::Display for Line {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
&Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
|
&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),
|
&Line::Query(ref query_instr) => write!(f, "{}", query_instr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user