diff --git a/src/eval.rs b/src/eval.rs index a3cfe54e13..5ff5242d02 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fmt::Display}; +use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc}; use crate::{ parser::Operator, Block, BlockId, Call, Expr, Expression, ParserState, Span, Statement, VarId, @@ -59,13 +59,17 @@ pub struct State<'a> { pub parser_state: &'a ParserState, } -pub struct Stack { +pub struct StackFrame { pub vars: HashMap, + pub parent: Option, } -impl Stack { - pub fn get_var(&self, var_id: VarId) -> Result { - match self.vars.get(&var_id) { +pub type Stack = Rc>; + +impl StackFrame { + pub fn get_var(this: Stack, var_id: VarId) -> Result { + let this = this.borrow(); + match this.vars.get(&var_id) { Some(v) => Ok(v.clone()), _ => { println!("var_id: {}", var_id); @@ -74,14 +78,32 @@ impl Stack { } } - pub fn add_var(&mut self, var_id: VarId, value: Value) { - self.vars.insert(var_id, value); + pub fn add_var(this: Stack, var_id: VarId, value: Value) { + let mut this = this.borrow_mut(); + this.vars.insert(var_id, value); + } + + pub fn enter_scope(this: Stack) -> Stack { + Rc::new(RefCell::new(StackFrame { + vars: HashMap::new(), + parent: Some(this), + })) + } + + pub fn print_stack(&self) { + println!("===frame==="); + for (var, val) in &self.vars { + println!("{}: {:?}", var, val); + } + if let Some(parent) = &self.parent { + parent.borrow().print_stack() + } } } pub fn eval_operator( _state: &State, - _stack: &mut Stack, + _stack: Stack, op: &Expression, ) -> Result { match op { @@ -93,7 +115,7 @@ pub fn eval_operator( } } -fn eval_call(state: &State, stack: &mut Stack, call: &Call) -> Result { +fn eval_call(state: &State, stack: Stack, call: &Call) -> Result { let decl = state.parser_state.get_decl(call.decl_id); if let Some(block_id) = decl.body { for (arg, param) in call @@ -101,14 +123,15 @@ fn eval_call(state: &State, stack: &mut Stack, call: &Call) -> Result Result Result { if val { let block = state.parser_state.get_block(then_block); + let stack = StackFrame::enter_scope(stack); eval_block(state, stack, block) } else if let Some(else_case) = else_case { println!("{:?}", else_case); if let Some(else_expr) = else_case.as_keyword() { if let Some(block_id) = else_expr.as_block() { let block = state.parser_state.get_block(block_id); + let stack = StackFrame::enter_scope(stack); eval_block(state, stack, block) } else { eval_expression(state, stack, else_expr) @@ -160,7 +185,7 @@ fn eval_call(state: &State, stack: &mut Stack, call: &Call) -> Result Result Result { match &expr.expr { @@ -187,13 +212,13 @@ pub fn eval_expression( val: *i, span: expr.span, }), - Expr::Var(var_id) => stack.get_var(*var_id), + Expr::Var(var_id) => StackFrame::get_var(stack, *var_id), Expr::Call(call) => eval_call(state, stack, call), Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)), Expr::Operator(_) => Ok(Value::Unknown), Expr::BinaryOp(lhs, op, rhs) => { - let lhs = eval_expression(state, stack, lhs)?; - let op = eval_operator(state, stack, op)?; + let lhs = eval_expression(state, stack.clone(), lhs)?; + let op = eval_operator(state, stack.clone(), op)?; let rhs = eval_expression(state, stack, rhs)?; match op { @@ -205,13 +230,14 @@ pub fn eval_expression( Expr::Subexpression(block_id) => { let block = state.parser_state.get_block(*block_id); + let stack = StackFrame::enter_scope(stack); eval_block(state, stack, block) } Expr::Block(block_id) => Ok(Value::Block(*block_id)), Expr::List(x) => { let mut output = vec![]; for expr in x { - output.push(eval_expression(state, stack, expr)?); + output.push(eval_expression(state, stack.clone(), expr)?); } Ok(Value::List(output)) } @@ -226,12 +252,12 @@ pub fn eval_expression( } } -pub fn eval_block(state: &State, stack: &mut Stack, block: &Block) -> Result { +pub fn eval_block(state: &State, stack: Stack, block: &Block) -> Result { let mut last = Ok(Value::Unknown); for stmt in &block.stmts { if let Statement::Expression(expression) = stmt { - last = Ok(eval_expression(state, stack, expression)?); + last = Ok(eval_expression(state, stack.clone(), expression)?); } } diff --git a/src/lib.rs b/src/lib.rs index 47915ab09d..12f5329c20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ mod tests; mod type_check; pub use declaration::Declaration; -pub use eval::{eval_block, eval_expression, Stack, State}; +pub use eval::{eval_block, eval_expression, Stack, StackFrame, State}; pub use lex::{lex, Token, TokenContents}; pub use lite_parse::{lite_parse, LiteBlock, LiteCommand, LiteStatement}; pub use parse_error::ParseError; diff --git a/src/main.rs b/src/main.rs index 95c0d594b8..991e310e80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; use engine_q::{ - eval_block, NuHighlighter, ParserState, ParserWorkingSet, Signature, Stack, State, SyntaxShape, + eval_block, NuHighlighter, ParserState, ParserWorkingSet, Signature, StackFrame, State, + SyntaxShape, }; fn main() -> std::io::Result<()> { @@ -73,6 +74,8 @@ fn main() -> std::io::Result<()> { working_set.add_decl(sig.into()); let sig = Signature::build("blocks"); working_set.add_decl(sig.into()); + let sig = Signature::build("stack"); + working_set.add_decl(sig.into()); let sig = Signature::build("add"); working_set.add_decl(sig.into()); @@ -131,9 +134,10 @@ fn main() -> std::io::Result<()> { let prompt = DefaultPrompt::new(1); let mut current_line = 1; - let mut stack = Stack { + let stack = Rc::new(RefCell::new(StackFrame { vars: HashMap::new(), - }; + parent: None, + })); loop { let input = line_editor.read_line(&prompt)?; @@ -150,6 +154,8 @@ fn main() -> std::io::Result<()> { } else if s.trim() == "blocks" { parser_state.borrow().print_blocks(); continue; + } else if s.trim() == "stack" { + stack.borrow().print_stack(); } // println!("input: '{}'", s); @@ -176,7 +182,7 @@ fn main() -> std::io::Result<()> { parser_state: &*parser_state.borrow(), }; - let output = eval_block(&state, &mut stack, &block); + let output = eval_block(&state, stack.clone(), &block); println!("{:#?}", output); } Signal::CtrlC => {