Implement a rudimentary symbol table
This commit is contained in:
parent
cb1c0d80f8
commit
83c0c59ae9
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,15 @@ use crate::{
|
|||||||
utils::Result3,
|
utils::Result3,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{super::{
|
use super::{
|
||||||
ast::FunctionDeclaration,
|
super::{
|
||||||
block::parse_block,
|
ast::FunctionDeclaration,
|
||||||
utils::{parse_token_type, try_token_type},
|
block::parse_block,
|
||||||
ParseResult,
|
utils::{parse_token_type, try_token_type},
|
||||||
}, params_list::parse_params_list};
|
ParseResult,
|
||||||
|
},
|
||||||
|
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;
|
||||||
|
@ -2,4 +2,3 @@ pub mod arguments_list;
|
|||||||
|
|
||||||
pub mod function_declaration;
|
pub mod function_declaration;
|
||||||
pub mod params_list;
|
pub mod params_list;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user