use std::{cmp::Ordering, ops::Deref};
use ahash::{AHashMap, AHashSet};
use compact_str::CompactString;
use lady_deirdre::{
analysis::{AnalysisResult, AttrContext, Computable, Grammar, SharedComputable, TaskHandle},
sync::{Shared, SyncBuildHasher},
syntax::NodeRef,
};
use crate::{
analysis::{Closeness, ModuleResultEx, StringEstimation},
runtime::PackageMeta,
semantics::*,
syntax::ScriptNode,
};
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct LocalNames {
pub(crate) packages: Shared<LocalPackageMap>,
pub(crate) idents: Shared<LocalIdentMap>,
pub(crate) lets: Shared<LocalLetMap>,
pub(crate) namespaces: Shared<LocalNamespacesMap>,
}
impl SharedComputable for LocalNames {
type Node = ScriptNode;
#[inline(always)]
fn compute_shared<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Shared<Self>> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = script_node.locals().forward()?;
let analysis = locals.analysis.read(context).forward()?;
Ok(analysis.names.clone())
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct LocalPackageMap {
pub(crate) map: AHashMap<NodeRef, LocalPackageResolution>,
}
impl SharedComputable for LocalPackageMap {
type Node = ScriptNode;
#[inline(always)]
fn compute_shared<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Shared<Self>> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = script_node.locals().forward()?;
let names = locals.names.read(context).forward()?;
Ok(names.as_ref().packages.clone())
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct LocalIdentMap {
pub(crate) map: AHashMap<NodeRef, IdentLocalResolution>,
}
impl SharedComputable for LocalIdentMap {
type Node = ScriptNode;
#[inline(always)]
fn compute_shared<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Shared<Self>> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = script_node.locals().forward()?;
let names = locals.names.read(context).forward()?;
Ok(names.as_ref().idents.clone())
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct LocalLetMap {
pub(crate) map: AHashMap<NodeRef, Shared<LocalLetInits>>,
}
impl SharedComputable for LocalLetMap {
type Node = ScriptNode;
#[inline(always)]
fn compute_shared<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Shared<Self>> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = script_node.locals().forward()?;
let names = locals.names.read(context).forward()?;
Ok(names.as_ref().lets.clone())
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct LocalNamespacesMap {
pub(crate) map: AHashMap<NodeRef, Shared<LocalNamespace>>,
}
impl SharedComputable for LocalNamespacesMap {
type Node = ScriptNode;
#[inline(always)]
fn compute_shared<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Shared<Self>> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = script_node.locals().forward()?;
let names = locals.names.read(context).forward()?;
Ok(names.as_ref().namespaces.clone())
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct LocalLetInits {
pub(crate) set: AHashSet<NodeRef>,
}
impl SharedComputable for LocalLetInits {
type Node = ScriptNode;
#[inline(always)]
fn compute_shared<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Shared<Self>> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let scope_attr = script_node
.scope_attr()
.forward()?
.read(context)
.forward()?;
let Some(scope_node) = scope_attr.scope_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = scope_node.locals().forward()?;
let vars = locals.lets.read(context).forward()?;
Ok(vars.as_ref().map.get(node_ref).cloned().unwrap_or_default())
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub(crate) struct LocalPackageResolution {
pub(crate) parent: Option<&'static PackageMeta>,
pub(crate) package: Option<&'static PackageMeta>,
}
impl Computable for LocalPackageResolution {
type Node = ScriptNode;
#[inline(always)]
fn compute<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Self> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let scope_attr = script_node
.scope_attr()
.forward()?
.read(context)
.forward()?;
let Some(scope_node) = scope_attr.scope_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = scope_node.locals().forward()?;
let vars = locals.packages.read(context).forward()?;
Ok(vars.as_ref().map.get(node_ref).copied().unwrap_or_default())
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct LocalNamespace {
pub(crate) map: AHashMap<CompactString, Shared<Name>>,
}
impl SharedComputable for LocalNamespace {
type Node = ScriptNode;
fn compute_shared<H: TaskHandle, S: SyncBuildHasher>(
context: &mut AttrContext<Self::Node, H, S>,
) -> AnalysisResult<Shared<Self>> {
log_attr!(context);
let node_ref = context.node_ref();
let doc_read = context.read_doc(node_ref.id).forward()?;
let Some(script_node) = node_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let scope_attr = script_node
.scope_attr()
.forward()?
.read(context)
.forward()?;
let Some(scope_node) = scope_attr.scope_ref.deref(doc_read.deref()) else {
return Ok(Default::default());
};
let locals = scope_node.locals().forward()?;
let namespaces_attr = locals.namespaces.read(context).forward()?;
let Some(result) = namespaces_attr.as_ref().map.get(node_ref) else {
return Ok(Default::default());
};
Ok(result.clone())
}
}
impl LocalNamespace {
pub(crate) fn estimate_one<'a>(&'a self, pattern: &str, result: &mut Option<NameEstimation>) {
for (probe, desc) in &self.map {
let closeness = probe.estimate(pattern);
if let Some(current) = &result {
match current.closeness.cmp(&closeness) {
Ordering::Less => (),
Ordering::Equal => {
if ¤t.name <= probe {
continue;
}
}
Ordering::Greater => continue,
}
}
*result = Some(NameEstimation {
closeness,
name: probe.clone(),
desc: desc.clone(),
});
}
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct Name {
pub(crate) init: bool,
pub(crate) decl: NodeRef,
pub(crate) defs: AHashSet<NodeRef>,
}
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct NameEstimation {
pub(crate) closeness: Closeness,
pub(crate) name: CompactString,
pub(crate) desc: Shared<Name>,
}