2021-09-02 18:21:37 +00:00
|
|
|
use super::EngineState;
|
2021-08-15 22:33:34 +00:00
|
|
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
|
|
|
|
2021-09-02 18:21:37 +00:00
|
|
|
use crate::{ShellError, Value, VarId};
|
2021-08-15 22:33:34 +00:00
|
|
|
|
2021-09-03 02:57:18 +00:00
|
|
|
#[derive(Clone)]
|
2021-09-02 18:21:37 +00:00
|
|
|
pub struct EvaluationContext {
|
2021-09-02 08:25:22 +00:00
|
|
|
pub engine_state: Rc<RefCell<EngineState>>,
|
2021-08-15 22:33:34 +00:00
|
|
|
pub stack: Stack,
|
|
|
|
}
|
|
|
|
|
2021-09-02 18:21:37 +00:00
|
|
|
impl EvaluationContext {
|
2021-08-15 22:33:34 +00:00
|
|
|
pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> {
|
|
|
|
self.stack.get_var(var_id)
|
|
|
|
}
|
|
|
|
|
2021-09-02 18:21:37 +00:00
|
|
|
pub fn enter_scope(&self) -> EvaluationContext {
|
2021-08-15 22:33:34 +00:00
|
|
|
Self {
|
2021-09-02 08:25:22 +00:00
|
|
|
engine_state: self.engine_state.clone(),
|
2021-08-15 22:33:34 +00:00
|
|
|
stack: self.stack.clone().enter_scope(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_var(&self, var_id: VarId, value: Value) {
|
2021-09-06 18:05:46 +00:00
|
|
|
// 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 07:35:59 +00:00
|
|
|
Value::Stream { stream, span } => Value::List {
|
2021-09-07 07:07:11 +00:00
|
|
|
vals: stream.collect(),
|
2021-09-06 18:05:46 +00:00
|
|
|
span,
|
|
|
|
},
|
|
|
|
x => x,
|
|
|
|
};
|
|
|
|
|
2021-08-15 22:33:34 +00: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),
|
|
|
|
})))
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|