use std::{
borrow::Borrow,
collections::HashMap,
hash::Hash,
ops::{Index, IndexMut},
rc::Rc,
};
pub type Env<K, V> = Box<HashMap<K, V>>;
#[derive(Debug)]
pub enum LexicalScope<K, V> {
Empty,
Root(Env<K, V>),
Nested(Rc<LexicalScope<K, V>>, Env<K, V>),
}
impl<K, V> Clone for LexicalScope<K, V>
where
K: Clone,
V: Clone,
{
fn clone(&self) -> Self {
match self {
Self::Empty => Self::Empty,
Self::Root(scope) => Self::Root(scope.clone()),
Self::Nested(parent, scope) => Self::Nested(Rc::clone(parent), scope.clone()),
}
}
}
impl<K, V> Default for LexicalScope<K, V> {
fn default() -> Self {
Self::Empty
}
}
impl<K, V> LexicalScope<K, V> {
pub fn is_empty(&self) -> bool {
match self {
Self::Empty => true,
Self::Root(_) => false,
Self::Nested(parent, env) => env.is_empty() && parent.is_empty(),
}
}
}
impl<K, V> LexicalScope<K, V>
where
K: Clone,
V: Clone,
{
pub fn enter(&mut self) {
let moved = Rc::new(core::mem::take(self));
*self = Self::Nested(moved, Env::default());
}
pub fn exit(&mut self) {
match core::mem::replace(self, Self::Empty) {
Self::Empty | Self::Root(_) => (),
Self::Nested(parent, _) => {
*self = Rc::unwrap_or_clone(parent);
}
}
}
}
impl<K, V> LexicalScope<K, V>
where
K: Eq + Hash,
{
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
match self {
Self::Empty => {
let mut env = Env::default();
env.insert(k, v);
*self = Self::Root(env);
None
}
Self::Root(env) => env.insert(k, v),
Self::Nested(_, env) => env.insert(k, v),
}
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
match self {
Self::Empty => None,
Self::Root(env) => env.get(key),
Self::Nested(parent, env) => env.get(key).or_else(|| parent.get(key)),
}
}
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
match self {
Self::Empty => None,
Self::Root(env) => env.get_mut(key),
Self::Nested(parent, env) => env
.get_mut(key)
.or_else(|| Rc::get_mut(parent).and_then(|p| p.get_mut(key))),
}
}
pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
match self {
Self::Empty => None,
Self::Root(env) => env.get_key_value(key),
Self::Nested(parent, env) => {
env.get_key_value(key).or_else(|| parent.get_key_value(key))
}
}
}
pub fn get_key<Q>(&self, key: &Q) -> Option<&K>
where
K: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
self.get_key_value(key).map(|(k, _)| k)
}
}
impl<K, V, Q> Index<&Q> for LexicalScope<K, V>
where
K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
type Output = V;
#[inline]
fn index(&self, key: &Q) -> &Self::Output {
self.get(key).unwrap()
}
}
impl<K, V, Q> IndexMut<&Q> for LexicalScope<K, V>
where
K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
#[inline]
fn index_mut(&mut self, key: &Q) -> &mut Self::Output {
self.get_mut(key).unwrap()
}
}