use crate::netlist::{ElabError, InstanceId, TemplateId};
#[derive(Debug, Clone)]
pub struct InstanceNode {
pub id: InstanceId,
pub template: TemplateId,
pub parent: Option<InstanceId>,
pub name: String,
pub array_path: Vec<u32>,
pub children: Vec<InstanceId>,
}
pub(crate) fn array_path_of(instance: sv_lang::Symbol<'_>) -> Result<Vec<u32>, ElabError> {
let via_instance_array: Vec<u32> = instance.instance_array_path().collect();
if !via_instance_array.is_empty() {
return Ok(via_instance_array);
}
let mut indices: Vec<u32> = Vec::new();
let mut current = instance.parent();
while let Some(sym) = current {
match sym.kind() {
sv_lang_kinds::SymbolKind::InstanceBody | sv_lang_kinds::SymbolKind::Root => break,
sv_lang_kinds::SymbolKind::GenerateBlockArray => {}
sv_lang_kinds::SymbolKind::GenerateBlock => {
if let Some(index) = sym.generate_block_array_index() {
let v = index.as_i64().ok_or_else(|| {
ElabError::Frontend(format!(
"generate block `{}` has a non-integer loop-iteration index",
sym.hierarchical_path()
))
})?;
let v = u32::try_from(v).map_err(|_| ElabError::Frontend(format!(
"generate block `{}` has an out-of-range/negative loop-iteration index {v}",
sym.hierarchical_path()
)))?;
indices.push(v);
}
}
other => {
return Err(ElabError::UnsupportedConstruct {
hier_path: sym.hierarchical_path(),
detail: format!(
"unrecognized ancestor of kind {other:?} between instance `{}` and its enclosing InstanceBody",
instance.hierarchical_path()
),
});
}
}
current = sym.parent();
}
indices.reverse();
Ok(indices)
}
#[derive(Debug, Default)]
pub struct InstanceTree {
nodes: Vec<InstanceNode>,
}
impl InstanceTree {
pub(crate) fn new() -> Self {
InstanceTree { nodes: Vec::new() }
}
pub(crate) fn push(&mut self, node: InstanceNode) -> usize {
self.nodes.push(node);
self.nodes.len() - 1
}
pub(crate) fn node_mut(&mut self, id: InstanceId) -> &mut InstanceNode {
&mut self.nodes[id.0 as usize]
}
pub fn node(&self, id: InstanceId) -> &InstanceNode {
&self.nodes[id.0 as usize]
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
}