///|
pub(all) struct DesignMetrics {
mut modules : Int
mut ports : Int
mut signals : Int
mut assignments : Int
mut always_blocks : Int
mut instances : Int
mut expressions : Int
mut statements : Int
mut maximum_control_depth : Int
} derive(Eq, Debug)
///|
fn append_unique(names : Array[String], name : String) -> Unit {
if !names.contains(name) {
names.push(name)
}
}
///|
pub fn Expression::referenced_names(self : Expression) -> Array[String] {
let names : Array[String] = []
match self {
Name(name, _) => names.push(name)
Unary(_, operand, _) =>
for name in operand.referenced_names() {
append_unique(names, name)
}
Binary(left, _, right, _) => {
for name in left.referenced_names() {
append_unique(names, name)
}
for name in right.referenced_names() {
append_unique(names, name)
}
}
Index(base, index, _) => {
for name in base.referenced_names() {
append_unique(names, name)
}
for name in index.referenced_names() {
append_unique(names, name)
}
}
Number(_, _) | StringLiteral(_, _) | Unknown(_) => ()
}
names
}
///|
pub fn Statement::assigned_names(self : Statement) -> Array[String] {
let names : Array[String] = []
match self {
Assignment(target, _, _, _) =>
for name in target.referenced_names() {
append_unique(names, name)
}
Block(_, _) => ()
If(_, then_branch, else_branch, _) => {
for name in then_branch.assigned_names() {
append_unique(names, name)
}
match else_branch {
Some(branch) =>
for name in branch.assigned_names() {
append_unique(names, name)
}
None => ()
}
}
Case(_, arms, _) =>
for arm in arms {
for name in arm.body.assigned_names() {
append_unique(names, name)
}
}
Empty(_) | Unknown(_) => ()
}
match self {
Block(statements, _) =>
for statement in statements {
for name in statement.assigned_names() {
append_unique(names, name)
}
}
_ => ()
}
names
}
///|
pub fn Statement::read_names(self : Statement) -> Array[String] {
let names : Array[String] = []
match self {
Assignment(target, value, _, _) => {
for name in value.referenced_names() {
append_unique(names, name)
}
for name in target.referenced_names() {
append_unique(names, name)
}
}
Block(statements, _) =>
for statement in statements {
for name in statement.read_names() {
append_unique(names, name)
}
}
If(condition, then_branch, else_branch, _) => {
for name in condition.referenced_names() {
append_unique(names, name)
}
for name in then_branch.read_names() {
append_unique(names, name)
}
match else_branch {
Some(branch) =>
for name in branch.read_names() {
append_unique(names, name)
}
None => ()
}
}
Case(expression, arms, _) => {
for name in expression.referenced_names() {
append_unique(names, name)
}
for arm in arms {
for choice in arm.choices {
for name in choice.referenced_names() {
append_unique(names, name)
}
}
for name in arm.body.read_names() {
append_unique(names, name)
}
}
}
Empty(_) | Unknown(_) => ()
}
names
}
///|
pub fn Statement::control_depth(self : Statement) -> Int {
match self {
Empty(_) | Unknown(_) | Assignment(_, _, _, _) => 0
Block(statements, _) => {
let mut depth = 0
for statement in statements {
let value = statement.control_depth()
if value > depth {
depth = value
}
}
depth
}
If(_, then_branch, else_branch, _) => {
let mut depth = 1 + then_branch.control_depth()
match else_branch {
Some(branch) => {
let value = 1 + branch.control_depth()
if value > depth {
depth = value
}
}
None => ()
}
depth
}
Case(_, arms, _) => {
let mut depth = 1
for arm in arms {
let value = 1 + arm.body.control_depth()
if value > depth {
depth = value
}
}
depth
}
}
}
///|
pub fn Module::port_names(self : Module) -> Array[String] {
self.ports.map(fn(port) { port.name })
}
///|
pub fn Module::signal_count(self : Module) -> Int {
self.signals.length()
}
///|
pub fn Module::assignment_count(self : Module) -> Int {
let mut count = 0
for item in self.items {
match item {
Assign(_) => count += 1
Statement(statement) => count += statement.assigned_names().length()
Always(always) => count += always.body.assigned_names().length()
_ => ()
}
}
count
}
///|
pub fn Design::metrics(self : Design) -> DesignMetrics {
let metrics : DesignMetrics = {
modules: self.modules.length(),
ports: 0,
signals: 0,
assignments: 0,
always_blocks: 0,
instances: 0,
expressions: 0,
statements: 0,
maximum_control_depth: 0,
}
for mod in self.modules {
metrics.ports += mod.ports.length()
metrics.signals += mod.signals.length()
metrics.assignments += mod.assignment_count()
metrics.instances += mod.instance_names().length()
for item in mod.items {
match item {
Assign(assign) => {
metrics.expressions += assign.target.node_count()
metrics.expressions += assign.value.node_count()
}
Always(always) => {
metrics.always_blocks += 1
metrics.statements += always.body.node_count()
let depth = always.body.control_depth()
if depth > metrics.maximum_control_depth {
metrics.maximum_control_depth = depth
}
}
Statement(statement) => {
metrics.statements += statement.node_count()
let depth = statement.control_depth()
if depth > metrics.maximum_control_depth {
metrics.maximum_control_depth = depth
}
}
Instance(_) | Unknown(_) => ()
}
}
}
metrics
}