///|
pub(all) enum ContractStatus {
Match
WidthMismatch
DirectionMismatch
MissingPort
UnknownModule
UnknownWidth
} derive(Eq, Debug)
///|
pub(all) struct PortContract {
parent_module : String
instance_name : String
port_name : String
expression_name : String?
status : ContractStatus
span : @source.Span
} derive(Eq, Debug)
///|
fn connection_port(
child : ModuleInfo,
connection : @syntax.Connection,
index : Int,
) -> @syntax.Port? {
match connection.port_name {
Some(name) => {
let mut result : @syntax.Port? = None
for port in child.ports {
if port.name == name {
result = Some(port)
}
}
result
}
None => child.ports.get(index)
}
}
///|
fn contract_status(parent_width : Width, child_width : Width) -> ContractStatus {
match (parent_width, child_width) {
(Known(left), Known(right)) =>
if left == right {
Match
} else {
WidthMismatch
}
_ => UnknownWidth
}
}
///|
fn contracts_for_instance(
modules : Array[ModuleInfo],
parent_name : String,
instance : @syntax.Instance,
) -> Array[PortContract] {
let contracts : Array[PortContract] = []
let mut child : ModuleInfo? = None
for mod in modules {
if mod.name == instance.module_name {
child = Some(mod)
}
}
match child {
None =>
for connection in instance.connections {
contracts.push({
parent_module: parent_name,
instance_name: instance.instance_name,
port_name: match connection.port_name {
Some(name) => name
None => ""
},
expression_name: expression_name(connection.expression),
status: UnknownModule,
span: connection.span,
})
}
Some(child_module) =>
for index, connection in instance.connections {
match connection_port(child_module, connection, index) {
None =>
contracts.push({
parent_module: parent_name,
instance_name: instance.instance_name,
port_name: match connection.port_name {
Some(name) => name
None => ""
},
expression_name: expression_name(connection.expression),
status: MissingPort,
span: connection.span,
})
Some(port) =>
contracts.push({
parent_module: parent_name,
instance_name: instance.instance_name,
port_name: port.name,
expression_name: expression_name(connection.expression),
status: contract_status(
expression_width(modules, parent_name, connection.expression),
width_of_range(port.width),
),
span: connection.span,
})
}
}
}
contracts
}
///|
/// Return one stable contract result for every instance connection.
pub fn SemanticIndex::port_contracts(
self : SemanticIndex,
) -> Array[PortContract] {
let contracts : Array[PortContract] = []
for mod in self.modules {
for item in mod.instances {
match self.source_instance(mod.name, item.instance_name) {
Some(instance) =>
for
contract in contracts_for_instance(self.modules, mod.name, instance) {
contracts.push(contract)
}
None => ()
}
}
}
contracts
}
///|
fn SemanticIndex::source_instance(
self : SemanticIndex,
parent_name : String,
instance_name : String,
) -> @syntax.Instance? {
for mod in self.modules {
if mod.name == parent_name {
for item in mod.instances {
if item.instance_name == instance_name {
for syntax_mod in self.syntax_modules {
if syntax_mod.name == parent_name {
for syntax_item in syntax_mod.items {
match syntax_item {
@syntax.Instance(value) =>
if value.instance_name == instance_name {
return Some(value)
}
_ => ()
}
}
}
}
}
}
}
}
None
}