june_lang/
symbol_table.rs

1use 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    // TODO: supporting forward references will require supporting empty values
17    // in the globals table
18    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}