variable classification al a carte
This commit is contained in:
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
180
src/fixtures.rs
180
src/fixtures.rs
@@ -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(®);
|
||||
@@ -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,24 +142,13 @@ 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();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
let TempVarStatus { ref mut temp_var_data, ..} = self.temp_vars.get_mut(u).unwrap();
|
||||
|
||||
temp_var_data.use_set = use_set;
|
||||
temp_var_data.populate_conflict_set();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, u: Var) -> Option<&mut VariableFixture<'a>> {
|
||||
self.perm_vars.get_mut(&u)
|
||||
}
|
||||
|
||||
fn iter_mut(&mut self) -> indexmap::map::IterMut<Var, VariableFixture<'a>> {
|
||||
self.perm_vars.iter_mut()
|
||||
}
|
||||
|
||||
fn record_temp_info(&mut self, tvd: &mut TempVarData, arg_c: usize, term_loc: GenContext) {
|
||||
match term_loc {
|
||||
GenContext::Head | GenContext::Last(_) => {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ impl VarPtr {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum TermRef<'a> {
|
||||
AnonVar(Level),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user