use super::region::Region;
use crate::ast::*;
use crate::data::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[derive(Clone)]
pub enum NamedEntityKind {
AliasOf(Arc<NamedEntity>),
OtherAlias,
File,
InterfaceFile,
RecordField,
Component,
Attribute,
Function,
Procedure,
EnumLiteral,
TypeDeclaration(Vec<Arc<NamedEntity>>),
Subtype(Subtype),
IncompleteType,
InterfaceType,
Label,
Object(ObjectClass),
InterfaceObject(InterfaceObject),
PhysicalLiteral,
DeferredConstant,
ProtectedType(Arc<Region<'static>>),
Library,
Entity(Arc<Region<'static>>),
Configuration(Arc<Region<'static>>),
Package(Arc<Region<'static>>),
UninstPackage(Arc<Region<'static>>),
PackageInstance(Arc<Region<'static>>),
Context(Arc<Region<'static>>),
LocalPackageInstance(Arc<Region<'static>>),
}
impl NamedEntityKind {
pub fn from_object_declaration(decl: &ObjectDeclaration) -> NamedEntityKind {
if decl.class == ObjectClass::Constant && decl.expression.is_none() {
NamedEntityKind::DeferredConstant
} else {
NamedEntityKind::Object(decl.class)
}
}
pub fn is_deferred_constant(&self) -> bool {
if let NamedEntityKind::DeferredConstant = self {
true
} else {
false
}
}
pub fn is_non_deferred_constant(&self) -> bool {
if let NamedEntityKind::Object(ObjectClass::Constant) = self {
true
} else {
false
}
}
pub fn is_protected_type(&self) -> bool {
if let NamedEntityKind::ProtectedType(..) = self {
true
} else {
false
}
}
pub fn is_type(&self) -> bool {
match self {
NamedEntityKind::IncompleteType
| NamedEntityKind::ProtectedType(..)
| NamedEntityKind::InterfaceType
| NamedEntityKind::Subtype(..)
| NamedEntityKind::TypeDeclaration(..) => true,
_ => false,
}
}
pub fn describe(&self) -> &str {
use NamedEntityKind::*;
match self {
AliasOf(..) => "alias",
OtherAlias => "alias",
File => "file",
InterfaceFile => "file",
RecordField => "file",
Component => "file",
Attribute => "file",
Procedure => "procedure",
Function => "function",
EnumLiteral => "enum literal",
TypeDeclaration(..) => "type",
Subtype(..) => "subtype",
IncompleteType => "type",
InterfaceType => "type",
Label => "label",
Object(class) => class.describe(),
InterfaceObject(object) => object.class.describe(),
PhysicalLiteral => "physical literal",
DeferredConstant => "deferred constant",
ProtectedType(..) => "protected type",
Library => "library",
Entity(..) => "entity",
Configuration(..) => "configuration",
Package(..) => "package",
UninstPackage(..) => "uninstantiated package",
PackageInstance(..) => "package instance",
Context(..) => "context",
LocalPackageInstance(..) => "package instance",
}
}
}
#[derive(Clone)]
pub struct InterfaceObject {
pub class: ObjectClass,
pub mode: Mode,
pub subtype: Subtype,
pub has_default: bool,
}
#[derive(Clone)]
pub struct Subtype {
base: Arc<NamedEntity>,
}
impl Subtype {
pub fn new(base: Arc<NamedEntity>) -> Subtype {
debug_assert!(base.actual_kind().is_type());
Subtype { base }
}
}
impl ObjectClass {
fn describe(&self) -> &str {
use ObjectClass::*;
match self {
Constant => "constant",
Variable => "variable",
Signal => "signal",
SharedVariable => "shared variable",
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct EntityId {
id: usize,
}
pub struct NamedEntity {
id: EntityId,
designator: Designator,
kind: NamedEntityKind,
decl_pos: Option<SrcPos>,
}
impl NamedEntity {
pub fn new(
designator: impl Into<Designator>,
kind: NamedEntityKind,
decl_pos: Option<&SrcPos>,
) -> NamedEntity {
NamedEntity::new_with_id(new_id(), designator, kind, decl_pos)
}
pub fn new_with_id(
id: EntityId,
designator: impl Into<Designator>,
kind: NamedEntityKind,
decl_pos: Option<&SrcPos>,
) -> NamedEntity {
NamedEntity {
id,
decl_pos: decl_pos.cloned(),
designator: designator.into(),
kind,
}
}
pub fn id(&self) -> EntityId {
self.id
}
pub fn decl_pos(&self) -> Option<&SrcPos> {
self.decl_pos.as_ref()
}
pub fn designator(&self) -> &Designator {
&self.designator
}
pub fn kind(&self) -> &NamedEntityKind {
&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 {
match self.actual_kind() {
NamedEntityKind::Procedure
| NamedEntityKind::Function
| NamedEntityKind::EnumLiteral => true,
_ => false,
}
}
pub fn as_actual(&self) -> &NamedEntity {
match self.kind() {
NamedEntityKind::AliasOf(ref ent) => ent.as_actual(),
_ => self,
}
}
pub fn actual_kind(&self) -> &NamedEntityKind {
self.as_actual().kind()
}
pub fn is_alias_of(&self, other: &NamedEntity) -> bool {
match self.kind() {
NamedEntityKind::AliasOf(ref ent) => {
if ent.id() == other.id() {
true
} else {
ent.is_alias_of(other)
}
}
_ => false,
}
}
pub fn describe(&self) -> String {
if let NamedEntityKind::AliasOf(..) = self.kind {
format!(
"alias '{}' of {}",
self.designator,
self.as_actual().describe()
)
} else {
format!("{} '{}'", self.kind.describe(), self.designator)
}
}
}
static COUNTER: AtomicUsize = AtomicUsize::new(1);
pub fn new_id() -> EntityId {
EntityId {
id: COUNTER.fetch_add(1, Ordering::Relaxed),
}
}