use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use crate::Width;
use crate::hash::{bytes, combine};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub enum SymbolKey {
U64(u64),
Str(Arc<str>),
Fresh(u64),
}
impl SymbolKey {
pub(crate) fn structural_hash(&self) -> u64 {
match self {
SymbolKey::U64(k) => combine(1, *k),
SymbolKey::Str(s) => bytes(2, s.as_bytes()),
SymbolKey::Fresh(k) => combine(3, *k),
}
}
pub(crate) fn is_plain_identifier(s: &str) -> bool {
let mut chars = s.chars();
matches!(chars.next(), Some(c) if c.is_ascii_alphabetic() || c == '_')
&& chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '.')
&& !crate::text::is_reserved(s)
}
}
impl fmt::Display for SymbolKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SymbolKey::U64(k) => write!(f, "#{k}"),
SymbolKey::Str(s) if SymbolKey::is_plain_identifier(s) => f.write_str(s),
SymbolKey::Str(s) => {
f.write_str("\"")?;
for c in s.chars() {
match c {
'"' => f.write_str("\\\"")?,
'\\' => f.write_str("\\\\")?,
'\n' => f.write_str("\\n")?,
'\t' => f.write_str("\\t")?,
'\r' => f.write_str("\\r")?,
'\0' => f.write_str("\\0")?,
c if c.is_ascii_graphic() || c == ' ' => write!(f, "{c}")?,
c => write!(f, "\\u{{{:x}}}", c as u32)?,
}
}
f.write_str("\"")
}
SymbolKey::Fresh(k) => write!(f, "${k}"),
}
}
}
impl From<u64> for SymbolKey {
fn from(k: u64) -> Self {
SymbolKey::U64(k)
}
}
impl From<&str> for SymbolKey {
fn from(s: &str) -> Self {
SymbolKey::Str(Arc::from(s))
}
}
impl From<String> for SymbolKey {
fn from(s: String) -> Self {
SymbolKey::Str(Arc::from(s))
}
}
impl From<Arc<str>> for SymbolKey {
fn from(s: Arc<str>) -> Self {
SymbolKey::Str(s)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct SymbolId(pub(crate) u32);
impl SymbolId {
pub fn index(self) -> u32 {
self.0
}
}
#[derive(Clone, Debug)]
pub(crate) struct SymEntry {
pub(crate) key: SymbolKey,
pub(crate) width: Width,
pub(crate) node: u32,
}
#[derive(Clone, Debug, Default)]
pub(crate) struct SymbolTable {
pub(crate) entries: Vec<SymEntry>,
pub(crate) index: HashMap<SymbolKey, u32>,
pub(crate) next_fresh: u64,
}
impl SymbolTable {
pub(crate) fn clear(&mut self) {
self.entries.clear();
self.index.clear();
self.next_fresh = 0;
}
}