use pepl_stdlib::Value;
use std::collections::BTreeMap;
#[derive(Debug, Clone)]
struct Scope {
bindings: BTreeMap<String, Value>,
}
impl Scope {
fn new() -> Self {
Self {
bindings: BTreeMap::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct Environment {
scopes: Vec<Scope>,
}
impl Environment {
pub fn new() -> Self {
Self {
scopes: vec![Scope::new()],
}
}
pub fn push_scope(&mut self) {
self.scopes.push(Scope::new());
}
pub fn pop_scope(&mut self) {
if self.scopes.len() > 1 {
self.scopes.pop();
}
}
pub fn define(&mut self, name: &str, value: Value) {
if let Some(scope) = self.scopes.last_mut() {
scope.bindings.insert(name.to_string(), value);
}
}
pub fn get(&self, name: &str) -> Option<&Value> {
for scope in self.scopes.iter().rev() {
if let Some(v) = scope.bindings.get(name) {
return Some(v);
}
}
None
}
pub fn set(&mut self, name: &str, value: Value) -> bool {
for scope in self.scopes.iter_mut().rev() {
if scope.bindings.contains_key(name) {
scope.bindings.insert(name.to_string(), value);
return true;
}
}
false
}
pub fn global_bindings(&self) -> &BTreeMap<String, Value> {
&self.scopes[0].bindings
}
pub fn restore_global(&mut self, bindings: BTreeMap<String, Value>) {
self.scopes[0].bindings = bindings;
}
}
impl Default for Environment {
fn default() -> Self {
Self::new()
}
}