use std::collections::{BTreeMap, BTreeSet};
use indexmap::IndexMap;
use machine_check_common::iir::property::{
IProperty, ISubproperty, ISubpropertyFixedPoint, ISubpropertyFunc, ISubpropertyNext,
};
use crate::{
wir::{WProperty, WSubproperty, YConverted},
Error,
};
impl WProperty<YConverted> {
pub fn into_iir(self) -> Result<IProperty, Error> {
let mut subproperties = Vec::new();
let mut subproperty_dependencies = BTreeMap::<usize, BTreeSet<usize>>::new();
let mut subproperty_dependents = BTreeMap::<usize, Vec<usize>>::new();
for (subproperty_index, subproperty) in self.subproperties.iter().enumerate() {
subproperty_dependencies.insert(subproperty_index, subproperty.dependencies());
if let WSubproperty::FixedPoint(_) = subproperty {
subproperty_dependents.insert(subproperty_index, Vec::new());
}
}
for subproperty_index in 0..self.subproperties.len() {
for dependency_index in &subproperty_dependencies[&subproperty_index] {
let dependency = &self.subproperties[*dependency_index];
if let WSubproperty::FixedPoint(fixed_point) = dependency {
if Some(subproperty_index) != fixed_point.parent {
subproperty_dependents
.get_mut(dependency_index)
.expect("Fixed point should have dependents available")
.push(subproperty_index);
}
}
}
}
for (subproperty_index, subproperty) in self.subproperties.into_iter().enumerate() {
let subproperty = match subproperty {
WSubproperty::Func(subproperty) => ISubproperty::Func(ISubpropertyFunc {
parent: subproperty.parent,
func: subproperty.func.into_iir(&IndexMap::new())?,
children: subproperty.children,
dependencies: subproperty_dependencies
.remove(&subproperty_index)
.expect("Subproperty should have dependencies available"),
display: subproperty.display,
}),
WSubproperty::FixedPoint(subproperty) => {
let dependents = subproperty_dependents
.remove(&subproperty_index)
.expect("Fixed point should have dependents available");
ISubproperty::FixedPoint(ISubpropertyFixedPoint {
parent: subproperty.parent,
universal: subproperty.greatest,
inner: subproperty.inner,
dependents,
display: subproperty.display,
})
}
WSubproperty::Next(subproperty) => ISubproperty::Next(ISubpropertyNext {
parent: subproperty.parent,
universal: subproperty.universal,
inner: subproperty.inner,
display: subproperty.display,
}),
};
subproperties.push(subproperty);
}
Ok(IProperty { subproperties })
}
}