use crate::value::Value; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use std::fmt::Debug; use std::sync::Arc; /// An evaluation scope. Scopes map variable names to Values and aid in evaluating blocks and expressions. #[derive(Deserialize, Serialize, Debug, Clone)] pub struct Scope { vars: IndexMap, env: IndexMap, parent: Option>, } impl Scope { pub fn vars(&self) -> IndexMap { //FIXME: should this be an interator? let mut output = IndexMap::new(); for v in &self.vars { output.insert(v.0.clone(), v.1.clone()); } if let Some(parent) = &self.parent { for v in parent.vars() { if !output.contains_key(&v.0) { output.insert(v.0.clone(), v.1.clone()); } } } output } pub fn env(&self) -> IndexMap { //FIXME: should this be an interator? let mut output = IndexMap::new(); for v in &self.env { output.insert(v.0.clone(), v.1.clone()); } if let Some(parent) = &self.parent { for v in parent.env() { if !output.contains_key(&v.0) { output.insert(v.0.clone(), v.1.clone()); } } } output } pub fn var(&self, name: &str) -> Option { if let Some(value) = self.vars().get(name) { Some(value.clone()) } else { None } } pub fn from_env(env: IndexMap) -> Arc { Arc::new(Scope { vars: IndexMap::new(), env, parent: None, }) } pub fn append_var(this: Arc, name: impl Into, value: Value) -> Arc { let mut vars = IndexMap::new(); vars.insert(name.into(), value); Arc::new(Scope { vars, env: IndexMap::new(), parent: Some(this), }) } pub fn append_vars(this: Arc, vars: IndexMap) -> Arc { Arc::new(Scope { vars, env: IndexMap::new(), parent: Some(this), }) } pub fn append_env(this: Arc, env: IndexMap) -> Arc { Arc::new(Scope { vars: IndexMap::new(), env, parent: Some(this), }) } /// Create an empty scope pub fn create() -> Arc { Arc::new(Scope { vars: IndexMap::new(), env: IndexMap::new(), parent: None, }) } }