1use std::collections::HashMap;
2use std::rc::Rc;
3
4#[derive(Clone, Debug, Eq, PartialEq)]
5pub enum SymbolScope {
6 LOCAL,
7 Global,
8 Builtin,
9 Free,
10 Function,
11}
12
13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct Symbol {
15 pub name: String,
16 pub scope: SymbolScope,
17 pub index: usize,
18}
19
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct SymbolTable {
22 pub outer: Option<Rc<SymbolTable>>,
23 symbols: HashMap<String, Rc<Symbol>>,
24 pub free_symbols: Vec<Rc<Symbol>>,
25 pub num_definitions: usize,
26}
27
28impl SymbolTable {
29 pub fn new() -> SymbolTable {
30 SymbolTable { symbols: HashMap::new(), free_symbols: vec![], num_definitions: 0, outer: None }
31 }
32
33 pub fn new_enclosed_symbol_table(outer: SymbolTable) -> SymbolTable {
34 SymbolTable { symbols: HashMap::new(), free_symbols: vec![], num_definitions: 0, outer: Some(Rc::new(outer)) }
35 }
36
37 pub fn define(&mut self, name: String) -> Rc<Symbol> {
38 let mut scope = SymbolScope::LOCAL;
39 if self.outer.is_none() {
40 scope = SymbolScope::Global;
41 }
42
43 let symbol = Rc::new(Symbol { name: name.clone(), index: self.num_definitions, scope });
44
45 self.num_definitions += 1;
46 self.symbols.insert(name.clone(), Rc::clone(&symbol));
47 return symbol;
48 }
49
50 pub fn resolve(&mut self, name: String) -> Option<Rc<Symbol>> {
52 if let Some(sym) = self.symbols.get(&name) {
53 return Some(sym.clone());
54 }
55
56 if let Some(outer) = &self.outer {
58 if let Some(original) = outer.resolve_readonly(&name) {
60 return match original.scope {
61 SymbolScope::Global | SymbolScope::Builtin => Some(original),
63 SymbolScope::LOCAL | SymbolScope::Free | SymbolScope::Function => {
65 Some(self.define_free(original))
66 }
67 };
68 }
69 }
70
71 None
72 }
73
74 fn resolve_readonly(&self, name: &str) -> Option<Rc<Symbol>> {
76 if let Some(sym) = self.symbols.get(name) {
77 return Some(sym.clone());
78 }
79 if let Some(outer) = &self.outer {
80 return outer.resolve_readonly(name);
81 }
82 None
83 }
84
85 pub fn define_builtin(&mut self, index: usize, name: String) -> Rc<Symbol> {
86 let symbol = Rc::new(Symbol { name: name.clone(), index, scope: SymbolScope::Builtin });
87 self.symbols.insert(name.clone(), Rc::clone(&symbol));
88 return symbol;
89 }
90
91 pub fn define_function_name(&mut self, name: String) -> Rc<Symbol> {
92 let symbol = Rc::new(Symbol { name: name.clone(), index: 0, scope: SymbolScope::Function });
93 self.symbols.insert(name.clone(), Rc::clone(&symbol));
94 return symbol;
95 }
96
97 pub fn define_free(&mut self, original: Rc<Symbol>) -> Rc<Symbol> {
98 self.free_symbols.push(Rc::clone(&original));
99 let symbol = Rc::new(Symbol { name: original.name.clone(), index: self.free_symbols.len() - 1, scope: SymbolScope::Free });
100 self.symbols.insert(original.name.clone(), Rc::clone(&symbol));
101 return symbol;
102 }
103}