nushell/crates/nu-protocol/src/engine/evaluation_context.rs

126 lines
3.3 KiB
Rust
Raw Normal View History

2021-09-02 20:21:37 +02:00
use super::EngineState;
2021-08-16 00:33:34 +02:00
use std::{cell::RefCell, collections::HashMap, rc::Rc};
2021-09-02 20:21:37 +02:00
use crate::{ShellError, Value, VarId};
2021-08-16 00:33:34 +02:00
2021-09-03 04:57:18 +02:00
#[derive(Clone)]
2021-09-02 20:21:37 +02:00
pub struct EvaluationContext {
2021-09-02 10:25:22 +02:00
pub engine_state: Rc<RefCell<EngineState>>,
2021-08-16 00:33:34 +02:00
pub stack: Stack,
}
2021-09-02 20:21:37 +02:00
impl EvaluationContext {
2021-08-16 00:33:34 +02:00
pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> {
self.stack.get_var(var_id)
}
2021-09-02 20:21:37 +02:00
pub fn enter_scope(&self) -> EvaluationContext {
2021-08-16 00:33:34 +02:00
Self {
2021-09-02 10:25:22 +02:00
engine_state: self.engine_state.clone(),
2021-08-16 00:33:34 +02:00
stack: self.stack.clone().enter_scope(),
}
}
pub fn add_var(&self, var_id: VarId, value: Value) {
// We need to make values concreate before we assign them to variables, as stream values
// will drain and remain drained.
//
// TODO: find a good home for this
// TODO: add ctrl-c support
let value = match value {
2021-09-07 09:35:59 +02:00
Value::Stream { stream, span } => Value::List {
vals: stream.collect(),
span,
},
x => x,
};
2021-08-16 00:33:34 +02:00
self.stack.add_var(var_id, value);
}
pub fn add_env_var(&self, var: String, value: String) {
self.stack.add_env_var(var, value);
}
pub fn print_stack(&self) {
self.stack.print_stack();
}
}
#[derive(Debug)]
pub struct StackFrame {
pub vars: HashMap<VarId, Value>,
pub env_vars: HashMap<String, String>,
pub parent: Option<Stack>,
}
#[derive(Clone, Debug)]
pub struct Stack(Rc<RefCell<StackFrame>>);
impl Default for Stack {
fn default() -> Self {
Self::new()
}
}
impl Stack {
pub fn new() -> Stack {
Stack(Rc::new(RefCell::new(StackFrame {
vars: HashMap::new(),
env_vars: HashMap::new(),
parent: None,
})))
}
pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> {
let this = self.0.borrow();
match this.vars.get(&var_id) {
Some(v) => Ok(v.clone()),
_ => {
if let Some(parent) = &this.parent {
parent.get_var(var_id)
} else {
Err(ShellError::InternalError("variable not found".into()))
}
}
}
}
pub fn add_var(&self, var_id: VarId, value: Value) {
let mut this = self.0.borrow_mut();
this.vars.insert(var_id, value);
}
pub fn add_env_var(&self, var: String, value: String) {
let mut this = self.0.borrow_mut();
this.env_vars.insert(var, value);
}
pub fn enter_scope(self) -> Stack {
Stack(Rc::new(RefCell::new(StackFrame {
vars: HashMap::new(),
env_vars: HashMap::new(),
parent: Some(self),
})))
}
2021-09-19 21:29:58 +02:00
pub fn get_env_vars(&self) -> HashMap<String, String> {
self.0.borrow().env_vars.clone()
}
2021-08-16 00:33:34 +02:00
pub fn print_stack(&self) {
println!("===frame===");
println!("vars:");
for (var, val) in &self.0.borrow().vars {
println!(" {}: {:?}", var, val);
}
println!("env vars:");
for (var, val) in &self.0.borrow().env_vars {
println!(" {}: {:?}", var, val);
}
if let Some(parent) = &self.0.borrow().parent {
parent.print_stack()
}
}
}