use std::collections::HashMap;
use crate::{Addr, expressions::Identifier};
pub type EnvScope = HashMap<Identifier, Addr>;
#[derive(Debug, Clone)]
pub struct Environment {
scopes: Vec<EnvScope>,
}
impl Default for Environment {
fn default() -> Self {
Environment {
scopes: vec![EnvScope::new()],
}
}
}
impl Environment {
pub fn define(&mut self, key: Identifier, value: Addr) -> Option<Addr> {
if let Some(last_scope) = self.scopes.last_mut()
&& let Some(old_v) = last_scope.insert(key, value)
{
return old_v.into();
}
None
}
pub fn drop(&mut self, key: &Identifier) -> Option<Addr> {
for s in self.scopes.iter_mut().rev() {
if let Some(val) = s.remove(key) {
return val.into();
}
}
None
}
pub fn get_cloned(&self, key: &Identifier) -> Option<Addr> {
for s in self.scopes.iter().rev() {
if let Some(val) = s.get(key).cloned() {
return val.into();
}
}
None
}
pub fn get_mut(&mut self, key: &Identifier) -> Option<&mut Addr> {
for s in self.scopes.iter_mut().rev() {
if let Some(val) = s.get_mut(key) {
return val.into();
}
}
None
}
pub fn get_ptr(&self, key: &Identifier) -> Option<Addr> {
for s in self.scopes.iter().rev() {
if let Some(addr) = s.get(key) {
return Some(*addr);
}
}
None
}
pub fn enter_scope(&mut self) {
self.scopes.push(EnvScope::new());
}
pub fn leave_scope(&mut self) {
if self.scopes.len() > 1 {
self.scopes.pop();
}
}
pub fn extend_from(&mut self, other: &EnvScope) {
for (ident, value) in other {
self.define(ident.clone(), *value);
}
}
pub fn current_items(&self) -> EnvScope {
let mut result = EnvScope::new();
for s in self.scopes.clone() {
for (ident, v) in s {
result.insert(ident, v);
}
}
result
}
pub fn clear(&mut self) {
self.scopes.clear();
self.scopes.push(EnvScope::new());
}
}