// Copyright (c) 2016-2021 Fabian Schuiki //! This module implements lowering of the AST to the HIR. //! //! Note that unpacking here refers to the process of taking a reference to an //! AST node, creating an ID for it, and adding it to the AST table for later //! lowering to HIR. 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::*; /// Emit a compiler bug and return `Err`. 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> { /// Unpack an AST expression. pub fn unpack_expr(&self, ast: &'ast ast::Expr, scope_id: ScopeRef) -> Result { let id = ExprRef::new(NodeId::alloc()); self.set_ast(id, (scope_id, ast)); Ok(id) } /// Unpack an AST subtype indication. pub fn unpack_subtype_ind( &self, ast: &'ast ast::SubtypeInd, scope_id: ScopeRef, ) -> Result { // let ctx = TermContext::new(self, scope_id); // let term = ctx.termify_subtype_ind(ast)?; // let id = ctx.term_to_subtype_ind(term)?.value; // Ok(id) // let id = SubtypeIndRef::new(NodeId::alloc()); // self.set_ast(id, (scope_id, ast)); // Ok(id) let ctx = AddContext::new(self, scope_id); ctx.add_subtype_ind(ast) } /// Unpack a compound name as a type mark. pub fn unpack_type_mark( &self, ast: LatentName<'ast>, scope_id: ScopeRef, ) -> Result> { let id = LatentTypeMarkRef::new(NodeId::alloc()); self.set_ast(id, (scope_id, ast)); Ok(Spanned::new(id, ast.span())) } /// Unpack a compound name as a package name. pub fn unpack_package_name( &self, ast: LatentName<'ast>, scope_id: ScopeRef, ) -> Result> { let id = LatentPkgRef::new(NodeId::alloc()); self.set_ast(id, (scope_id, ast)); Ok(Spanned::new(id, ast.span())) } /// Unpack a compound name as a subprogram name. pub fn unpack_subprog_name( &self, ast: LatentName<'ast>, scope_id: ScopeRef, ) -> Result> { let id = LatentSubprogRef::new(NodeId::alloc()); self.set_ast(id, (scope_id, ast)); Ok(Spanned::new(id, ast.span())) } /// Unpack a slice of AST declarative items into a list of items admissible /// in the declarative part of a block. /// /// See IEEE 1076-2008 section 3.3.2. pub fn unpack_block_decls( &self, scope_id: ScopeRef, decls: &'ast [ast::DeclItem], container_name: &str, ) -> Result> { 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::(decl)?); } ast::ObjKind::Signal => { refs.extend(ctx.add_signal_decl::(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::(decl)?); } ast::ObjKind::File => { refs.extend(ctx.add_file_decl::(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) } } /// Unpack a slice of AST declarative items into a list of items admissible /// in the declarative part of a process. /// /// See IEEE 1076-2008 section 11.3. pub fn unpack_process_decls( &self, scope_id: ScopeRef, decls: &'ast [ast::DeclItem], container_name: &str, ) -> Result> { 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::(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::(decl)?); } ast::ObjKind::File => { refs.extend(ctx.add_file_decl::(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) } } /// Unpack a slice of AST declarative items into a list of items admissible /// in the declarative part of a subprogram. /// /// See IEEE 1076-2008 section 4.3. pub fn unpack_subprog_decls( &self, scope_id: ScopeRef, decls: &'ast [ast::DeclItem], ) -> Result> { 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::(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::(decl)?); } ast::ObjKind::File => { refs.extend(ctx.add_file_decl::(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) } } /// Unpack a slice of concurrent statements. /// /// See IEEE 1076-2008 section 11.1. pub fn unpack_concurrent_stmts( &self, scope_id: ScopeRef, stmts: &'ast [ast::Stmt], container_name: &str, ) -> Result> { 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) } } /// Unpack a slice of sequential statements. /// /// See IEEE 1076-2008 section 10. pub fn unpack_sequential_stmts( &self, scope_id: ScopeRef, stmts: &'ast [ast::Stmt], container_name: &str, ) -> Result> { let ctx = AddContext::new(self, scope_id); ctx.add_seq_stmts(stmts, container_name) } /// Unpack a signal assignment target. /// /// See IEEE 1076-2008 section 10.5.2.1. pub fn unpack_signal_assign_target( &self, scope_id: ScopeRef, target: &'ast ast::AssignTarget, ) -> Result { 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(()) } } } /// Unpack a signal assignment mode. /// /// See IEEE 1076-2008 section 10.5. pub fn unpack_signal_assign_mode( &self, scope_id: ScopeRef, mode: &'ast Spanned, tyctx: &TypeCtx<'ctx>, ) -> Result> { 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()); // guaranteed by parser 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, )) } /// Unpack a delay mechanism. /// /// See IEEE 1076-2008 section 10.5.2.1. If no mechanism is specified, /// inertial is assumed. Theoretically, the inertial transport mechanism is /// mapped to reject-inertial with the pulse rejection limit determined by /// the delay of the first element in the waveform. We don't have that /// information readily available at this time, so we simply map to /// inertial and leave the resolution of this to stages further down the /// pipeline. pub fn unpack_delay_mechanism( &self, scope_id: ScopeRef, dm: &'ast Option>, ) -> Result { 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) } } /// Unpack the the waves of a simple wave assignment. pub fn unpack_cond_waveforms( &self, _scope_id: ScopeRef, waves: &'ast [ast::CondWave], _tyctx: &TypeCtx<'ctx>, ) -> Result> { // Determine if we have a "else". let (_when, _other) = if waves.last().unwrap().1.is_some() { (&waves[..], None) } else { (&waves[..waves.len() - 1], Some(&waves.last().unwrap().1)) }; // for w in when { // } // let o = match other { // Some(o) => Some(self.unpack_waveform(scope_id, other)?), // None => None, // }; unimp!(self, "conditional waveforms"); } /// Unpack a single waveform. /// /// See IEEE 1076-2008 section 10.5.2. pub fn unpack_waveform( &self, scope_id: ScopeRef, wave: &'ast ast::Wave, tyctx: &TypeCtx<'ctx>, ) -> Result { 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)?; // TODO: Set the type context for the expression. // self.set_type_context(expr, TypeCtx::Type(/* somehow refer to builtin `time` type */)); Some(expr) } None => None, }, }) }) .collect() } /// Ensure that parenthesis contain only a list of expressions. /// /// This is useful since the parser generally expects parenthesized /// expressions of the form `(expr|expr|expr => expr, expr)` even in palces /// where only `(expr, expr)` would be applicable. This function takes the /// parenthesized expression and ensures it is of the latter form. 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() } /// Lower an AST subprogram specification to HIR. pub fn lower_subprog_spec( &self, scope_id: ScopeRef, ast: &'ast ast::SubprogSpec, ) -> Result { 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, }) } /// Lower the name of an AST subprogram to HIR and perform checks. pub fn lower_subprog_name( &self, kind: hir::SubprogKind, name: &'ast ast::PrimaryName, ) -> Result> { 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) } /// Unpack generics from a list of interface declarations. /// /// See IEEE 1076-2008 section 6.5.6.1. pub fn unpack_generics( &self, scope_id: ScopeRef, decls: &'ast [ast::IntfDecl], into: &mut Vec, ) -> 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)?; // let ty = SubtypeIndRef(NodeId::alloc()); // self.set_ast(ty, (scope_id, &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(()) } } /// Unpack a generic map from a parenthesized list of elements. /// /// See IEEE 1076-2008 section 6.5.7.2. pub fn unpack_generic_map( &self, _scope_id: ScopeRef, elems: &'ast ast::ParenElems, ) -> Result> { if !elems.value.is_empty() { unimp_msg!(self, "generic map aspect", elems.span); } Ok(Vec::new()) } } // Lower an entity to HIR. 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 { // Port clauses ast::DeclItem::PortgenClause(_, Spanned{ value: ast::PortgenKind::Port, span }, ref decls) => { // For ports only signal interface declarations are allowed. 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)?; // let ty = SubtypeIndRef(NodeId::alloc()); // self.set_ast(ty, (id.into(), &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; } } } } // Generic clauses 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; } } } // TODO(strict): Complain about multiple port and generic clauses. // TODO(strict): Complain when port and generic clauses are not the // first in the entity. Ok(self.sb.arenas.hir.entity.alloc(entity)) }); // Lower an interface signal to HIR. 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)) }); // Lower a package declaration to HIR. 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 generic_maps = Vec::new(); let mut decls = Vec::new(); let mut had_fails = false; // Filter the declarations in the package to only those that we actually // support, and separate the generic clauses and maps. 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()); // let subid = TypeDeclRef(NodeId::alloc()); // self.set_ast(subid, (scope, decl)); // decls.push(subid.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::(decl)?); } ast::ObjKind::Signal => { decls.extend(ctx.add_signal_decl::(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::(decl)?); } ast::ObjKind::File => { decls.extend(ctx.add_file_decl::(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, })) } }); // Lower a package body to HIR. 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::(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::(decl)?); } ast::ObjKind::File => { decls.extend(ctx.add_file_decl::(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, })) } }); // Lower a package instantiation to HIR. 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, })) }); // // Lower an expression to HIR. // impl_make!(self, id: ExprRef => &hir::Expr { // let (scope_id, ast) = self.ast(id); // let data = match ast.data { // // Literals // ast::LitExpr(..) => { // let term_ctx = TermContext::new(self, scope_id); // let term = term_ctx.termify_expr(ast)?; // term_ctx.term_to_expr_raw(term)?.data // } // // Unary operators. // ast::UnaryExpr(op, ref arg) => { // let op = self.lower_unary_op(Spanned::new(op, ast.span))?; // let subid = ExprRef(NodeId::alloc()); // self.set_ast(subid, (scope_id, arg.as_ref())); // hir::ExprData::Unary(op, vec![], subid) // } // // Ranges. // ast::BinaryExpr(ast::BinaryOp::Dir(d), ref lb, ref rb) => { // hir::ExprData::Range(d, self.unpack_expr(lb, scope_id)?, self.unpack_expr(rb, scope_id)?) // } // // Binary operators. // // ast::BinaryExpr(op, ref lhs, ref rhs) => { // // } // // Names. // ast::NameExpr(ref name) => { // let (_, defs, matched_span, tail_parts) = self.resolve_compound_name(name, scope_id, false)?; // debugln!("name {} matched {:?}, tail {:?}", name.span.extract(), defs, tail_parts); // // If there are multiple definitions, perform overload resolution by // // consulting the type context for the expression. // let defs: Vec<_> = if defs.len() > 1 { // if let Some(tyctx) = self.type_context_resolved(id)? { // let ty = self.deref_named_type(tyctx)?; // if self.sess.opts.trace_scoreboard { // debugln!("[SB][VHDL][OVLD] resolve overloaded `{}`", matched_span.extract()); // debugln!("[SB][VHDL][OVLD] context requires {:?}", ty); // } // // Filter out the defs that are typed and that match the // // type imposed by the expression context. // let mut filtered = Vec::new(); // for def in defs { // let defty = self.deref_named_type(match def.value { // Def::Enum(EnumRef(id,_)) => self.ty(id)?, // // TODO: Add subprograms and everything else that // // can match here. // _ => { // if self.sess.opts.trace_scoreboard { // debugln!("[SB][VHDL][OVLD] discarding irrelevant {:?}", def.value); // } // continue; // } // })?; // if defty == ty { // filtered.push(def); // if self.sess.opts.trace_scoreboard { // debugln!("[SB][VHDL][OVLD] accepting {:?}", def.value); // } // } else { // if self.sess.opts.trace_scoreboard { // debugln!("[SB][VHDL][OVLD] discarding {:?} because mismatching type {:?}", def.value, defty); // } // } // } // // If the filtering left no overloads, emit an error. // if filtered.is_empty() { // self.emit( // DiagBuilder2::error(format!("no overload of `{}` applicable", matched_span.extract())) // .span(matched_span) // ); // // TODO: Print the required type and the type of what // // has been found. // return Err(()); // } // filtered // } else { // defs // } // } else { // defs // }; // // Make sure we only have one definition. If we have more than one, // // perform overload resolution by consulting the type context for // // the expression. // let def = if defs.len() == 1 { // *defs.last().unwrap() // } else { // self.emit( // DiagBuilder2::error(format!("`{}` is ambiguous", matched_span.extract())) // .span(matched_span) // ); // return Err(()); // }; // // // Create the expression representation of the definition. // let mut expr: &'ctx hir::Expr = self.sb.arenas.hir.expr.alloc(hir::Expr{ // parent: scope_id, // span: matched_span, // data: hir::ExprData::Name(def.value, def.span), // }); // // // Unpack the remaining parts of the name. // for part in tail_parts { // // Allocate a node ID for the inner expression and store it away in // // the HIR table. // let inner = ExprRef::new(NodeId::alloc()); // let inner_span = expr.span; // self.set_hir(inner, expr); // // match *part { // ast::NamePart::Select(name) => { // let rn = self.resolvable_from_primary_name(&name)?; // expr = self.sb.arenas.hir.expr.alloc(hir::Expr{ // parent: scope_id, // span: Span::union(inner_span, rn.span), // data: hir::ExprData::Select(inner, rn), // }); // } // // ast::NamePart::Signature(ref _sig) => unimplemented!(), // // ast::NamePart::Attribute(ident) => { // expr = self.sb.arenas.hir.expr.alloc(hir::Expr{ // parent: scope_id, // span: Span::union(inner_span, ident.span), // data: hir::ExprData::Attr(inner, Spanned::new(ident.name.into(), ident.span)), // }); // } // // // Call expressions can map to different things. First we need // // to know what type the callee has. Based on this, the list of // // arguments can be associated with the correct ports. Or in // // case the callee is a type, we perform a type conversion. // ast::NamePart::Call(ref _elems) => { // let callee_ty = self.ty(inner)?; // panic!("call to {:?} not implemented", callee_ty); // // let mut had_named = false; // // for i in 0..elems.len() { // // // } // } // // // Disallow `.all` in expressions. // ast::NamePart::SelectAll(span) => { // self.emit( // DiagBuilder2::error("`.all` in an expression") // .span(span) // ); // return Err(()); // } // // // Disallow ranges in expressions. // ast::NamePart::Range(ref expr) => { // self.emit( // DiagBuilder2::error("range in an expression") // .span(expr.span) // ); // return Err(()); // } // } // } // // // return self.compound_name_to_expr(name, scope_id); // return Ok(expr); // } // // // All other expressions we simply do not support. // _ => { // self.emit( // DiagBuilder2::error("invalid expression") // .span(ast.span) // ); // return Err(()); // } // }; // Ok(self.sb.arenas.hir.expr.alloc(hir::Expr{ // parent: scope_id, // span: ast.span, // data: data, // })) // }); // // // Lower a type declaration to HIR. // impl_make!(self, id: TypeDeclRef => &hir::TypeDecl { // let (scope_id, ast) = self.ast(id); // let data = if let Some(ref spanned_data) = ast.data { // Some(Spanned::new(match spanned_data.value { // // Integer, real, and physical types. // ast::RangeType(ref range_expr, ref units) => { // let (dir, lb, rb) = match range_expr.data { // ast::BinaryExpr(ast::BinaryOp::Dir(dir), ref lb_expr, ref rb_expr) => { // // let ctx = AddContext::new(self, scope_id); // // let lb = ctx.add_expr(lb_expr)?; // // let rb = ctx.add_expr(rb_expr)?; // let lb = ExprRef(NodeId::alloc()); // let rb = ExprRef(NodeId::alloc()); // self.set_ast(lb, (scope_id.into(), lb_expr.as_ref())); // self.set_ast(rb, (scope_id.into(), rb_expr.as_ref())); // (dir, lb, rb) // } // _ => { // self.emit( // DiagBuilder2::error("Invalid range expression") // .span(range_expr.span) // ); // return Err(()); // } // }; // if let Some(ref units) = *units { // // Determine the primary unit. // let mut prim_iter = units // .iter() // .enumerate() // .filter(|&(_, &(_, ref expr))| expr.is_none()) // .map(|(index, &(name, _))| (index, name)); // let primary = match prim_iter.next() { // Some(u) => u, // None => { // self.emit( // DiagBuilder2::error(format!("physical type `{}` has no primary unit", ast.name.value)) // .span(ast.span) // .add_note("A physical type must have a primary unit of the form `;`. See IEEE 1076-2008 section 5.2.4.") // ); // return Err(()); // } // }; // let mut had_fails = false; // for (_, name) in prim_iter { // self.emit( // DiagBuilder2::error(format!("physical type `{}` has multiple primary units", ast.name.value)) // .span(name.span) // .add_note("A physical type cannot have multiple primary units. See IEEE 1076-2008 section 5.2.4.") // ); // had_fails = true; // } // if had_fails { // return Err(()); // } // debugln!("primary unit {:#?}", primary); // // // Determine the units and how they are defined with respect // // to each other. // let term_ctx = TermContext::new(self, scope_id); // let table = units // .iter() // .map(|&(name, ref expr)|{ // let rel = if let Some(ref expr) = *expr { // let term = term_ctx.termify_expr(expr)?; // let (value, unit) = match term.value { // Term::PhysLit(value, unit) => (value, unit), // _ => { // self.emit( // DiagBuilder2::error(format!("`{}` is not a valid secondary unit", term.span.extract())) // .span(term.span) // ); // debugln!("It is a {:#?}", term.value); // return Err(()); // } // }; // if unit.value.0 != id { // self.emit( // DiagBuilder2::error(format!("`{}` is not a unit in the physical type `{}`", term.span.extract(), ast.name.value)) // .span(term.span) // .add_note(format!("`{}` has been declared here:", term.span.extract())) // .span(unit.span) // ); // } // Some((value, unit.value.1)) // } else { // None // }; // Ok((Spanned::new(name.name, name.span), rel)) // }) // .collect::>>() // .into_iter() // .collect::>>()?; // // // Determine the scale of each unit with respect to the // // primary unit. // let scale_table = table // .iter() // .map(|&(name, ref rel)|{ // let mut abs = BigInt::from(1); // let mut rel_to = rel.as_ref(); // while let Some(&(ref scale, index)) = rel_to { // abs = abs * scale; // rel_to = table[index].1.as_ref(); // } // (name, abs, rel.clone()) // }) // .collect::>(); // // hir::TypeData::Physical(dir, lb, rb, scale_table, primary.0) // } else { // hir::TypeData::Range(dir, lb, rb) // } // } // // // Enumeration types. // ast::EnumType(ref elems) => { // let mut lits = Vec::new(); // for elem in &elems.value { // // Unpack the element. Make sure it only consists of an // // expression that is either an identifier or a character // // literal. // let lit = if !elem.choices.value.is_empty() { // None // } else { // match elem.expr.data { // ast::NameExpr(ast::CompoundName{ // primary: ast::PrimaryName{ kind, span, .. }, // ref parts, // .. // }) if parts.is_empty() => { // match kind { // ast::PrimaryNameKind::Ident(n) => Some(hir::EnumLit::Ident(Spanned::new(n, span))), // ast::PrimaryNameKind::Char(c) => Some(hir::EnumLit::Char(Spanned::new(c, span))), // _ => None, // } // } // _ => None // } // }; // // // If the unpacking was successful, add the literal to the list // // of enumeration literals. // if let Some(lit) = lit { // lits.push(lit); // } else { // self.emit( // DiagBuilder2::error("not an enumeration literal") // .span(elem.span) // .add_note("expected an identifier or character literal") // ); // continue; // } // } // hir::TypeData::Enum(lits) // } // // ast::AccessType(ref subty) => { // hir::TypeData::Access(self.unpack_subtype_ind(subty, scope_id)?) // } // // ast::ArrayType(ref indices, ref elem_subty) => { // // Ensure that we have at least on index, and ensure that there // // are no stray choices (`expr|expr =>`) in the list. Then map // // each index into its own node, unpack the element subtype, and // // we're done. // assert!(indices.value.len() > 0); // let indices = self // .sanitize_paren_elems_as_exprs(&indices.value, "an array type index") // .into_iter() // .map(|index|{ // let id = ArrayTypeIndexRef::new(NodeId::alloc()); // self.set_ast(id, (scope_id, index)); // id // }) // .collect(); // let ctx = TermContext::new(self, scope_id); // let subty = ctx.termify_subtype_ind(elem_subty)?; // let elem_subty = ctx.term_to_subtype_ind(subty)?.value; // let add_ctx = AddContext::new(self, scope_id); // let elem_subty = add_ctx.add_subtype_ind_hir(elem_subty)?; // hir::TypeData::Array(indices, elem_subty) // } // // ast::FileType(ref name) => { // let ctx = TermContext::new(self, scope_id); // let term = ctx.termify_compound_name(name)?; // let tm = ctx.term_to_type_mark(term)?; // hir::TypeData::File(tm) // } // // ast::RecordType(ref fields) => { // let fields = fields.iter().flat_map(|&(ref names, ref subty)|{ // let subty = self.unpack_subtype_ind(subty, scope_id); // names.iter().map(move |name| Ok((Spanned::new(name.name, name.span), subty?))) // }).collect::>>()?; // hir::TypeData::Record(fields) // } // // ast::ProtectedType(..) => unimp_msg!(self, "protected types", ast.span), // }, spanned_data.span)) // } else { // None // }; // let decl = hir::TypeDecl{ // parent: scope_id, // name: ast.name, // data: data, // }; // Ok(self.sb.arenas.hir.type_decl.alloc(decl)) // }); // Lower an architecture to HIR. 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 sensitivity, ref decls, ref stmts, postponed, .. } => { // TODO: map sensititivty 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 { 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_make!(self, id: SubtypeIndRef => &hir::SubtypeInd { // let (scope_id, ast) = self.ast(id); // let ctx = TermContext::new(self, scope_id); // let term = ctx.termify_subtype_ind(ast)?; // Ok(self.sb.arenas.hir.subtype_ind.alloc(ctx.term_to_subtype_ind(term)?.value)) // }); impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {} // Lower a subprogram declaration to HIR. 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, })) }); // Lower a subprogram body to HIR. 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, })) }); // Lower a subprogram instantiation to HIR. 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 { 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) });