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