rain_lang/parser/
symbol_table.rs

1/*!
2A simple symbol table struct, used to build a rain AST into a rain IR graph
3*/
4
5use std::hash::Hash;
6use indexmap::{IndexMap, Equivalent};
7
8/// A simple, generic symbol table
9#[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    /// Create a new, empty symbol table
17    pub fn new() -> SymbolTable<K, V> {
18        Self::with_capacity(0)
19    }
20    /// Create a symbol table with a given capacity
21    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    /// Get the current depth
28    pub fn depth(&self) -> usize { self.scopes.len() - 1 }
29    /// Register a given symbol at the current depth, returning the current definition at
30    /// the current depth, if any.
31    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    /// Get the definition of a current symbol, along with its depth, if any
47    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    /// Get the definition of a current symbol
52    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    /// Mutably get the definition of a current symbol, along with its depth, if any
57    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    /// Try to mutably get the definition of a current symbol at the current depth
62    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    //TODO: get_mut
70    /// Get the mutable definition of a current symbol, along with its depth, if any
71    /// Jump to a given depth, removing obsolete definitions.
72    /// Return the number of keys and definitions removed, as well as keys touched, if any.
73    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    /// Add a level of depth
87    pub fn push(&mut self) { self.jump_to_depth(self.depth() + 1); }
88    /// Try to remove a level of depth. Does nothing if depth  = 0
89    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}