Implement a rudimentary symbol table

master
Araozu 2024-02-02 06:53:24 -05:00
parent cb1c0d80f8
commit 83c0c59ae9
4 changed files with 59 additions and 22 deletions

View File

@ -10,6 +10,8 @@ use symbol_table::{SymbolEntry, SymbolTable};
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{borrow::BorrowMut, rc::Rc};
use super::*; use super::*;
#[test] #[test]
@ -24,17 +26,18 @@ mod tests {
#[test] #[test]
fn test_2() { fn test_2() {
let mut global_scope = SymbolTable::new(); let global_scope = SymbolTable::new();
let main_function = SymbolEntry::new_function(vec![], String::from("Unit")); let main_function = SymbolEntry::new_function(vec![], String::from("Unit"));
global_scope.insert("main".into(), main_function); global_scope.insert("main".into(), main_function);
global_scope.insert("db_url".into(), SymbolEntry::Variable("String".into())); global_scope.insert("db_url".into(), SymbolEntry::Variable("String".into()));
let add_function = let add_function =
SymbolEntry::new_function(vec!["Int".into(), "Int".into()], "Int".into()); SymbolEntry::new_function(vec!["Int".into(), "Int".into()], "Int".into());
global_scope.insert("add".into(), add_function); global_scope.insert("add".into(), add_function);
let mut main_function_scope = SymbolTable::new_from_parent(&global_scope); let main_function_scope = SymbolTable::new_from_parent(&global_scope);
main_function_scope.insert("message".into(), SymbolEntry::Variable("String".into())); main_function_scope.insert("message".into(), SymbolEntry::Variable("String".into()));
assert!(main_function_scope.test(&"message".into())); assert!(main_function_scope.test(&"message".into()));
@ -42,11 +45,11 @@ mod tests {
assert_eq!(main_function_scope.test(&"non_existant".into()), false); assert_eq!(main_function_scope.test(&"non_existant".into()), false);
let mut add_function_scope = SymbolTable::new_from_parent(&global_scope); let mut add_function_scope = SymbolTable::new_from_parent(&global_scope);
add_function_scope.insert("a".into(), SymbolEntry::Variable("Int".into())); add_function_scope.insert("a".into(), SymbolEntry::Variable("Int".into()));
add_function_scope.insert("b".into(), SymbolEntry::Variable("Int".into())); add_function_scope.insert("b".into(), SymbolEntry::Variable("Int".into()));
assert!(add_function_scope.test(&"a".into())); assert!(add_function_scope.test(&"a".into()));
global_scope.insert("test".into(), SymbolEntry::Variable("Int".into())); global_scope.insert("test".into(), SymbolEntry::Variable("Int".into()));
} }
} }

View File

@ -1,9 +1,14 @@
use std::{collections::HashMap, rc::Rc, cell::RefCell}; use std::{cell::RefCell, collections::HashMap, rc::Rc};
/// Public interface for the symbol table
pub struct SymbolTable {
node: Rc<RefCell<SymbolTableNode>>,
}
// struct for a symbol table // struct for a symbol table
pub struct SymbolTable<'a> { struct SymbolTableNode {
// the parent scope // the parent scope
parent: Option<Rc<RefCell<&'a SymbolTable<'a>>>>, parent: Option<Rc<RefCell<SymbolTableNode>>>,
// the current scope // the current scope
scope: HashMap<String, SymbolEntry>, scope: HashMap<String, SymbolEntry>,
} }
@ -15,19 +20,46 @@ pub enum SymbolEntry {
Function(Vec<String>, String), Function(Vec<String>, String),
} }
impl SymbolTable<'_> { impl SymbolTable {
/// Creates a new, global symbol table /// Creates a new, global symbol table
pub fn new<'a>() -> SymbolTable<'a> { pub fn new() -> SymbolTable {
SymbolTable { SymbolTable {
node: Rc::new(RefCell::new(SymbolTableNode::new())),
}
}
pub fn new_from_parent(parent: &SymbolTable) -> SymbolTable {
let new_table = SymbolTableNode::new_from_parent(&parent.node);
SymbolTable {
node: Rc::new(RefCell::new(new_table)),
}
}
/// Inserts a new symbol into the current table scope
pub fn insert(&self, key: String, value: SymbolEntry) {
self.node.borrow_mut().insert(key, value);
}
/// Tests if a symbol is declared in the current or parent scopes
pub fn test(&self, key: &String) -> bool {
self.node.borrow_mut().test(key)
}
}
impl SymbolTableNode {
/// Creates a new, global symbol table
pub fn new<'a>() -> SymbolTableNode {
SymbolTableNode {
parent: None, parent: None,
scope: HashMap::new(), scope: HashMap::new(),
} }
} }
/// Creates a new symbol table with a parent /// Creates a new symbol table with a parent
pub fn new_from_parent<'a>(parent: &'a SymbolTable<'a>) -> SymbolTable<'a> { pub fn new_from_parent<'a>(parent: &Rc<RefCell<SymbolTableNode>>) -> SymbolTableNode {
SymbolTable { SymbolTableNode {
parent: Some(Rc::new(RefCell::new(parent))), parent: Some(Rc::clone(&parent)),
scope: HashMap::new(), scope: HashMap::new(),
} }
} }
@ -38,16 +70,16 @@ impl SymbolTable<'_> {
} }
/// Tests if a symbol is declared in the current or parent scopes /// Tests if a symbol is declared in the current or parent scopes
pub fn test(&self, key: &String) -> bool { pub fn test(&mut self, key: &String) -> bool {
if self.scope.contains_key(key) { if self.scope.contains_key(key) {
return true; return true;
} }
match &self.parent { match &self.parent {
Some(parent) => { Some(parent) => {
let parent = parent.borrow(); let mut parent = parent.as_ref().borrow_mut();
parent.test(key) parent.test(key)
}, }
None => false, None => false,
} }
} }

View File

@ -4,12 +4,15 @@ use crate::{
utils::Result3, utils::Result3,
}; };
use super::{super::{ use super::{
super::{
ast::FunctionDeclaration, ast::FunctionDeclaration,
block::parse_block, block::parse_block,
utils::{parse_token_type, try_token_type}, utils::{parse_token_type, try_token_type},
ParseResult, ParseResult,
}, params_list::parse_params_list}; },
params_list::parse_params_list,
};
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration, ()> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration, ()> {
let mut current_pos = pos; let mut current_pos = pos;

View File

@ -2,4 +2,3 @@ pub mod arguments_list;
pub mod function_declaration; pub mod function_declaration;
pub mod params_list; pub mod params_list;