use crate::{
impl_table_key,
ir::{ExtUnit, Signature, Unit, UnitBuilder, UnitData, UnitName},
table::{PrimaryTable, TableKey},
verifier::Verifier,
};
use rayon::prelude::*;
use std::collections::{BTreeSet, HashMap};
#[derive(Serialize, Deserialize)]
pub struct Module {
pub(crate) units: PrimaryTable<UnitId, UnitData>,
unit_order: BTreeSet<UnitId>,
pub(crate) decls: PrimaryTable<DeclId, DeclData>,
decl_order: BTreeSet<DeclId>,
link_table: Option<HashMap<(UnitId, ExtUnit), LinkedUnit>>,
location_hints: HashMap<UnitId, usize>,
}
impl Module {
pub fn new() -> Self {
Self {
units: PrimaryTable::new(),
unit_order: BTreeSet::new(),
decls: PrimaryTable::new(),
decl_order: BTreeSet::new(),
link_table: None,
location_hints: Default::default(),
}
}
pub fn dump(&self) -> ModuleDumper {
ModuleDumper(self)
}
pub fn add_unit(&mut self, data: UnitData) -> UnitId {
let unit = self.units.add(data);
self.unit_order.insert(unit);
self.link_table = None;
unit
}
pub fn remove_unit(&mut self, unit: UnitId) {
self.units.remove(unit);
self.unit_order.remove(&unit);
}
pub fn declare(&mut self, name: UnitName, sig: Signature) -> DeclId {
self.add_decl(DeclData {
name,
sig,
loc: None,
})
}
pub fn add_decl(&mut self, data: DeclData) -> DeclId {
let decl = self.decls.add(data);
self.decl_order.insert(decl);
self.link_table = None;
decl
}
pub fn remove_decl(&mut self, decl: DeclId) {
self.decls.remove(decl);
self.decl_order.remove(&decl);
}
pub fn units<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
self.unit_order.iter().map(move |&id| self.unit(id))
}
pub fn units_mut<'a>(&'a mut self) -> impl Iterator<Item = UnitBuilder<'a>> + 'a {
self.units
.storage
.iter_mut()
.map(|(&id, data)| UnitBuilder::new(UnitId::new(id), data))
}
pub fn par_units<'a>(&'a self) -> impl ParallelIterator<Item = Unit<'a>> + 'a {
self.unit_order.par_iter().map(move |&id| self.unit(id))
}
pub fn par_units_mut<'a>(&'a mut self) -> impl ParallelIterator<Item = UnitBuilder<'a>> + 'a {
self.units
.storage
.par_iter_mut()
.map(|(&id, data)| UnitBuilder::new(UnitId::new(id), data))
}
pub fn functions<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
self.units().filter(|unit| unit.is_function())
}
pub fn processes<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
self.units().filter(|unit| unit.is_process())
}
pub fn entities<'a>(&'a self) -> impl Iterator<Item = Unit<'a>> + 'a {
self.units().filter(|unit| unit.is_entity())
}
pub fn decls<'a>(&'a self) -> impl Iterator<Item = DeclId> + 'a {
self.decl_order.iter().cloned()
}
pub fn unit(&self, unit: UnitId) -> Unit {
Unit::new(unit, &self[unit])
}
pub fn unit_mut(&mut self, unit: UnitId) -> UnitBuilder {
self.link_table = None;
UnitBuilder::new(unit, &mut self[unit])
}
pub fn symbols<'a>(&'a self) -> impl Iterator<Item = (&UnitName, LinkedUnit, &Signature)> + 'a {
self.units()
.map(|unit| (unit.name(), LinkedUnit::Def(unit.id()), unit.sig()))
.chain(
self.decls()
.map(move |decl| (&self[decl].name, LinkedUnit::Decl(decl), &self[decl].sig)),
)
}
pub fn local_symbols<'a>(
&'a self,
) -> impl Iterator<Item = (&UnitName, LinkedUnit, &Signature)> + 'a {
self.symbols().filter(|&(name, ..)| name.is_local())
}
pub fn global_symbols<'a>(
&'a self,
) -> impl Iterator<Item = (&UnitName, LinkedUnit, &Signature)> + '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, sig) in self.symbols() {
if let Some((existing, _)) = symbols.insert(name, (unit, sig)) {
if !existing.is_decl() {
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() {
for (ext_unit, data) in unit.extern_units() {
let (to, to_sig) = match symbols.get(&data.name).cloned() {
Some(to) => to,
None => {
eprintln!(
"unit {} not found; referenced in {}",
data.name,
unit.name()
);
failed = true;
continue;
}
};
if to_sig != &data.sig {
eprintln!(
"signature mismatch: {} has {}, but reference in {} expects {}",
data.name,
to_sig,
unit.name(),
data.sig
);
failed = true;
continue;
}
linked.insert((unit.id(), 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 fn lookup_ext_unit(&self, ext_unit: ExtUnit, within: UnitId) -> Option<LinkedUnit> {
self.link_table
.as_ref()
.and_then(|lt| lt.get(&(within, ext_unit)))
.cloned()
}
pub fn set_location_hint(&mut self, mod_unit: UnitId, loc: usize) {
self.location_hints.insert(mod_unit, loc);
}
pub fn location_hint(&self, mod_unit: UnitId) -> Option<usize> {
self.location_hints.get(&mod_unit).cloned()
}
}
impl std::ops::Index<UnitId> for Module {
type Output = UnitData;
fn index(&self, idx: UnitId) -> &UnitData {
&self.units[idx]
}
}
impl std::ops::IndexMut<UnitId> for Module {
fn index_mut(&mut self, idx: UnitId) -> &mut UnitData {
self.link_table = None;
&mut self.units[idx]
}
}
impl std::ops::Index<DeclId> for Module {
type Output = DeclData;
fn index(&self, idx: DeclId) -> &DeclData {
&self.decls[idx]
}
}
impl std::ops::IndexMut<DeclId> for Module {
fn index_mut(&mut self, idx: DeclId) -> &mut DeclData {
self.link_table = None;
&mut self.decls[idx]
}
}
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.id())?;
write!(f, "{}", unit)?;
}
if newline && !self.0.decls().count() > 0 {
writeln!(f, "")?;
}
for decl in self.0.decls() {
if newline {
writeln!(f, "")?;
}
newline = true;
let data = &self.0[decl];
write!(f, "declare {} {}", data.name, data.sig)?;
}
Ok(())
}
}
impl_table_key! {
struct UnitId(u32) as "u";
struct DeclId(u32) as "decl";
}
#[derive(Serialize, Deserialize)]
pub struct DeclData {
pub sig: Signature,
pub name: UnitName,
pub loc: Option<usize>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum LinkedUnit {
Def(UnitId),
Decl(DeclId),
}
impl LinkedUnit {
pub fn is_def(&self) -> bool {
match self {
LinkedUnit::Def(..) => true,
_ => false,
}
}
pub fn is_decl(&self) -> bool {
match self {
LinkedUnit::Decl(..) => true,
_ => false,
}
}
}