Implement a rudimentary symbol table

This commit is contained in:
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)]
mod tests {
use std::{borrow::BorrowMut, rc::Rc};
use super::*;
#[test]
@ -24,17 +26,18 @@ mod tests {
#[test]
fn test_2() {
let mut global_scope = SymbolTable::new();
let global_scope = SymbolTable::new();
let main_function = SymbolEntry::new_function(vec![], String::from("Unit"));
global_scope.insert("main".into(), main_function);
global_scope.insert("db_url".into(), SymbolEntry::Variable("String".into()));
let add_function =
SymbolEntry::new_function(vec!["Int".into(), "Int".into()], "Int".into());
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()));
assert!(main_function_scope.test(&"message".into()));
@ -42,11 +45,11 @@ mod tests {
assert_eq!(main_function_scope.test(&"non_existant".into()), false);
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("b".into(), SymbolEntry::Variable("Int".into()));
assert!(add_function_scope.test(&"a".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
pub struct SymbolTable<'a> {
struct SymbolTableNode {
// the parent scope
parent: Option<Rc<RefCell<&'a SymbolTable<'a>>>>,
parent: Option<Rc<RefCell<SymbolTableNode>>>,
// the current scope
scope: HashMap<String, SymbolEntry>,
}
@ -15,19 +20,46 @@ pub enum SymbolEntry {
Function(Vec<String>, String),
}
impl SymbolTable<'_> {
impl SymbolTable {
/// Creates a new, global symbol table
pub fn new<'a>() -> SymbolTable<'a> {
pub fn new() -> 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,
scope: HashMap::new(),
}
}
/// Creates a new symbol table with a parent
pub fn new_from_parent<'a>(parent: &'a SymbolTable<'a>) -> SymbolTable<'a> {
SymbolTable {
parent: Some(Rc::new(RefCell::new(parent))),
pub fn new_from_parent<'a>(parent: &Rc<RefCell<SymbolTableNode>>) -> SymbolTableNode {
SymbolTableNode {
parent: Some(Rc::clone(&parent)),
scope: HashMap::new(),
}
}
@ -38,16 +70,16 @@ impl SymbolTable<'_> {
}
/// 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) {
return true;
}
match &self.parent {
Some(parent) => {
let parent = parent.borrow();
let mut parent = parent.as_ref().borrow_mut();
parent.test(key)
},
}
None => false,
}
}

View File

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

View File

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