#![allow(unused_imports)]
use std;
use std::fmt::Debug;
use std::collections::HashMap;
use std::cell::{Cell, RefCell};
use moore_common::{Session, Verbosity};
use moore_common::name::*;
use moore_common::source::*;
use moore_common::errors::*;
use moore_common::NodeId;
use moore_common::score::{GenericContext, NodeMaker, NodeStorage, Result};
use moore_common::util::{HasDesc, HasSpan};
use typed_arena::Arena;
use num::{BigInt, Signed};
use llhd;
use crate::syntax::ast;
use crate::hir;
use crate::ty::*;
use crate::konst::*;
use crate::codegen::Codegen;
use crate::typeck::{Typeck, TypeckContext};
use crate::lazy::*;
use crate::arenas::Alloc;
use crate::builtin;
use crate::op::*;
pub use crate::builtin::*;
macro_rules! impl_make {
($slf:tt, $id:ident: $id_ty:ty => &$out_ty:ty $blk:block) => {
impl<'lazy, 'sb, 'ast, 'ctx> NodeMaker<$id_ty, &'ctx $out_ty> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn make(&$slf, $id: $id_ty) -> Result<&'ctx $out_ty> $blk
}
};
($slf:tt, $id:ident: $id_ty:ty => $out_ty:ty $blk:block) => {
impl<'lazy, 'sb, 'ast, 'ctx> NodeMaker<$id_ty, $out_ty> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn make(&$slf, $id: $id_ty) -> Result<$out_ty> $blk
}
}
}
mod lower_hir;
mod scope;
mod cval;
pub struct ScoreContext<'lazy, 'sb: 'lazy, 'ast: 'sb, 'ctx: 'sb> {
pub sess: &'lazy Session,
pub global: &'lazy GenericContext,
pub sb: &'sb ScoreBoard<'ast, 'ctx>,
pub lazy: &'lazy LazyPhaseTable<'sb, 'ast, 'ctx>,
}
pub struct ScoreBoard<'ast, 'ctx> {
pub arenas: &'ctx Arenas,
span_table: RefCell<HashMap<NodeId, Span>>,
libs: RefCell<HashMap<LibRef, Vec<&'ast ast::DesignUnit>>>,
lib_names: RefCell<HashMap<Name, LibRef>>,
ast_table: RefCell<AstTable<'ast>>,
hir_table: RefCell<HirTable<'ctx>>,
def_table: RefCell<HashMap<ScopeRef, &'ctx Defs>>,
arch_table: RefCell<HashMap<LibRef, &'ctx ArchTable>>,
pub llmod: RefCell<llhd::Module>,
lldecl_table: RefCell<HashMap<NodeId, llhd::ValueRef>>,
lldef_table: RefCell<HashMap<NodeId, llhd::ValueRef>>,
pub ty_table: RefCell<HashMap<NodeId, &'ctx Ty>>,
scope_table: RefCell<HashMap<ScopeRef, &'ctx Scope>>,
const_table: RefCell<HashMap<NodeId, &'ctx Const>>,
tyctx_table: RefCell<HashMap<NodeId, TypeCtx<'ctx>>>,
pub typeck_table: RefCell<HashMap<NodeId, Result<()>>>,
pub typeval_table: RefCell<HashMap<NodeId, Result<&'ctx Ty>>>,
pub scope2_table: RefCell<HashMap<ScopeRef, crate::scope::Scope>>,
}
impl<'ast, 'ctx> ScoreBoard<'ast, 'ctx> {
pub fn new(arenas: &'ctx Arenas) -> ScoreBoard<'ast, 'ctx> {
let sb = ScoreBoard {
arenas: arenas,
span_table: RefCell::new(HashMap::new()),
libs: RefCell::new(HashMap::new()),
lib_names: RefCell::new(HashMap::new()),
ast_table: RefCell::new(AstTable::new()),
hir_table: RefCell::new(HirTable::new()),
def_table: RefCell::new(HashMap::new()),
arch_table: RefCell::new(HashMap::new()),
llmod: RefCell::new(llhd::Module::new()),
lldecl_table: RefCell::new(HashMap::new()),
lldef_table: RefCell::new(HashMap::new()),
ty_table: RefCell::new(HashMap::new()),
scope_table: RefCell::new(HashMap::new()),
const_table: RefCell::new(HashMap::new()),
tyctx_table: RefCell::new(HashMap::new()),
typeck_table: RefCell::new(HashMap::new()),
typeval_table: RefCell::new(HashMap::new()),
scope2_table: RefCell::new(HashMap::new()),
};
builtin::register_builtins(&sb);
sb
}
pub fn intern_const<T>(&self, konst: T) -> &'ctx Const
where
T: Into<Const>,
{
self.arenas.konst.alloc(konst.into())
}
pub fn intern_ty<T>(&self, ty: T) -> &'ctx Ty
where
T: Into<Ty>,
{
self.arenas.ty.alloc(ty.into())
}
}
impl<'lazy, 'sb, 'ast, 'ctx> DiagEmitter for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn emit(&self, diag: DiagBuilder2) {
self.sess.emit(diag)
}
}
impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
pub fn add_library(&self, name: Name, id: LibRef, lib: Vec<&'ast ast::DesignUnit>) {
self.sb.libs.borrow_mut().insert(id, lib);
self.sb.lib_names.borrow_mut().insert(name, id);
}
pub fn span<I>(&self, id: I) -> Option<Span>
where
I: Into<NodeId>,
{
self.sb.span_table.borrow().get(&id.into()).map(|v| *v)
}
pub fn set_span<I>(&self, id: I, span: Span)
where
I: Into<NodeId>,
{
self.sb.span_table.borrow_mut().set(id.into(), span);
}
pub fn bug<I>(&self, id: I, msg: String)
where
I: Into<NodeId>,
{
let mut d = DiagBuilder2::bug(msg);
if let Some(span) = self.span(id) {
d = d.span(span);
}
self.emit(d);
}
pub fn ast<I>(&self, id: I) -> <AstTable<'ast> as NodeStorage<I>>::Node
where
I: 'ast + Copy + Debug,
AstTable<'ast>: NodeStorage<I>,
<AstTable<'ast> as NodeStorage<I>>::Node: Copy + Debug,
{
match self.sb.ast_table.borrow().get(&id) {
Some(&node) => node,
None => panic!("AST for {:?} should exist", id),
}
}
pub fn set_ast<I>(&self, id: I, ast: <AstTable<'ast> as NodeStorage<I>>::Node)
where
I: Copy + Debug,
AstTable<'ast>: NodeStorage<I>,
{
self.sb.ast_table.borrow_mut().set(id, ast);
}
pub fn hir<I>(&self, id: I) -> Result<<HirTable<'ctx> as NodeStorage<I>>::Node>
where
I: 'ctx + Copy + Debug,
HirTable<'ctx>: NodeStorage<I>,
ScoreContext<'lazy, 'sb, 'ast, 'ctx>: NodeMaker<I, <HirTable<'ctx> as NodeStorage<I>>::Node>,
<HirTable<'ctx> as NodeStorage<I>>::Node: Copy + Debug,
{
if let Some(&node) = self.sb.hir_table.borrow().get(&id) {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make hir for {:?}", id);
}
let node = self.make(id)?;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] hir for {:?} is {:?}", id, node);
}
self.set_hir(id, node);
Ok(node)
}
pub fn set_hir<I>(&self, id: I, hir: <HirTable<'ctx> as NodeStorage<I>>::Node)
where
I: Copy + Debug,
HirTable<'ctx>: NodeStorage<I>,
{
self.sb.hir_table.borrow_mut().set(id, hir);
}
pub fn existing_hir<I>(&self, id: I) -> Result<<HirTable<'ctx> as NodeStorage<I>>::Node>
where
I: Copy + Debug,
HirTable<'ctx>: NodeStorage<I>,
<HirTable<'ctx> as NodeStorage<I>>::Node: Copy + Debug,
{
match self.sb.hir_table.borrow().get(&id) {
Some(&node) => Ok(node),
None => {
self.emit(DiagBuilder2::bug(format!("hir for {:?} should exist", id)));
Err(())
}
}
}
pub fn lazy_hir<I, R>(&self, id: I) -> Result<&'ctx R>
where
I: Copy + Debug,
R: Debug + 'ctx,
LazyHirTable<'sb, 'ast, 'ctx>: NodeStorage<I, Node = LazyNode<Box<for<'a, 'b> Fn(&'a ScoreContext<'b, 'sb, 'ast, 'ctx>) -> Result<R> + 'sb>>>,
HirTable<'ctx>: NodeStorage<I, Node = &'ctx R>,
hir::Arenas: Alloc<'ctx, 'ctx, R>,
{
if let Some(&node) = self.sb.hir_table.borrow().get(&id) {
return Ok(node);
}
let hir = self.lazy.hir.run(id, self)?;
let allocd = self.sb.arenas.hir.alloc(hir);
self.sb.hir_table.borrow_mut().set(id, allocd);
Ok(allocd)
}
pub fn defs(&self, id: ScopeRef) -> Result<&'ctx Defs> {
if let Some(&node) = self.sb.def_table.borrow().get(&id) {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make defs for {:?}", id);
}
let node = self.make(id)?;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] defs for {:?} is {:?}", id, node);
}
if self.sb.def_table.borrow_mut().insert(id, node).is_some() {
panic!("node should not exist");
}
Ok(node)
}
pub fn archs(&self, id: LibRef) -> Result<&'ctx ArchTable> {
if let Some(&node) = self.sb.arch_table.borrow().get(&id) {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make arch for {:?}", id);
}
let node = self.make(id)?;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] arch for {:?} is {:?}", id, node);
}
if self.sb.arch_table.borrow_mut().insert(id, node).is_some() {
panic!("node should not exist");
}
Ok(node)
}
pub fn lldecl<I>(&self, id: I) -> Result<llhd::ValueRef>
where
I: 'ctx + Copy + Debug + Into<NodeId>,
ScoreContext<'lazy, 'sb, 'ast, 'ctx>: NodeMaker<I, DeclValueRef>,
{
if let Some(node) = self.sb.lldecl_table.borrow().get(&id.into()).cloned() {
return Ok(node);
}
if let Some(node) = self.sb.lldef_table.borrow().get(&id.into()).cloned() {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make lldecl for {:?}", id);
}
let node = self.make(id)?.0;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] lldecl for {:?} is {:?}", id, node);
}
if self.sb
.lldecl_table
.borrow_mut()
.insert(id.into(), node.clone())
.is_some()
{
panic!("node should not exist");
}
Ok(node)
}
pub fn lldef<I>(&self, id: I) -> Result<llhd::ValueRef>
where
I: 'ctx + Copy + Debug + Into<NodeId>,
ScoreContext<'lazy, 'sb, 'ast, 'ctx>: NodeMaker<I, DefValueRef>,
{
if let Some(node) = self.sb.lldef_table.borrow().get(&id.into()).cloned() {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make lldef for {:?}", id);
}
let node = self.make(id)?.0;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] lldef for {:?} is {:?}", id, node);
}
if self.sb
.lldef_table
.borrow_mut()
.insert(id.into(), node.clone())
.is_some()
{
panic!("node should not exist");
}
Ok(node)
}
pub fn ty<I>(&self, id: I) -> Result<&'ctx Ty>
where
I: 'ctx + Copy + Debug + Into<NodeId>,
ScoreContext<'lazy, 'sb, 'ast, 'ctx>: NodeMaker<I, &'ctx Ty>,
{
if let Some(node) = self.sb.ty_table.borrow().get(&id.into()).cloned() {
return Ok(node);
}
if let Some(&node) = self.sb.typeval_table.borrow().get(&id.into()) {
return node;
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make ty for {:?}", id);
}
let node = self.make(id)?;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] ty for {:?} is {:?}", id, node);
}
if self.sb
.ty_table
.borrow_mut()
.insert(id.into(), node)
.is_some()
{
self.emit(DiagBuilder2::bug(format!(
"type for {:?} already in the scoreboard",
id
)));
return Err(());
}
Ok(node)
}
pub fn lazy_typeck<I>(&self, id: I) -> Result<()>
where
I: Into<NodeId>,
{
let ctx = TypeckContext::new(self);
ctx.lazy_typeck(id);
if ctx.finish() {
Ok(())
} else {
Err(())
}
}
pub fn lazy_typeval<I>(&self, id: I) -> Result<&'ctx Ty>
where
I: Into<NodeId>,
{
let ctx = TypeckContext::new(self);
let result = ctx.lazy_typeval(id);
if ctx.finish() {
result
} else {
Err(())
}
}
pub fn scope(&self, id: ScopeRef) -> Result<&'ctx Scope> {
if let Some(node) = self.sb.scope_table.borrow().get(&id.into()).cloned() {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make scope for {:?}", id);
}
let node = self.make(id)?;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] scope for {:?} is {:?}", id, node);
}
if self.sb.scope_table.borrow_mut().insert(id, node).is_some() {
panic!("node should not exist");
}
Ok(node)
}
pub fn const_value<I>(&self, id: I) -> Result<&'ctx Const>
where
I: 'ctx + Copy + Debug + Into<NodeId>,
ScoreContext<'lazy, 'sb, 'ast, 'ctx>: NodeMaker<I, &'ctx Const>,
{
if let Some(node) = self.sb.const_table.borrow().get(&id.into()).cloned() {
return Ok(node);
}
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] make const for {:?}", id);
}
let node = self.make(id)?;
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] const for {:?} is {:?}", id, node);
}
if self.sb
.const_table
.borrow_mut()
.insert(id.into(), node)
.is_some()
{
panic!("node should not exist");
}
Ok(node)
}
pub fn type_context<I>(&self, id: I) -> Option<TypeCtx<'ctx>>
where
I: Copy + Debug + Into<NodeId>,
{
self.sb.tyctx_table.borrow().get(&id.into()).map(|&t| t)
}
pub fn type_context_resolved<I>(&self, id: I) -> Result<Option<&'ctx Ty>>
where
I: Copy + Debug + Into<NodeId>,
{
Ok(match self.type_context(id) {
Some(TypeCtx::Type(t)) => Some(t),
Some(TypeCtx::TypeOf(id)) => Some(self.ty(id)?),
Some(TypeCtx::Inherit(id)) => self.type_context_resolved(id)?,
None => None,
})
}
pub fn set_type_context<I, T>(&self, id: I, tyctx: T)
where
I: Copy + Debug + Into<NodeId>,
TypeCtx<'ctx>: From<T>,
{
self.sb
.tyctx_table
.borrow_mut()
.insert(id.into(), tyctx.into());
}
pub fn set_type_context_optional<I, T>(&self, id: Option<I>, tyctx: T)
where
I: Copy + Debug + Into<NodeId>,
TypeCtx<'ctx>: From<T>,
{
match id {
Some(id) => self.set_type_context(id, tyctx),
None => (),
}
}
}
#[derive(Debug, Clone)]
pub struct DeclValueRef(pub llhd::ValueRef);
#[derive(Debug, Clone)]
pub struct DefValueRef(pub llhd::ValueRef);
impl<'lazy, 'sb, 'ast, 'ctx> NodeMaker<LibRef, &'ctx hir::Lib> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn make(&self, id: LibRef) -> Result<&'ctx hir::Lib> {
let mut lib = hir::Lib::new();
for du in &self.sb.libs.borrow()[&id] {
let ctx_id = CtxItemsRef(NodeId::alloc());
self.set_ast(ctx_id, (id.into(), du.ctx.as_slice()));
match du.data {
ast::DesignUnitData::EntityDecl(ref decl) => {
let subid = EntityRef(NodeId::alloc());
self.set_ast(subid, (id, ctx_id, decl));
lib.entities.push(subid);
}
ast::DesignUnitData::CfgDecl(ref decl) => {
let subid = CfgRef(NodeId::alloc());
self.set_ast(subid, (id, ctx_id, decl));
lib.cfgs.push(subid);
}
ast::DesignUnitData::PkgDecl(ref decl) => {
let subid = PkgDeclRef(NodeId::alloc());
self.set_ast(subid, (ctx_id.into(), decl));
lib.pkg_decls.push(subid);
}
ast::DesignUnitData::PkgInst(ref decl) => {
let subid = PkgInstRef(NodeId::alloc());
self.set_ast(subid, (ctx_id.into(), decl));
lib.pkg_insts.push(subid);
}
ast::DesignUnitData::CtxDecl(ref decl) => {
let subid = CtxRef(NodeId::alloc());
self.set_ast(subid, (id, ctx_id, decl));
lib.ctxs.push(subid);
}
ast::DesignUnitData::ArchBody(ref decl) => {
let subid = ArchRef(NodeId::alloc());
self.set_ast(subid, (id, ctx_id.into(), decl));
lib.archs.push(subid);
}
ast::DesignUnitData::PkgBody(ref decl) => {
let subid = PkgBodyRef(NodeId::alloc());
self.set_ast(subid, (ctx_id.into(), decl));
lib.pkg_bodies.push(subid);
}
}
}
Ok(self.sb.arenas.hir.lib.alloc(lib))
}
}
impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
pub fn resolvable_from_primary_name(&self, primary: &ast::PrimaryName) -> Result<Spanned<ResolvableName>> {
ResolvableName::from_primary_name(primary, self.sess)
}
pub fn resolve_name(&self, name: Spanned<ResolvableName>, scope_id: ScopeRef, only_defs: bool, allow_fail: bool) -> Result<Vec<Spanned<Def>>> {
if self.sess.opts.verbosity.contains(Verbosity::NAMES) {
debugln!("resolving `{}` in scope {:?}", name.value, scope_id);
}
if self.sess.opts.trace_scoreboard {
debugln!(
"[SB][VHDL] resolve {:?} in scope {:?}",
name.value,
scope_id
);
}
let mut found_defs = Vec::new();
let parent_id = if !(*BUILTIN_SCOPE_REFS).contains(&scope_id) {
if only_defs {
let defs = self.defs(scope_id)?;
if let Some(d) = defs.get(&name.value) {
found_defs.extend(d);
}
None
} else {
let scope = self.scope(scope_id)?;
for &defs_id in &scope.defs {
let defs = self.defs(defs_id)?;
if let Some(d) = defs.get(&name.value) {
found_defs.extend(d);
}
}
if let Some(d) = scope.explicit_defs.get(&name.value) {
found_defs.extend(d.iter());
}
scope.parent
}
} else {
None
};
{
let tbl = self.sb.scope2_table.borrow();
if let Some(scope) = tbl.get(&scope_id) {
if let Some(d) = scope.defs.get(&name.value) {
found_defs.extend(d);
}
if let Some(d) = scope.imported_defs.get(&name.value) {
found_defs.extend(d);
}
for &id in &scope.imported_scopes {
if let Some(scope) = tbl.get(&id) {
if let Some(d) = scope.defs.get(&name.value) {
found_defs.extend(d);
}
}
}
}
}
if found_defs.is_empty() {
if let Some(parent_id) = parent_id {
self.resolve_name(name, parent_id, only_defs, allow_fail)
} else if allow_fail {
Ok(vec![])
} else {
self.emit(DiagBuilder2::error(format!("`{}` is not known", name.value)).span(name.span));
Err(())
}
} else {
if self.sess.opts.trace_scoreboard {
debugln!("[SB][VHDL] resolved {:?} to {:?}", name.value, found_defs);
}
if self.sess.opts.verbosity.contains(Verbosity::NAMES) {
self.emit(DiagBuilder2::note(format!("resolved `{}` to {:?}", name.value, found_defs)).span(name.span));
}
Ok(found_defs)
}
}
pub fn resolve_compound_name<'a>(&self, name: &'a ast::CompoundName, scope_id: ScopeRef, only_defs: bool) -> Result<(ResolvableName, Vec<Spanned<Def>>, Span, &'a [ast::NamePart])> {
if self.sess.opts.trace_scoreboard {
debugln!(
"[SB][VHDL] resolve compound {:?} in scope {:?}",
name,
scope_id
);
}
let mut seen_span = name.primary.span;
let mut res_name = self.resolvable_from_primary_name(&name.primary)?;
let mut defs = self.resolve_name(res_name, scope_id, only_defs, false)?;
for i in 0..name.parts.len() {
match name.parts[i] {
ast::NamePart::Select(ref pn) => {
let def = if defs.len() == 1 {
defs[0]
} else {
let span_str = seen_span.extract();
let mut d = DiagBuilder2::error(format!("`{}` is ambiguous", span_str))
.span(seen_span)
.add_note(format!(
"`{}` refers to the following {} items:",
span_str,
defs.len()
));
for def in &defs {
d = d.span(def.span);
}
self.emit(d);
return Err(());
};
let scope = match def.value {
Def::Lib(id) => id.into(),
Def::Pkg(id) => id.into(),
Def::BuiltinPkg(id) => id.into(),
d => {
self.emit(DiagBuilder2::error(format!("cannot select into {:?}", d)).span(pn.span));
return Err(());
}
};
seen_span.expand(pn.span);
res_name = self.resolvable_from_primary_name(pn)?;
defs = self.resolve_name(res_name, scope, true, false)?;
}
_ => return Ok((res_name.value, defs, seen_span, &name.parts[i..])),
}
}
Ok((res_name.value, defs, seen_span, &[]))
}
pub fn builtin_boolean_type(&self) -> &'ctx Ty {
self.intern_ty(Ty::Null)
}
pub fn builtin_time_type(&self) -> &'ctx Ty {
self.intern_ty(Ty::Null)
}
pub fn builtin_string_type(&self) -> &'ctx Ty {
self.intern_ty(Ty::Null)
}
pub fn builtin_severity_type(&self) -> &'ctx Ty {
self.intern_ty(Ty::Null)
}
}
impl<'lazy, 'sb, 'ast, 'ctx> NodeMaker<LibRef, &'ctx ArchTable> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn make(&self, id: LibRef) -> Result<&'ctx ArchTable> {
let lib = self.hir(id)?;
let defs = self.defs(ScopeRef::Lib(id.into()))?;
let mut res = ArchTable::new();
res.by_entity = lib.entities
.iter()
.map(|&id| (id, EntityArchTable::new()))
.collect();
let mut had_fails = false;
for &arch_ref in &lib.archs {
let arch = self.ast(arch_ref).2;
let entity_name = match if arch.target.parts.is_empty() {
match arch.target.primary.kind {
ast::PrimaryNameKind::Ident(n) => Some(n),
_ => None,
}
} else {
None
} {
Some(n) => n,
None => {
self.emit(
DiagBuilder2::error(format!(
"`{}` is not a valid entity name",
arch.target.span.extract()
)).span(arch.target.span),
);
had_fails = true;
continue;
}
};
let entity = match defs.get(&entity_name.into()) {
Some(e) => {
let last = e.last().unwrap();
match last.value {
Def::Entity(e) => e,
_ => {
self.emit(
DiagBuilder2::error(format!("`{}` is not an entity", entity_name))
.span(arch.target.span)
.add_note(format!("`{}` defined here:", entity_name))
.span(last.span),
);
had_fails = true;
continue;
}
}
}
None => {
self.emit(DiagBuilder2::error(format!("Unknown entity `{}`", entity_name)).span(arch.target.span));
had_fails = true;
continue;
}
};
let entry = res.by_entity.get_mut(&entity).unwrap();
entry.ordered.push(arch_ref);
entry.by_name.insert(arch.name.value, arch_ref);
res.by_arch.insert(arch_ref, entity);
}
if had_fails {
Err(())
} else {
Ok(self.sb.arenas.archs.alloc(res))
}
}
}
impl<'lazy, 'sb, 'ast, 'ctx> NodeMaker<ArchRef, DeclValueRef> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn make(&self, _: ArchRef) -> Result<DeclValueRef> {
unimplemented!();
}
}
impl<'lazy, 'sb, 'ast, 'ctx> NodeMaker<ArchRef, DefValueRef> for ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
fn make(&self, id: ArchRef) -> Result<DefValueRef> {
let typeck_ctx = TypeckContext::new(self);
typeck_ctx.typeck(self.ast(id).0);
if !typeck_ctx.finish() {
return Err(());
}
let hir = self.hir(id)?;
let entity = self.hir(hir.entity)?;
debugln!("entity ports: {:?}", entity.ports);
let mut in_tys = Vec::new();
let mut out_tys = Vec::new();
let mut in_names = Vec::new();
let mut out_names = Vec::new();
for &port in &entity.ports {
let hir = self.hir(port)?;
let ty = self.map_type(self.ty(hir.ty)?)?;
match hir.mode {
hir::IntfSignalMode::In | hir::IntfSignalMode::Inout | hir::IntfSignalMode::Linkage => {
in_tys.push(ty.clone());
in_names.push(hir.name.value);
}
_ => (),
}
match hir.mode {
hir::IntfSignalMode::Out | hir::IntfSignalMode::Inout | hir::IntfSignalMode::Buffer => {
out_tys.push(ty.clone());
out_names.push(hir.name.value);
}
_ => (),
}
}
let ty = llhd::entity_ty(in_tys, out_tys);
let name = format!("{}_{}", entity.name.value, hir.name.value);
let mut entity = llhd::Entity::new(name, ty);
for (arg, &name) in entity.inputs_mut().iter_mut().zip(in_names.iter()) {
arg.set_name(name.as_str().to_owned());
}
for (arg, &name) in entity.outputs_mut().iter_mut().zip(out_names.iter()) {
arg.set_name(name.as_str().to_owned());
}
for &decl_id in &hir.decls {
self.codegen(decl_id, &mut entity)?;
}
for &stmt_id in &hir.stmts {
self.codegen(stmt_id, &mut entity)?;
}
Ok(DefValueRef(
self.sb.llmod.borrow_mut().add_entity(entity).into(),
))
}
}
impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
pub fn default_value_for_type(&self, ty: &Ty) -> Result<&'ctx Const> {
match *ty {
Ty::Named(_, ty) => self.default_value_for_type(self.ty(ty)?),
Ty::Null => Ok(self.intern_const(Const::Null)),
Ty::Enum(ref _ty) => {
Ok(self.intern_const(Const::Null))
}
Ty::Physical(ref ty) => Ok(self.intern_const(ConstInt::new(
Some(ty.base.clone()),
ty.base.left_bound.clone(),
))),
Ty::Int(ref ty) => Ok(self.intern_const(ConstInt::new(Some(ty.clone()), ty.left_bound.clone()))),
Ty::UniversalInt => panic!("universal integer has no default value"),
Ty::UnboundedInt => panic!("unbounded integer has no default value"),
Ty::Subprog(..) => panic!("subprogram type has no default value"),
Ty::Access(_) => Ok(self.intern_const(Const::Null)),
Ty::Array(ref ty) => {
self.emit(DiagBuilder2::bug(format!(
"default value for type `{}` not implemented",
ty
)));
Ok(self.intern_const(Const::Null))
}
Ty::File(ref ty) => {
self.emit(DiagBuilder2::bug(format!(
"default value for type `{}` not implemented",
ty
)));
Ok(self.intern_const(Const::Null))
}
Ty::Record(ref ty) => {
self.emit(DiagBuilder2::bug(format!(
"default value for type `{}` not implemented",
ty
)));
Ok(self.intern_const(Const::Null))
}
}
}
pub fn intern_const<T>(&self, konst: T) -> &'ctx Const
where
T: Into<Const>,
{
self.sb.intern_const(konst)
}
pub fn intern_ty<T>(&self, ty: T) -> &'ctx Ty
where
T: Into<Ty>,
{
self.sb.intern_ty(ty)
}
}
pub struct Arenas {
pub hir: hir::Arenas,
pub defs: Arena<Defs>,
pub archs: Arena<ArchTable>,
pub scope: Arena<Scope>,
pub ty: Arena<Ty>,
pub konst: Arena<Const>,
}
impl Arenas {
pub fn new() -> Arenas {
Arenas {
hir: hir::Arenas::new(),
defs: Arena::new(),
archs: Arena::new(),
scope: Arena::new(),
ty: Arena::new(),
konst: Arena::new(),
}
}
}
#[derive(Debug)]
pub struct ArchTable {
pub by_arch: HashMap<ArchRef, EntityRef>,
pub by_entity: HashMap<EntityRef, EntityArchTable>,
}
#[derive(Debug)]
pub struct EntityArchTable {
pub ordered: Vec<ArchRef>,
pub by_name: HashMap<Name, ArchRef>,
}
impl ArchTable {
pub fn new() -> ArchTable {
ArchTable {
by_arch: HashMap::new(),
by_entity: HashMap::new(),
}
}
}
impl EntityArchTable {
pub fn new() -> EntityArchTable {
EntityArchTable {
ordered: Vec::new(),
by_name: HashMap::new(),
}
}
}
pub type Defs = HashMap<ResolvableName, Vec<Spanned<Def>>>;
#[derive(Debug)]
pub struct Scope {
pub parent: Option<ScopeRef>,
pub defs: Vec<ScopeRef>,
pub explicit_defs: Defs,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ResolvableName {
Ident(Name),
Bit(char),
Operator(Operator),
}
impl ResolvableName {
pub fn from_primary_name<C>(primary: &ast::PrimaryName, context: C) -> Result<Spanned<ResolvableName>>
where
C: DiagEmitter,
{
match primary.kind {
ast::PrimaryNameKind::Ident(n) => Ok(Spanned::new(ResolvableName::Ident(n), primary.span)),
ast::PrimaryNameKind::Char(c) => Ok(Spanned::new(ResolvableName::Bit(c), primary.span)),
ast::PrimaryNameKind::String(s) => match Operator::from_name(s) {
Some(op) => Ok(Spanned::new(ResolvableName::Operator(op), primary.span)),
None => {
context.emit(
DiagBuilder2::error(format!("`{}` is not a valid operator symbol", s))
.span(primary.span)
.add_note("see IEEE 1076-2008 section 9.2 for a list of operators"),
);
Err(())
}
},
}
}
pub fn is_ident(&self) -> bool {
match *self {
ResolvableName::Ident(_) => true,
_ => false,
}
}
pub fn is_bit(&self) -> bool {
match *self {
ResolvableName::Bit(_) => true,
_ => false,
}
}
pub fn is_operator(&self) -> bool {
match *self {
ResolvableName::Operator(_) => true,
_ => false,
}
}
}
impl std::fmt::Display for ResolvableName {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
ResolvableName::Ident(n) => write!(f, "{}", n),
ResolvableName::Bit(n) => write!(f, "{}", n),
ResolvableName::Operator(n) => write!(f, "{}", n),
}
}
}
impl From<Name> for ResolvableName {
fn from(name: Name) -> ResolvableName {
ResolvableName::Ident(name)
}
}
impl From<char> for ResolvableName {
fn from(c: char) -> ResolvableName {
ResolvableName::Bit(c)
}
}
impl From<Operator> for ResolvableName {
fn from(op: Operator) -> ResolvableName {
ResolvableName::Operator(op)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum TypeCtx<'ctx> {
Type(&'ctx Ty),
TypeOf(TypedNodeRef),
Inherit(NodeId),
}
impl<'ctx> From<&'ctx Ty> for TypeCtx<'ctx> {
fn from(ty: &'ctx Ty) -> TypeCtx<'ctx> {
TypeCtx::Type(ty)
}
}
impl<'ctx, T> From<T> for TypeCtx<'ctx>
where
TypedNodeRef: From<T>,
{
fn from(id: T) -> TypeCtx<'ctx> {
TypeCtx::TypeOf(id.into())
}
}
node_ref!(ArchRef);
node_ref!(BuiltinPkgRef);
node_ref!(CfgRef);
node_ref!(CtxItemsRef);
node_ref!(CtxRef);
node_ref!(DesignUnitRef);
node_ref!(EntityRef);
node_ref!(ExprRef);
node_ref!(AggregateRef);
node_ref!(IntfConstRef);
node_ref!(IntfSignalRef);
node_ref!(IntfVarRef);
node_ref!(IntfFileRef);
node_ref!(IntfPkgRef);
node_ref!(IntfSubprogRef);
node_ref!(IntfTypeRef);
node_ref!(LibRef);
node_ref!(PkgBodyRef);
node_ref!(PkgDeclRef);
node_ref!(PkgInstRef);
node_ref!(SubprogBodyRef);
node_ref!(SubprogDeclRef);
node_ref!(SubprogInstRef);
node_ref!(SubtypeIndRef);
node_ref!(TypeDeclRef);
node_ref!(SubtypeDeclRef);
node_ref!(WaitStmtRef);
node_ref!(AssertStmtRef);
node_ref!(ReportStmtRef);
node_ref!(SigAssignStmtRef);
node_ref!(VarAssignStmtRef);
node_ref!(CallStmtRef);
node_ref!(IfStmtRef);
node_ref!(CaseStmtRef);
node_ref!(LoopStmtRef);
node_ref!(NexitStmtRef);
node_ref!(ReturnStmtRef);
node_ref!(NullStmtRef);
node_ref!(BlockStmtRef);
node_ref!(ProcessStmtRef);
node_ref!(ConcCallStmtRef);
node_ref!(ConcAssertStmtRef);
node_ref!(ConcSigAssignStmtRef);
node_ref!(CompInstStmtRef);
node_ref!(ForGenStmtRef);
node_ref!(IfGenStmtRef);
node_ref!(CaseGenStmtRef);
node_ref!(ConstDeclRef);
node_ref!(SignalDeclRef);
node_ref!(VarDeclRef);
node_ref!(FileDeclRef);
node_ref!(AliasDeclRef);
node_ref!(CompDeclRef);
node_ref!(AttrDeclRef);
node_ref!(AttrSpecRef);
node_ref!(CfgSpecRef);
node_ref!(DisconSpecRef);
node_ref!(GroupDeclRef);
node_ref!(GroupTempRef);
node_ref!(ArrayTypeIndexRef);
node_ref!(GenericMapRef);
node_ref!(PortMapRef);
node_ref!(LatentTypeMarkRef);
node_ref!(LatentPkgRef);
node_ref!(LatentSubprogRef);
node_ref!(BuiltinOpRef);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct EnumRef(pub TypeDeclRef, pub usize);
impl Into<NodeId> for EnumRef {
fn into(self) -> NodeId {
panic!("EnumRef cannot be converted into a NodeId");
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct UnitRef(pub TypeDeclRef, pub usize);
impl Into<NodeId> for UnitRef {
fn into(self) -> NodeId {
panic!("UnitRef cannot be converted into a NodeId");
}
}
node_ref_group!(
Def: Arch(ArchRef),
Cfg(CfgRef),
Ctx(CtxRef),
Entity(EntityRef),
Lib(LibRef),
Pkg(PkgDeclRef),
PkgInst(PkgInstRef),
BuiltinPkg(BuiltinPkgRef),
BuiltinOp(BuiltinOpRef),
Type(TypeDeclRef),
Subtype(SubtypeDeclRef),
Enum(EnumRef),
Unit(UnitRef),
Const(ConstDeclRef),
Signal(SignalRef),
File(FileDeclRef),
Var(VarDeclRef),
Alias(AliasDeclRef),
Comp(CompDeclRef),
Attr(AttrDeclRef),
GroupTemp(GroupTempRef),
Group(GroupDeclRef),
Subprog(SubprogDeclRef),
SubprogInst(SubprogInstRef),
Stmt(StmtRef),
);
node_ref_group!(
ScopeRef: Lib(LibRef),
CtxItems(CtxItemsRef),
Entity(EntityRef),
BuiltinPkg(BuiltinPkgRef),
Pkg(PkgDeclRef),
PkgBody(PkgBodyRef),
Arch(ArchRef),
Process(ProcessStmtRef),
Subprog(SubprogDeclRef),
SubprogBody(SubprogBodyRef),
);
node_ref_group!(
GenericRef: Type(IntfTypeRef),
Subprog(IntfSubprogRef),
Pkg(IntfPkgRef),
Const(IntfConstRef),
);
node_ref_group!(
IntfObjRef: Const(IntfConstRef),
Var(IntfVarRef),
Signal(IntfSignalRef),
File(IntfFileRef),
);
node_ref_group!(TypeMarkRef: Type(TypeDeclRef), Subtype(SubtypeDeclRef),);
impl From<TypeMarkRef> for Def {
fn from(tm: TypeMarkRef) -> Def {
match tm {
TypeMarkRef::Type(id) => id.into(),
TypeMarkRef::Subtype(id) => id.into(),
}
}
}
node_ref_group!(SignalRef: Intf(IntfSignalRef), Decl(SignalDeclRef),);
node_ref_group!(PkgRef: Decl(PkgDeclRef), Inst(PkgInstRef),);
node_ref_group!(SubprogRef: Decl(SubprogDeclRef), Inst(SubprogInstRef),);
node_ref_group!(
DeclInPkgRef: Subprog(SubprogDeclRef),
SubprogInst(SubprogInstRef),
Pkg(PkgDeclRef),
PkgInst(PkgInstRef),
Type(TypeDeclRef),
Subtype(SubtypeDeclRef),
Const(ConstDeclRef),
Signal(SignalDeclRef),
Var(VarDeclRef),
File(FileDeclRef),
Alias(AliasDeclRef),
Comp(CompDeclRef),
Attr(AttrDeclRef),
AttrSpec(AttrSpecRef),
Discon(DisconSpecRef),
GroupTemp(GroupTempRef),
Group(GroupDeclRef),
);
node_ref_group!(
DeclInPkgBodyRef: Subprog(SubprogDeclRef),
SubprogBody(SubprogBodyRef),
SubprogInst(SubprogInstRef),
Pkg(PkgDeclRef),
PkgBody(PkgBodyRef),
PkgInst(PkgInstRef),
Type(TypeDeclRef),
Subtype(SubtypeDeclRef),
Const(ConstDeclRef),
Var(VarDeclRef),
File(FileDeclRef),
Alias(AliasDeclRef),
Attr(AttrDeclRef),
AttrSpec(AttrSpecRef),
GroupTemp(GroupTempRef),
Group(GroupDeclRef),
);
node_ref_group!(
DeclInSubprogRef: Subprog(SubprogDeclRef),
SubprogBody(SubprogBodyRef),
SubprogInst(SubprogInstRef),
Pkg(PkgDeclRef),
PkgBody(PkgBodyRef),
PkgInst(PkgInstRef),
Type(TypeDeclRef),
Subtype(SubtypeDeclRef),
Const(ConstDeclRef),
Var(VarDeclRef),
File(FileDeclRef),
Alias(AliasDeclRef),
Attr(AttrDeclRef),
AttrSpec(AttrSpecRef),
GroupTemp(GroupTempRef),
Group(GroupDeclRef),
);
node_ref_group!(
DeclInBlockRef: Subprog(SubprogDeclRef),
SubprogBody(SubprogBodyRef),
SubprogInst(SubprogInstRef),
Pkg(PkgDeclRef),
PkgBody(PkgBodyRef),
PkgInst(PkgInstRef),
Type(TypeDeclRef),
Subtype(SubtypeDeclRef),
Const(ConstDeclRef),
Signal(SignalDeclRef),
Var(VarDeclRef),
File(FileDeclRef),
Alias(AliasDeclRef),
Comp(CompDeclRef),
Attr(AttrDeclRef),
AttrSpec(AttrSpecRef),
CfgSpec(CfgSpecRef),
Discon(DisconSpecRef),
GroupTemp(GroupTempRef),
Group(GroupDeclRef),
);
node_ref_group!(
DeclInProcRef: Subprog(SubprogDeclRef),
SubprogBody(SubprogBodyRef),
SubprogInst(SubprogInstRef),
Pkg(PkgDeclRef),
PkgBody(PkgBodyRef),
PkgInst(PkgInstRef),
Type(TypeDeclRef),
Subtype(SubtypeDeclRef),
Const(ConstDeclRef),
Var(VarDeclRef),
File(FileDeclRef),
Alias(AliasDeclRef),
Attr(AttrDeclRef),
AttrSpec(AttrSpecRef),
GroupTemp(GroupTempRef),
Group(GroupDeclRef),
);
node_ref_group!(
ConcStmtRef: Block(BlockStmtRef),
Process(ProcessStmtRef),
ConcProcCall(ConcCallStmtRef),
ConcAssert(ConcAssertStmtRef),
ConcSigAssign(ConcSigAssignStmtRef),
CompInst(CompInstStmtRef),
ForGen(ForGenStmtRef),
IfGen(IfGenStmtRef),
CaseGen(CaseGenStmtRef),
);
node_ref_group!(
SeqStmtRef: Wait(WaitStmtRef),
Assert(AssertStmtRef),
Report(ReportStmtRef),
SigAssign(SigAssignStmtRef),
VarAssign(VarAssignStmtRef),
ProcCall(CallStmtRef),
If(IfStmtRef),
Case(CaseStmtRef),
Loop(LoopStmtRef),
Nexit(NexitStmtRef),
Return(ReturnStmtRef),
Null(NullStmtRef),
);
node_ref_group!(StmtRef: Conc(ConcStmtRef), Seq(SeqStmtRef),);
node_ref_group!(TypedNodeRef: SubtypeInd(SubtypeIndRef), Signal(SignalRef),);
node_storage!(AstTable<'ast>:
ctx_items: CtxItemsRef => (ScopeRef, &'ast [ast::CtxItem]),
entity_decls: EntityRef => (LibRef, CtxItemsRef, &'ast ast::EntityDecl),
cfg_decls: CfgRef => (LibRef, CtxItemsRef, &'ast ast::CfgDecl),
pkg_decls: PkgDeclRef => (ScopeRef, &'ast ast::PkgDecl),
pkg_insts: PkgInstRef => (ScopeRef, &'ast ast::PkgInst),
ctx_decls: CtxRef => (LibRef, CtxItemsRef, &'ast ast::CtxDecl),
arch_bodies: ArchRef => (LibRef, CtxItemsRef, &'ast ast::ArchBody),
pkg_bodies: PkgBodyRef => (ScopeRef, &'ast ast::PkgBody),
intf_sigs: IntfSignalRef => (ScopeRef, &'ast ast::IntfObjDecl, SubtypeIndRef, &'ast ast::Ident),
intf_types: IntfTypeRef => (ScopeRef, &'ast ast::TypeDecl),
intf_subprogs: IntfSubprogRef => (ScopeRef, &'ast ast::IntfSubprogDecl),
intf_pkgs: IntfPkgRef => (ScopeRef, &'ast ast::PkgInst),
intf_consts: IntfConstRef => (ScopeRef, &'ast ast::IntfObjDecl, SubtypeIndRef, &'ast ast::Ident),
type_decls: TypeDeclRef => (ScopeRef, &'ast ast::TypeDecl),
subtype_decls: SubtypeDeclRef => (ScopeRef, &'ast ast::SubtypeDecl),
subprog_bodies: SubprogBodyRef => (ScopeRef, &'ast ast::Subprog),
subprog_decls: SubprogDeclRef => (ScopeRef, &'ast ast::Subprog),
subprog_insts: SubprogInstRef => (ScopeRef, &'ast ast::Subprog),
alias_decls: AliasDeclRef => (ScopeRef, &'ast ast::AliasDecl),
comp_decls: CompDeclRef => (ScopeRef, &'ast ast::CompDecl),
attr_decls: AttrDeclRef => (ScopeRef, &'ast ast::AttrDecl),
attr_specs: AttrSpecRef => (ScopeRef, &'ast ast::AttrDecl),
cfg_specs: CfgSpecRef => (ScopeRef, &'ast ast::CfgSpec),
discon_specs: DisconSpecRef => (ScopeRef, &'ast ast::DisconSpec),
group_decls: GroupDeclRef => (ScopeRef, &'ast ast::GroupDecl),
group_temps: GroupTempRef => (ScopeRef, &'ast ast::GroupDecl),
exprs: ExprRef => (ScopeRef, &'ast ast::Expr),
proc_stmts: ProcessStmtRef => (ScopeRef, &'ast ast::Stmt),
sig_assign_stmts: SigAssignStmtRef => (ScopeRef, &'ast ast::Stmt),
var_assign_stmts: VarAssignStmtRef => (ScopeRef, &'ast ast::Stmt),
array_type_indices: ArrayTypeIndexRef => (ScopeRef, &'ast ast::Expr),
type_marks: LatentTypeMarkRef => (ScopeRef, LatentName<'ast>),
pkg_names: LatentPkgRef => (ScopeRef, LatentName<'ast>),
subprog_names: LatentSubprogRef => (ScopeRef, LatentName<'ast>),
);
node_storage!(HirTable<'ctx>:
libs: LibRef => &'ctx hir::Lib,
entities: EntityRef => &'ctx hir::Entity,
archs: ArchRef => &'ctx hir::Arch,
intf_sigs: IntfSignalRef => &'ctx hir::IntfSignal,
subtype_inds: SubtypeIndRef => &'ctx hir::SubtypeInd,
pkgs: PkgDeclRef => &'ctx hir::Package,
pkg_bodies: PkgBodyRef => &'ctx hir::PackageBody,
pkg_insts: PkgInstRef => &'ctx hir::PackageInst,
type_decls: TypeDeclRef => &'ctx hir::TypeDecl,
subtype_decls: SubtypeDeclRef => &'ctx hir::SubtypeDecl,
exprs: ExprRef => &'ctx hir::Expr,
aggregate: AggregateRef => &'ctx hir::Aggregate,
const_decls: ConstDeclRef => &'ctx hir::Decl<hir::ConstDecl>,
signal_decls: SignalDeclRef => &'ctx hir::Decl<hir::SignalDecl>,
variable_decls: VarDeclRef => &'ctx hir::Decl<hir::VarDecl>,
file_decls: FileDeclRef => &'ctx hir::Decl<hir::FileDecl>,
process_stmts: ProcessStmtRef => &'ctx hir::ProcessStmt,
sig_assign_stmts: SigAssignStmtRef => &'ctx hir::SigAssignStmt,
array_type_indices: ArrayTypeIndexRef => &'ctx Spanned<hir::ArrayTypeIndex>,
subprogs: SubprogDeclRef => &'ctx hir::Subprog,
subprog_bodies: SubprogBodyRef => &'ctx hir::SubprogBody,
subprog_insts: SubprogInstRef => &'ctx hir::SubprogInst,
latent_type_marks: LatentTypeMarkRef => Spanned<TypeMarkRef>,
latent_pkgs: LatentPkgRef => Spanned<PkgRef>,
latent_subprogs: LatentSubprogRef => Spanned<SubprogRef>,
wait_stmts: WaitStmtRef => &'ctx hir::Stmt<hir::WaitStmt>,
assert_stmts: AssertStmtRef => &'ctx hir::Stmt<hir::AssertStmt>,
report_stmts: ReportStmtRef => &'ctx hir::Stmt<hir::ReportStmt>,
var_assign_stmts: VarAssignStmtRef => &'ctx hir::Stmt<hir::VarAssignStmt>,
call_stmt: CallStmtRef => &'ctx hir::Stmt<hir::CallStmt>,
if_stmt: IfStmtRef => &'ctx hir::Stmt<hir::IfStmt>,
case_stmt: CaseStmtRef => &'ctx hir::Stmt<hir::CaseStmt>,
loop_stmt: LoopStmtRef => &'ctx hir::Stmt<hir::LoopStmt>,
nexit_stmt: NexitStmtRef => &'ctx hir::Stmt<hir::NexitStmt>,
return_stmt: ReturnStmtRef => &'ctx hir::Stmt<hir::ReturnStmt>,
null_stmt: NullStmtRef => &'ctx hir::Stmt<hir::NullStmt>,
);
lazy_static! {
static ref BUILTIN_PKG_SCOPES: HashMap<BuiltinPkgRef, Scope> = {
let mut scopes = HashMap::new();
scopes.insert(*STANDARD_PKG_REF, Scope{
parent: None,
defs: vec![(*STANDARD_PKG_REF).into()],
explicit_defs: HashMap::new(),
});
scopes
};
static ref BUILTIN_PKG_DEFS: HashMap<BuiltinPkgRef, Defs> = {
let mut table = HashMap::new();
table.insert(*STANDARD_PKG_REF, {
let defs = HashMap::new();
defs
});
table
};
}
#[derive(Copy, Clone, Debug)]
pub enum LatentName<'ast> {
Simple(&'ast Spanned<Name>),
Primary(&'ast ast::PrimaryName),
Compound(&'ast ast::CompoundName),
}
impl<'ast> From<&'ast Spanned<Name>> for LatentName<'ast> {
fn from(other: &'ast Spanned<Name>) -> LatentName<'ast> {
LatentName::Simple(other)
}
}
impl<'ast> From<&'ast ast::PrimaryName> for LatentName<'ast> {
fn from(other: &'ast ast::PrimaryName) -> LatentName<'ast> {
LatentName::Primary(other)
}
}
impl<'ast> From<&'ast ast::CompoundName> for LatentName<'ast> {
fn from(other: &'ast ast::CompoundName) -> LatentName<'ast> {
LatentName::Compound(other)
}
}
impl<'ast> HasSpan for LatentName<'ast> {
fn span(&self) -> Span {
match *self {
LatentName::Simple(n) => n.span,
LatentName::Primary(n) => n.span,
LatentName::Compound(n) => n.span,
}
}
}
impl<'ast> HasDesc for LatentName<'ast> {
fn desc(&self) -> &'static str {
"name"
}
}