#![allow(dead_code)]
use crate::common::errors::*;
use crate::common::name::Name;
use crate::common::score::{GenericContext, NodeMaker, NodeRef, Result};
use crate::common::source::Spanned;
use crate::common::NodeId;
use crate::common::Session;
use crate::svlog::{self, ast as svlog_ast, Context};
use crate::vhdl;
use crate::vhdl::syntax::ast as vhdl_ast;
use std;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use typed_arena::Arena;
pub struct ScoreContext<'lazy, 'sb: 'lazy, 'ast: 'sb, 'ctx: 'sb> {
pub sess: &'lazy Session,
pub sb: &'sb ScoreBoard<'ast, 'ctx>,
pub vhdl: &'sb vhdl::score::ScoreBoard<'ast, 'ctx>,
pub vhdl_phases: &'lazy vhdl::lazy::LazyPhaseTable<'sb, 'ast, 'ctx>,
pub svlog: &'sb svlog::GlobalContext<'ast>,
}
pub struct ScoreBoard<'ast, 'ctx> {
arenas: &'ctx Arenas,
pub root: RootRef,
libs: RefCell<HashMap<LibRef, (Name, &'ast [Ast<'ast>])>>,
defs: RefCell<HashMap<ScopeRef, &'ctx Defs>>,
}
impl<'lazy, 'sb, 'ast, 'ctx> GenericContext for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {}
impl<'ast, 'ctx> ScoreBoard<'ast, 'ctx> {
pub fn new(arenas: &'ctx Arenas) -> ScoreBoard<'ast, 'ctx> {
ScoreBoard {
arenas: arenas,
root: RootRef::new(NodeId::alloc()),
libs: RefCell::new(HashMap::new()),
defs: RefCell::new(HashMap::new()),
}
}
}
impl<'ast, 'ctx> std::fmt::Debug for ScoreBoard<'ast, 'ctx> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Libraries:")?;
for (k, v) in self.libs.borrow().iter() {
write!(f, "\n - {:?}: contains {} root nodes", k, v.1.len())?;
}
write!(f, "\nDefs:")?;
for (k, &v) in self.defs.borrow().iter() {
write!(f, "\n - scope {:?}: contains {} defs nodes", k, v.len())?;
for (n, d) in v {
write!(f, "\n - `{:?}` -> {:?}", n, d)?;
}
}
Ok(())
}
}
impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
pub fn vhdl(&'lazy self) -> vhdl::score::ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
vhdl::score::ScoreContext {
sess: self.sess,
global: self,
sb: self.vhdl,
lazy: self.vhdl_phases,
}
}
pub fn add_library(&self, name: Name, asts: &'ast [Ast<'ast>]) -> LibRef {
let id = LibRef::new(NodeId::alloc());
self.sb.libs.borrow_mut().insert(id, (name, asts));
let vhdl_ast = asts
.iter()
.flat_map(|v| match *v {
Ast::Vhdl(ref a) => a.iter(),
_ => [].iter(),
})
.collect();
self.vhdl()
.add_library(name, vhdl::score::LibRef::new(id.into()), vhdl_ast);
let svlog_ast = asts.iter().filter_map(|v| match *v {
Ast::Svlog(ref a) => Some(a),
_ => None,
});
self.svlog.add_files(svlog_ast);
id
}
pub fn defs(&self, id: ScopeRef) -> Result<&'ctx Defs> {
if let Some(&node) = self.sb.defs.borrow().get(&id) {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
println!("[SB] make defs for {:?}", id);
}
let node = self.make(id)?;
if self.sess.opts.trace_scoreboard {
println!("[SB] defs for {:?} is {:?}", id, node);
}
if self.sb.defs.borrow_mut().insert(id, node).is_some() {
panic!("node should not exist");
}
Ok(node)
}
}
impl<'lazy, 'sb, 'ast, 'ctx> NodeMaker<ScopeRef, &'ctx Defs>
for ScoreContext<'lazy, 'sb, 'ast, 'ctx>
{
fn make(&self, id: ScopeRef) -> Result<&'ctx Defs> {
match id {
ScopeRef::Root(_) => {
let mut defs = HashMap::new();
for (&id, &(name, _)) in self.sb.libs.borrow().iter() {
if defs.insert(name, Def::Lib(id)).is_some() {
self.sess.emit(DiagBuilder2::fatal(format!(
"Library `{}` defined multiple times",
name
)));
return Err(());
}
}
Ok(self.sb.arenas.defs.alloc(defs))
}
ScopeRef::Lib(id) => {
let lib = self.sb.libs.borrow()[&id];
let vhdl =
self.vhdl()
.defs(vhdl::score::ScopeRef::Lib(vhdl::score::LibRef::new(
id.into(),
)))?;
if self.sess.opts.trace_scoreboard {
println!("[SB] vhdl_sb returned {:?}", vhdl);
}
let names: HashSet<Name> = vhdl
.iter()
.filter_map(|(&k, _)| match k {
vhdl::score::ResolvableName::Ident(n) => Some(n),
_ => None,
})
.chain(self.svlog.modules().map(|(k, _)| k))
.collect();
debug!("names defined in library: {:?}", names);
let mut defs = HashMap::new();
let mut had_dups = false;
for name in names {
let vhdl_defs = match vhdl.get(&name.into()) {
Some(v) => v.iter(),
None => [].iter(),
};
let svlog_defs = self.svlog.find_module(name.into());
let both_defs: Vec<Spanned<Def>> = vhdl_defs
.map(|d| Spanned::new(Def::Vhdl(d.value), d.span))
.chain(
svlog_defs.map(|id| Spanned::new(Def::Svlog(id), self.svlog.span(id))),
)
.collect();
if both_defs.len() > 1 {
let mut diag =
DiagBuilder2::error(format!("`{}` declared multiple times", name));
for def in both_defs {
diag = diag.span(def.span);
}
self.sess.emit(diag);
had_dups = true;
continue;
}
defs.insert(name, both_defs[0].value);
}
if had_dups {
return Err(());
}
Ok(self.sb.arenas.defs.alloc(defs))
}
}
}
}
pub struct Arenas {
pub vhdl: vhdl::score::Arenas,
defs: Arena<Defs>,
}
impl Arenas {
pub fn new() -> Arenas {
Arenas {
vhdl: vhdl::score::Arenas::new(),
defs: Arena::new(),
}
}
}
#[derive(Debug)]
pub enum Ast<'a> {
Vhdl(Vec<vhdl_ast::DesignUnit>),
Svlog(svlog_ast::SourceFile<'a>),
}
pub type Defs = HashMap<Name, Def>;
node_ref!(RootRef);
node_ref!(LibRef);
node_ref_group!(
Def: Lib(LibRef),
Vhdl(vhdl::score::Def),
Svlog(NodeId),
);
node_ref_group!(ScopeRef: Root(RootRef), Lib(LibRef),);