forked from extern/nushell
Refactor scope (#2602)
* Refactor scope to have parents * Refactor scope to have parents * Refactor scope to have parents * Clippy Co-authored-by: Jonathan Turner <jonathan@pop-os.localdomain>
This commit is contained in:
@ -2,30 +2,121 @@ 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.
|
||||
/// Additionally, holds the value for the special $it variable, a variable used to refer to the value passing
|
||||
/// through the pipeline at that moment
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct Scope {
|
||||
pub it: Value,
|
||||
pub vars: IndexMap<String, Value>,
|
||||
pub env: IndexMap<String, String>,
|
||||
vars: IndexMap<String, Value>,
|
||||
env: IndexMap<String, String>,
|
||||
parent: Option<Arc<Scope>>,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
/// Create an empty scope
|
||||
pub fn new() -> Scope {
|
||||
Scope {
|
||||
it: Value::nothing(),
|
||||
vars: IndexMap::new(),
|
||||
env: IndexMap::new(),
|
||||
pub fn vars(&self) -> IndexMap<String, Value> {
|
||||
//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<String, String> {
|
||||
//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<Value> {
|
||||
if let Some(value) = self.vars().get(name) {
|
||||
Some(value.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Scope {
|
||||
fn default() -> Scope {
|
||||
Scope::new()
|
||||
pub fn it(&self) -> Option<Value> {
|
||||
self.var("$it")
|
||||
}
|
||||
|
||||
pub fn from_env(env: IndexMap<String, String>) -> Arc<Scope> {
|
||||
Arc::new(Scope {
|
||||
vars: IndexMap::new(),
|
||||
env,
|
||||
parent: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn append_it(this: Arc<Self>, it: Value) -> Arc<Scope> {
|
||||
let mut vars = IndexMap::new();
|
||||
vars.insert("$it".into(), it);
|
||||
Arc::new(Scope {
|
||||
vars,
|
||||
env: IndexMap::new(),
|
||||
parent: Some(this),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn append_var(this: Arc<Self>, name: String, value: Value) -> Arc<Scope> {
|
||||
let mut vars = IndexMap::new();
|
||||
vars.insert(name, value);
|
||||
Arc::new(Scope {
|
||||
vars,
|
||||
env: IndexMap::new(),
|
||||
parent: Some(this),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn append_vars(this: Arc<Self>, vars: IndexMap<String, Value>) -> Arc<Scope> {
|
||||
Arc::new(Scope {
|
||||
vars,
|
||||
env: IndexMap::new(),
|
||||
parent: Some(this),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn append_env(this: Arc<Self>, env: IndexMap<String, String>) -> Arc<Scope> {
|
||||
Arc::new(Scope {
|
||||
vars: IndexMap::new(),
|
||||
env,
|
||||
parent: Some(this),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create an empty scope
|
||||
pub fn create() -> Arc<Scope> {
|
||||
Arc::new(Scope {
|
||||
vars: IndexMap::new(),
|
||||
env: IndexMap::new(),
|
||||
parent: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user