]> Repositorios git - scryer-prolog.git/commitdiff
variable classification al a carte
authorMark Thom <[email protected]>
Sun, 13 Nov 2022 17:13:37 +0000 (10:13 -0700)
committerMark <[email protected]>
Fri, 23 Jun 2023 20:11:22 +0000 (14:11 -0600)
Cargo.lock
Cargo.toml
src/allocator.rs
src/codegen.rs
src/fixtures.rs
src/iterators.rs
src/machine/disjuncts.rs
src/parser/ast.rs

index 46c5a14f68bd6b1b07d48e8e6138fd5f38c5074e..7cc11f218e78380311ddbe6dbbdd6e9b3397b13a 100644 (file)
@@ -1855,6 +1855,7 @@ version = "0.9.1"
 dependencies = [
  "assert_cmd",
  "base64",
+ "bit-set",
  "blake2 0.8.1",
  "chrono",
  "cpu-time",
index 975ba64fdbd773e64d11409b9a014caec4df5a52..f358126aa99a623afb5020ad2fea679a3e4091bc 100644 (file)
@@ -27,6 +27,7 @@ to-syn-value_derive = "0.1.0"
 walkdir = "2"
 
 [dependencies]
+bit-set = "0.5.3"
 cpu-time = "1.0.0"
 crossterm = "0.20.0"
 dirs-next = "2.0.0"
index bc0d2f449c856a6f87a5b1b8f0fd5879c82c4b84..50e9c7c330377de4dfba5e96889c427bd3a4a7c5 100644 (file)
@@ -63,32 +63,30 @@ pub(crate) trait Allocator {
     // TODO: wha.. why?? grrr. it drains the VarStatus data from vs (which it owns!)
     // into self.bindings and perm_vs after all is computed (i.e. vs.populate_restricting_sets()
     // and vs.set_perm_vals(has_deep_cut) have both been called).
+    /*
     fn drain_var_data<'a>(
         &mut self,
-        vs: VariableFixtures<'a>,
+        vs: VariableFixtures,
         num_of_chunks: usize,
-    ) -> VariableFixtures<'a> {
+    ) -> VariableFixtures {
         let mut perm_vs = VariableFixtures::new();
 
-        for (var, (var_status, cells)) in vs.into_iter() {
+        for (var, var_status) in vs.into_iter() {
             match var_status {
                 VarStatus::Temp(chunk_num, tvd) => {
                     self.bindings_mut()
-                        .insert(var.clone(), VarData::Temp(chunk_num, 0, tvd));
-
-                    if chunk_num + 1 == num_of_chunks {
-                        perm_vs.insert_last_chunk_temp_var(var);
-                    }
+                        .insert(var.clone(), VarAlloc::Temp(chunk_num, 0, tvd));
                 }
                 VarStatus::Perm(_) => {
-                    self.bindings_mut().insert(var.clone(), VarData::Perm(0));
-                    perm_vs.insert(var, (var_status, cells));
+                    self.bindings_mut().insert(var.clone(), VarAlloc::Perm(0));
+                    perm_vs.insert(var, var_status);
                 }
             };
         }
 
         perm_vs
     }
+    */
 
     fn get(&self, var: Var) -> RegType {
         self.bindings()
@@ -102,8 +100,8 @@ pub(crate) trait Allocator {
 
     fn record_register(&mut self, var: Var, r: RegType) {
         match self.bindings_mut().get_mut(&var).unwrap() {
-            &mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
-            &mut VarData::Perm(ref mut s) => *s = r.reg_num(),
+            &mut VarAlloc::Temp(_, ref mut s, _) => *s = r.reg_num(),
+            &mut VarAlloc::Perm(ref mut s) => *s = r.reg_num(),
         }
     }
 }
index a3fdc99b98d226a034e74898a3dfb2daa920a2a9..65f49971ca4a69018b3ee1f09aee0af0fc83e5e1 100644 (file)
@@ -1,7 +1,6 @@
 use crate::atom_table::*;
 use crate::parser::ast::*;
 use crate::{perm_v, temp_v};
-
 use crate::allocator::*;
 use crate::arithmetic::*;
 use crate::debray_allocator::*;
@@ -22,14 +21,14 @@ use std::cell::Cell;
 use std::collections::VecDeque;
 
 #[derive(Debug)]
-pub(crate) struct ConjunctInfo<'a> {
-    pub(crate) perm_vs: VariableFixtures<'a>,
+pub(crate) struct ConjunctInfo {
+    pub(crate) perm_vs: VariableFixtures,
     pub(crate) num_of_chunks: usize,
     pub(crate) has_deep_cut: bool,
 }
 
-impl<'a> ConjunctInfo<'a> {
-    fn new(perm_vs: VariableFixtures<'a>, num_of_chunks: usize, has_deep_cut: bool) -> Self {
+impl ConjunctInfo {
+    fn new(perm_vs: VariableFixtures, num_of_chunks: usize, has_deep_cut: bool) -> Self {
         ConjunctInfo {
             perm_vs,
             num_of_chunks,
@@ -191,8 +190,8 @@ impl DebrayAllocator {
     #[inline(always)]
     pub(crate) fn get_binding(&self, name: &Var) -> Option<RegType> {
         match self.bindings().get(name) {
-            Some(&VarData::Temp(_, t, _)) if t != 0 => Some(RegType::Temp(t)),
-            Some(&VarData::Perm(p)) if p != 0 => Some(RegType::Perm(p)),
+            Some(&VarAlloc::Temp(_, t, _)) if t != 0 => Some(RegType::Temp(t)),
+            Some(&VarAlloc::Perm(p)) if p != 0 => Some(RegType::Perm(p)),
             _ => None,
         }
     }
@@ -861,7 +860,7 @@ impl<'b> CodeGenerator<'b> {
     fn compile_seq<'a>(
         &mut self,
         iter: ChunkedIterator<'a>,
-        conjunct_info: &ConjunctInfo<'a>,
+        conjunct_info: &ConjunctInfo,
         code: &mut Code,
     ) -> Result<(), CompilationError> {
         for (chunk_num, _, terms) in iter.rule_body_iter() {
@@ -925,11 +924,11 @@ impl<'b> CodeGenerator<'b> {
         }
     }
 
-    fn compile_cleanup<'a>(
+    fn compile_cleanup(
         &mut self,
         code: &mut Code,
-        conjunct_info: &ConjunctInfo<'a>,
-        toc: &'a QueryTerm,
+        conjunct_info: &ConjunctInfo,
+        toc: &QueryTerm,
     ) {
         // add a proceed to bookend any trailing cuts.
         match toc {
@@ -937,7 +936,7 @@ impl<'b> CodeGenerator<'b> {
                 code.push(instr!("proceed"));
             }
             _ => {}
-        };
+        }
 
         // perform lco.
         let dealloc_index = Self::lco(code);
index 6774098964cc8caec0b2078ac4161c3bf72cc6a9..f75a80423c9f4ceabc9143613f923ef6d477d1a4 100644 (file)
@@ -4,6 +4,7 @@ use crate::forms::*;
 use crate::instructions::*;
 use crate::iterators::*;
 
+use bit_set::*;
 use indexmap::{IndexMap, IndexSet};
 
 use std::cell::Cell;
@@ -11,15 +12,23 @@ use std::collections::BTreeSet;
 use std::mem::swap;
 use std::vec::Vec;
 
-// labeled with chunk numbers.
+pub(crate) type OccurrenceSet = IndexSet<(GenContext, usize)>;
+
 #[derive(Debug)]
-pub(crate) enum VarStatus {
-    Perm(usize),
-    Temp(usize, TempVarData), // Perm(chunk_num) | Temp(chunk_num, _)
+pub(crate) struct TempVarData {
+    pub(crate) last_term_arity: usize,
+    pub(crate) use_set: OccurrenceSet,
+    pub(crate) no_use_set: BitSet<usize>,
+    pub(crate) conflict_set: BitSet<usize>,
 }
 
-pub(crate) type OccurrenceSet = BTreeSet<(GenContext, usize)>;
+#[derive(Debug)]
+pub(crate) struct TempVarStatus {
+    chunk_num: usize,
+    temp_var_data: TempVarData,
+}
 
+// TODO: get ridda this! I think.
 // Perm: 0 initially, a stack register once processed.
 // Temp: labeled with chunk_num and temp offset (unassigned if 0).
 #[derive(Debug)]
@@ -37,21 +46,13 @@ impl VarData {
     }
 }
 
-#[derive(Debug)]
-pub(crate) struct TempVarData {
-    pub(crate) last_term_arity: usize,
-    pub(crate) use_set: OccurrenceSet,
-    pub(crate) no_use_set: BTreeSet<usize>,
-    pub(crate) conflict_set: BTreeSet<usize>,
-}
-
 impl TempVarData {
     pub(crate) fn new(last_term_arity: usize) -> Self {
         TempVarData {
             last_term_arity: last_term_arity,
-            use_set: BTreeSet::new(),
-            no_use_set: BTreeSet::new(),
-            conflict_set: BTreeSet::new(),
+            use_set: BitSet::new(),
+            no_use_set: BitSet::new(),
+            conflict_set: BitSet::new(),
         }
     }
 
@@ -68,7 +69,7 @@ impl TempVarData {
     pub(crate) fn populate_conflict_set(&mut self) {
         if self.last_term_arity > 0 {
             let arity = self.last_term_arity;
-            let mut conflict_set: BTreeSet<usize> = (1..arity).collect();
+            let mut conflict_set: BitSet<usize> = (1..arity).collect();
 
             for &(_, reg) in self.use_set.iter() {
                 conflict_set.remove(&reg);
@@ -79,26 +80,26 @@ impl TempVarData {
     }
 }
 
-type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
-
 #[derive(Debug)]
-pub(crate) struct VariableFixtures<'a> {
-    perm_vars: IndexMap<Var, VariableFixture<'a>>,
-    last_chunk_temp_vars: IndexSet<Var>, // TODO: has no use at all!
+pub(crate) struct VariableFixtures {
+    temp_vars: IndexMap<usize, TempVarStatus>,
+    last_chunk_temp_vars: IndexSet<usize>, // TODO: has no use at all! remove it.
 }
 
 impl<'a> VariableFixtures<'a> {
     pub(crate) fn new() -> Self {
         VariableFixtures {
-            perm_vars: IndexMap::new(),
+            temp_vars: IndexMap::new(),
             last_chunk_temp_vars: IndexSet::new(),
         }
     }
 
+    // TODO: get rid of this also.
     pub(crate) fn insert(&mut self, var: Var, vs: VariableFixture<'a>) {
-        self.perm_vars.insert(var, vs);
+        self.temp_vars.insert(var, vs);
     }
 
+    // TODO: used?
     pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Var) {
         self.last_chunk_temp_vars.insert(var);
     }
@@ -114,27 +115,26 @@ impl<'a> VariableFixtures<'a> {
         // Compute the conflict set of u.
 
         // 1.
-        let mut use_sets: IndexMap<Var, OccurrenceSet> = IndexMap::new();
+        let mut use_sets: IndexMap<usize, OccurrenceSet> = IndexMap::new();
 
-        for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
-            if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
-                let mut use_set = OccurrenceSet::new();
+        for (var_gen_index, ref mut var_status) in self.temp_vars.iter_mut() {
+            let TempVarStatus { ref mut temp_var_data, .. } = var_status;
+            let mut use_set = OccurrenceSet::new();
 
-                swap(&mut var_data.use_set, &mut use_set);
-                use_sets.insert((*var).clone(), use_set);
-            }
+            mem::swap(&mut temp_var_data.use_set, &mut use_set);
+            use_sets.insert(var_gen_index, use_set);
         }
 
         for (u, use_set) in use_sets.drain(..) {
             // 2.
             for &(term_loc, reg) in use_set.iter() {
                 if let GenContext::Last(cn_u) = term_loc {
-                    for (ref t, &mut (ref mut var_status, _)) in self.iter_mut() {
-                        if let &mut VarStatus::Temp(cn_t, ref mut t_data) = var_status {
-                            if cn_u == cn_t && u != **t {
-                                if !t_data.uses_reg(reg) {
-                                    t_data.no_use_set.insert(reg);
-                                }
+                    for (var_gen_index, ref mut var_status) in self.terms_vars.iter_mut() {
+                        let TempVarStatus { chunk_num, ref mut temp_var_data } = var_status;
+
+                        if cn_u == chunk_num && u != var_gen_index {
+                            if !temp_var_data.uses_reg(reg) {
+                                temp_var_data.no_use_set.insert(reg);
                             }
                         }
                     }
@@ -142,22 +142,11 @@ impl<'a> VariableFixtures<'a> {
             }
 
             // 3.
-            match self.get_mut(u).unwrap() {
-                &mut (VarStatus::Temp(_, ref mut u_data), _) => {
-                    u_data.use_set = use_set;
-                    u_data.populate_conflict_set();
-                }
-                _ => {}
-            };
-        }
-    }
-
-    fn get_mut(&mut self, u: Var) -> Option<&mut VariableFixture<'a>> {
-        self.perm_vars.get_mut(&u)
-    }
+            let TempVarStatus { ref mut temp_var_data, ..} = self.temp_vars.get_mut(u).unwrap();
 
-    fn iter_mut(&mut self) -> indexmap::map::IterMut<Var, VariableFixture<'a>> {
-        self.perm_vars.iter_mut()
+            temp_var_data.use_set = use_set;
+            temp_var_data.populate_conflict_set();
+        }
     }
 
     fn record_temp_info(&mut self, tvd: &mut TempVarData, arg_c: usize, term_loc: GenContext) {
@@ -169,84 +158,27 @@ impl<'a> VariableFixtures<'a> {
         };
     }
 
-    pub(crate) fn vars_above_threshold(&self, index: usize) -> usize {
-        let mut var_count = 0;
-
-        for &(ref var_status, _) in self.values() {
-            if let &VarStatus::Perm(i) = var_status {
-                if i > index {
-                    var_count += 1;
-                }
-            }
-        }
-
-        var_count
-    }
-
-    pub(crate) fn mark_vars_in_chunk<I>(&mut self, iter: I, lt_arity: usize, term_loc: GenContext)
-    where
-        I: Iterator<Item = TermRef<'a>>,
-    {
+    pub(crate) fn mark_temp_var(
+        &mut self,
+        generated_var_index: usize,
+        lvl: Level,
+        classify_info: &ClassifyInfo,
+        term_loc: GenContext,
+    ) {
         let chunk_num = term_loc.chunk_num();
-        let mut arg_c = 1;
-
-        for term_ref in iter {
-            if let &TermRef::Var(lvl, cell, ref var) = &term_ref {
-                let mut status = self.perm_vars.swap_remove(var).unwrap_or((
-                    VarStatus::Temp(chunk_num, TempVarData::new(lt_arity)),
-                    Vec::new(),
-                ));
 
-                status.1.push(cell);
-
-                match status.0 {
-                    VarStatus::Temp(cn, ref mut tvd) if cn == chunk_num => {
-                        if let Level::Shallow = lvl {
-                            self.record_temp_info(tvd, arg_c, term_loc);
-                        }
-                    }
-                    _ => status.0 = VarStatus::Perm(chunk_num),
-                };
-
-                self.perm_vars.insert(var.clone(), status);
+        let mut status = self.temp_vars.swap_remove(generated_var_index).unwrap_or_else(|| {
+            TempVarStatus {
+                chunk_num,
+                temp_var_data: TempVarData::new(classify_info.arity),
             }
+        });
 
-            if let Level::Shallow = term_ref.level() {
-                arg_c += 1;
-            }
+        if let Level::Shallow = lvl {
+            self.record_temp_info(&mut status, classify_info.arg_c, term_loc);
         }
-    }
 
-    pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Var, VariableFixture<'a>> {
-        self.perm_vars.into_iter()
-    }
-
-    fn values(&self) -> indexmap::map::Values<Var, VariableFixture<'a>> {
-        self.perm_vars.values()
-    }
-
-    pub(crate) fn size(&self) -> usize {
-        self.perm_vars.len()
-    }
-
-    pub(crate) fn set_perm_vals(&self, has_deep_cuts: bool) {
-        let mut values_vec: Vec<_> = self
-            .values()
-            .filter_map(|ref v| match &v.0 {
-                &VarStatus::Perm(i) => Some((i, &v.1)),
-                _ => None,
-            })
-            .collect();
-
-        values_vec.sort_by_key(|ref v| v.0);
-
-        let offset = has_deep_cuts as usize;
-
-        for (i, (_, cells)) in values_vec.into_iter().rev().enumerate() {
-            for cell in cells {
-                cell.set(VarReg::Norm(RegType::Perm(i + 1 + offset)));
-            }
-        }
+        self.temp_vars.insert(Var::Generated(generated_var_index), status);
     }
 }
 
index ac87a451417e36ab45b9a4a077f98eac492f3795..bbd9fb70da70324c201cabc9dcdb2a0e83a71447 100644 (file)
@@ -40,7 +40,6 @@ impl VarPtr {
     }
 }
 
-
 #[derive(Debug, Clone)]
 pub(crate) enum TermRef<'a> {
     AnonVar(Level),
index adbf341cff90c2adc9777a9d6f0d42014bcdd0d2..19e460c39f21dfb56c881f956cf340ea51e16431 100644 (file)
@@ -9,6 +9,7 @@ paper "Compiling Large Disjunctions" to Scryer Prolog.
  */
 
 use crate::atom_table::*;
+use crate::fixtures::VariableFixtures;
 use crate::forms::*;
 use crate::instructions::*;
 use crate::iterators::*;
@@ -34,7 +35,7 @@ struct BranchNumber {
 impl Default for BranchNumber {
     fn default() -> Self {
         Self {
-            branch_num: Rational::from(1 << 10),
+            branch_num: Rational::from(1 << 63),
             delta: Rational::from(1),
         }
     }
@@ -86,16 +87,19 @@ impl BranchNumber {
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct VarInfo {
+    var_ptr: VarPtr,
+    classify_info: ClassifyInfo,
+    lvl: Level,
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ChunkInfo {
     chunk_num: usize,
-    vars: Vec<VarPtr>, // pointer to incidence
-}
-
-impl ChunkInfo {
-    fn new(chunk_num: usize) -> Self {
-        ChunkInfo { chunk_num, vars: vec![] }
-    }
+    term_loc: GenContext,
+    // pointer to incidence, term occurrence arity.
+    vars: Vec<VarInfo>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -140,6 +144,23 @@ enum ChunkType {
     Last,
 }
 
+impl ChunkType {
+    #[inline(always)]
+    fn to_gen_context(self, chunk_num: usize) -> GenContext {
+        match self {
+            ChunkType::Head => GenContext::Head,
+            ChunkType::Mid => GenContext::Mid(chunk_num),
+            ChunkType::Last => GenContext::Last(chunk_num),
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ClassifyInfo {
+    arg_c: usize,
+    arity: usize,
+}
+
 enum TraversalState {
     // construct a QueryTerm::Branch with number of disjuncts, reset
     // the chunk type to that of the chunk preceding the disjunct.
@@ -199,8 +220,15 @@ pub struct VarRecord {
     pub num_occurrences: usize,
 }
 
-pub type ClassifyFactResult = (Term, Vec<VarRecord>);
-pub type ClassifyRuleResult = (Term, Vec<QueryTerm>, Vec<VarRecord>);
+// TODO: already exists a VarData! although it may no longer exist??
+// Also, the name is too similar to VarInfo. Think of better names!
+pub struct VarData {
+    pub records:  Vec<VarRecord>,
+    pub fixtures: VariableFixtures,
+}
+
+pub type ClassifyFactResult = (Term, VarData);
+pub type ClassifyRuleResult = (Term, Vec<QueryTerm>, VarData);
 
 fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> BranchInfo {
     let mut branch_info = BranchInfo::new(BranchNumber::default());
@@ -238,19 +266,20 @@ fn flatten_into_disjunct(build_stack: &mut Vec<QueryTerm>, preceding_len: usize)
 
 fn term_in_other_chunk(term: &Term) -> Option<bool> {
     match term {
-        Term::Clause(_, name, terms) => Some(!ClauseType::is_inbuilt(name, terms.len())),
+        Term::Clause(_, name, terms) => Some(!ClauseType::is_inbuilt(*name, terms.len())),
         Term::Literal(_, Literal::Atom(atom!("!"))) |
         Term::Literal(_, Literal::Char('!')) => Some(false),
-        Term::Literal(_, Literal::Atom(name)) => Some(!ClauseType::is_inbuilt(name, 0)),
+        Term::Literal(_, Literal::Atom(name)) => Some(!ClauseType::is_inbuilt(*name, 0)),
         Term::Var(..) => Some(true),
         _ => None,
     }
 }
 
 // returns true if the insertion of SetLastChunkType was the final push.
+// expects that iter iterates over a conjunct of Terms in reverse order.
 fn insert_set_last_chunk_type(
     state_stack: &mut Vec<TraversalState>,
-    iter: impl Iterator<Item = TraversalState>,
+    mut iter: impl Iterator<Item = TraversalState>,
 ) -> bool {
     let beg = state_stack.len();
     let mut idx = beg;
@@ -269,6 +298,7 @@ fn insert_set_last_chunk_type(
                 if will_break {
                     state_stack.push(TraversalState::SetLastChunkType);
                     state_stack.push(traversal_st);
+
                     break;
                 } else {
                     state_stack.push(traversal_st);
@@ -356,15 +386,22 @@ impl VariableClassifier {
     }
 
     fn probe_body_term(&mut self, term: &Term, term_loc: GenContext) {
+        let mut classify_info = ClassifyInfo { arg_c: 0, arity: term.arity() };
+
         // second arg is true to iterate the root, which may be a variable
         for term_ref in breadth_first_iter(term, true) {
-            if let TermRef::Var(_, _, var_name) = term_ref {
-                self.probe_body_var(Var::from(var_name), term_loc);
+            if let TermRef::Var(lvl, _, var_name) = term_ref {
+                let var_info = VarInfo { var_ptr: VarPtr::from(&var_name), lvl, classify_info };
+                self.probe_body_var(var_name, term_loc, var_info);
+            }
+
+            if let Level::Shallow = term_ref.level() {
+                classify_info.arg_c += 1;
             }
         }
     }
 
-    fn probe_body_var(&mut self, var_name: Var, chunk_type: ChunkType) {
+    fn probe_body_var(&mut self, var_name: Var, term_loc: GenContext, var_info: VarInfo) {
         let branch_info_v = self.branch_map.entry(var_name)
             .or_insert_with(|| vec![]);
 
@@ -387,11 +424,15 @@ impl VariableClassifier {
         };
 
         if needs_new_chunk {
-            branch_info.chunks.push(ChunkInfo::new(self.current_chunk_num));
+            branch_info.chunks.push(ChunkInfo {
+                chunk_num: self.current_chunk_num,
+                term_loc,
+                vars: vec![],
+            });
         }
 
         let chunk_info = branch_info.chunks.last_mut().unwrap();
-        chunk_info.vars.push(VarPtr::from(&var_name));
+        chunk_info.vars.push(var_info);
     }
 
     fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
@@ -401,9 +442,14 @@ impl VariableClassifier {
             _ => return Err(CompilationError::InvalidRuleHead),
         }
 
+        let mut classify_info = ClassifyInfo {
+            arg_c: 0,
+            arity: term.arity(),
+        };
+
         // false argument to breadth_first_iter because the root is not iterable.
         for term_ref in breadth_first_iter(term, false) {
-            if let TermRef::Var(_, _, var_name) = term_ref {
+            if let TermRef::Var(lvl, _, var_name) = term_ref {
                 // the body of the if let here is an inlined
                 // "probe_head_var". note the difference between it
                 // and "probe_body_var".
@@ -420,11 +466,21 @@ impl VariableClassifier {
                 let needs_new_chunk = branch_info.chunks.is_empty();
 
                 if needs_new_chunk {
-                    branch_info.chunks.push(ChunkInfo::new(self.current_chunk_num));
+                    branch_info.chunks.push(ChunkInfo {
+                        chunk_num: self.current_chunk_num,
+                        term_loc: GenContext::Head,
+                        vars: vec![]
+                    });
                 }
 
                 let chunk_info = branch_info.chunks.last_mut().unwrap();
-                chunk_info.vars.push(VarPtr::from(&var_name));
+                let var_info = VarInfo { var_ptr: VarPtr::from(&var_name), classify_info, lvl };
+
+                chunk_info.vars.push(var_info);
+            }
+
+            if let Level::Shallow = term_ref.level() {
+                classify_info.arg_c += 1;
             }
         }
 
@@ -584,6 +640,8 @@ impl VariableClassifier {
                             }
                         }
                         Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
+                            let term_loc = chunk_type.to_gen_context(self.current_chunk_num);
+
                             let predicate_name = terms.pop().unwrap();
                             let module_name = terms.pop().unwrap();
 
@@ -592,7 +650,7 @@ impl VariableClassifier {
                                     Term::Literal(_, Literal::Atom(module_name)),
                                     Term::Literal(_, Literal::Atom(predicate_name)),
                                 ) => {
-                                    if !ClauseType::is_inbuilt(name, 0) {
+                                    if !ClauseType::is_inbuilt(predicate_name, 0) {
                                         state_stack.push(TraversalState::IncrChunkNum);
                                     }
 
@@ -649,6 +707,8 @@ impl VariableClassifier {
                             }
                         }
                         Term::Clause(cell, atom!("$call_with_inference_counting"), terms) if terms.len() == 1 => {
+                            let term_loc = chunk_type.to_gen_context(self.current_chunk_num);
+
                             for term in terms.iter() {
                                 self.probe_body_term(term, term_loc);
                             }
@@ -663,6 +723,8 @@ impl VariableClassifier {
                                 state_stack.push(TraversalState::IncrChunkNum);
                             }
 
+                            let term_loc = chunk_type.to_gen_context(self.current_chunk_num);
+
                             for term in terms.iter() {
                                 self.probe_body_term(term, term_loc);
                             }
@@ -694,6 +756,7 @@ impl VariableClassifier {
                                 ),
                             );
                         }
+
                         _ => {
                             return Err(CompilationError::InadmissibleQueryTerm);
                         }
@@ -707,25 +770,18 @@ impl VariableClassifier {
 }
 
 impl BranchMap {
-    pub fn separate_and_classify_variables(&mut self) -> Vec<VarRecord> {
-        let mut var_num = 0usize;
-        let mut records = vec![];
+    pub fn separate_and_classify_variables(&mut self) -> VarData {
+        let mut var_num  = 0usize;
+        let mut var_data = VarData {
+            records:  vec![],
+            fixtures: VariableFixtures::new(),
+        };
 
         for branches in self.values_mut() {
             for branch in branches.iter_mut() {
                 let mut num_occurrences = 0;
                 let mut chunk_occurrences = vec![];
 
-                for chunk in branch.chunks.iter_mut() {
-                    num_occurrences += chunk.vars.len();
-
-                    for var in chunk.vars.iter_mut() {
-                        var.set(Var::Generated(var_num));
-                    }
-
-                    chunk_occurrences.push(chunk.chunk_num);
-                }
-
                 let classification = if branch.chunks.len() > 1 {
                     VarClassification::Perm
                 } else {
@@ -739,13 +795,37 @@ impl BranchMap {
                         .unwrap_or(VarClassification::Void)
                 };
 
-                records.push(VarRecord { classification, chunk_occurrences, num_occurrences });
+                for chunk in branch.chunks.iter_mut() {
+                    num_occurrences += chunk.vars.len();
+
+                    if let VarClassification::Temp = classification {
+                        for var_info in chunk.vars.iter_mut() {
+                            var_info.var_ptr.set(Var::Generated(var_num));
+                            var_data.fixtures.mark_temp_var(
+                                var_num,
+                                var_info.lvl,
+                                &var_info.classify_info,
+                                chunk.term_loc,
+                            );
+                        }
+                    } else {
+                        for var_info in chunk.vars.iter_mut() {
+                            var_info.var_ptr.set(Var::Generated(var_num));
+                        }
+                    }
+
+                    chunk_occurrences.push(chunk.chunk_num);
+                }
+
+                let record = VarRecord { classification, chunk_occurrences, num_occurrences };
+                var_data.records.push(record);
+
                 var_num += 1;
             }
         }
 
-        debug_assert_eq!(records.len(), var_num);
+        debug_assert_eq!(var_data.records.len(), var_num);
 
-        records
+        var_data
     }
 }
index 78bd55b4d9b6bf1dfaa6dba039affbc9530c8591..73c91c6a4070ce13d48cb64fad9bff1cc4f510ee 100644 (file)
@@ -227,7 +227,7 @@ macro_rules! perm_v {
     };
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum GenContext {
     Head,
     Mid(usize),