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 {
31 symbols: HashMap::new(),
32 free_symbols: vec![],
33 num_definitions: 0,
34 outer: None,
35 }
36 }
37
38 pub fn new_enclosed_symbol_table(outer: SymbolTable) -> SymbolTable {
39 SymbolTable {
40 symbols: HashMap::new(),
41 free_symbols: vec![],
42 num_definitions: 0,
43 outer: Some(Rc::new(outer)),
44 }
45 }
46
47 pub fn define(&mut self, name: String) -> Rc<Symbol> {
48 let mut scope = SymbolScope::LOCAL;
49 if self.outer.is_none() {
50 scope = SymbolScope::Global;
51 }
52
53 let symbol = Rc::new(Symbol {
54 name: name.clone(),
55 index: self.num_definitions,
56 scope,
57 });
58
59 self.num_definitions += 1;
60 self.symbols.insert(name.clone(), Rc::clone(&symbol));
61 return symbol;
62 }
63
64 pub fn visible_names(&self) -> Vec<String> {
65 let mut names = self
66 .outer
67 .as_ref()
68 .map(|outer| outer.visible_names())
69 .unwrap_or_default();
70 names.extend(self.symbols.keys().cloned());
71 names
72 }
73
74 pub fn global_symbols(&self) -> Vec<(String, usize)> {
77 let mut table = self;
78 while let Some(outer) = table.outer.as_deref() {
79 table = outer;
80 }
81 let mut globals: Vec<(String, usize)> = table
82 .symbols
83 .values()
84 .filter(|symbol| symbol.scope == SymbolScope::Global)
85 .map(|symbol| (symbol.name.clone(), symbol.index))
86 .collect();
87 globals.sort();
88 globals
89 }
90
91 pub fn resolve(&mut self, name: String) -> Option<Rc<Symbol>> {
93 if let Some(sym) = self.symbols.get(&name) {
94 return Some(sym.clone());
95 }
96
97 let outer = self.outer.take()?;
101 let mut outer_table = outer.as_ref().clone();
102 let original = outer_table.resolve(name);
103 self.outer = Some(Rc::new(outer_table));
104 let original = original?;
105 match original.scope {
106 SymbolScope::Global | SymbolScope::Builtin => Some(original),
107 SymbolScope::LOCAL | SymbolScope::Free | SymbolScope::Function => {
108 Some(self.define_free(original))
109 }
110 }
111 }
112
113 pub fn define_builtin(&mut self, index: usize, name: String) -> Rc<Symbol> {
114 let symbol = Rc::new(Symbol {
115 name: name.clone(),
116 index,
117 scope: SymbolScope::Builtin,
118 });
119 self.symbols.insert(name.clone(), Rc::clone(&symbol));
120 return symbol;
121 }
122
123 pub fn define_function_name(&mut self, name: String) -> Rc<Symbol> {
124 let symbol = Rc::new(Symbol {
125 name: name.clone(),
126 index: 0,
127 scope: SymbolScope::Function,
128 });
129 self.symbols.insert(name.clone(), Rc::clone(&symbol));
130 return symbol;
131 }
132
133 pub fn define_free(&mut self, original: Rc<Symbol>) -> Rc<Symbol> {
134 self.free_symbols.push(Rc::clone(&original));
135 let symbol = Rc::new(Symbol {
136 name: original.name.clone(),
137 index: self.free_symbols.len() - 1,
138 scope: SymbolScope::Free,
139 });
140 self.symbols
141 .insert(original.name.clone(), Rc::clone(&symbol));
142 return symbol;
143 }
144}