use mago_atom::AtomSet;
use mago_atom::atom;
use serde::Deserialize;
use serde::Serialize;
use mago_atom::Atom;
use mago_atom::AtomMap;
pub type SymbolIdentifier = (Atom, Atom);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
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, Serialize, Deserialize, Debug, PartialEq)]
pub struct Symbols {
all: AtomMap<SymbolKind>,
namespaces: AtomSet,
}
impl Symbols {
#[inline]
#[must_use]
pub fn new() -> Symbols {
Symbols { all: AtomMap::default(), namespaces: AtomSet::default() }
}
#[inline]
pub fn add_class_name(&mut self, name: Atom) {
self.namespaces.extend(get_symbol_namespaces(name));
self.all.insert(name, SymbolKind::Class);
}
#[inline]
pub fn add_interface_name(&mut self, name: Atom) {
self.namespaces.extend(get_symbol_namespaces(name));
self.all.insert(name, SymbolKind::Interface);
}
#[inline]
pub fn add_trait_name(&mut self, name: Atom) {
self.namespaces.extend(get_symbol_namespaces(name));
self.all.insert(name, SymbolKind::Trait);
}
#[inline]
pub fn add_enum_name(&mut self, name: Atom) {
self.namespaces.extend(get_symbol_namespaces(name));
self.all.insert(name, SymbolKind::Enum);
}
#[inline]
#[must_use]
pub fn get_kind(&self, name: Atom) -> Option<SymbolKind> {
self.all.get(&name).copied() }
#[inline]
#[must_use]
pub fn contains(&self, name: Atom) -> bool {
self.all.contains_key(&name)
}
pub fn contains_namespace(&self, namespace: Atom) -> bool {
self.namespaces.contains(&namespace)
}
#[inline]
#[must_use]
pub fn contains_class(&self, name: Atom) -> bool {
matches!(self.get_kind(name), Some(SymbolKind::Class))
}
#[inline]
#[must_use]
pub fn contains_interface(&self, name: Atom) -> bool {
matches!(self.get_kind(name), Some(SymbolKind::Interface))
}
#[inline]
#[must_use]
pub fn contains_trait(&self, name: Atom) -> bool {
matches!(self.get_kind(name), Some(SymbolKind::Trait))
}
#[inline]
#[must_use]
pub fn contains_enum(&self, name: Atom) -> bool {
matches!(self.get_kind(name), Some(SymbolKind::Enum))
}
#[inline]
#[must_use]
pub fn get_all(&self) -> &AtomMap<SymbolKind> {
&self.all
}
#[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: Atom) {
self.all.remove(&name);
}
}
impl Default for Symbols {
#[inline]
fn default() -> Self {
Self::new()
}
}
pub(super) fn get_symbol_namespaces(symbol_name: Atom) -> impl Iterator<Item = Atom> {
let s = symbol_name.as_str();
s.as_bytes().iter().enumerate().filter_map(move |(i, &byte)| if byte == b'\\' { Some(atom(&s[..i])) } else { None })
}