1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use itertools::Itertools;
use std::fmt::{self, Display};
use std::sync::{Arc, Mutex};
use string_interner::DefaultStringInterner;
use string_interner::Symbol as _;

#[derive(Clone, Default)]
pub struct SymbolTable(pub Arc<Mutex<DefaultStringInterner>>);

impl SymbolTable {
    pub fn get(&self, name: &str) -> Option<Symbol> {
        let table = self.0.lock().unwrap();
        table.get(name).map(|sym| Symbol(Arc::clone(&self.0), sym))
    }

    pub fn sym(&self, name: &str) -> Symbol {
        let mut table = self.0.lock().unwrap();
        let sym = table.get_or_intern(name);
        Symbol(Arc::clone(&self.0), sym)
    }

    pub fn new_with_prefix(&self, prefix: &str) -> Symbol {
        let mut table = self.0.lock().unwrap();
        let sym = if table.get(prefix).is_none() {
            table.get_or_intern(prefix)
        } else {
            let mut i = 0;
            loop {
                let s = format!("{prefix}_{i}");
                if table.get(&s).is_none() {
                    break table.get_or_intern(s);
                }
                i += 1;
            }
        };
        Symbol(Arc::clone(&self.0), sym)
    }
}

impl std::hash::Hash for SymbolTable {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        let table = self.0.lock().unwrap();
        table.len().hash(state);
        for t in &*table {
            t.hash(state);
        }
    }
}

impl fmt::Debug for SymbolTable {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let table = self.0.lock().unwrap();
        write!(f, "{}", (&table).into_iter().map(|(_, s)| s).join(" "))
    }
}

#[derive(Clone)]
pub struct Symbol(Arc<Mutex<DefaultStringInterner>>, string_interner::DefaultSymbol);

impl PartialEq for Symbol {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.0, &other.0) && self.1 == other.1
    }
}

impl Eq for Symbol {}

impl PartialOrd for Symbol {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Symbol {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.1.cmp(&other.1)
    }
}

impl std::hash::Hash for Symbol {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.1.hash(state)
    }
}

impl std::fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Ok(table) = self.0.lock() {
            if let Some(s) = table.resolve(self.1) {
                return write!(f, "{s}");
            }
        }
        write!(f, "<Sym{}>", self.1.to_usize())
    }
}

impl fmt::Debug for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Display::fmt(&self, f)
    }
}

#[derive(Clone, Debug, Default)]
pub struct SymbolValues(Vec<Option<i64>>);

impl SymbolValues {
    pub fn with(mut self, s: &Symbol, v: i64) -> Self {
        self[s] = Some(v);
        self
    }

    pub fn set(&mut self, s: &Symbol, v: i64) {
        self[s] = Some(v);
    }
}

impl std::ops::Index<&Symbol> for SymbolValues {
    type Output = Option<i64>;
    fn index(&self, index: &Symbol) -> &Self::Output {
        if index.1.to_usize() < self.0.len() {
            &self.0[index.1.to_usize()]
        } else {
            &None
        }
    }
}

impl std::ops::IndexMut<&Symbol> for SymbolValues {
    fn index_mut(&mut self, index: &Symbol) -> &mut Self::Output {
        if index.1.to_usize() >= self.0.len() {
            self.0.resize_with(index.1.to_usize() + 1, Default::default)
        }
        &mut self.0[index.1.to_usize()]
    }
}