use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet;
use serde::Deserialize;
use serde::Serialize;
use std::cell::Cell;
use std::cell::RefCell;
use std::cell::RefMut;
use std::rc::Rc;
#[derive(Clone, Default)]
pub struct SymbolIdGenerator(Rc<Cell<usize>>);
impl SymbolIdGenerator {
pub fn next(&self) -> usize {
let id = self.0.get();
self.0.set(id + 1);
id
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct Symbol {
pub id: usize, }
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum ScopeType {
Module,
Closure,
Block,
}
#[derive(Default)]
pub struct ScopeData {
parent: Option<Scope>,
pub symbols: FxHashMap<String, Symbol>,
pub boxed_var_decls: FxHashSet<Symbol>, pub boxed_var_captures: FxHashSet<Symbol>, }
#[derive(Clone)]
pub struct Scope {
pub typ: ScopeType,
symbol_id_generator: SymbolIdGenerator,
data: Rc<RefCell<ScopeData>>,
}
impl Scope {
pub fn new(typ: ScopeType) -> Self {
Self {
typ,
data: Default::default(),
symbol_id_generator: Default::default(),
}
}
pub fn new_child(&self, typ: ScopeType) -> Self {
Self {
typ,
symbol_id_generator: self.symbol_id_generator.clone(),
data: Rc::new(RefCell::new(ScopeData {
parent: Some(self.clone()),
..Default::default()
})),
}
}
pub fn add_symbol(&self, name: String) -> bool {
self
.data
.borrow_mut()
.symbols
.insert(name, Symbol {
id: self.symbol_id_generator.next(),
})
.is_none()
}
pub fn has_symbol(&self, name: &str) -> bool {
self.data.borrow().symbols.contains_key(name)
}
pub fn get_symbol(&self, name: &str) -> Symbol {
self.data.borrow().symbols.get(name).unwrap().clone()
}
pub fn declaration_is_boxed(&self, symbol: Symbol) -> bool {
self.data.borrow().boxed_var_decls.contains(&symbol)
}
pub fn captures_box_of(&self, symbol: Symbol) -> bool {
self.data.borrow().boxed_var_captures.contains(&symbol)
}
pub fn borrow(&self) -> RefMut<ScopeData> {
self.data.borrow_mut()
}
pub fn borrow_mut(&self) -> RefMut<ScopeData> {
self.data.borrow_mut()
}
pub fn find_symbol_declaration(&self, name: &str) -> Option<(Scope, Symbol)> {
let mut cur = Some(self.clone());
while let Some(scope) = cur {
if let Some(symbol) = scope.data.borrow_mut().symbols.get(name) {
return Some((scope.clone(), *symbol));
};
cur = scope.parent();
}
None
}
pub fn find_nearest_scope<P: Fn(ScopeType) -> bool>(&self, pred: P) -> Option<Scope> {
let mut cur = Some(self.clone());
while let Some(scope) = cur {
if pred(scope.typ) {
return Some(scope.clone());
};
cur = scope.parent();
}
None
}
pub fn find_nearest_closure(&self) -> Option<Scope> {
self.find_nearest_scope(|t| t == ScopeType::Closure)
}
pub fn parent(&self) -> Option<Scope> {
self.data.borrow().parent.clone()
}
}
impl PartialEq for Scope {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.data, &other.data)
}
}
impl Eq for Scope {}