variable revision
This commit is contained in:
@@ -1156,7 +1156,7 @@ impl MachineState {
|
||||
) -> Result<Number, MachineStub> {
|
||||
let stub_gen = || functor_stub(atom!("is"), 2);
|
||||
|
||||
let root_loc = if value.is_ref() {
|
||||
let root_loc = if value.is_ref() && !value.is_stack_var() {
|
||||
value.get_value() as usize
|
||||
} else {
|
||||
let type_error = self.type_error(ValidType::Evaluable, value);
|
||||
|
||||
@@ -2283,40 +2283,36 @@ impl Machine {
|
||||
term_reg: RegType,
|
||||
vars: Vec<HeapCellValue>,
|
||||
) -> Result<(), SessionError> {
|
||||
let cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
|
||||
|
||||
// append the variables of vars.
|
||||
let focus = cell.get_value() as usize;
|
||||
let header_loc = term_nth_arg(&self.machine_st.heap, focus, 0).unwrap();
|
||||
let name = term_name(&self.machine_st.heap, header_loc).unwrap();
|
||||
let old_arity = term_arity(&self.machine_st.heap, header_loc);
|
||||
let body_cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
|
||||
|
||||
let new_header_loc = self.machine_st.heap.len();
|
||||
let new_arity = old_arity + vars.len();
|
||||
let arity = vars.len();
|
||||
|
||||
self.machine_st.heap.push(atom_as_cell!(name, new_arity));
|
||||
|
||||
for idx in header_loc + 1 .. header_loc + 1 + old_arity {
|
||||
self.machine_st.heap.push(self.machine_st.heap[idx]);
|
||||
}
|
||||
self.machine_st.heap.push(atom_as_cell!(atom!(""), arity));
|
||||
|
||||
for var in vars {
|
||||
self.machine_st.heap.push(var);
|
||||
}
|
||||
|
||||
let value = if new_arity > 0 {
|
||||
let head_loc = if arity > 0 {
|
||||
str_loc_as_cell!(new_header_loc)
|
||||
} else {
|
||||
heap_loc_as_cell!(new_header_loc)
|
||||
};
|
||||
|
||||
let mut compile = |cell| {
|
||||
let term_loc = self.machine_st.heap.len();
|
||||
|
||||
self.machine_st.heap.push(atom_as_cell!(atom!(":-"), 2));
|
||||
self.machine_st.heap.push(head_loc);
|
||||
self.machine_st.heap.push(body_cell);
|
||||
|
||||
let mut compile = || {
|
||||
use crate::heap_iter::eager_stackful_preorder_iter;
|
||||
|
||||
let mut loader: Loader<'_, InlineLoadState<'_>> =
|
||||
Loader::new(self, InlineTermStream {});
|
||||
|
||||
let mut term = loader.copy_term_from_heap(cell);
|
||||
let mut term = loader.copy_term_from_heap(str_loc_as_cell!(term_loc));
|
||||
|
||||
let settings = CodeGenSettings {
|
||||
global_clock_tick: None,
|
||||
@@ -2326,14 +2322,14 @@ impl Machine {
|
||||
|
||||
let value = term.heap[term.focus];
|
||||
|
||||
term.var_locs = var_locs_from_iter(
|
||||
term.inverse_var_locs = inverse_var_locs_from_iter(
|
||||
eager_stackful_preorder_iter(&mut term.heap, value),
|
||||
);
|
||||
|
||||
loader.compile_standalone_clause(term, settings)
|
||||
};
|
||||
|
||||
let StandaloneCompileResult { clause_code, .. } = compile(value)?;
|
||||
let StandaloneCompileResult { clause_code, .. } = compile()?;
|
||||
self.code.extend(clause_code);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -80,9 +80,34 @@ impl BranchNumber {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ClassifiedVar {
|
||||
Anon { term_loc: usize },
|
||||
InSitu { var_num: usize },
|
||||
Generated { term_loc: usize },
|
||||
}
|
||||
|
||||
impl ClassifiedVar {
|
||||
fn term_loc(&self) -> Option<usize> {
|
||||
if let &ClassifiedVar::Generated { term_loc } = self {
|
||||
Some(term_loc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_classified_var(inverse_var_locs: &InverseVarLocs, term_loc: usize) -> ClassifiedVar {
|
||||
if inverse_var_locs.contains_key(&term_loc) {
|
||||
ClassifiedVar::Generated { term_loc }
|
||||
} else {
|
||||
ClassifiedVar::Anon { term_loc }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VarInfo {
|
||||
var_ptr: VarPtr,
|
||||
var: ClassifiedVar,
|
||||
chunk_type: ChunkType,
|
||||
classify_info: ClassifyInfo,
|
||||
lvl: Level,
|
||||
@@ -90,7 +115,6 @@ pub struct VarInfo {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ChunkInfo {
|
||||
chunk_num: usize,
|
||||
term_loc: GenContext,
|
||||
// pointer to incidence, term occurrence arity.
|
||||
vars: Vec<VarInfo>,
|
||||
@@ -111,7 +135,7 @@ impl BranchInfo {
|
||||
}
|
||||
}
|
||||
|
||||
type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
|
||||
type BranchMapInt = IndexMap<ClassifiedVar, Vec<BranchInfo>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BranchMap(BranchMapInt);
|
||||
@@ -174,8 +198,6 @@ enum TraversalState {
|
||||
pub struct VariableClassifier {
|
||||
call_policy: CallPolicy,
|
||||
current_branch_num: BranchNumber,
|
||||
current_chunk_num: usize,
|
||||
current_chunk_type: ChunkType,
|
||||
branch_map: BranchMap,
|
||||
var_num: usize,
|
||||
root_set: RootSet,
|
||||
@@ -183,11 +205,42 @@ pub struct VariableClassifier {
|
||||
global_cut_var_num_override: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct VarPtrIndex {
|
||||
pub chunk_num: usize,
|
||||
pub term_loc: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VarPtr {
|
||||
Numbered(usize),
|
||||
Anon,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct VarLocsToNums {
|
||||
map: IndexMap<VarPtrIndex, usize>,
|
||||
}
|
||||
|
||||
impl VarLocsToNums {
|
||||
pub fn insert(&mut self, key: VarPtrIndex, var_num: usize) {
|
||||
self.map.insert(key, var_num);
|
||||
}
|
||||
|
||||
pub fn get(&self, idx: VarPtrIndex) -> VarPtr {
|
||||
self.map.get(&idx)
|
||||
.cloned()
|
||||
.map(VarPtr::Numbered)
|
||||
.unwrap_or_else(|| VarPtr::Anon)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct VarData {
|
||||
pub records: VariableRecords,
|
||||
pub global_cut_var_num: Option<usize>,
|
||||
pub allocates: bool,
|
||||
pub var_locs_to_nums: VarLocsToNums,
|
||||
}
|
||||
|
||||
impl VarData {
|
||||
@@ -211,10 +264,13 @@ impl VarData {
|
||||
|
||||
match build_stack.front_mut() {
|
||||
Some(ChunkedTerms::Branch(_)) => {
|
||||
build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
||||
build_stack.push_front(ChunkedTerms::Chunk {
|
||||
chunk_num: 0,
|
||||
terms: VecDeque::from(vec![term]),
|
||||
});
|
||||
}
|
||||
Some(ChunkedTerms::Chunk(chunk)) => {
|
||||
chunk.push_front(term);
|
||||
Some(ChunkedTerms::Chunk { terms, .. }) => {
|
||||
terms.push_front(term);
|
||||
}
|
||||
None => {
|
||||
unreachable!()
|
||||
@@ -256,8 +312,6 @@ impl VariableClassifier {
|
||||
Self {
|
||||
call_policy,
|
||||
current_branch_num: BranchNumber::default(),
|
||||
current_chunk_num: 0,
|
||||
current_chunk_type: ChunkType::Head,
|
||||
branch_map: BranchMap(BranchMapInt::new()),
|
||||
root_set: RootSet::new(),
|
||||
var_num: 0,
|
||||
@@ -276,7 +330,7 @@ impl VariableClassifier {
|
||||
Ok(self.branch_map.separate_and_classify_variables(
|
||||
self.var_num,
|
||||
self.global_cut_var_num,
|
||||
self.current_chunk_num,
|
||||
0,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -298,7 +352,7 @@ impl VariableClassifier {
|
||||
let mut var_data = self.branch_map.separate_and_classify_variables(
|
||||
self.var_num,
|
||||
self.global_cut_var_num,
|
||||
self.current_chunk_num,
|
||||
query_terms.current_chunk_num,
|
||||
);
|
||||
|
||||
var_data.emit_initial_get_level(&mut query_terms);
|
||||
@@ -327,32 +381,13 @@ impl VariableClassifier {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
|
||||
if self.current_chunk_type.is_last() {
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn try_set_chunk_at_call_boundary(&mut self) -> bool {
|
||||
if self.current_chunk_type.is_last() {
|
||||
self.current_chunk_num += 1;
|
||||
true
|
||||
} else {
|
||||
self.current_chunk_type = ChunkType::Last;
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_body_term(
|
||||
&mut self,
|
||||
arg_c: usize,
|
||||
arity: usize,
|
||||
term: &mut FocusedHeap,
|
||||
term_loc: usize,
|
||||
context: GenContext,
|
||||
) {
|
||||
let classify_info = ClassifyInfo { arg_c, arity };
|
||||
|
||||
@@ -372,23 +407,24 @@ impl VariableClassifier {
|
||||
}
|
||||
|
||||
let var_loc = subterm.get_value() as usize;
|
||||
let var_ptr = term.var_locs.read_next_var_ptr_at_key(var_loc).unwrap();
|
||||
let var = to_classified_var(&term.inverse_var_locs, var_loc);
|
||||
|
||||
self.probe_body_var(VarInfo {
|
||||
var_ptr: var_ptr.clone(),
|
||||
lvl,
|
||||
classify_info,
|
||||
chunk_type: self.current_chunk_type,
|
||||
});
|
||||
self.probe_body_var(
|
||||
context,
|
||||
VarInfo {
|
||||
var,
|
||||
lvl,
|
||||
classify_info,
|
||||
chunk_type: context.chunk_type(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_body_var(&mut self, var_info: VarInfo) {
|
||||
let term_loc = self
|
||||
.current_chunk_type
|
||||
.to_gen_context(self.current_chunk_num);
|
||||
|
||||
let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone()).or_default();
|
||||
fn probe_body_var(&mut self, context: GenContext, var_info: VarInfo) {
|
||||
let chunk_num = context.chunk_num();
|
||||
let branch_info_v = self.branch_map.entry(var_info.var)
|
||||
.or_default();
|
||||
|
||||
let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
|
||||
!self.root_set.contains(&last_bi.branch_num)
|
||||
@@ -403,15 +439,14 @@ impl VariableClassifier {
|
||||
let branch_info = branch_info_v.last_mut().unwrap();
|
||||
|
||||
let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() {
|
||||
last_ci.chunk_num != self.current_chunk_num
|
||||
last_ci.term_loc.chunk_num() != chunk_num
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if needs_new_chunk {
|
||||
branch_info.chunks.push(ChunkInfo {
|
||||
chunk_num: self.current_chunk_num,
|
||||
term_loc,
|
||||
term_loc: context,
|
||||
vars: vec![],
|
||||
});
|
||||
}
|
||||
@@ -420,17 +455,17 @@ impl VariableClassifier {
|
||||
chunk_info.vars.push(var_info);
|
||||
}
|
||||
|
||||
fn probe_in_situ_var(&mut self, var_num: usize) {
|
||||
fn probe_in_situ_var(&mut self, context: GenContext, var_num: usize) {
|
||||
let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
|
||||
|
||||
let var_info = VarInfo {
|
||||
var_ptr: VarPtr::from(Var::InSitu(var_num)),
|
||||
var: ClassifiedVar::InSitu { var_num },
|
||||
classify_info,
|
||||
chunk_type: self.current_chunk_type,
|
||||
chunk_type: context.chunk_type(),
|
||||
lvl: Level::Shallow,
|
||||
};
|
||||
|
||||
self.probe_body_var(var_info);
|
||||
self.probe_body_var(context, var_info);
|
||||
}
|
||||
|
||||
fn classify_head_variables(
|
||||
@@ -473,13 +508,13 @@ impl VariableClassifier {
|
||||
continue;
|
||||
}
|
||||
|
||||
let h = subterm.get_value() as usize;
|
||||
let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone();
|
||||
let term_loc = subterm.get_value() as usize;
|
||||
let var = to_classified_var(&term.inverse_var_locs, term_loc);
|
||||
|
||||
// the body of the if let here is an inlined
|
||||
// "probe_head_var". note the difference between it
|
||||
// and "probe_body_var".
|
||||
let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
|
||||
let branch_info_v = self.branch_map.entry(var).or_default();
|
||||
let needs_new_branch = branch_info_v.is_empty();
|
||||
|
||||
if needs_new_branch {
|
||||
@@ -491,7 +526,6 @@ impl VariableClassifier {
|
||||
|
||||
if needs_new_chunk {
|
||||
branch_info.chunks.push(ChunkInfo {
|
||||
chunk_num: self.current_chunk_num,
|
||||
term_loc: GenContext::Head,
|
||||
vars: vec![],
|
||||
});
|
||||
@@ -499,9 +533,9 @@ impl VariableClassifier {
|
||||
|
||||
let chunk_info = branch_info.chunks.last_mut().unwrap();
|
||||
let var_info = VarInfo {
|
||||
var_ptr,
|
||||
var,
|
||||
classify_info,
|
||||
chunk_type: self.current_chunk_type,
|
||||
chunk_type: ChunkType::Head,
|
||||
lvl,
|
||||
};
|
||||
|
||||
@@ -515,7 +549,7 @@ impl VariableClassifier {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn new_cut_state(&mut self) -> TraversalState {
|
||||
fn new_cut_state(&mut self, context: GenContext) -> TraversalState {
|
||||
let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override {
|
||||
(var_num, false)
|
||||
} else if let Some(var_num) = self.global_cut_var_num {
|
||||
@@ -529,7 +563,7 @@ impl VariableClassifier {
|
||||
(var_num, true)
|
||||
};
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
self.probe_in_situ_var(context, var_num);
|
||||
|
||||
TraversalState::Cut { var_num, is_global }
|
||||
}
|
||||
@@ -546,8 +580,6 @@ impl VariableClassifier {
|
||||
}];
|
||||
let mut build_stack = ChunkedTermVec::new();
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
|
||||
'outer: while let Some(traversal_st) = state_stack.pop() {
|
||||
match traversal_st {
|
||||
TraversalState::AddBranchNum(branch_num) => {
|
||||
@@ -568,21 +600,22 @@ impl VariableClassifier {
|
||||
TraversalState::BuildDisjunct(preceding_len) => {
|
||||
flatten_into_disjunct(&mut build_stack, preceding_len);
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
build_stack.current_chunk_type = ChunkType::Mid;
|
||||
build_stack.current_chunk_num += 1;
|
||||
}
|
||||
TraversalState::BuildFinalDisjunct(preceding_len) => {
|
||||
flatten_into_disjunct(&mut build_stack, preceding_len);
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
build_stack.current_chunk_type = ChunkType::Mid;
|
||||
build_stack.current_chunk_num += 1;
|
||||
}
|
||||
TraversalState::GetCutPoint { var_num, prev_b } => {
|
||||
if self.try_set_chunk_at_inlined_boundary() {
|
||||
if build_stack.try_set_chunk_at_inlined_boundary() {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
let context = build_stack.current_gen_context();
|
||||
self.probe_in_situ_var(context, var_num);
|
||||
build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
|
||||
}
|
||||
TraversalState::OverrideGlobalCutVar(var_num) => {
|
||||
@@ -592,11 +625,12 @@ impl VariableClassifier {
|
||||
self.global_cut_var_num_override = old_override;
|
||||
}
|
||||
TraversalState::Cut { var_num, is_global } => {
|
||||
if self.try_set_chunk_at_inlined_boundary() {
|
||||
if build_stack.try_set_chunk_at_inlined_boundary() {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
let context = build_stack.current_gen_context();
|
||||
self.probe_in_situ_var(context, var_num);
|
||||
|
||||
build_stack.push_chunk_term(if is_global {
|
||||
QueryTerm::GlobalCut(var_num)
|
||||
@@ -608,11 +642,12 @@ impl VariableClassifier {
|
||||
});
|
||||
}
|
||||
TraversalState::CutPrev(var_num) => {
|
||||
if self.try_set_chunk_at_inlined_boundary() {
|
||||
if build_stack.try_set_chunk_at_inlined_boundary() {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
let context = build_stack.current_gen_context();
|
||||
self.probe_in_situ_var(context, var_num);
|
||||
|
||||
build_stack.push_chunk_term(QueryTerm::LocalCut {
|
||||
var_num,
|
||||
@@ -630,24 +665,26 @@ impl VariableClassifier {
|
||||
mut term_loc,
|
||||
} => {
|
||||
// return true iff new chunk should be added.
|
||||
let update_chunk_data = |classifier: &mut Self, key: PredicateKey| {
|
||||
let update_chunk_data = |build_stack: &mut ChunkedTermVec, key: PredicateKey| {
|
||||
if ClauseType::is_inlined(key.0, key.1) {
|
||||
classifier.try_set_chunk_at_inlined_boundary()
|
||||
build_stack.try_set_chunk_at_inlined_boundary()
|
||||
} else {
|
||||
classifier.try_set_chunk_at_call_boundary()
|
||||
build_stack.try_set_chunk_at_call_boundary()
|
||||
}
|
||||
};
|
||||
|
||||
macro_rules! add_chunk {
|
||||
($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{
|
||||
if update_chunk_data($classifier, $key) {
|
||||
($key:expr, $tag:expr, $term_loc:expr) => {{
|
||||
if update_chunk_data(&mut build_stack, $key) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
let context = build_stack.current_gen_context();
|
||||
|
||||
for (arg_c, term_loc) in
|
||||
($term_loc + 1 ..= $term_loc + $key.1).enumerate()
|
||||
{
|
||||
$classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
|
||||
self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context);
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
|
||||
@@ -655,21 +692,23 @@ impl VariableClassifier {
|
||||
$key,
|
||||
terms.as_ref_mut($term_loc),
|
||||
HeapCellValue::build_with($tag, $term_loc as u64),
|
||||
$classifier.call_policy,
|
||||
self.call_policy,
|
||||
)));
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! add_qualified_chunk {
|
||||
($classifier:ident, $module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
|
||||
if update_chunk_data($classifier, $key) {
|
||||
($module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
|
||||
if update_chunk_data(&mut build_stack, $key) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
let context = build_stack.current_gen_context();
|
||||
|
||||
for (arg_c, term_loc) in
|
||||
($term_loc + 1..$term_loc + $key.1 + 1).enumerate()
|
||||
{
|
||||
$classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
|
||||
self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context);
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(QueryTerm::Clause(
|
||||
@@ -679,7 +718,7 @@ impl VariableClassifier {
|
||||
$module_name,
|
||||
terms.as_ref_mut($term_loc),
|
||||
HeapCellValue::build_with($tag, $term_loc as u64),
|
||||
$classifier.call_policy,
|
||||
self.call_policy,
|
||||
),
|
||||
));
|
||||
}};
|
||||
@@ -698,7 +737,7 @@ impl VariableClassifier {
|
||||
continue;
|
||||
}
|
||||
|
||||
add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc);
|
||||
add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc);
|
||||
}
|
||||
(atom!(","), 2) => {
|
||||
let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
@@ -764,8 +803,8 @@ impl VariableClassifier {
|
||||
TraversalState::BuildFinalDisjunct(build_stack_len);
|
||||
}
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
build_stack.current_chunk_type = ChunkType::Mid;
|
||||
build_stack.current_chunk_num += 1;
|
||||
}
|
||||
(atom!("->"), 2) => {
|
||||
let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
|
||||
@@ -841,8 +880,8 @@ impl VariableClassifier {
|
||||
});
|
||||
state_stack.push(TraversalState::AddBranchNum(branch_num));
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
build_stack.current_chunk_type = ChunkType::Mid;
|
||||
build_stack.current_chunk_num += 1;
|
||||
|
||||
self.var_num += 1;
|
||||
}
|
||||
@@ -862,7 +901,6 @@ impl VariableClassifier {
|
||||
.get_name_and_arity();
|
||||
|
||||
add_qualified_chunk!(
|
||||
self,
|
||||
module_name,
|
||||
key,
|
||||
HeapCellValueTag::Str,
|
||||
@@ -874,7 +912,6 @@ impl VariableClassifier {
|
||||
let key = (predicate_name, predicate_arity);
|
||||
|
||||
add_qualified_chunk!(
|
||||
self,
|
||||
module_name,
|
||||
key,
|
||||
HeapCellValueTag::Str,
|
||||
@@ -890,12 +927,14 @@ impl VariableClassifier {
|
||||
_ => {}
|
||||
);
|
||||
|
||||
if update_chunk_data(self, (atom!("call"), 2)) {
|
||||
if update_chunk_data(&mut build_stack, (atom!("call"), 2)) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_body_term(1, 0, terms, module_name_loc);
|
||||
self.probe_body_term(2, 0, terms, predicate_term_loc);
|
||||
let context = build_stack.current_gen_context();
|
||||
|
||||
self.probe_body_term(1, 0, terms, module_name_loc, context);
|
||||
self.probe_body_term(2, 0, terms, predicate_term_loc, context);
|
||||
|
||||
let h = terms.heap.len();
|
||||
|
||||
@@ -920,7 +959,7 @@ impl VariableClassifier {
|
||||
self.call_policy = CallPolicy::Counted;
|
||||
}
|
||||
(name, arity) => {
|
||||
add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc);
|
||||
add_chunk!((name, arity), HeapCellValueTag::Str, subterm_loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -928,14 +967,16 @@ impl VariableClassifier {
|
||||
debug_assert_eq!(arity, 0);
|
||||
|
||||
if name == atom!("!") {
|
||||
state_stack.push(self.new_cut_state());
|
||||
let context = build_stack.current_gen_context();
|
||||
state_stack.push(self.new_cut_state(context));
|
||||
} else {
|
||||
add_chunk!(self, (name, 0), HeapCellValueTag::Var, term_loc);
|
||||
add_chunk!((name, 0), HeapCellValueTag::Var, term_loc);
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
if c == '!' {
|
||||
state_stack.push(self.new_cut_state());
|
||||
let context = build_stack.current_gen_context();
|
||||
state_stack.push(self.new_cut_state(context));
|
||||
} else {
|
||||
return Err(CompilationError::InadmissibleQueryTerm);
|
||||
}
|
||||
@@ -947,7 +988,7 @@ impl VariableClassifier {
|
||||
continue;
|
||||
}
|
||||
|
||||
add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h);
|
||||
add_chunk!((atom!("call"), 1), HeapCellValueTag::Var, h);
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InadmissibleQueryTerm);
|
||||
@@ -975,13 +1016,13 @@ impl BranchMap {
|
||||
records: VariableRecords::new(var_num),
|
||||
global_cut_var_num,
|
||||
allocates: current_chunk_num > 0,
|
||||
var_locs_to_nums: VarLocsToNums::default(),
|
||||
};
|
||||
|
||||
for (var, branches) in self.iter_mut() {
|
||||
let (mut var_num, var_num_incr) = if let Var::InSitu(var_num) = *var.borrow() {
|
||||
(var_num, false)
|
||||
} else {
|
||||
(var_data.records.len(), true)
|
||||
let (mut var_num, var_num_incr) = match var {
|
||||
&ClassifiedVar::InSitu { var_num} => (var_num, false),
|
||||
_ => (var_data.records.len(), true)
|
||||
};
|
||||
|
||||
for branch in branches.iter_mut() {
|
||||
@@ -999,10 +1040,13 @@ impl BranchMap {
|
||||
|
||||
for var_info in chunk.vars.iter_mut() {
|
||||
if var_info.lvl == Level::Shallow {
|
||||
let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
|
||||
let context = var_info
|
||||
.chunk_type
|
||||
.to_gen_context(chunk.term_loc.chunk_num());
|
||||
|
||||
temp_var_data
|
||||
.use_set
|
||||
.insert((term_loc, var_info.classify_info.arg_c));
|
||||
.insert((context, var_info.classify_info.arg_c));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1018,9 +1062,13 @@ impl BranchMap {
|
||||
for chunk in branch.chunks.iter_mut() {
|
||||
var_data.records[var_num].num_occurrences += chunk.vars.len();
|
||||
|
||||
for var_info in chunk.vars.iter_mut() {
|
||||
let is_anon = var_info.var_ptr.is_anon();
|
||||
var_info.var_ptr.set(Var::Generated { is_anon, var_num });
|
||||
if let Some(term_loc) = var.term_loc() {
|
||||
let chunk_num = chunk.term_loc.chunk_num();
|
||||
|
||||
var_data.var_locs_to_nums.insert(
|
||||
VarPtrIndex { chunk_num, term_loc },
|
||||
var_num,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,10 +33,12 @@ pub(crate) trait UnmarkPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) struct IteratorUMP {
|
||||
mark_phase: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn invert_marker<UMP: UnmarkPolicy>(iter: &mut StacklessPreOrderHeapIter<UMP>) {
|
||||
if iter.heap[iter.start].get_forwarding_bit() {
|
||||
while !iter.backward() {}
|
||||
@@ -50,6 +52,7 @@ fn invert_marker<UMP: UnmarkPolicy>(iter: &mut StacklessPreOrderHeapIter<UMP>) {
|
||||
while iter.forward().is_some() {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl UnmarkPolicy for IteratorUMP {
|
||||
#[inline(always)]
|
||||
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
|
||||
@@ -150,8 +153,8 @@ impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self {
|
||||
heap[start].set_forwarding_bit(true);
|
||||
let next = heap[start].get_value();
|
||||
|
||||
@@ -467,11 +467,20 @@ impl Iterator for QueryState<'_> {
|
||||
// this should halt the search for solutions as it
|
||||
// does in the Scryer top-level. the exception term is
|
||||
// contained in self.machine_st.ball.
|
||||
let h = machine.machine_st.heap.len();
|
||||
machine
|
||||
let h = machine.machine_st.heap.cell_len();
|
||||
|
||||
if let Err(resource_err_loc) = machine
|
||||
.machine_st
|
||||
.heap
|
||||
.extend(machine.machine_st.ball.stub.clone());
|
||||
.append(&machine.machine_st.ball.stub)
|
||||
{
|
||||
return Some(Err(Term::from_heapcell(
|
||||
machine,
|
||||
machine.machine_st.heap[resource_err_loc],
|
||||
&mut IndexMap::new(),
|
||||
)));
|
||||
}
|
||||
|
||||
let exception_term =
|
||||
Term::from_heapcell(machine, machine.machine_st.heap[h], &mut var_names.clone());
|
||||
|
||||
@@ -487,7 +496,7 @@ impl Iterator for QueryState<'_> {
|
||||
}
|
||||
|
||||
if machine.machine_st.p == LIB_QUERY_SUCCESS {
|
||||
if term_write_result.var_dict.is_empty() {
|
||||
if term_write_result.inverse_var_locs.is_empty() {
|
||||
self.machine.machine_st.backtrack();
|
||||
return Some(Ok(LeafAnswer::True));
|
||||
}
|
||||
@@ -496,47 +505,39 @@ impl Iterator for QueryState<'_> {
|
||||
}
|
||||
|
||||
let mut bindings: BTreeMap<String, Term> = BTreeMap::new();
|
||||
let inverse_var_locs = &term_write_result.inverse_var_locs;
|
||||
|
||||
let var_dict = &term_write_result.var_dict;
|
||||
|
||||
for (var_key, term_to_be_printed) in var_dict.iter() {
|
||||
let mut var_name = var_key.to_string();
|
||||
for (var_loc, var_name) in inverse_var_locs.iter() {
|
||||
if var_name.starts_with('_') {
|
||||
let should_print = var_names.values().any(|x| match x.borrow().clone() {
|
||||
Var::Named(v) => v == var_name,
|
||||
_ => false,
|
||||
});
|
||||
let should_print = var_names.values().any(|v| v == var_name);
|
||||
if !should_print {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let mut term =
|
||||
Term::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone());
|
||||
let var_loc = *var_loc;
|
||||
let term =
|
||||
Term::from_heapcell(machine, heap_loc_as_cell!(var_loc), &mut var_names.clone());
|
||||
|
||||
if let Term::Var(ref term_str) = term {
|
||||
if *term_str == var_name {
|
||||
if *term_str == **var_name {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Var dict is in the order things appear in the query. If var_name appears
|
||||
// after term in the query, switch their places.
|
||||
let var_name_idx = var_dict
|
||||
.get_index_of(&VarKey::VarPtr(Var::Named(var_name.clone()).into()))
|
||||
.unwrap();
|
||||
let term_idx =
|
||||
var_dict.get_index_of(&VarKey::VarPtr(Var::Named(term_str.clone()).into()));
|
||||
if let Some(idx) = term_idx {
|
||||
if idx < var_name_idx {
|
||||
let new_term = Term::Var(var_name);
|
||||
let new_var_name = term_str.into();
|
||||
term = new_term;
|
||||
var_name = new_var_name;
|
||||
}
|
||||
// inverse_var_locs is in the order things appear in
|
||||
// the query. If var_name appears after term in the
|
||||
// query, switch their places.
|
||||
let var_cell = machine
|
||||
.machine_st
|
||||
.store(machine.machine_st.deref(machine.machine_st.heap[var_loc]));
|
||||
|
||||
if (var_cell.get_value() as usize) < var_loc {
|
||||
bindings.insert(term_str.clone(), Term::Var(var_name.to_string()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bindings.insert(var_name, term);
|
||||
bindings.insert(var_name.to_string(), term);
|
||||
}
|
||||
|
||||
// NOTE: there are outstanding choicepoints, backtrack
|
||||
@@ -605,27 +606,10 @@ impl Machine {
|
||||
|
||||
self.allocate_stub_choice_point();
|
||||
|
||||
// Write parsed term to heap
|
||||
let term_write_result =
|
||||
write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
|
||||
.expect("couldn't write term to heap");
|
||||
|
||||
let var_names: IndexMap<_, _> = term_write_result
|
||||
.var_dict
|
||||
.iter()
|
||||
.map(|(var_key, cell)| match var_key {
|
||||
// NOTE: not the intention behind Var::InSitu here but
|
||||
// we can hijack it to store anonymous variables
|
||||
// without creating problems.
|
||||
VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))),
|
||||
VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()),
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Write term to heap
|
||||
self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc];
|
||||
|
||||
self.machine_st.registers[1] = self.machine_st.heap[term.focus];
|
||||
self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
|
||||
|
||||
let call_index_p = self
|
||||
.indices
|
||||
.code_dir
|
||||
@@ -634,12 +618,22 @@ impl Machine {
|
||||
.local()
|
||||
.unwrap();
|
||||
|
||||
let var_names: IndexMap<_, _> = term
|
||||
.inverse_var_locs
|
||||
.iter()
|
||||
.map(|(var_loc, var)| {
|
||||
let cell = self.machine_st.heap[*var_loc];
|
||||
(cell, var.clone())
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.machine_st.execute_at_index(1, call_index_p);
|
||||
|
||||
let stub_b = self.machine_st.b;
|
||||
|
||||
QueryState {
|
||||
machine: self,
|
||||
term: term_write_result,
|
||||
term,
|
||||
stub_b,
|
||||
var_names,
|
||||
called: false,
|
||||
|
||||
@@ -499,7 +499,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
|
||||
term.copy_term_from_machine_heap(machine_st, cell);
|
||||
term.var_locs = var_locs_from_iter(
|
||||
term.inverse_var_locs = inverse_var_locs_from_iter(
|
||||
fact_iterator::<false>(
|
||||
&mut term.heap,
|
||||
&mut stack,
|
||||
@@ -1107,7 +1107,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
);
|
||||
|
||||
let value = term.heap[term.focus];
|
||||
term.var_locs = var_locs_from_iter(eager_stackful_preorder_iter(&mut term.heap, value));
|
||||
term.inverse_var_locs = inverse_var_locs_from_iter(
|
||||
eager_stackful_preorder_iter(&mut term.heap, value),
|
||||
);
|
||||
Ok(term)
|
||||
}
|
||||
|
||||
|
||||
@@ -472,8 +472,8 @@ impl MachineState {
|
||||
fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
|
||||
match err {
|
||||
ArithmeticError::UninstantiatedVar => self.instantiation_error(),
|
||||
ArithmeticError::NonEvaluableFunctor(literal, arity) => {
|
||||
let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]);
|
||||
ArithmeticError::NonEvaluableFunctor(cell, arity) => {
|
||||
let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]);
|
||||
|
||||
self.type_error(ValidType::Evaluable, culprit)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use indexmap::IndexMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
|
||||
@@ -202,13 +203,13 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
|
||||
|
||||
fn push_var_eq_functors(
|
||||
heap: &mut Heap,
|
||||
iter: impl Iterator<Item = (usize, VarPtr)>, // (&'a VarPtr, &'a HeapCellValue)>,
|
||||
iter: impl Iterator<Item = (usize, Var)>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Vec<HeapCellValue> {
|
||||
let mut list_of_var_eqs = vec![];
|
||||
|
||||
for (var_loc, var_ptr) in iter { // (var, binding) in iter {
|
||||
let var_atom = AtomTable::build_with(atom_tbl, &*var_ptr.borrow().to_string());
|
||||
for (var_loc, var) in iter { // (var, binding) in iter {
|
||||
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
|
||||
let h = heap.len();
|
||||
let binding = heap[var_loc];
|
||||
|
||||
@@ -541,20 +542,15 @@ impl MachineState {
|
||||
|
||||
pub fn write_read_term_options(
|
||||
&mut self,
|
||||
mut var_list: Vec<(VarPtr, HeapCellValue, usize)>,
|
||||
mut var_list: Vec<(Var, HeapCellValue, usize)>,
|
||||
singleton_var_list: Vec<HeapCellValue>,
|
||||
) -> CallResult {
|
||||
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
|
||||
|
||||
let list_of_var_eqs = push_var_eq_functors(
|
||||
&mut self.heap,
|
||||
var_list.iter().filter_map(|(var_ptr, var, _)| {
|
||||
if var_ptr.is_anon() {
|
||||
None
|
||||
} else {
|
||||
let var_loc = var.get_value() as usize;
|
||||
Some((var_loc, var_ptr.clone()))
|
||||
}
|
||||
var_list.iter().map(|(var_name, var, _)| {
|
||||
(var.get_value() as usize, var_name.clone())
|
||||
}),
|
||||
&self.atom_tbl,
|
||||
);
|
||||
@@ -630,20 +626,14 @@ impl MachineState {
|
||||
|
||||
let singleton_var_list = push_var_eq_functors(
|
||||
&mut self.heap,
|
||||
term.var_locs
|
||||
term.inverse_var_locs
|
||||
.iter()
|
||||
.filter_map(|(var_loc, var_ptrs)| {
|
||||
let var_ptr = var_ptrs.front().unwrap();
|
||||
|
||||
if var_ptr.is_anon() {
|
||||
return None;
|
||||
}
|
||||
|
||||
.filter_map(|(var_loc, var_name)| {
|
||||
// add h to offset the term variable into its heap location.
|
||||
let r = Ref::heap_cell(var_loc);
|
||||
let r = Ref::heap_cell(*var_loc);
|
||||
|
||||
if singleton_var_set.get(&r).cloned().unwrap_or(false) {
|
||||
Some((var_loc, var_ptr.clone()))
|
||||
Some((*var_loc, var_name.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -659,13 +649,12 @@ impl MachineState {
|
||||
|
||||
let mut var_list = Vec::with_capacity(singleton_var_set.len());
|
||||
|
||||
for (var_loc, var_ptrs) in term.var_locs.iter() {
|
||||
let var_ptr = var_ptrs.front().unwrap().clone();
|
||||
for (var_loc, var_name) in term.inverse_var_locs {
|
||||
let r = Ref::heap_cell(var_loc);
|
||||
let cell = self.heap[var_loc];
|
||||
|
||||
if let Some(idx) = singleton_var_set.get_index_of(&r) {
|
||||
var_list.push((var_ptr, cell, idx));
|
||||
var_list.push((var_name, cell, idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,7 +776,7 @@ impl MachineState {
|
||||
|
||||
let printer = match self.try_from_list(self.registers[6], stub_gen) {
|
||||
Ok(addrs) => {
|
||||
let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
|
||||
let mut var_names: IndexMap<HeapCellValue, Var> = IndexMap::new();
|
||||
|
||||
for addr in addrs {
|
||||
read_heap_cell!(addr,
|
||||
@@ -805,18 +794,18 @@ impl MachineState {
|
||||
|
||||
read_heap_cell!(atom,
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
var_names.insert(var, VarPtr::from(c.to_string()));
|
||||
var_names.insert(var, Rc::new(c.to_string()));
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||
debug_assert_eq!(_arity, 0);
|
||||
var_names.insert(var, VarPtr::from(&*name.as_str()));
|
||||
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||
.get_name_and_arity();
|
||||
|
||||
debug_assert_eq!(arity, 0);
|
||||
var_names.insert(var, VarPtr::from(&*name.as_str()));
|
||||
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
|
||||
@@ -59,10 +59,10 @@ impl MockWAM {
|
||||
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
|
||||
|
||||
let var_names = term_write_result
|
||||
.var_locs
|
||||
.inverse_var_locs
|
||||
.iter()
|
||||
.map(|(var_loc, var_ptrs)| {
|
||||
(self.machine_st.heap[var_loc], var_ptrs.front().unwrap().clone())
|
||||
.map(|(var_loc, var_name)| {
|
||||
(self.machine_st.heap[*var_loc], var_name.clone())
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user