use std::collections::BTreeMap;
use std::sync::Arc;
use pedant_syntax::go::{GoDeclarationKind, GoFactSpan};
use pedant_types::{
DefinitionHandle, ResolutionUnitHandle, SourcePosition, SourceSpan, SymbolKind,
};
use crate::resolution::identity::position;
use super::error::GoResolutionError;
#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) struct TypeName {
pub(super) qualifier: Option<Box<str>>,
pub(super) name: Box<str>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(super) struct EmbeddedType {
pub(super) unit: usize,
pub(super) name: Arc<str>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(super) struct Embedding {
pub(super) embedded: EmbeddedType,
pub(super) pointer: bool,
}
pub(super) struct Slot {
pub(super) handle: DefinitionHandle,
pub(super) kind: SymbolKind,
pub(super) declared: Option<GoDeclarationKind>,
pub(super) unit: usize,
pub(super) name: Arc<str>,
pub(super) site: SourceSpan,
pub(super) holder: Option<usize>,
pub(super) conditional: bool,
pub(super) pointer_receiver: bool,
pub(super) general_terms: bool,
pub(super) result: Option<TypeName>,
}
impl Slot {
pub(super) fn is_type(&self) -> bool {
matches!(
self.kind,
SymbolKind::Struct
| SymbolKind::Interface
| SymbolKind::DefinedType
| SymbolKind::TypeAlias
)
}
pub(super) fn is_interface(&self) -> bool {
matches!(self.kind, SymbolKind::Interface)
}
pub(super) fn is_concrete_type(&self) -> bool {
matches!(self.kind, SymbolKind::Struct | SymbolKind::DefinedType)
}
pub(super) fn is_interface_method(&self) -> bool {
self.declared == Some(GoDeclarationKind::InterfaceMethod)
}
pub(super) fn is_concrete_method(&self) -> bool {
self.declared == Some(GoDeclarationKind::Method)
}
pub(super) fn is_embedded_field(&self) -> bool {
self.declared == Some(GoDeclarationKind::EmbeddedField)
}
}
pub(super) fn site(path: &Arc<str>, span: GoFactSpan) -> SourceSpan {
SourceSpan::new(
Arc::clone(path),
SourcePosition::new(position(span.start_line()), position(span.start_column())),
SourcePosition::new(position(span.end_line()), position(span.end_column())),
)
}
pub(super) struct UnitIndex {
pub(super) handle: ResolutionUnitHandle,
pub(super) package: usize,
names: BTreeMap<Box<str>, Vec<usize>>,
holders: BTreeMap<Box<str>, Vec<usize>>,
embeds: BTreeMap<Box<str>, Vec<Embedding>>,
declarations: BTreeMap<Box<str>, BTreeMap<u32, usize>>,
}
impl UnitIndex {
pub(super) fn new(handle: ResolutionUnitHandle, package: usize) -> Self {
Self {
handle,
package,
names: BTreeMap::new(),
holders: BTreeMap::new(),
embeds: BTreeMap::new(),
declarations: BTreeMap::new(),
}
}
pub(super) fn declare(&mut self, name: &str, slot: usize) {
self.names.entry(Box::from(name)).or_default().push(slot);
}
pub(super) fn hold(&mut self, owner: &str, slot: usize) {
self.holders.entry(Box::from(owner)).or_default().push(slot);
}
pub(super) fn embed(&mut self, owner: &str, embedding: Embedding) {
self.embeds
.entry(Box::from(owner))
.or_default()
.push(embedding);
}
pub(super) fn state(&mut self, source: &str, declaration: u32, slot: usize) {
self.declarations
.entry(Box::from(source))
.or_default()
.insert(declaration, slot);
}
pub(super) fn named(&self, name: &str) -> &[usize] {
self.names.get(name).map(Vec::as_slice).unwrap_or_default()
}
pub(super) fn held(&self, owner: &str) -> &[usize] {
self.holders
.get(owner)
.map(Vec::as_slice)
.unwrap_or_default()
}
pub(super) fn embedded(&self, owner: &str) -> &[Embedding] {
self.embeds
.get(owner)
.map(Vec::as_slice)
.unwrap_or_default()
}
pub(super) fn declared(&self, source: &str, declaration: u32) -> Option<usize> {
self.declarations.get(source)?.get(&declaration).copied()
}
}
#[derive(Default)]
pub(super) struct Index {
slots: Vec<Slot>,
units: Vec<UnitIndex>,
}
impl Index {
pub(super) fn push(&mut self, slot: Slot) -> usize {
self.slots.push(slot);
self.slots.len() - 1
}
pub(super) fn open(&mut self, unit: UnitIndex) {
self.units.push(unit);
}
pub(super) fn unit(&self, unit: usize) -> Option<&UnitIndex> {
self.units.get(unit)
}
pub(super) fn tables_mut(&mut self, unit: usize) -> Result<&mut UnitIndex, GoResolutionError> {
self.units.get_mut(unit).ok_or_else(|| unopened(unit))
}
pub(super) fn unit_handle(
&self,
unit: usize,
) -> Result<ResolutionUnitHandle, GoResolutionError> {
self.unit(unit)
.map(|found| found.handle.clone())
.ok_or_else(|| unopened(unit))
}
pub(super) fn slot(&self, slot: usize) -> Option<&Slot> {
self.slots.get(slot)
}
pub(super) fn stated(&self) -> &[Slot] {
&self.slots
}
}
fn unopened(unit: usize) -> GoResolutionError {
GoResolutionError::UnitMapping {
unit: position(unit),
reason: Box::from("no index was opened for this package context"),
}
}