From a66d666beda87024691dda2ce9d17baeb149114e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 13 Nov 2022 10:13:37 -0700 Subject: [PATCH] variable classification al a carte --- Cargo.lock | 1 + Cargo.toml | 1 + src/allocator.rs | 22 +++-- src/codegen.rs | 23 +++-- src/fixtures.rs | 180 ++++++++++++--------------------------- src/iterators.rs | 1 - src/machine/disjuncts.rs | 156 ++++++++++++++++++++++++--------- src/parser/ast.rs | 2 +- 8 files changed, 198 insertions(+), 188 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46c5a14f..7cc11f21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1855,6 +1855,7 @@ version = "0.9.1" dependencies = [ "assert_cmd", "base64", + "bit-set", "blake2 0.8.1", "chrono", "cpu-time", diff --git a/Cargo.toml b/Cargo.toml index 975ba64f..f358126a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/allocator.rs b/src/allocator.rs index bc0d2f44..50e9c7c3 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -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(), } } } diff --git a/src/codegen.rs b/src/codegen.rs index a3fdc99b..65f49971 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -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 { 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); diff --git a/src/fixtures.rs b/src/fixtures.rs index 67740989..f75a8042 100644 --- a/src/fixtures.rs +++ b/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, + pub(crate) conflict_set: BitSet, } -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, - pub(crate) conflict_set: BTreeSet, -} - 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 = (1..arity).collect(); + let mut conflict_set: BitSet = (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>); - #[derive(Debug)] -pub(crate) struct VariableFixtures<'a> { - perm_vars: IndexMap>, - last_chunk_temp_vars: IndexSet, // TODO: has no use at all! +pub(crate) struct VariableFixtures { + temp_vars: IndexMap, + last_chunk_temp_vars: IndexSet, // 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 = IndexMap::new(); + let mut use_sets: IndexMap = 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> { - 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(&mut self, iter: I, lt_arity: usize, term_loc: GenContext) - where - I: Iterator>, - { + 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> { - self.perm_vars.into_iter() - } - - fn values(&self) -> indexmap::map::Values> { - 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); } } diff --git a/src/iterators.rs b/src/iterators.rs index ac87a451..bbd9fb70 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -40,7 +40,6 @@ impl VarPtr { } } - #[derive(Debug, Clone)] pub(crate) enum TermRef<'a> { AnonVar(Level), diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index adbf341c..19e460c3 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -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, // 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, } #[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); -pub type ClassifyRuleResult = (Term, Vec, Vec); +// 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, + pub fixtures: VariableFixtures, +} + +pub type ClassifyFactResult = (Term, VarData); +pub type ClassifyRuleResult = (Term, Vec, VarData); fn merge_branch_seq>(branches: Iter) -> BranchInfo { let mut branch_info = BranchInfo::new(BranchNumber::default()); @@ -238,19 +266,20 @@ fn flatten_into_disjunct(build_stack: &mut Vec, preceding_len: usize) fn term_in_other_chunk(term: &Term) -> Option { 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, - iter: impl Iterator, + mut iter: impl Iterator, ) -> 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 { - 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 } } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 78bd55b4..73c91c6a 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -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), -- 2.54.0