use mago_word::WordSet;
use mago_word::word;
use mago_word::Word;
use mago_word::WordMap;
pub type SymbolIdentifier = (Word, Word);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SymbolKind {
Class,
Enum,
Trait,
Interface,
}
impl SymbolKind {
#[inline]
#[must_use]
pub const fn is_class(&self) -> bool {
matches!(self, SymbolKind::Class)
}
#[inline]
#[must_use]
pub const fn is_enum(&self) -> bool {
matches!(self, SymbolKind::Enum)
}
#[inline]
#[must_use]
pub const fn is_trait(&self) -> bool {
matches!(self, SymbolKind::Trait)
}
#[inline]
#[must_use]
pub const fn is_interface(&self) -> bool {
matches!(self, SymbolKind::Interface)
}
#[inline]
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
SymbolKind::Class => "class",
SymbolKind::Enum => "enum",
SymbolKind::Trait => "trait",
SymbolKind::Interface => "interface",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Symbols {
all: WordMap<SymbolKind>,
namespaces: WordSet,
}
impl Symbols {
#[inline]
#[must_use]
pub fn new() -> Symbols {
Symbols { all: WordMap::default(), namespaces: WordSet::default() }
}
#[inline]
pub fn add_symbol_name(&mut self, name: Word, kind: SymbolKind) {
self.namespaces.extend(get_symbol_namespaces(name));
self.all.insert(name, kind);
}
#[inline]
#[must_use]
pub fn get_kind(&self, name: Word) -> Option<SymbolKind> {
self.all.get(&name).copied() }
#[inline]
#[must_use]
pub fn contains(&self, name: Word) -> bool {
self.all.contains_key(&name)
}
#[must_use]
pub fn contains_namespace(&self, namespace: Word) -> bool {
self.namespaces.contains(&namespace)
}
#[inline]
#[must_use]
pub fn contains_enum(&self, name: Word) -> bool {
matches!(self.get_kind(name), Some(SymbolKind::Enum))
}
#[inline]
pub fn extend(&mut self, other: Symbols) {
self.namespaces.extend(other.namespaces);
for (entry, kind) in other.all {
self.all.entry(entry).or_insert(kind);
}
}
#[inline]
pub fn extend_ref(&mut self, other: &Symbols) {
self.namespaces.extend(other.namespaces.iter().copied());
for (entry, kind) in &other.all {
self.all.entry(*entry).or_insert(*kind);
}
}
#[inline]
pub fn remove(&mut self, name: Word) {
self.all.remove(&name);
}
}
pub(super) fn get_symbol_namespaces(symbol_name: Word) -> impl Iterator<Item = Word> {
let bytes: Vec<u8> = symbol_name.as_bytes().to_vec();
(0..bytes.len()).filter_map(move |i| if bytes[i] == b'\\' { Some(word(&bytes[..i])) } else { None })
}