///|
pub(all) struct ModuleMetrics {
module_name : String
ports : Int
signals : Int
instances : Int
items : Int
driven_signals : Int
undriven_signals : Int
expression_nodes : Int
} derive(Eq, Debug)
///|
pub fn SemanticIndex::module_metrics(
self : SemanticIndex,
module_name : String,
) -> ModuleMetrics? {
match self.find_module(module_name) {
None => None
Some(mod) => {
let mut driven = 0
let mut undriven = 0
for signal in mod.signals {
if signal.has_driver() {
driven += 1
} else if !signal.from_port {
undriven += 1
}
}
let mut expression_nodes = 0
for syntax_mod in self.syntax_modules {
if syntax_mod.name == module_name {
for item in syntax_mod.items {
match item {
@syntax.Assign(assign) => {
expression_nodes += assign.target.node_count()
expression_nodes += assign.value.node_count()
}
@syntax.Always(always) =>
expression_nodes += always.body.node_count()
@syntax.Statement(statement) =>
expression_nodes += statement.node_count()
_ => ()
}
}
}
}
Some({
module_name,
ports: mod.ports.length(),
signals: mod.signals.length(),
instances: mod.instances.length(),
items: mod.ports.length() +
mod.signals.length() +
mod.instances.length(),
driven_signals: driven,
undriven_signals: undriven,
expression_nodes,
})
}
}
}
///|
pub fn SemanticIndex::all_module_metrics(
self : SemanticIndex,
) -> Array[ModuleMetrics] {
let result : Array[ModuleMetrics] = []
for mod in self.modules {
match self.module_metrics(mod.name) {
Some(metrics) => result.push(metrics)
None => ()
}
}
result
}
///|
pub fn SemanticIndex::dependency_nodes(self : SemanticIndex) -> Array[String] {
let names : Array[String] = []
for mod in self.modules {
if !names.contains(mod.name) {
names.push(mod.name)
}
}
for edge in self.graph.edges() {
let (parent, child) = edge
if !names.contains(parent) {
names.push(parent)
}
if !names.contains(child) {
names.push(child)
}
}
names
}
///|
pub fn SemanticIndex::reverse_dependencies(
self : SemanticIndex,
child_name : String,
) -> Array[String] {
let result : Array[String] = []
for edge in self.graph.edges() {
let (parent, child) = edge
if child == child_name && !result.contains(parent) {
result.push(parent)
}
}
result
}
///|
pub fn SemanticIndex::children_of(
self : SemanticIndex,
parent_name : String,
) -> Array[String] {
let result : Array[String] = []
for edge in self.graph.edges() {
let (parent, child) = edge
if parent == parent_name && !result.contains(child) {
result.push(child)
}
}
result
}
///|
fn add_reachable(
index : SemanticIndex,
name : String,
seen : Array[String],
) -> Unit {
if seen.contains(name) {
return
}
seen.push(name)
for child in index.children_of(name) {
add_reachable(index, child, seen)
}
}
///|
pub fn SemanticIndex::reachable_modules(
self : SemanticIndex,
root : String,
) -> Array[String] {
let result : Array[String] = []
add_reachable(self, root, result)
result
}
///|
pub fn SemanticIndex::is_recursive(self : SemanticIndex, root : String) -> Bool {
let reachable = self.reachable_modules(root)
for child in self.children_of(root) {
if child == root ||
(reachable.contains(child) && self.children_of(child).contains(root)) {
return true
}
}
false
}
///|
pub fn SemanticIndex::graph_depth(self : SemanticIndex, root : String) -> Int {
let mut frontier : Array[String] = [root]
let seen : Array[String] = [root]
let mut depth = 0
while frontier.length() > 0 {
let next : Array[String] = []
for name in frontier {
for child in self.children_of(name) {
if !seen.contains(child) {
seen.push(child)
next.push(child)
}
}
}
if next.length() > 0 {
depth += 1
}
frontier = next
}
depth
}
///|
pub fn SemanticIndex::edge_count(self : SemanticIndex) -> Int {
self.graph.edges().length()
}
///|
pub fn SemanticIndex::duplicate_edge_count(self : SemanticIndex) -> Int {
let mut duplicates = 0
let edges = self.graph.edges()
for i, edge in edges {
for j in 0.. Int {
let mut count = 0
for mod in self.modules {
for signal in mod.signals {
if signal.width is Known(value) && value == width {
count += 1
}
}
}
count
}
///|
pub fn SemanticIndex::unknown_width_count(self : SemanticIndex) -> Int {
let mut count = 0
for mod in self.modules {
for signal in mod.signals {
if signal.width is Unknown {
count += 1
}
}
}
count
}
///|
pub fn SemanticIndex::driver_kind_count(
self : SemanticIndex,
kind : DriveKind,
) -> Int {
let mut count = 0
for mod in self.modules {
for signal in mod.signals {
for driver in signal.drivers {
if driver.kind == kind {
count += 1
}
}
}
}
count
}
///|
pub fn SemanticIndex::contract_status_count(
self : SemanticIndex,
status : ContractStatus,
) -> Int {
let mut count = 0
for contract in self.port_contracts() {
if contract.status == status {
count += 1
}
}
count
}
///|
pub fn SemanticIndex::analytics_summary(self : SemanticIndex) -> String {
"modules=" +
self.module_count().to_string() +
", edges=" +
self.edge_count().to_string() +
", roots=" +
self.hierarchy_roots().length().to_string() +
", unknown_widths=" +
self.unknown_width_count().to_string() +
", undriven=" +
self.undriven_total().to_string()
}
///|
pub fn SemanticIndex::undriven_total(self : SemanticIndex) -> Int {
let mut count = 0
for mod in self.modules {
count += self.undriven_signals(mod.name).length()
}
count
}