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