use crate::{
semantic_analysis::{ast_node::TypedEnumVariant, ast_node::TypedStructField, TypedAstNode},
Ident,
};
use sway_types::span::Span;
use petgraph::{graph::EdgeIndex, prelude::NodeIndex};
mod namespace;
use namespace::ControlFlowNamespace;
pub(crate) use namespace::FunctionNamespaceEntry;
pub type EntryPoint = NodeIndex;
pub type ExitPoint = NodeIndex;
#[derive(Clone, Default)]
pub struct ControlFlowGraph {
pub(crate) graph: Graph,
pub(crate) entry_points: Vec<NodeIndex>,
pub(crate) namespace: ControlFlowNamespace,
}
pub type Graph = petgraph::Graph<ControlFlowGraphNode, ControlFlowGraphEdge>;
#[derive(Clone)]
pub struct ControlFlowGraphEdge(String);
impl std::fmt::Debug for ControlFlowGraphEdge {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl std::convert::From<&str> for ControlFlowGraphEdge {
fn from(o: &str) -> Self {
ControlFlowGraphEdge(o.to_string())
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone)]
pub enum ControlFlowGraphNode {
OrganizationalDominator(String),
#[allow(clippy::large_enum_variant)]
ProgramNode(TypedAstNode),
EnumVariant {
span: Span,
variant_name: String,
},
MethodDeclaration {
span: Span,
method_name: Ident,
},
StructField {
struct_field_name: Ident,
span: Span,
},
}
impl std::fmt::Debug for ControlFlowGraphNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
ControlFlowGraphNode::OrganizationalDominator(s) => s.to_string(),
ControlFlowGraphNode::ProgramNode(node) => format!("{:?}", node),
ControlFlowGraphNode::EnumVariant { variant_name, .. } => {
format!("Enum variant {}", variant_name)
}
ControlFlowGraphNode::MethodDeclaration { method_name, .. } => {
format!("Method {}", method_name.as_str())
}
ControlFlowGraphNode::StructField {
struct_field_name, ..
} => {
format!("Struct field {}", struct_field_name.as_str())
}
};
f.write_str(&text)
}
}
impl std::convert::From<&TypedAstNode> for ControlFlowGraphNode {
fn from(other: &TypedAstNode) -> Self {
ControlFlowGraphNode::ProgramNode(other.clone())
}
}
impl std::convert::From<&TypedEnumVariant> for ControlFlowGraphNode {
fn from(other: &TypedEnumVariant) -> Self {
ControlFlowGraphNode::EnumVariant {
variant_name: other.name.as_str().to_string(),
span: other.span.clone(),
}
}
}
impl std::convert::From<&TypedStructField> for ControlFlowGraphNode {
fn from(other: &TypedStructField) -> Self {
ControlFlowGraphNode::StructField {
struct_field_name: other.name.clone(),
span: other.span.clone(),
}
}
}
impl std::convert::From<String> for ControlFlowGraphNode {
fn from(other: String) -> Self {
ControlFlowGraphNode::OrganizationalDominator(other)
}
}
impl std::convert::From<&str> for ControlFlowGraphNode {
fn from(other: &str) -> Self {
ControlFlowGraphNode::OrganizationalDominator(other.to_string())
}
}
impl ControlFlowGraph {
pub(crate) fn add_edge_from_entry(&mut self, to: NodeIndex, label: ControlFlowGraphEdge) {
for entry in &self.entry_points {
self.graph.add_edge(*entry, to, label.clone());
}
}
pub(crate) fn add_node(&mut self, node: ControlFlowGraphNode) -> NodeIndex {
self.graph.add_node(node)
}
pub(crate) fn add_edge(
&mut self,
from: NodeIndex,
to: NodeIndex,
edge: ControlFlowGraphEdge,
) -> EdgeIndex {
self.graph.add_edge(from, to, edge)
}
#[allow(dead_code)]
pub(crate) fn visualize(&self) {
use petgraph::dot::Dot;
println!("{:?}", Dot::with_config(&self.graph, &[]));
}
}