use arc_swap::ArcSwapOption;
use fnv::FnvHashMap;
use super::analyze::*;
use super::formal_region::FormalRegion;
use super::formal_region::GpkgInterfaceEnt;
use super::formal_region::GpkgRegion;
use super::formal_region::InterfaceEnt;
use super::formal_region::RecordElement;
use super::formal_region::RecordRegion;
use super::named_entity::Design;
use super::named_entity::Object;
use super::named_entity::ObjectEnt;
use super::named_entity::Overloaded;
use super::named_entity::OverloadedEnt;
use super::named_entity::Signature;
use super::named_entity::Subtype;
use super::named_entity::Type;
use super::named_entity::TypeEnt;
use super::region::*;
use super::AnyEntKind;
use super::EntRef;
use super::EntityId;
use super::Related;
use crate::ast::ActualPart;
use crate::ast::AssociationElement;
use crate::ast::Expression;
use crate::ast::Literal;
use crate::ast::Name;
use crate::ast::Operator;
use crate::ast::PackageInstantiation;
use crate::data::DiagnosticHandler;
use crate::Diagnostic;
use crate::NullDiagnostics;
impl<'a> AnalyzeContext<'a> {
fn package_generic_map(
&self,
scope: &Scope<'a>,
generics: GpkgRegion<'a>,
generic_map: &mut [AssociationElement],
diagnostics: &mut dyn DiagnosticHandler,
) -> FatalResult<FnvHashMap<EntityId, EntRef<'a>>> {
let mut mapping = FnvHashMap::default();
for (idx, assoc) in generic_map.iter_mut().enumerate() {
let formal = if let Some(formal) = &mut assoc.formal {
if let Name::Designator(des) = &mut formal.item {
match generics.lookup(&formal.pos, &des.item) {
Ok((_, ent)) => {
des.set_unique_reference(&ent);
ent
}
Err(err) => {
diagnostics.push(err);
continue;
}
}
} else {
diagnostics.error(
&formal.pos,
"Expected simple name for package generic formal",
);
continue;
}
} else if let Some(ent) = generics.nth(idx) {
ent
} else {
diagnostics.error(&assoc.actual.pos, "Extra actual for generic map");
continue;
};
match &mut assoc.actual.item {
ActualPart::Expression(expr) => match formal {
GpkgInterfaceEnt::Type(uninst_typ) => {
let typ = if let Expression::Name(name) = expr {
match name.as_mut() {
Name::Slice(prefix, _) => self.type_name(
scope,
&prefix.pos,
&mut prefix.item,
diagnostics,
)?,
Name::CallOrIndexed(call) if call.could_be_indexed_name() => self
.type_name(
scope,
&call.name.pos,
&mut call.name.item,
diagnostics,
)?,
_ => self.type_name(scope, &assoc.actual.pos, name, diagnostics)?,
}
} else {
diagnostics
.error(&assoc.actual.pos, "Cannot map expression to type generic");
None
};
if let Some(typ) = typ {
mapping.insert(uninst_typ.id(), typ.into());
}
}
GpkgInterfaceEnt::Constant(obj) => self.expr_with_ttyp(
scope,
obj.type_mark(),
&assoc.actual.pos,
expr,
diagnostics,
)?,
GpkgInterfaceEnt::Subprogram(_) => match expr {
Expression::Name(name) => {
if let Err(err) =
self.name_resolve(scope, &assoc.actual.pos, name, diagnostics)
{
diagnostics.push(err.into_non_fatal()?);
};
}
Expression::Literal(Literal::String(string)) => {
if Operator::from_latin1(string.clone()).is_none() {
diagnostics.error(&assoc.actual.pos, "Invalid operator symbol");
}
}
_ => diagnostics.error(
&assoc.actual.pos,
"Cannot map expression to subprogram generic",
),
},
GpkgInterfaceEnt::Package(_) => match expr {
Expression::Name(name) => {
if let Err(err) =
self.name_resolve(scope, &assoc.actual.pos, name, diagnostics)
{
diagnostics.push(err.into_non_fatal()?);
};
}
_ => diagnostics.error(
&assoc.actual.pos,
"Cannot map expression to package generic",
),
},
},
ActualPart::Open => {
}
}
}
Ok(mapping)
}
pub fn generic_package_instance(
&self,
scope: &Scope<'a>,
unit: &mut PackageInstantiation,
diagnostics: &mut dyn DiagnosticHandler,
) -> FatalResult<Option<Region<'a>>> {
let PackageInstantiation {
package_name,
generic_map,
..
} = unit;
match self.analyze_package_instance_name(scope, package_name) {
Ok(package_region) => {
let nested = scope.nested().in_package_declaration();
let (generics, other) = package_region.to_package_generic();
let mapping = if let Some(generic_map) = generic_map {
self.package_generic_map(&nested, generics, generic_map, diagnostics)?
} else {
FnvHashMap::default()
};
for uninst in other {
match self.instantiate(&mapping, uninst) {
Ok(inst) => {
nested.add(inst, diagnostics);
}
Err(err) => {
let mut diag = Diagnostic::error(&unit.ident.tree.pos, err);
if let Some(pos) = uninst.decl_pos() {
diag.add_related(pos, "When instantiating this declaration");
}
diagnostics.push(diag);
}
}
}
Ok(Some(nested.into_region()))
}
Err(err) => {
diagnostics.push(err.into_non_fatal()?);
Ok(None)
}
}
}
fn instantiate(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
uninst: EntRef<'a>,
) -> Result<EntRef<'a>, String> {
let designator = uninst.designator().clone();
let decl_pos = uninst.decl_pos().cloned();
let kind = self.map_kind(mapping, uninst.kind())?;
let inst = self
.arena
.alloc(designator, Related::InstanceOf(uninst), kind, decl_pos);
for implicit_uninst in uninst.implicits.iter() {
unsafe {
self.arena
.add_implicit(inst.id(), self.instantiate(mapping, implicit_uninst)?);
}
}
Ok(inst)
}
fn map_kind(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
kind: &'a AnyEntKind<'a>,
) -> Result<AnyEntKind<'a>, String> {
Ok(match kind {
AnyEntKind::ExternalAlias { class, type_mark } => AnyEntKind::ExternalAlias {
class: *class,
type_mark: self.map_type_ent(mapping, *type_mark)?,
},
AnyEntKind::ObjectAlias {
base_object,
type_mark,
} => AnyEntKind::ObjectAlias {
base_object: if let Some(obj) =
ObjectEnt::from_any(self.instantiate(mapping, base_object)?)
{
obj
} else {
return Err(
"Internal error, expected instantiated object to be object".to_owned()
);
},
type_mark: self.map_type_ent(mapping, *type_mark)?,
},
AnyEntKind::File(subtype) => AnyEntKind::File(self.map_subtype(mapping, *subtype)?),
AnyEntKind::InterfaceFile(typ) => {
AnyEntKind::InterfaceFile(self.map_type_ent(mapping, *typ)?)
}
AnyEntKind::Component(region) => {
AnyEntKind::Component(self.map_region(mapping, region)?)
}
AnyEntKind::Attribute(typ) => AnyEntKind::Attribute(self.map_type_ent(mapping, *typ)?),
AnyEntKind::Overloaded(overloaded) => {
AnyEntKind::Overloaded(self.map_overloaded(mapping, overloaded)?)
}
AnyEntKind::Type(typ) => AnyEntKind::Type(self.map_type(mapping, typ)?),
AnyEntKind::ElementDeclaration(subtype) => {
AnyEntKind::ElementDeclaration(self.map_subtype(mapping, *subtype)?)
}
AnyEntKind::Label => AnyEntKind::Label,
AnyEntKind::Object(obj) => AnyEntKind::Object(self.map_object(mapping, obj)?),
AnyEntKind::LoopParameter => AnyEntKind::LoopParameter,
AnyEntKind::PhysicalLiteral(typ) => {
AnyEntKind::PhysicalLiteral(self.map_type_ent(mapping, *typ)?)
}
AnyEntKind::DeferredConstant(subtype) => {
AnyEntKind::DeferredConstant(self.map_subtype(mapping, *subtype)?)
}
AnyEntKind::Library => AnyEntKind::Library,
AnyEntKind::Design(design) => match design {
Design::PackageInstance(region) => {
AnyEntKind::Design(Design::PackageInstance(self.map_region(mapping, region)?))
}
_ => {
return Err(format!(
"Internal error, did not expect to instantiate {}",
design.describe()
));
}
},
})
}
fn map_overloaded(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
overloaded: &'a Overloaded<'a>,
) -> Result<Overloaded<'a>, String> {
Ok(match overloaded {
Overloaded::SubprogramDecl(signature) => {
Overloaded::SubprogramDecl(self.map_signature(mapping, signature)?)
}
Overloaded::Subprogram(signature) => {
Overloaded::Subprogram(self.map_signature(mapping, signature)?)
}
Overloaded::InterfaceSubprogram(signature) => {
Overloaded::InterfaceSubprogram(self.map_signature(mapping, signature)?)
}
Overloaded::EnumLiteral(signature) => {
Overloaded::EnumLiteral(self.map_signature(mapping, signature)?)
}
Overloaded::Alias(alias) => {
let alias_inst = self.instantiate(mapping, alias)?;
if let Ok(overloaded) = OverloadedEnt::from_any(alias_inst) {
Overloaded::Alias(overloaded)
} else {
return Err(
"Internal error, expected overloaded when instantiating overloaded entity"
.to_owned(),
);
}
}
})
}
fn map_signature(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
signature: &'a Signature<'a>,
) -> Result<Signature<'a>, String> {
let Signature {
formals,
return_type,
} = signature;
let FormalRegion {
typ,
entities: uninst_entities,
} = formals;
let mut inst_entities = Vec::with_capacity(uninst_entities.len());
for uninst in uninst_entities {
let inst = self.instantiate(mapping, uninst)?;
if let Some(inst) = InterfaceEnt::from_any(inst) {
inst_entities.push(inst);
} else {
return Err(
"Internal error, expected interface to be instantiated as interface".to_owned(),
);
}
}
let return_type = if let Some(return_type) = return_type {
Some(self.map_type_ent(mapping, *return_type)?)
} else {
None
};
Ok(Signature {
formals: FormalRegion {
typ: *typ,
entities: inst_entities,
},
return_type,
})
}
fn map_region(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
region: &'a Region<'a>,
) -> Result<Region<'a>, String> {
let Region {
entities: uninst_entities,
kind,
..
} = region;
let mut inst_region = Region::default();
inst_region.kind = *kind;
for (_, uninst) in uninst_entities.iter() {
match uninst {
NamedEntities::Single(uninst) => {
let inst = self.instantiate(mapping, uninst)?;
inst_region.add(inst, &mut NullDiagnostics);
}
NamedEntities::Overloaded(overloaded) => {
for uninst in overloaded.entities() {
let inst = self.instantiate(mapping, uninst.into())?;
inst_region.add(inst, &mut NullDiagnostics);
}
}
}
}
Ok(inst_region)
}
fn map_type(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
typ: &'a Type<'a>,
) -> Result<Type<'a>, String> {
Ok(match typ {
Type::Array { indexes, elem_type } => {
let mut mapped_indexes = Vec::with_capacity(indexes.len());
for index_typ in indexes.iter() {
mapped_indexes.push(if let Some(index_typ) = index_typ {
Some(self.map_type_ent(mapping, *index_typ)?)
} else {
None
})
}
Type::Array {
indexes: mapped_indexes,
elem_type: self.map_type_ent(mapping, *elem_type)?,
}
}
Type::Enum(symbols) => Type::Enum(symbols.clone()),
Type::Integer => Type::Integer,
Type::Real => Type::Real,
Type::Physical => Type::Physical,
Type::Access(subtype) => Type::Access(self.map_subtype(mapping, *subtype)?),
Type::Record(region) => {
let mut elems = Vec::with_capacity(region.elems.len());
for uninst in region.elems.iter() {
let inst = self.instantiate(mapping, uninst)?;
if let Some(inst) = RecordElement::from_any(inst) {
elems.push(inst);
} else {
return Err("Internal error, expected instantiated record element to be record element".to_owned());
}
}
Type::Record(RecordRegion { elems })
}
Type::Subtype(subtype) => Type::Subtype(self.map_subtype(mapping, *subtype)?),
Type::Protected(region, _) => {
Type::Protected(self.map_region(mapping, region)?, ArcSwapOption::default())
}
Type::File => Type::File,
Type::Alias(typ) => Type::Alias(self.map_type_ent(mapping, *typ)?),
Type::Universal(utyp) => Type::Universal(*utyp),
Type::Incomplete => Type::Incomplete,
Type::Interface => Type::Interface,
})
}
fn map_object(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
obj: &Object<'a>,
) -> Result<Object<'a>, String> {
let Object {
class,
mode,
subtype,
has_default,
} = obj;
Ok(Object {
class: *class,
mode: *mode,
subtype: self.map_subtype(mapping, *subtype)?,
has_default: *has_default,
})
}
fn map_type_ent(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
typ: TypeEnt<'a>,
) -> Result<TypeEnt<'a>, String> {
if let Some(ent) = mapping.get(&typ.id()) {
if let Some(typ) = TypeEnt::from_any(ent) {
return Ok(typ);
} else {
return Err(format!(
"Internal error when mapping type, expected type got {}",
ent.describe()
));
}
}
Ok(typ)
}
fn map_subtype(
&self,
mapping: &FnvHashMap<EntityId, EntRef<'a>>,
subtype: Subtype<'a>,
) -> Result<Subtype<'a>, String> {
let Subtype { type_mark } = subtype;
Ok(Subtype {
type_mark: self.map_type_ent(mapping, type_mark)?,
})
}
}