use std::collections::HashMap;
use crate::SVal;
#[derive(Debug, Default, Clone)]
pub struct SymbolScope {
symbols: HashMap<String, Symbol>,
}
impl SymbolScope {
pub fn insert(&mut self, name: &str, symbol: Symbol) {
self.symbols.insert(name.to_owned(), symbol);
}
pub fn remove(&mut self, name: &str) -> Option<Symbol> {
self.symbols.remove(name)
}
pub fn get(&self, name: &str) -> Option<&Symbol> {
self.symbols.get(name)
}
pub fn get_mut(&mut self, name: &str) -> Option<&mut Symbol> {
self.symbols.get_mut(name)
}
pub fn set_variable(&mut self, name: &str, value: SVal) -> bool {
if let Some(var) = self.get_mut(name) {
var.set(value);
return true;
}
false
}
}
#[derive(Debug, Clone)]
pub enum Symbol {
Variable(SVal),
}
impl Symbol {
pub fn var(&self) -> SVal {
match self {
Symbol::Variable(val) => val.clone(),
}
}
pub fn set(&mut self, val: SVal) {
match self {
Symbol::Variable(var) => {
if var.is_boxed() && !val.is_boxed() { match var {
SVal::Boxed(var) => {
*var.lock().unwrap() = val;
},
_ => {}
}
} else { *var = val;
}
}
}
}
}
#[derive(Debug, Clone)]
pub struct SymbolTable {
scopes: HashMap<i32, SymbolScope>,
scope: i32,
}
impl Default for SymbolTable {
fn default() -> Self {
let mut table = Self {
scope: 0,
scopes: Default::default(),
};
table.scopes.insert(0, SymbolScope::default());
table
}
}
impl SymbolTable {
pub fn new_scope(&mut self) {
self.scope += 1;
self.scopes.insert(self.scope, SymbolScope::default());
}
pub fn current(&mut self) -> &mut SymbolScope {
self.scopes.get_mut(&self.scope).expect("No current scope!")
}
pub fn end_scope(&mut self) {
if self.scope > 0 {
self.scopes.remove(&self.scope);
self.scope -= 1;
}
}
pub fn insert(&mut self, name: &str, symbol: Symbol) {
self.current().insert(name, symbol);
}
pub fn remove(&mut self, name: &str) -> Option<Symbol> {
self.current().remove(name)
}
pub fn has_in_current(&mut self, name: &str) -> bool {
self.current().get(name).is_some()
}
pub fn get(&mut self, name: &str) -> Option<&Symbol> {
let mut curr = self.scope;
while curr >= 0 {
let scope = self.scopes.get(&curr).expect("No scope!");
if let Some(symbol) = scope.get(name) {
return Some(symbol);
}
curr -= 1;
}
None
}
pub fn set_variable(&mut self, name: &str, value: &SVal) -> bool {
for i in (0..self.scope + 1).rev() {
if let Some(scope) = self.scopes.get_mut(&i) {
if scope.set_variable(name, value.clone()) {
return true;
}
}
}
false
}
}