use super::formal_region::FormalRegion;
use super::region::Region;
use crate::ast::ExternalObjectClass;
use crate::ast::{
AnyPrimaryUnit, Designator, HasIdent, Ident, ObjectClass, SubprogramDeclaration,
SubprogramDesignator, WithDecl,
};
use crate::data::*;
mod types;
pub use types::{BaseType, Subtype, Type, TypeEnt, TypedSelection, UniversalType};
mod overloaded;
pub use overloaded::{Overloaded, OverloadedEnt, Signature, SignatureKey};
mod object;
pub use object::{Object, ObjectEnt};
mod design;
pub use design::{Design, DesignEnt};
mod arena;
pub use arena::{Arena, ArenaId, EntityId, FinalArena};
pub enum AnyEntKind<'a> {
ExternalAlias {
class: ExternalObjectClass,
type_mark: TypeEnt<'a>,
},
ObjectAlias {
base_object: ObjectEnt<'a>,
type_mark: TypeEnt<'a>,
},
File(Subtype<'a>),
InterfaceFile(TypeEnt<'a>),
Component(Region<'a>),
Attribute(TypeEnt<'a>),
Overloaded(Overloaded<'a>),
Type(Type<'a>),
ElementDeclaration(Subtype<'a>),
Label,
Object(Object<'a>),
LoopParameter(Option<BaseType<'a>>),
PhysicalLiteral(TypeEnt<'a>),
DeferredConstant(Subtype<'a>),
Library,
Design(Design<'a>),
}
impl<'a> AnyEntKind<'a> {
pub(crate) fn new_function_decl(
formals: FormalRegion<'a>,
return_type: TypeEnt<'a>,
) -> AnyEntKind<'a> {
AnyEntKind::Overloaded(Overloaded::SubprogramDecl(Signature::new(
formals,
Some(return_type),
)))
}
pub(crate) fn new_procedure_decl(formals: FormalRegion<'a>) -> AnyEntKind<'a> {
AnyEntKind::Overloaded(Overloaded::SubprogramDecl(Signature::new(formals, None)))
}
pub fn is_deferred_constant(&self) -> bool {
matches!(self, AnyEntKind::DeferredConstant(..))
}
pub fn is_non_deferred_constant(&self) -> bool {
matches!(
self,
AnyEntKind::Object(Object {
class: ObjectClass::Constant,
mode: None,
..
})
)
}
pub fn is_protected_type(&self) -> bool {
matches!(self, AnyEntKind::Type(Type::Protected(..)))
}
pub fn is_type(&self) -> bool {
matches!(self, AnyEntKind::Type(..))
}
pub fn describe(&self) -> &str {
use AnyEntKind::*;
match self {
ObjectAlias { .. } => "object alias",
ExternalAlias { .. } => "external alias",
File(..) => "file",
InterfaceFile(..) => "file",
ElementDeclaration(..) => "element declaration",
Component(..) => "component",
Attribute(..) => "attribute",
Overloaded(overloaded) => overloaded.describe(),
Label => "label",
LoopParameter(_) => "loop parameter",
Object(object) => object.class.describe(),
PhysicalLiteral(..) => "physical literal",
DeferredConstant(..) => "deferred constant",
Library => "library",
Design(design) => design.describe(),
Type(typ) => typ.describe(),
}
}
}
impl<'a> std::fmt::Debug for AnyEntKind<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.describe())
}
}
impl<'a> std::fmt::Debug for AnyEnt<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let AnyEnt {
id,
related,
implicits,
designator,
kind,
decl_pos,
} = self;
let mut s = f.debug_struct(stringify!(AnyEnt));
s.field(stringify!(id), id);
s.field(stringify!(related), related);
s.field(stringify!(implicits), &implicits.len());
s.field(stringify!(designator), designator);
s.field(stringify!(kind), kind);
s.field(stringify!(decl_pos), decl_pos);
s.finish()
}
}
pub type EntRef<'a> = &'a AnyEnt<'a>;
#[derive(Debug, Copy, Clone)]
pub enum Related<'a> {
ImplicitOf(EntRef<'a>),
InstanceOf(EntRef<'a>),
None,
}
pub struct AnyEnt<'a> {
pub id: EntityId,
pub related: Related<'a>,
pub implicits: Vec<EntRef<'a>>,
pub designator: Designator,
pub kind: AnyEntKind<'a>,
pub decl_pos: Option<SrcPos>,
}
impl Arena {
pub fn implicit<'a>(
&'a self,
of_ent: EntRef<'a>,
designator: impl Into<Designator>,
kind: AnyEntKind<'a>,
decl_pos: Option<&SrcPos>,
) -> EntRef<'a> {
self.alloc(
designator.into(),
Related::ImplicitOf(of_ent),
kind,
decl_pos.cloned(),
)
}
pub fn define<'a, T: HasIdent>(
&'a self,
decl: &mut WithDecl<T>,
kind: AnyEntKind<'a>,
) -> EntRef<'a> {
let ent = self.explicit(decl.tree.name().clone(), kind, Some(decl.tree.pos()));
decl.decl = Some(ent.id());
ent
}
pub fn explicit<'a>(
&'a self,
designator: impl Into<Designator>,
kind: AnyEntKind<'a>,
decl_pos: Option<&SrcPos>,
) -> EntRef<'a> {
self.alloc(designator.into(), Related::None, kind, decl_pos.cloned())
}
}
impl<'a> AnyEnt<'a> {
pub fn id(&self) -> EntityId {
self.id
}
pub fn is_implicit(&self) -> bool {
match self.related {
Related::ImplicitOf(_) => true,
Related::InstanceOf(ent) => ent.is_implicit(),
Related::None => false,
}
}
pub fn is_subprogram(&self) -> bool {
matches!(
self.kind,
AnyEntKind::Overloaded(Overloaded::Subprogram(..))
)
}
pub fn is_subprogram_decl(&self) -> bool {
matches!(
self.kind,
AnyEntKind::Overloaded(Overloaded::SubprogramDecl(..))
)
}
pub fn is_explicit(&self) -> bool {
!self.is_implicit()
}
pub fn decl_pos(&self) -> Option<&SrcPos> {
self.decl_pos.as_ref()
}
pub fn designator(&self) -> &Designator {
&self.designator
}
pub fn kind(&self) -> &AnyEntKind {
&self.kind
}
pub fn error(&self, diagnostics: &mut dyn DiagnosticHandler, message: impl Into<String>) {
if let Some(ref pos) = self.decl_pos {
diagnostics.push(Diagnostic::error(pos, message));
}
}
pub fn is_overloaded(&self) -> bool {
self.signature().is_some()
}
pub fn signature(&self) -> Option<&Signature> {
match self.actual_kind() {
AnyEntKind::Overloaded(ref overloaded) => Some(overloaded.signature()),
_ => None,
}
}
pub fn as_actual(&self) -> &AnyEnt {
match self.kind() {
AnyEntKind::Overloaded(Overloaded::Alias(ref ent)) => ent.as_actual(),
AnyEntKind::Type(Type::Alias(ref ent)) => ent.as_actual(),
_ => self,
}
}
pub(crate) fn add_implicit(&mut self, ent: EntRef<'a>) {
self.implicits.push(ent);
}
pub fn actual_kind(&self) -> &AnyEntKind {
self.as_actual().kind()
}
pub fn is_alias_of(&self, other: &AnyEnt) -> bool {
match self.kind() {
AnyEntKind::Type(Type::Alias(ref ent)) => {
if ent.id() == other.id() {
true
} else {
ent.is_alias_of(other)
}
}
_ => false,
}
}
pub fn describe(&self) -> String {
match self.kind {
AnyEntKind::Object(Object {
ref class,
mode: Some(ref mode),
..
}) => {
if *class == ObjectClass::Constant {
format!("interface {} '{}'", class.describe(), self.designator,)
} else {
format!(
"interface {} '{}' : {}",
class.describe(),
self.designator,
mode
)
}
}
AnyEntKind::Overloaded(ref overloaded) => {
format!("{}{}", self.designator, overloaded.signature().describe())
}
AnyEntKind::Type(Type::Universal(typ)) => format!("type {}", typ.describe().to_owned()),
_ => format!("{} '{}'", self.kind.describe(), self.designator),
}
}
}
impl<'a> std::cmp::PartialEq for AnyEnt<'a> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<'a> std::hash::Hash for AnyEnt<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id().hash(state)
}
}
impl<'a> Eq for AnyEnt<'a> {}
pub trait HasEntityId {
fn ent_id(&self) -> Option<EntityId>;
}
impl HasEntityId for AnyPrimaryUnit {
fn ent_id(&self) -> Option<EntityId> {
delegate_primary!(self, unit, unit.ident.decl)
}
}
impl WithDecl<Ident> {
pub fn define<'a>(&mut self, arena: &'a Arena, kind: AnyEntKind<'a>) -> EntRef<'a> {
let ent = arena.explicit(self.tree.name().clone(), kind, Some(self.tree.pos()));
self.decl = Some(ent.id());
ent
}
}
impl WithDecl<WithPos<SubprogramDesignator>> {
pub fn define<'a>(&mut self, arena: &'a Arena, kind: AnyEntKind<'a>) -> EntRef<'a> {
let ent = arena.explicit(
self.tree.item.clone().into_designator(),
kind,
Some(&self.tree.pos),
);
self.decl = Some(ent.id());
ent
}
}
impl WithDecl<WithPos<Designator>> {
pub fn define<'a>(&mut self, arena: &'a Arena, kind: AnyEntKind<'a>) -> EntRef<'a> {
let ent = arena.explicit(self.tree.item.clone(), kind, Some(&self.tree.pos));
self.decl = Some(ent.id());
ent
}
}
impl SubprogramDeclaration {
pub fn define<'a>(&mut self, arena: &'a Arena, kind: AnyEntKind<'a>) -> EntRef<'a> {
match self {
SubprogramDeclaration::Function(f) => f.designator.define(arena, kind),
SubprogramDeclaration::Procedure(p) => p.designator.define(arena, kind),
}
}
}