use crate::HashMap;
use crate::conv::context::Config;
use crate::ir::{Component, Signature};
use std::collections::hash_map::Entry;
use std::sync::Arc;
use veryl_parser::token_range::TokenRange;
#[derive(Clone, Default)]
pub struct InstanceHistory {
hierarchy: Vec<(Signature, Option<TokenRange>)>,
full: HashMap<Signature, Option<(Arc<Component>, bool)>>,
}
impl InstanceHistory {
pub fn get(&self, sig: &Signature) -> Option<(Arc<Component>, bool)> {
self.full.get(sig).cloned().flatten()
}
pub fn set(&mut self, sig: &Signature, component: Arc<Component>, in_generic: bool) {
if let Some(x) = self.full.get_mut(sig) {
*x = Some((component, in_generic));
}
}
pub fn remove(&mut self, sig: &Signature) {
self.full.remove(sig);
}
pub fn get_current_signature(&self) -> Option<&Signature> {
self.hierarchy.last().map(|(sig, _)| sig)
}
pub fn overridden_frames(&self) -> Vec<(&Signature, &TokenRange)> {
let mut ret: Vec<_> = self
.hierarchy
.iter()
.rev()
.map_while(|(sig, site)| {
site.as_ref()
.filter(|_| sig.has_overrides())
.map(|x| (sig, x))
})
.collect();
ret.reverse();
ret
}
pub fn push(
&mut self,
mut sig: Signature,
site: Option<TokenRange>,
config: &Config,
) -> Result<bool, InstanceHistoryError> {
sig.normalize();
if self.hierarchy.len() > config.instance_depth_limit {
return Err(InstanceHistoryError::ExceedDepthLimit(self.hierarchy.len()));
}
if self.full.len() > config.instance_total_limit {
return Err(InstanceHistoryError::ExceedTotalLimit(self.full.len()));
}
if self.hierarchy.iter().any(|(x, _)| *x == sig) {
return Err(InstanceHistoryError::InfiniteRecursion);
}
self.hierarchy.push((sig.clone(), site));
match self.full.entry(sig) {
Entry::Occupied(_) => Ok(false),
Entry::Vacant(x) => {
x.insert(None);
Ok(true)
}
}
}
pub fn pop(&mut self) {
self.hierarchy.pop();
}
pub fn clear(&mut self) {
self.hierarchy.clear();
self.full.clear();
}
}
#[derive(Debug)]
pub enum InstanceHistoryError {
ExceedDepthLimit(usize),
ExceedTotalLimit(usize),
InfiniteRecursion,
}