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(&self, name: String) -> Option<Rc<Symbol>> {
51 let symbol = self.symbols.get(&name);
52 if symbol.is_none() && self.outer.is_some() {
53 return self.outer.as_ref().unwrap().resolve(name);
54 }
55 return symbol.cloned();
56 }
57
58 pub fn define_builtin(&mut self, index: usize, name: String) -> Rc<Symbol> {
59 let symbol = Rc::new(Symbol { name: name.clone(), index, scope: SymbolScope::Builtin });
60 self.symbols.insert(name.clone(), Rc::clone(&symbol));
61 return symbol;
62 }
63
64 pub fn define_function_name(&mut self, name: String) -> Rc<Symbol> {
65 let symbol = Rc::new(Symbol { name: name.clone(), index: 0, scope: SymbolScope::Function });
66 self.symbols.insert(name.clone(), Rc::clone(&symbol));
67 return symbol;
68 }
69
70 pub fn define_free(&mut self, original: Rc<Symbol>) -> Rc<Symbol> {
71 self.free_symbols.push(Rc::clone(&original));
72 let symbol = Rc::new(Symbol { name: original.name.clone(), index: self.free_symbols.len() - 1, scope: SymbolScope::Free });
73 self.symbols.insert(original.name.clone(), Rc::clone(&symbol));
74 return symbol;
75 }
76}