use log::debug;
use orrery_core::{identifier::Id, semantic};
use super::{
HierarchyNode,
graph_base::{EdgeIndex, GraphInternal},
};
use crate::RenderError;
#[derive(Debug)]
pub struct ContainmentScope<'a, 'idx> {
container: Option<Id>,
graph: GraphInternal<'a, Id, EdgeIndex<'idx>>,
}
impl<'a, 'idx> ContainmentScope<'a, 'idx> {
pub fn container(&self) -> Option<Id> {
self.container
}
pub fn node_ids(&self) -> impl Iterator<Item = Id> {
self.graph.nodes()
}
pub fn nodes_count(&self) -> usize {
self.graph.nodes_count()
}
fn new(container: Option<Id>) -> Self {
ContainmentScope {
container,
graph: GraphInternal::new(),
}
}
fn add_node(&mut self, node: &semantic::Node) {
let id = node.id();
self.graph.add_node(id, id);
}
fn contains_node(&self, id: Id) -> bool {
self.graph.contains_node(id)
}
fn root_ids(&self) -> impl Iterator<Item = Id> {
self.graph.roots()
}
fn outgoing_node_ids(&self, source_id: Id) -> impl Iterator<Item = Id> {
self.graph.outgoing_nodes(source_id)
}
fn add_relation(&mut self, source_id: Id, target_id: Id, relation_idx: EdgeIndex<'idx>) {
self.graph.add_edge(source_id, target_id, relation_idx);
}
fn relation_indices(&self) -> impl Iterator<Item = EdgeIndex<'idx>> {
self.graph.edges()
}
fn populate_component_graph(
graph: &mut ComponentGraph<'a, '_>,
elements: &'a [semantic::Element],
container: Option<Id>,
) -> Result<Vec<HierarchyNode<'a, 'idx>>, RenderError> {
let mut child_diagrams = vec![];
let mut containment_scope = ContainmentScope::new(container);
for element in elements {
if let semantic::Element::Node(node) = element {
graph.add_node(&mut containment_scope, node);
match node.block() {
semantic::Block::Scope(scope) => {
debug!(
"Processing nested scope with {} elements",
scope.elements().len()
);
let mut inner_child_diagrams = Self::populate_component_graph(
graph,
scope.elements(),
Some(node.id()),
)?;
child_diagrams.append(&mut inner_child_diagrams);
}
semantic::Block::Diagram(inner_diagram) => {
debug!(
"Processing nested diagram of kind {:?}",
inner_diagram.kind()
);
let inner_hierarchy_child =
HierarchyNode::build_from_ast_diagram(inner_diagram, Some(node.id()))?;
child_diagrams.push(inner_hierarchy_child);
}
semantic::Block::None => {}
}
}
}
for element in elements {
match element {
semantic::Element::Relation(relation) => {
graph.add_relation(&mut containment_scope, relation);
}
semantic::Element::Node(..) => {}
semantic::Element::Activate(..)
| semantic::Element::Deactivate(..)
| semantic::Element::Fragment(..)
| semantic::Element::Note(..) => {
unreachable!("Unexpected element type")
}
}
}
graph.containment_scopes.push(containment_scope);
Ok(child_diagrams)
}
}
#[derive(Debug)]
pub struct ComponentGraph<'a, 'idx> {
graph: GraphInternal<'idx, &'a semantic::Node, &'a semantic::Relation>,
containment_scopes: Vec<ContainmentScope<'a, 'idx>>,
}
impl<'a, 'idx> ComponentGraph<'a, 'idx> {
pub fn node_by_id(&self, id: Id) -> Option<&semantic::Node> {
self.graph.node(id)
}
pub fn containment_scopes(&self) -> std::slice::Iter<'_, ContainmentScope<'a, 'idx>> {
self.containment_scopes.iter()
}
pub fn scope_nodes(
&self,
containment_scope: &ContainmentScope,
) -> impl Iterator<Item = &semantic::Node> {
containment_scope
.node_ids()
.map(|id| self.graph.node_unchecked(id))
}
pub fn scope_relations(
&self,
containment_scope: &ContainmentScope,
) -> impl Iterator<Item = &semantic::Relation> {
containment_scope
.relation_indices()
.map(|idx| self.graph.edge_unchecked(idx))
}
pub fn scope_roots(
&self,
containment_scope: &ContainmentScope,
) -> impl Iterator<Item = &semantic::Node> {
containment_scope
.root_ids()
.map(|id| self.graph.node_unchecked(id))
}
pub fn scope_outgoing_neighbors(
&self,
containment_scope: &ContainmentScope,
source_id: Id,
) -> impl Iterator<Item = &semantic::Node> {
containment_scope
.outgoing_node_ids(source_id)
.map(|id| self.graph.node_unchecked(id))
}
pub(super) fn new_from_elements(
elements: &'a [semantic::Element],
) -> Result<(Self, Vec<HierarchyNode<'a, 'idx>>), RenderError> {
let mut graph = Self::new();
let children = ContainmentScope::populate_component_graph(&mut graph, elements, None)?;
Ok((graph, children))
}
fn new() -> Self {
Self {
graph: GraphInternal::new(),
containment_scopes: Vec::new(),
}
}
fn add_node(
&mut self,
containment_scope: &mut ContainmentScope<'a, 'idx>,
node: &'a semantic::Node,
) {
self.graph.add_node(node.id(), node);
containment_scope.add_node(node);
}
fn add_relation(
&mut self,
containment_scope: &mut ContainmentScope<'a, 'idx>,
relation: &'a semantic::Relation,
) {
let source_id = relation.source();
let target_id = relation.target();
let idx = self.graph.add_edge(source_id, target_id, relation);
if containment_scope.contains_node(source_id) && containment_scope.contains_node(target_id)
{
containment_scope.add_relation(source_id, target_id, idx);
}
}
}