use crate::{
impl_table_key,
ir::{DataFlowGraph, Entity, ExtUnit, Function, Process, Signature, Unit, UnitName},
table::PrimaryTable,
verifier::Verifier,
};
use std::collections::{BTreeSet, HashMap};
pub struct Module {
units: PrimaryTable<ModUnit, ModUnitData>,
unit_order: BTreeSet<ModUnit>,
link_table: Option<HashMap<(ModUnit, ExtUnit), ModUnit>>,
}
impl std::ops::Index<ModUnit> for Module {
type Output = ModUnitData;
fn index(&self, idx: ModUnit) -> &ModUnitData {
&self.units[idx]
}
}
impl std::ops::IndexMut<ModUnit> for Module {
fn index_mut(&mut self, idx: ModUnit) -> &mut ModUnitData {
self.link_table = None;
&mut self.units[idx]
}
}
impl Module {
pub fn new() -> Self {
Self {
units: PrimaryTable::new(),
unit_order: BTreeSet::new(),
link_table: None,
}
}
pub fn dump(&self) -> ModuleDumper {
ModuleDumper(self)
}
pub fn add_function(&mut self, func: Function) -> ModUnit {
self.add_unit(ModUnitData::Function(func))
}
pub fn add_process(&mut self, prok: Process) -> ModUnit {
self.add_unit(ModUnitData::Process(prok))
}
pub fn add_entity(&mut self, ent: Entity) -> ModUnit {
self.add_unit(ModUnitData::Entity(ent))
}
pub fn declare(&mut self, name: UnitName, sig: Signature) -> ModUnit {
self.add_unit(ModUnitData::Declare { sig, name })
}
fn add_unit(&mut self, data: ModUnitData) -> ModUnit {
let unit = self.units.add(data);
self.unit_order.insert(unit);
self.link_table = None;
unit
}
pub fn remove_unit(&mut self, unit: ModUnit) {
self.units.remove(unit);
self.unit_order.remove(&unit);
}
pub fn units<'a>(&'a self) -> impl Iterator<Item = ModUnit> + 'a {
self.unit_order.iter().cloned()
}
pub fn functions<'a>(&'a self) -> impl Iterator<Item = &'a Function> + 'a {
self.units().flat_map(move |unit| self[unit].get_function())
}
pub fn processes<'a>(&'a self) -> impl Iterator<Item = &'a Process> + 'a {
self.units().flat_map(move |unit| self[unit].get_process())
}
pub fn entities<'a>(&'a self) -> impl Iterator<Item = &'a Entity> + 'a {
self.units().flat_map(move |unit| self[unit].get_entity())
}
pub fn declarations<'a>(&'a self) -> impl Iterator<Item = (&'a UnitName, &'a Signature)> + 'a {
self.units()
.flat_map(move |unit| self[unit].get_declaration())
}
pub fn is_function(&self, unit: ModUnit) -> bool {
self[unit].is_function()
}
pub fn is_process(&self, unit: ModUnit) -> bool {
self[unit].is_process()
}
pub fn is_entity(&self, unit: ModUnit) -> bool {
self[unit].is_entity()
}
pub fn is_declaration(&self, unit: ModUnit) -> bool {
self[unit].is_declaration()
}
pub fn unit_name(&self, unit: ModUnit) -> &UnitName {
self[unit].name()
}
pub fn unit_sig(&self, unit: ModUnit) -> &Signature {
self[unit].sig()
}
pub fn get_function(&self, unit: ModUnit) -> Option<&Function> {
self[unit].get_function()
}
pub fn get_function_mut(&mut self, unit: ModUnit) -> Option<&mut Function> {
self.link_table = None;
self[unit].get_function_mut()
}
pub fn function(&self, unit: ModUnit) -> &Function {
self[unit].get_function().expect("unit is not a function")
}
pub fn function_mut(&mut self, unit: ModUnit) -> &mut Function {
self.link_table = None;
self[unit]
.get_function_mut()
.expect("unit is not a function")
}
pub fn get_process(&self, unit: ModUnit) -> Option<&Process> {
self[unit].get_process()
}
pub fn get_process_mut(&mut self, unit: ModUnit) -> Option<&mut Process> {
self.link_table = None;
self[unit].get_process_mut()
}
pub fn process(&self, unit: ModUnit) -> &Process {
self[unit].get_process().expect("unit is not a process")
}
pub fn process_mut(&mut self, unit: ModUnit) -> &mut Process {
self.link_table = None;
self[unit].get_process_mut().expect("unit is not a process")
}
pub fn get_entity(&self, unit: ModUnit) -> Option<&Entity> {
self[unit].get_entity()
}
pub fn get_entity_mut(&mut self, unit: ModUnit) -> Option<&mut Entity> {
self.link_table = None;
self[unit].get_entity_mut()
}
pub fn entity(&self, unit: ModUnit) -> &Entity {
self[unit].get_entity().expect("unit is not an entity")
}
pub fn entity_mut(&mut self, unit: ModUnit) -> &mut Entity {
self.link_table = None;
self[unit].get_entity_mut().expect("unit is not an entity")
}
pub fn symbols<'a>(&'a self) -> impl Iterator<Item = (&UnitName, ModUnit)> + 'a {
self.units().map(move |unit| (self[unit].name(), unit))
}
pub fn local_symbols<'a>(&'a self) -> impl Iterator<Item = (&UnitName, ModUnit)> + 'a {
self.symbols().filter(|&(name, _)| name.is_local())
}
pub fn global_symbols<'a>(&'a self) -> impl Iterator<Item = (&UnitName, ModUnit)> + 'a {
self.symbols().filter(|&(name, _)| name.is_global())
}
pub fn is_linked(&self) -> bool {
self.link_table.is_some()
}
pub fn link(&mut self) {
let mut failed = false;
let mut symbols = HashMap::new();
for (name, unit) in self.symbols() {
if let Some(existing) = symbols.insert(name, unit) {
if !self[existing].is_declaration() {
eprintln!("unit {} declared multiple times", name);
failed = true;
}
}
}
if failed {
panic!("linking failed; multiple uses of the same name");
}
let mut linked = HashMap::new();
for unit in self.units() {
let dfg = match self[unit].get_dfg() {
Some(dfg) => dfg,
None => continue,
};
for (ext_unit, data) in dfg.ext_units.iter() {
let to = match symbols.get(&data.name).cloned() {
Some(to) => to,
None => {
eprintln!(
"unit {} not found; referenced in {}",
data.name,
self.unit_name(unit)
);
failed = true;
continue;
}
};
if self.unit_sig(to) != &data.sig {
eprintln!(
"signature mismatch: {} has {}, but reference in {} expects {}",
data.name,
self.unit_sig(to),
self.unit_name(unit),
data.sig
);
failed = true;
continue;
}
linked.insert((unit, ext_unit), to);
}
}
if failed {
panic!("linking failed; unresolved references");
}
self.link_table = Some(linked);
}
pub fn verify(&self) {
let mut verifier = Verifier::new();
verifier.verify_module(self);
match verifier.finish() {
Ok(()) => (),
Err(errs) => {
eprintln!("");
eprintln!("Verified module:");
eprintln!("{}", self.dump());
eprintln!("");
eprintln!("Verification errors:");
eprintln!("{}", errs);
panic!("verification failed");
}
}
}
}
pub struct ModuleDumper<'a>(&'a Module);
impl std::fmt::Display for ModuleDumper<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut newline = false;
for unit in self.0.units() {
if newline {
writeln!(f, "")?;
writeln!(f, "")?;
}
newline = true;
write!(f, "{}: ", unit)?;
match &self.0[unit] {
ModUnitData::Function(unit) => write!(f, "{}", unit.dump())?,
ModUnitData::Process(unit) => write!(f, "{}", unit.dump())?,
ModUnitData::Entity(unit) => write!(f, "{}", unit.dump())?,
ModUnitData::Declare { sig, name } => write!(f, "declare {} {}", name, sig)?,
}
}
Ok(())
}
}
impl_table_key! {
struct ModUnit(u32) as "u";
}
pub enum ModUnitData {
Function(Function),
Process(Process),
Entity(Entity),
Declare { sig: Signature, name: UnitName },
}
impl ModUnitData {
pub fn get_function(&self) -> Option<&Function> {
match self {
ModUnitData::Function(unit) => Some(unit),
_ => None,
}
}
pub fn get_function_mut(&mut self) -> Option<&mut Function> {
match self {
ModUnitData::Function(unit) => Some(unit),
_ => None,
}
}
pub fn get_process(&self) -> Option<&Process> {
match self {
ModUnitData::Process(unit) => Some(unit),
_ => None,
}
}
pub fn get_process_mut(&mut self) -> Option<&mut Process> {
match self {
ModUnitData::Process(unit) => Some(unit),
_ => None,
}
}
pub fn get_entity(&self) -> Option<&Entity> {
match self {
ModUnitData::Entity(unit) => Some(unit),
_ => None,
}
}
pub fn get_entity_mut(&mut self) -> Option<&mut Entity> {
match self {
ModUnitData::Entity(unit) => Some(unit),
_ => None,
}
}
pub fn get_declaration(&self) -> Option<(&UnitName, &Signature)> {
match self {
ModUnitData::Declare { sig, name } => Some((name, sig)),
_ => None,
}
}
pub fn get_declaration_mut(&mut self) -> Option<(&mut UnitName, &mut Signature)> {
match self {
ModUnitData::Declare { sig, name } => Some((name, sig)),
_ => None,
}
}
pub fn is_function(&self) -> bool {
match self {
ModUnitData::Function(..) => true,
_ => false,
}
}
pub fn is_process(&self) -> bool {
match self {
ModUnitData::Process(..) => true,
_ => false,
}
}
pub fn is_entity(&self) -> bool {
match self {
ModUnitData::Entity(..) => true,
_ => false,
}
}
pub fn is_declaration(&self) -> bool {
match self {
ModUnitData::Declare { .. } => true,
_ => false,
}
}
pub fn sig(&self) -> &Signature {
match self {
ModUnitData::Function(unit) => unit.sig(),
ModUnitData::Process(unit) => unit.sig(),
ModUnitData::Entity(unit) => unit.sig(),
ModUnitData::Declare { sig, .. } => sig,
}
}
pub fn name(&self) -> &UnitName {
match self {
ModUnitData::Function(unit) => unit.name(),
ModUnitData::Process(unit) => unit.name(),
ModUnitData::Entity(unit) => unit.name(),
ModUnitData::Declare { name, .. } => name,
}
}
pub fn get_dfg(&self) -> Option<&DataFlowGraph> {
match self {
ModUnitData::Function(unit) => Some(unit.dfg()),
ModUnitData::Process(unit) => Some(unit.dfg()),
ModUnitData::Entity(unit) => Some(unit.dfg()),
_ => None,
}
}
pub fn get_dfg_mut(&mut self) -> Option<&mut DataFlowGraph> {
match self {
ModUnitData::Function(unit) => Some(unit.dfg_mut()),
ModUnitData::Process(unit) => Some(unit.dfg_mut()),
ModUnitData::Entity(unit) => Some(unit.dfg_mut()),
_ => None,
}
}
}