june_lang/
symbol_table.rs1use crate::types::*;
2use std::collections::HashMap;
3
4struct SymbolInfo {
5 idx: usize,
6 typ: Type,
7}
8
9pub struct CurrentFunction {
10 locals: usize,
11 frames: Vec<HashMap<String, SymbolInfo>>,
12}
13
14#[derive(Default)]
15pub struct SymbolTable {
16 globals: HashMap<String, SymbolInfo>,
19 functions: Vec<FnType>,
20 current: Option<CurrentFunction>,
21}
22
23impl SymbolTable {
24 pub fn enter_function(&mut self) {
25 assert!(self.current.is_none());
26 self.current = Some(CurrentFunction { locals: 0, frames: vec![] });
27 }
28
29 pub fn exit_function(&mut self) {
30 assert!(self.current.as_ref().unwrap().frames.is_empty());
31 self.current.take().unwrap();
32 }
33
34 pub fn num_locals(&self) -> Option<usize> {
35 self.current.as_ref().map(|f| f.locals)
36 }
37
38 pub fn def_global(&mut self, name: impl ToString, typ: Type) {
39 let idx = self.globals.len();
40 let name = name.to_string();
41 self.globals.insert(name, SymbolInfo { idx, typ });
42 }
43
44 fn get_global(&self, name: &str) -> Option<Resolution> {
45 self.globals.get(name).map(|SymbolInfo { idx, typ }| Resolution {
46 reference: Reference::Global { idx: *idx },
47 typ: typ.clone(),
48 })
49 }
50
51 pub fn def_fn(&mut self, params: Vec<Type>, ret: Option<Type>) -> FnType {
52 let ret = ret.map(|typ| Box::new(typ));
53 let typ = FnType { index: self.functions.len(), params, ret };
54 self.functions.push(typ.clone());
55 typ
56 }
57
58 pub fn push_frame(&mut self) {
59 self.current.as_mut().unwrap().frames.push(HashMap::new());
60 }
61
62 pub fn pop_frame(&mut self) {
63 self.current.as_mut().unwrap().frames.pop().unwrap();
64 }
65
66 pub fn def_local(&mut self, name: impl ToString, typ: Type) -> usize {
67 let func = &mut self.current.as_mut().unwrap();
68 let frame = func.frames.last_mut().unwrap();
69 frame.insert(name.to_string(), SymbolInfo { idx: func.locals, typ });
70 func.locals += 1;
71 func.locals - 1
72 }
73
74 fn get_frame(&self, name: &str, depth: usize) -> Option<Resolution> {
75 let func = self.current.as_ref().unwrap();
76 let i = func.frames.len() - depth - 1;
77 func.frames[i].get(name).map(|SymbolInfo { idx, typ }| Resolution {
78 reference: Reference::Stack { local_idx: *idx },
79 typ: typ.clone(),
80 })
81 }
82
83 pub fn get(&self, name: &str) -> Option<Resolution> {
84 let func = self.current.as_ref().unwrap();
85 (0..func.frames.len())
86 .find_map(|depth| self.get_frame(name, depth))
87 .or_else(|| self.get_global(name))
88 }
89}