use crate::add_ctx::AddContext;
use crate::common::score::NodeRef;
use crate::make_ctx::MakeContext;
use crate::op::*;
use crate::score::*;
use crate::syntax::lexer::token::Literal;
use crate::term::*;
macro_rules! unimp {
($slf:tt, $id:expr) => {{
$slf.emit(DiagBuilder2::bug(format!(
"lowering to HIR of {:?} not implemented",
$id
)));
return Err(());
}};
($slf:tt, $id:expr, $span:expr) => {{
$slf.emit(
DiagBuilder2::bug(format!("lowering to HIR of {:?} not implemented", $id)).span($span),
);
return Err(());
}};
}
macro_rules! unimp_msg {
($slf:tt, $msg:expr) => {{
$slf.emit(DiagBuilder2::bug(format!(
"lowering to HIR: {} not implemented",
$msg
)));
return Err(());
}};
($slf:tt, $msg:expr, $span:expr) => {{
$slf.emit(
DiagBuilder2::bug(format!("lowering to HIR: {} not implemented", $msg)).span($span),
);
return Err(());
}};
}
impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
pub fn unpack_expr(&self, ast: &'ast ast::Expr, scope_id: ScopeRef) -> Result<ExprRef> {
let id = ExprRef::new(NodeId::alloc());
self.set_ast(id, (scope_id, ast));
Ok(id)
}
pub fn unpack_subtype_ind(
&self,
ast: &'ast ast::SubtypeInd,
scope_id: ScopeRef,
) -> Result<SubtypeIndRef> {
let ctx = AddContext::new(self, scope_id);
ctx.add_subtype_ind(ast)
}
pub fn unpack_type_mark(
&self,
ast: LatentName<'ast>,
scope_id: ScopeRef,
) -> Result<Spanned<LatentTypeMarkRef>> {
let id = LatentTypeMarkRef::new(NodeId::alloc());
self.set_ast(id, (scope_id, ast));
Ok(Spanned::new(id, ast.span()))
}
pub fn unpack_package_name(
&self,
ast: LatentName<'ast>,
scope_id: ScopeRef,
) -> Result<Spanned<LatentPkgRef>> {
let id = LatentPkgRef::new(NodeId::alloc());
self.set_ast(id, (scope_id, ast));
Ok(Spanned::new(id, ast.span()))
}
pub fn unpack_subprog_name(
&self,
ast: LatentName<'ast>,
scope_id: ScopeRef,
) -> Result<Spanned<LatentSubprogRef>> {
let id = LatentSubprogRef::new(NodeId::alloc());
self.set_ast(id, (scope_id, ast));
Ok(Spanned::new(id, ast.span()))
}
pub fn unpack_block_decls(
&self,
scope_id: ScopeRef,
decls: &'ast [ast::DeclItem],
container_name: &str,
) -> Result<Vec<DeclInBlockRef>> {
let mut refs = Vec::new();
let mut had_fails = false;
let ctx = AddContext::new(self, scope_id);
for decl in decls {
match *decl {
ast::DeclItem::SubprogDecl(ref decl) => match decl.data {
ast::SubprogData::Decl => {
let subid = SubprogDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::SubprogData::Body { .. } => {
let subid = SubprogBodyRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::SubprogData::Inst { .. } => {
let subid = SubprogInstRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::PkgDecl(ref decl) => {
let subid = PkgDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::PkgBody(ref decl) => {
let subid = PkgBodyRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::PkgInst(ref decl) => {
let subid = PkgInstRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::TypeDecl(ref decl) => {
let subid = TypeDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::SubtypeDecl(ref decl) => {
let subid = SubtypeDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::ObjDecl(ref decl) => match decl.kind {
ast::ObjKind::Const => {
refs.extend(ctx.add_const_decl::<DeclInBlockRef>(decl)?);
}
ast::ObjKind::Signal => {
refs.extend(ctx.add_signal_decl::<DeclInBlockRef>(decl)?);
}
ast::ObjKind::Var => {
self.emit(
DiagBuilder2::error(format!(
"not a shared variable; only shared variables may appear in {}",
container_name
))
.span(decl.human_span()),
);
had_fails = true;
}
ast::ObjKind::SharedVar => {
refs.extend(ctx.add_var_decl::<DeclInBlockRef>(decl)?);
}
ast::ObjKind::File => {
refs.extend(ctx.add_file_decl::<DeclInBlockRef>(decl)?);
}
},
ast::DeclItem::AliasDecl(ref decl) => {
let subid = AliasDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::CompDecl(ref decl) => {
let subid = CompDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::AttrDecl(ref decl) => match decl.data {
ast::AttrData::Decl(..) => {
let subid = AttrDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::AttrData::Spec { .. } => {
let subid = AttrSpecRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::CfgSpec(ref decl) => {
let subid = CfgSpecRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::DisconDecl(ref decl) => {
let subid = DisconSpecRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::GroupDecl(ref decl) => match decl.data {
ast::GroupData::Decl(..) => {
let subid = GroupDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::GroupData::Temp { .. } => {
let subid = GroupTempRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::UseClause(..) => (),
ref wrong => {
self.emit(
DiagBuilder2::error(format!(
"a {} cannot appear in {}",
wrong.desc(),
container_name
))
.span(decl.human_span()),
);
had_fails = true;
}
}
}
if had_fails {
Err(())
} else {
Ok(refs)
}
}
pub fn unpack_process_decls(
&self,
scope_id: ScopeRef,
decls: &'ast [ast::DeclItem],
container_name: &str,
) -> Result<Vec<DeclInProcRef>> {
let mut refs = Vec::new();
let mut had_fails = false;
let ctx = AddContext::new(self, scope_id);
for decl in decls {
match *decl {
ast::DeclItem::SubprogDecl(ref decl) => match decl.data {
ast::SubprogData::Decl => {
let subid = SubprogDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::SubprogData::Body { .. } => {
let subid = SubprogBodyRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::SubprogData::Inst { .. } => {
let subid = SubprogInstRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::PkgDecl(ref decl) => {
let subid = PkgDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::PkgBody(ref decl) => {
let subid = PkgBodyRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::PkgInst(ref decl) => {
let subid = PkgInstRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::TypeDecl(ref decl) => {
let subid = TypeDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::SubtypeDecl(ref decl) => {
let subid = SubtypeDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::ObjDecl(ref decl) => match decl.kind {
ast::ObjKind::Const => {
refs.extend(ctx.add_const_decl::<DeclInProcRef>(decl)?);
}
ast::ObjKind::Signal => {
self.emit(
DiagBuilder2::error(format!(
"a signal declaration cannot appear in {}",
container_name
))
.span(decl.human_span()),
);
had_fails = true;
}
ast::ObjKind::SharedVar => {
self.emit(
DiagBuilder2::error(format!(
"not a variable; shared variables may not appear in {}",
container_name
))
.span(decl.human_span()),
);
had_fails = true;
}
ast::ObjKind::Var => {
refs.extend(ctx.add_var_decl::<DeclInProcRef>(decl)?);
}
ast::ObjKind::File => {
refs.extend(ctx.add_file_decl::<DeclInProcRef>(decl)?);
}
},
ast::DeclItem::AliasDecl(ref decl) => {
let subid = AliasDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::AttrDecl(ref decl) => match decl.data {
ast::AttrData::Decl(..) => {
let subid = AttrDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::AttrData::Spec { .. } => {
let subid = AttrSpecRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::GroupDecl(ref decl) => match decl.data {
ast::GroupData::Decl(..) => {
let subid = GroupDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::GroupData::Temp { .. } => {
let subid = GroupTempRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::UseClause(..) => (),
ref wrong => {
self.emit(
DiagBuilder2::error(format!(
"a {} cannot appear in {}",
wrong.desc(),
container_name
))
.span(decl.human_span()),
);
had_fails = true;
}
}
}
if had_fails {
Err(())
} else {
Ok(refs)
}
}
pub fn unpack_subprog_decls(
&self,
scope_id: ScopeRef,
decls: &'ast [ast::DeclItem],
) -> Result<Vec<DeclInSubprogRef>> {
let mut refs = Vec::new();
let mut had_fails = false;
let ctx = AddContext::new(self, scope_id);
for decl in decls {
match *decl {
ast::DeclItem::SubprogDecl(ref decl) => match decl.data {
ast::SubprogData::Decl => {
let subid = SubprogDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::SubprogData::Body { .. } => {
let subid = SubprogBodyRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::SubprogData::Inst { .. } => {
let subid = SubprogInstRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::PkgDecl(ref decl) => {
let subid = PkgDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::PkgBody(ref decl) => {
let subid = PkgBodyRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::PkgInst(ref decl) => {
let subid = PkgInstRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::TypeDecl(ref decl) => {
let subid = TypeDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::SubtypeDecl(ref decl) => {
let subid = SubtypeDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::ObjDecl(ref decl) => match decl.kind {
ast::ObjKind::Const => {
refs.extend(ctx.add_const_decl::<DeclInSubprogRef>(decl)?);
}
ast::ObjKind::Signal => {
self.emit(
DiagBuilder2::error(
"a signal declaration cannot appear in a subprogram",
)
.span(decl.human_span()),
);
had_fails = true;
}
ast::ObjKind::SharedVar => {
self.emit(
DiagBuilder2::error(
"not a variable; shared variables \
may not appear in a package body",
)
.span(decl.human_span()),
);
had_fails = true;
}
ast::ObjKind::Var => {
refs.extend(ctx.add_var_decl::<DeclInSubprogRef>(decl)?);
}
ast::ObjKind::File => {
refs.extend(ctx.add_file_decl::<DeclInSubprogRef>(decl)?);
}
},
ast::DeclItem::AliasDecl(ref decl) => {
let subid = AliasDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::DeclItem::AttrDecl(ref decl) => match decl.data {
ast::AttrData::Decl(..) => {
let subid = AttrDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::AttrData::Spec { .. } => {
let subid = AttrSpecRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::GroupDecl(ref decl) => match decl.data {
ast::GroupData::Decl(..) => {
let subid = GroupDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
ast::GroupData::Temp { .. } => {
let subid = GroupTempRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
refs.push(subid.into());
}
},
ast::DeclItem::UseClause(..) => (),
ref wrong => {
self.emit(
DiagBuilder2::error(format!(
"a {} cannot appear in a subprogram",
wrong.desc()
))
.span(decl.human_span()),
);
had_fails = true;
}
}
}
if had_fails {
Err(())
} else {
Ok(refs)
}
}
pub fn unpack_concurrent_stmts(
&self,
scope_id: ScopeRef,
stmts: &'ast [ast::Stmt],
container_name: &str,
) -> Result<Vec<ConcStmtRef>> {
let mut refs = Vec::new();
let mut had_fails = false;
let unimp = |s: &ast::Stmt| {
self.emit(
DiagBuilder2::bug(format!("{} not implemented", s.desc())).span(s.human_span()),
)
};
for stmt in stmts {
match stmt.data {
ast::BlockStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::InstOrCallStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::AssertStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::AssignStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::SelectAssignStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::IfGenStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::CaseGenStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::ForGenStmt { .. } => {
unimp(stmt);
had_fails = true;
}
ast::ProcStmt { .. } => {
let id = ProcessStmtRef(NodeId::alloc());
self.set_ast(id, (scope_id, stmt));
refs.push(id.into());
}
ref wrong => {
self.emit(
DiagBuilder2::error(format!(
"a {} cannot appear in {}",
wrong.desc(),
container_name
))
.span(stmt.human_span())
.add_note(format!(
"Only concurrent statements are allowed \
in {}. See IEEE 1076-2008 section 11.1.",
container_name
)),
);
had_fails = true;
}
}
}
if had_fails {
Err(())
} else {
Ok(refs)
}
}
pub fn unpack_sequential_stmts(
&self,
scope_id: ScopeRef,
stmts: &'ast [ast::Stmt],
container_name: &str,
) -> Result<Vec<SeqStmtRef>> {
let ctx = AddContext::new(self, scope_id);
ctx.add_seq_stmts(stmts, container_name)
}
pub fn unpack_signal_assign_target(
&self,
scope_id: ScopeRef,
target: &'ast ast::AssignTarget,
) -> Result<hir::SigAssignTarget> {
match *target {
ast::AssignTarget::Name(ref name) => {
let (_res_name, mut defs, res_span, tail) =
self.resolve_compound_name(name, scope_id, false)?;
if !tail.is_empty() {
self.emit(
DiagBuilder2::bug(
"handling of non-name signal assignment targets not implemented",
)
.span(name.span),
);
return Err(());
}
let sig = match defs.pop() {
Some(Spanned {
value: Def::Signal(id),
..
}) => id,
Some(_) => {
self.emit(
DiagBuilder2::error(format!(
"`{}` is not a signal",
res_span.extract()
))
.span(res_span),
);
return Err(());
}
None => unreachable!(),
};
if !defs.is_empty() {
self.emit(
DiagBuilder2::error(format!("`{}` is ambiguous", res_span.extract()))
.span(res_span),
);
return Err(());
}
Ok(hir::SigAssignTarget::Name(sig))
}
ast::AssignTarget::Aggregate(ref elems) => {
self.emit(
DiagBuilder2::error("aggregate signal assignment not implemented")
.span(elems.span),
);
Err(())
}
}
}
pub fn unpack_signal_assign_mode(
&self,
scope_id: ScopeRef,
mode: &'ast Spanned<ast::AssignMode>,
tyctx: &TypeCtx<'ctx>,
) -> Result<Spanned<hir::SigAssignKind>> {
Ok(Spanned::new(
match mode.value {
ast::AssignMode::Release(_fm) => {
unimp!(self, "release signal assignment mode");
}
ast::AssignMode::Force(_fm, ref _waves) => {
unimp!(self, "force signal assignment mode");
}
ast::AssignMode::Normal(ref dm, ref waves) => {
let dm = self.unpack_delay_mechanism(scope_id, dm)?;
assert!(!waves.is_empty());
if waves.len() > 1 || waves[0].1.is_some() {
hir::SigAssignKind::CondWave(
dm,
self.unpack_cond_waveforms(scope_id, waves, tyctx)?,
)
} else {
hir::SigAssignKind::SimpleWave(
dm,
self.unpack_waveform(scope_id, &waves[0].0, tyctx)?,
)
}
}
},
mode.span,
))
}
pub fn unpack_delay_mechanism(
&self,
scope_id: ScopeRef,
dm: &'ast Option<Spanned<ast::DelayMech>>,
) -> Result<hir::DelayMechanism> {
if let Some(Spanned { value: ref dm, .. }) = *dm {
Ok(match *dm {
ast::DelayMech::Transport => hir::DelayMechanism::Transport,
ast::DelayMech::Inertial => hir::DelayMechanism::Inertial,
ast::DelayMech::InertialReject(ref expr) => {
let expr = self.unpack_expr(expr, scope_id)?;
hir::DelayMechanism::RejectInertial(expr)
}
})
} else {
Ok(hir::DelayMechanism::Inertial)
}
}
pub fn unpack_cond_waveforms(
&self,
_scope_id: ScopeRef,
waves: &'ast [ast::CondWave],
_tyctx: &TypeCtx<'ctx>,
) -> Result<hir::Cond<hir::Waveform>> {
let (_when, _other) = if waves.last().unwrap().1.is_some() {
(&waves[..], None)
} else {
(&waves[..waves.len() - 1], Some(&waves.last().unwrap().1))
};
unimp!(self, "conditional waveforms");
}
pub fn unpack_waveform(
&self,
scope_id: ScopeRef,
wave: &'ast ast::Wave,
tyctx: &TypeCtx<'ctx>,
) -> Result<hir::Waveform> {
wave.elems
.iter()
.flat_map(|i| i.iter())
.map(|&(ref value, ref after)| {
Ok(hir::WaveElem {
value: match value.data {
ast::NullExpr => None,
_ => {
let expr = self.unpack_expr(value, scope_id)?;
self.set_type_context(expr, tyctx.clone());
Some(expr)
}
},
after: match *after {
Some(ref expr) => {
let expr = self.unpack_expr(expr, scope_id)?;
Some(expr)
}
None => None,
},
})
})
.collect()
}
pub fn sanitize_paren_elems_as_exprs(
&self,
elems: &'ast [ast::ParenElem],
context: &str,
) -> Vec<&'ast ast::Expr> {
elems
.iter()
.map(|elem| {
if !elem.choices.value.is_empty() {
let span = Span::union(
elem.choices.value[0].span,
elem.choices.value.last().unwrap().span,
);
self.emit(
DiagBuilder2::error(format!("`=>` not applicable in {}", context))
.span(span),
);
}
&elem.expr
})
.collect()
}
pub fn lower_subprog_spec(
&self,
scope_id: ScopeRef,
ast: &'ast ast::SubprogSpec,
) -> Result<hir::SubprogSpec> {
let kind = match (ast.kind, ast.purity) {
(ast::SubprogKind::Proc, None) => hir::SubprogKind::Proc,
(ast::SubprogKind::Func, None)
| (ast::SubprogKind::Func, Some(ast::SubprogPurity::Pure)) => {
hir::SubprogKind::PureFunc
}
(ast::SubprogKind::Func, Some(ast::SubprogPurity::Impure)) => {
hir::SubprogKind::ImpureFunc
}
(ast::SubprogKind::Proc, Some(_)) => {
self.emit(
DiagBuilder2::error(format!(
"Procedure `{}` cannot be pure/impure",
ast.name.span.extract()
))
.span(ast.name.span),
);
hir::SubprogKind::Proc
}
};
let name = self.lower_subprog_name(kind, &ast.name)?;
let mut generics = Vec::new();
if let Some(ref gc) = ast.generic_clause {
self.unpack_generics(scope_id, gc, &mut generics)?;
}
if let Some(ref gm) = ast.generic_map {
unimp_msg!(
self,
"lowering of generic maps in subprogram specifications",
gm.span
);
}
let generic_map = vec![];
if ast.params.is_some() {
unimp_msg!(
self,
"lowering of parameters in subprogram specifications",
name.span
);
}
let return_type = match ast.retty {
Some(ref name) => Some(self.unpack_type_mark(name.into(), scope_id)?),
None => None,
};
if ast.kind == ast::SubprogKind::Func && ast.retty.is_none() {
self.emit(
DiagBuilder2::error(format!("Function `{}` has no return type", name.value))
.span(name.span)
.add_note(
"Functions require a return type. Use a \
procedure if you want no return type. See \
IEEE 1076-2008 section 4.2.1.",
),
);
return Err(());
}
Ok(hir::SubprogSpec {
name: name,
kind: kind,
generics: generics,
generic_map: generic_map,
params: vec![],
return_type: return_type,
})
}
pub fn lower_subprog_name(
&self,
kind: hir::SubprogKind,
name: &'ast ast::PrimaryName,
) -> Result<Spanned<ResolvableName>> {
let name = self.resolvable_from_primary_name(&name)?;
if name.value.is_bit() {
self.emit(
DiagBuilder2::error(format!("`{}` is not a valid subprogram name", name.value))
.span(name.span)
.add_note(
"Bit literals cannot be used as subprogram \
names. See IEEE 1076-2008 section 4.2.1.",
),
);
return Err(());
}
if kind == hir::SubprogKind::Proc && !name.value.is_ident() {
self.emit(
DiagBuilder2::error(format!("`{}` overload must be a function", name.value))
.span(name.span)
.add_note(
"Procedures cannot overload operators. Use \
a function. See IEEE 1076-2008 section 4.2.1.",
),
);
return Err(());
}
Ok(name)
}
pub fn unpack_generics(
&self,
scope_id: ScopeRef,
decls: &'ast [ast::IntfDecl],
into: &mut Vec<GenericRef>,
) -> Result<()> {
let ctx = AddContext::new(self, scope_id);
let mut had_fails = false;
for decl in decls {
match *decl {
ast::IntfDecl::TypeDecl(ref decl) => {
let id = IntfTypeRef(NodeId::alloc());
self.set_ast(id, (scope_id, decl));
into.push(id.into());
}
ast::IntfDecl::SubprogSpec(ref decl) => {
let id = IntfSubprogRef(NodeId::alloc());
self.set_ast(id, (scope_id, decl));
into.push(id.into());
}
ast::IntfDecl::PkgInst(ref decl) => {
let id = IntfPkgRef(NodeId::alloc());
self.set_ast(id, (scope_id, decl));
into.push(id.into());
}
ast::IntfDecl::ObjDecl(
ref
decl
@
ast::IntfObjDecl {
kind: ast::IntfObjKind::Const,
..
},
) => {
let ty = ctx.add_subtype_ind(&decl.ty)?;
for name in &decl.names {
let id = IntfConstRef(NodeId::alloc());
self.set_ast(id, (scope_id, decl, ty, name));
into.push(id.into());
}
}
ref wrong => {
self.emit(
DiagBuilder2::error(format!(
"a {} cannot appear in a generic clause",
wrong.desc()
))
.span(wrong.human_span()),
);
had_fails = true;
}
}
}
if had_fails {
Err(())
} else {
Ok(())
}
}
pub fn unpack_generic_map(
&self,
_scope_id: ScopeRef,
elems: &'ast ast::ParenElems,
) -> Result<Vec<()>> {
if !elems.value.is_empty() {
unimp_msg!(self, "generic map aspect", elems.span);
}
Ok(Vec::new())
}
}
impl_make!(self, id: EntityRef => &hir::Entity {
let (lib, ctx_id, ast) = self.ast(id);
let mut entity = hir::Entity{
ctx_items: ctx_id,
lib: lib,
name: ast.name,
generics: Vec::new(),
ports: Vec::new(),
};
let mut port_spans = Vec::new();
let mut generic_spans = Vec::new();
let ctx = AddContext::new(self, id.into());
for decl in &ast.decls {
match *decl {
ast::DeclItem::PortgenClause(_, Spanned{ value: ast::PortgenKind::Port, span }, ref decls) => {
port_spans.push(span);
for decl in &decls.value {
match *decl {
ast::IntfDecl::ObjDecl(ref decl @ ast::IntfObjDecl{ kind: ast::IntfObjKind::Signal, .. }) => {
let ty = ctx.add_subtype_ind(&decl.ty)?;
for name in &decl.names {
let subid = IntfSignalRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl, ty, name));
entity.ports.push(subid);
}
}
ref wrong => {
self.emit(
DiagBuilder2::error(format!("a {} cannot appear in a port clause", wrong.desc()))
.span(wrong.human_span())
);
continue;
}
}
}
}
ast::DeclItem::PortgenClause(_, Spanned{ value: ast::PortgenKind::Generic, span }, ref decls) => {
generic_spans.push(span);
self.unpack_generics(id.into(), &decls.value, &mut entity.generics)?;
}
ref wrong => {
self.emit(
DiagBuilder2::error(format!("a {} cannot appear in an entity declaration", wrong.desc()))
.span(decl.human_span())
);
continue;
}
}
}
Ok(self.sb.arenas.hir.entity.alloc(entity))
});
impl_make!(self, id: IntfSignalRef => &hir::IntfSignal {
let (scope_id, decl, subty_id, ident) = self.ast(id);
let init = match decl.default {
Some(ref e) => {
let subid = ExprRef(NodeId::alloc());
self.set_ast(subid, (scope_id, e));
Some(subid)
}
None => None
};
let sig = hir::IntfSignal {
name: Spanned::new(ident.name, ident.span),
mode: match decl.mode {
None | Some(ast::IntfMode::In) => hir::IntfSignalMode::In,
Some(ast::IntfMode::Out) => hir::IntfSignalMode::Out,
Some(ast::IntfMode::Inout) => hir::IntfSignalMode::Inout,
Some(ast::IntfMode::Buffer) => hir::IntfSignalMode::Buffer,
Some(ast::IntfMode::Linkage) => hir::IntfSignalMode::Linkage,
},
ty: subty_id,
bus: decl.bus,
init: init,
};
Ok(self.sb.arenas.hir.intf_sig.alloc(sig))
});
impl_make!(self, id: PkgDeclRef => &hir::Package {
let (outer_scope, ast) = self.ast(id);
let scope = id.into();
self.subscope(scope, outer_scope);
let generics = Vec::new();
let mut decls = Vec::new();
let mut had_fails = false;
let ctx = AddContext::new(self, scope);
for decl in &ast.decls {
match *decl {
ast::DeclItem::SubprogDecl(ref decl) => {
match decl.data {
ast::SubprogData::Decl => {
let subid = SubprogDeclRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::SubprogData::Body{..} => {
self.emit(
DiagBuilder2::error(format!("a {} cannot appear in a package declaration", decl.desc()))
.span(decl.human_span())
.add_note("Only subprogram declarations or instantiations can appear in a package declaration. See IEEE 1076-2008 section 4.7.")
);
had_fails = true;
continue;
}
ast::SubprogData::Inst{..} => {
let subid = SubprogInstRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
}
}
ast::DeclItem::PkgDecl(ref decl) => {
let subid = PkgDeclRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::DeclItem::PkgInst(ref decl) => {
let subid = PkgInstRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::DeclItem::TypeDecl(ref decl) => {
decls.push(ctx.add_type_decl(decl)?.into());
}
ast::DeclItem::SubtypeDecl(ref decl) => {
let subid = SubtypeDeclRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::DeclItem::ObjDecl(ref decl) => {
match decl.kind {
ast::ObjKind::Const => {
decls.extend(ctx.add_const_decl::<DeclInPkgRef>(decl)?);
}
ast::ObjKind::Signal => {
decls.extend(ctx.add_signal_decl::<DeclInPkgRef>(decl)?);
}
ast::ObjKind::SharedVar => {
self.emit(
DiagBuilder2::error("not a variable; shared variables may not appear in a package declaration")
.span(decl.human_span())
);
had_fails = true;
}
ast::ObjKind::Var => {
decls.extend(ctx.add_var_decl::<DeclInPkgRef>(decl)?);
}
ast::ObjKind::File => {
decls.extend(ctx.add_file_decl::<DeclInPkgRef>(decl)?);
}
}
}
ast::DeclItem::AliasDecl(ref decl) => {
let subid = AliasDeclRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::DeclItem::CompDecl(ref decl) => {
let subid = CompDeclRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::DeclItem::AttrDecl(ref decl) => {
match decl.data {
ast::AttrData::Decl(..) => {
let subid = AttrDeclRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::AttrData::Spec{..} => {
let subid = AttrSpecRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
}
}
ast::DeclItem::DisconDecl(ref decl) => {
let subid = DisconSpecRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::DeclItem::GroupDecl(ref decl) => {
match decl.data {
ast::GroupData::Decl(..) => {
let subid = GroupDeclRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
ast::GroupData::Temp{..} => {
let subid = GroupTempRef(NodeId::alloc());
self.set_ast(subid, (scope, decl));
decls.push(subid.into());
}
}
}
ast::DeclItem::UseClause(..) => (),
ref wrong => {
self.emit(
DiagBuilder2::error(format!("a {} cannot appear in a package declaration", wrong.desc()))
.span(decl.human_span())
);
had_fails = true;
continue;
}
}
}
if had_fails {
Err(())
} else {
Ok(self.sb.arenas.hir.package.alloc(hir::Package{
parent: outer_scope,
name: ast.name,
generics: generics,
decls: decls,
}))
}
});
impl_make!(self, id: PkgBodyRef => &hir::PackageBody {
let (scope_id, ast) = self.ast(id);
let pkg = self.unpack_package_name((&ast.name).into(), scope_id)?;
let mut decls = Vec::new();
let mut had_fails = false;
let ctx = AddContext::new(self, scope_id);
for decl in &ast.decls {
match *decl {
ast::DeclItem::SubprogDecl(ref decl) => {
match decl.data {
ast::SubprogData::Decl => {
let subid = SubprogDeclRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
ast::SubprogData::Body{..} => {
let subid = SubprogBodyRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
ast::SubprogData::Inst{..} => {
let subid = SubprogInstRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
}
}
ast::DeclItem::PkgDecl(ref decl) => {
let subid = PkgDeclRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
ast::DeclItem::PkgBody(ref decl) => {
let subid = PkgBodyRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
ast::DeclItem::PkgInst(ref decl) => {
let subid = PkgInstRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
ast::DeclItem::TypeDecl(ref decl) => {
let subid = TypeDeclRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
ast::DeclItem::SubtypeDecl(ref decl) => {
let subid = SubtypeDeclRef(NodeId::alloc());
self.set_ast(subid, (id.into(), decl));
decls.push(subid.into());
}
ast::DeclItem::ObjDecl(ref decl) => {
match decl.kind {
ast::ObjKind::Const => {
decls.extend(ctx.add_const_decl::<DeclInPkgBodyRef>(decl)?);
}
ast::ObjKind::Signal => {
self.emit(
DiagBuilder2::error("a signal declaration cannot appear in a package body")
.span(decl.human_span())
);
had_fails = true;
}
ast::ObjKind::SharedVar => {
self.emit(
DiagBuilder2::error("not a variable; shared variables may not appear in a package body")
.span(decl.human_span())
);
had_fails = true;
}
ast::ObjKind::Var => {
decls.extend(ctx.add_var_decl::<DeclInPkgBodyRef>(decl)?);
}
ast::ObjKind::File => {
decls.extend(ctx.add_file_decl::<DeclInPkgBodyRef>(decl)?);
}
}
}
ast::DeclItem::AliasDecl(ref decl) => {
let subid = AliasDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
decls.push(subid.into());
}
ast::DeclItem::AttrDecl(ref decl) => {
match decl.data {
ast::AttrData::Decl(..) => {
let subid = AttrDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
decls.push(subid.into());
}
ast::AttrData::Spec{..} => {
let subid = AttrSpecRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
decls.push(subid.into());
}
}
}
ast::DeclItem::GroupDecl(ref decl) => {
match decl.data {
ast::GroupData::Decl(..) => {
let subid = GroupDeclRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
decls.push(subid.into());
}
ast::GroupData::Temp{..} => {
let subid = GroupTempRef(NodeId::alloc());
self.set_ast(subid, (scope_id, decl));
decls.push(subid.into());
}
}
}
ast::DeclItem::UseClause(..) => (),
ref wrong => {
self.emit(
DiagBuilder2::error(format!("a {} cannot appear in a package body", wrong.desc()))
.span(decl.human_span())
);
had_fails = true;
continue;
}
}
}
if had_fails {
Err(())
} else {
Ok(self.sb.arenas.hir.package_body.alloc(hir::PackageBody {
parent: scope_id,
name: ast.name,
pkg: pkg,
decls: decls,
}))
}
});
impl_make!(self, id: PkgInstRef => &hir::PackageInst {
let (scope_id, ast) = self.ast(id);
let pkg = self.unpack_package_name((&ast.target).into(), scope_id)?;
let gm = match ast.generics {
Some(ref g) => self.unpack_generic_map(scope_id, g)?,
None => vec![],
};
Ok(self.sb.arenas.hir.package_inst.alloc(hir::PackageInst {
parent: scope_id,
name: ast.name,
pkg: pkg,
generic_map: gm,
}))
});
impl_make!(self, id: SubtypeDeclRef => &hir::SubtypeDecl {
let (scope_id, ast) = self.ast(id);
let subty = self.unpack_subtype_ind(&ast.subtype, scope_id)?;
Ok(self.sb.arenas.hir.subtype_decl.alloc(hir::SubtypeDecl{
parent: scope_id,
name: ast.name,
subty: subty,
}))
});
impl_make!(self, id: ArchRef => &hir::Arch {
let (lib_id, ctx_id, ast) = self.ast(id);
let decls = self.unpack_block_decls(id.into(), &ast.decls, "an architecture")?;
let stmts = self.unpack_concurrent_stmts(id.into(), &ast.stmts, "an architecture")?;
let entity_id = *self.archs(lib_id)?.by_arch.get(&id).unwrap();
Ok(self.sb.arenas.hir.arch.alloc(hir::Arch{
ctx_items: ctx_id,
entity: entity_id,
name: ast.name,
decls: decls,
stmts: stmts,
}))
});
impl_make!(self, id: ProcessStmtRef => &hir::ProcessStmt {
let (scope_id, ast) = self.ast(id);
match ast.data {
ast::ProcStmt {
ref decls,
ref stmts,
postponed,
..
} => {
let decls = self.unpack_process_decls(id.into(), decls, "a process")?;
let stmts = self.unpack_sequential_stmts(id.into(), stmts, "a process")?;
Ok(self.sb.arenas.hir.process_stmt.alloc(hir::ProcessStmt {
parent: scope_id,
label: ast.label,
postponed: postponed,
sensitivity: hir::ProcessSensitivity::None,
decls: decls,
stmts: stmts,
}))
}
_ => unreachable!()
}
});
impl_make!(self, id: SigAssignStmtRef => &hir::SigAssignStmt {
let (scope_id, ast) = self.ast(id);
match ast.data {
ast::AssignStmt {
target: Spanned{ value: ref target, span: target_span },
ref mode,
guarded,
..
} => {
let target = self.unpack_signal_assign_target(scope_id, target)?;
let tyctx = match target {
hir::SigAssignTarget::Name(id) => TypeCtx::TypeOf(id.into()),
hir::SigAssignTarget::Aggregate => unimplemented!(),
};
let kind = self.unpack_signal_assign_mode(scope_id, mode, &tyctx)?;
if guarded {
self.emit(
DiagBuilder2::warning("sequential signal assignment cannot be guarded")
.span(ast.human_span())
.add_note("Only concurrent signal assignments can be guarded. See IEEE 1076-2008 section 11.6.")
);
}
Ok(self.sb.arenas.hir.sig_assign_stmt.alloc(hir::SigAssignStmt {
parent: scope_id,
span: ast.span,
label: ast.label,
target: target,
target_span: target_span,
kind: kind.value,
kind_span: kind.span,
}))
}
_ => unreachable!()
}
});
impl_make!(self, id: ArrayTypeIndexRef => &Spanned<hir::ArrayTypeIndex> {
let (scope_id, ast) = self.ast(id);
let ctx = TermContext::new(self, scope_id);
let term = ctx.termify_expr(ast)?;
let term = ctx.fold_term_as_type(term)?;
let index = match term.value {
Term::Range(dir, lb, rb) => {
let lb = ctx.term_to_expr(*lb)?;
let rb = ctx.term_to_expr(*rb)?;
hir::ArrayTypeIndex::Range(dir.value, lb, rb)
}
Term::UnboundedRange(subterm) => {
let tm = ctx.term_to_type_mark(*subterm)?;
hir::ArrayTypeIndex::Unbounded(tm)
}
Term::TypeMark(..) | Term::SubtypeInd(..) => {
let subty = ctx.term_to_subtype_ind(term)?.value;
let add_ctx = AddContext::new(self, scope_id);
let subty = add_ctx.add_subtype_ind_hir(subty)?;
hir::ArrayTypeIndex::Subtype(subty)
}
_ => {
self.emit(
DiagBuilder2::error(format!("`{}` is not a valid array index", term.span.extract()))
.span(term.span)
);
debugln!("It is a {:#?}", term);
return Err(());
}
};
Ok(self.sb.arenas.hir.array_type_index.alloc(Spanned::new(index, ast.span)))
});
impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {}
impl_make!(self, id: SubprogDeclRef => &hir::Subprog {
let (scope_id, ast) = self.ast(id);
let spec = self.lower_subprog_spec(id.into(), &ast.spec)?;
Ok(self.sb.arenas.hir.subprog.alloc(hir::Subprog {
parent: scope_id,
spec: spec,
}))
});
impl_make!(self, id: SubprogBodyRef => &hir::SubprogBody {
let (scope_id, ast) = self.ast(id);
let spec = self.lower_subprog_spec(id.into(), &ast.spec)?;
let subprog = self.unpack_subprog_name((&ast.spec.name).into(), scope_id)?;
let (decls, stmts) = match ast.data {
ast::SubprogData::Body { ref decls, ref stmts } => (decls, stmts),
_ => unreachable!(),
};
let decls = self.unpack_subprog_decls(id.into(), decls)?;
let stmts = self.unpack_sequential_stmts(id.into(), stmts, "a subprogram")?;
Ok(self.sb.arenas.hir.subprog_body.alloc(hir::SubprogBody {
parent: scope_id,
spec: spec,
subprog: subprog,
decls: decls,
stmts: stmts,
}))
});
impl_make!(self, id: SubprogInstRef => &hir::SubprogInst {
let (scope_id, ast) = self.ast(id);
let kind = match ast.spec.kind {
ast::SubprogKind::Proc => hir::SubprogKind::Proc,
ast::SubprogKind::Func => hir::SubprogKind::PureFunc,
};
let name = self.lower_subprog_name(kind, &ast.spec.name)?;
assert!(ast.spec.purity.is_none());
assert!(ast.spec.generic_clause.is_none());
assert!(ast.spec.generic_map.is_none());
assert!(ast.spec.params.is_none());
assert!(ast.spec.retty.is_none());
let (target_name, generics) = match ast.data {
ast::SubprogData::Inst { ref name, ref generics } => (name, generics),
_ => unreachable!(),
};
let subprog = self.unpack_subprog_name(target_name.into(), scope_id)?;
let generics = match *generics {
Some(ref g) => self.unpack_generic_map(scope_id, g)?,
None => vec![],
};
Ok(self.sb.arenas.hir.subprog_inst.alloc(hir::SubprogInst {
parent: scope_id,
kind: kind,
name: name,
subprog: subprog,
generic_map: generics,
}))
});
impl_make!(self, id: LatentTypeMarkRef => Spanned<TypeMarkRef> {
let (scope_id, ast) = self.ast(id);
let ctx = TermContext::new(self, scope_id);
let term = ctx.termify_latent_name(ast)?;
ctx.term_to_type_mark(term)
});