rain_lang/parser/
symbol_table.rs1use std::hash::Hash;
6use indexmap::{IndexMap, Equivalent};
7
8#[derive(Debug, Clone, Eq, PartialEq)]
10pub struct SymbolTable<K: Hash + Eq, V> {
11 symbols: IndexMap<K, Vec<(V, usize)>>,
12 scopes: Vec<Vec<usize>>
13}
14
15impl<K: Hash + Eq, V> SymbolTable<K, V> {
16 pub fn new() -> SymbolTable<K, V> {
18 Self::with_capacity(0)
19 }
20 pub fn with_capacity(n: usize) -> SymbolTable<K, V> {
22 SymbolTable {
23 symbols: IndexMap::with_capacity(n),
24 scopes: vec![Vec::new()]
25 }
26 }
27 pub fn depth(&self) -> usize { self.scopes.len() - 1 }
29 pub fn def(&mut self, key: K, mut value: V) -> Option<V> {
32 let depth = self.depth();
33 let entry = self.symbols.entry(key);
34 let index = entry.index();
35 let v = entry.or_insert_with(Vec::new);
36 if let Some((old_value, old_depth)) = v.last_mut() {
37 if depth == *old_depth {
38 std::mem::swap(old_value, &mut value);
39 return Some(value)
40 }
41 }
42 v.push((value, depth));
43 self.scopes.last_mut().unwrap().push(index);
44 None
45 }
46 pub fn get_full<Q>(&self, key: &Q) -> Option<(&V, usize)>
48 where Q: ?Sized + Hash + Equivalent<K> {
49 self.symbols.get(key).map(|v| v.last().map(|(v, d)| (v, *d))).flatten()
50 }
51 pub fn get<Q>(&self, key: &Q) -> Option<&V>
53 where Q: ?Sized + Hash + Equivalent<K> {
54 self.get_full(key).map(|(v, _)| v)
55 }
56 pub fn get_full_mut<Q>(&mut self, key: &Q) -> Option<(&mut V, usize)>
58 where Q: ?Sized + Hash + Equivalent<K> {
59 self.symbols.get_mut(key).map(|v| v.last_mut().map(|(v, d)| (v, *d))).flatten()
60 }
61 pub fn try_get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
63 where Q: ?Sized + Hash + Equivalent<K> {
64 let curr_depth = self.depth();
65 if let Some((value, depth)) = self.get_full_mut(key) {
66 if depth == curr_depth { Some(value) } else { None }
67 } else { None }
68 }
69 pub fn jump_to_depth(&mut self, depth: usize) {
74 let target = depth + 1;
75 while target > self.scopes.len() {
76 self.scopes.push(Vec::new());
77 }
78 while self.scopes.len() > target {
79 for ix in self.scopes.pop().unwrap() {
80 let (_, v) = if let Some(v) = self.symbols.get_index_mut(ix) { v }
81 else { continue };
82 v.pop();
83 }
84 }
85 }
86 pub fn push(&mut self) { self.jump_to_depth(self.depth() + 1); }
88 pub fn pop(&mut self) {
90 self.jump_to_depth(self.depth().saturating_sub(1))
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 #[test]
98 fn two_layer_symbol_table_works() {
99 let mut symbols = SymbolTable::<&str, usize>::new();
100 symbols.def("x", 3);
101 symbols.def("y", 7);
102 symbols.push();
103 symbols.def("x", 9);
104 symbols.def("z", 1);
105 assert_eq!(symbols.get_full("x"), Some((&9, 1)));
106 assert_eq!(symbols.get_full("y"), Some((&7, 0)));
107 assert_eq!(symbols.get_full("z"), Some((&1, 1)));
108 assert_eq!(symbols.try_get_mut("x"), Some(&mut 9));
109 assert_eq!(symbols.try_get_mut("y"), None);
110 assert_eq!(symbols.try_get_mut("z"), Some(&mut 1));
111 symbols.pop();
112 assert_eq!(symbols.get_full("x"), Some((&3, 0)));
113 assert_eq!(symbols.get_full("y"), Some((&7, 0)));
114 assert_eq!(symbols.get_full("z"), None);
115 assert_eq!(symbols.try_get_mut("x"), Some(&mut 3));
116 assert_eq!(symbols.try_get_mut("y"), Some(&mut 7));
117 assert_eq!(symbols.try_get_mut("z"), None);
118 }
119}