diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 24c6a453d9..c3db7cdffb 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -1,8 +1,7 @@ -use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc, time::Instant}; +use std::time::Instant; -use nu_parser::{ - Block, BlockId, Call, Expr, Expression, Operator, ParserState, Span, Statement, Type, VarId, -}; +use crate::{state::State, value::Value}; +use nu_parser::{Block, Call, Expr, Expression, Operator, Span, Statement, Type}; #[derive(Debug)] pub enum ShellError { @@ -19,216 +18,7 @@ pub enum ShellError { CantConvert(String, Span), } -#[derive(Debug, Clone)] -pub enum Value { - Bool { val: bool, span: Span }, - Int { val: i64, span: Span }, - Float { val: f64, span: Span }, - String { val: String, span: Span }, - List { val: Vec, span: Span }, - Block { val: BlockId, span: Span }, - Nothing { span: Span }, -} - -impl Value { - pub fn as_string(&self) -> Result { - match self { - Value::String { val, .. } => Ok(val.to_string()), - _ => Err(ShellError::CantConvert("string".into(), self.span())), - } - } - - pub fn span(&self) -> Span { - match self { - Value::Bool { span, .. } => *span, - Value::Int { span, .. } => *span, - Value::Float { span, .. } => *span, - Value::String { span, .. } => *span, - Value::List { span, .. } => *span, - Value::Block { span, .. } => *span, - Value::Nothing { span, .. } => *span, - } - } - - pub fn with_span(mut self, new_span: Span) -> Value { - match &mut self { - Value::Bool { span, .. } => *span = new_span, - Value::Int { span, .. } => *span = new_span, - Value::Float { span, .. } => *span = new_span, - Value::String { span, .. } => *span = new_span, - Value::List { span, .. } => *span = new_span, - Value::Block { span, .. } => *span = new_span, - Value::Nothing { span, .. } => *span = new_span, - } - - self - } - - pub fn get_type(&self) -> Type { - match self { - Value::Bool { .. } => Type::Bool, - Value::Int { .. } => Type::Int, - Value::Float { .. } => Type::Float, - Value::String { .. } => Type::String, - Value::List { .. } => Type::List(Box::new(Type::Unknown)), // FIXME - Value::Nothing { .. } => Type::Nothing, - Value::Block { .. } => Type::Block, - } - } -} - -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => lhs == rhs, - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => lhs == rhs, - (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => lhs == rhs, - (Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => lhs == rhs, - (Value::List { val: l1, .. }, Value::List { val: l2, .. }) => l1 == l2, - (Value::Block { val: b1, .. }, Value::Block { val: b2, .. }) => b1 == b2, - _ => false, - } - } -} - -impl Display for Value { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Value::Bool { val, .. } => { - write!(f, "{}", val) - } - Value::Int { val, .. } => { - write!(f, "{}", val) - } - Value::Float { val, .. } => { - write!(f, "{}", val) - } - Value::String { val, .. } => write!(f, "{}", val), - Value::List { .. } => write!(f, ""), - Value::Block { .. } => write!(f, ""), - Value::Nothing { .. } => write!(f, ""), - } - } -} - -impl Value { - pub fn add(&self, op: Span, rhs: &Value) -> Result { - let span = nu_parser::span(&[self.span(), rhs.span()]); - - match (self, rhs) { - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { - val: lhs + rhs, - span, - }), - (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float { - val: *lhs as f64 + *rhs, - span, - }), - (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float { - val: *lhs + *rhs as f64, - span, - }), - (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float { - val: lhs + rhs, - span, - }), - (Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String { - val: lhs.to_string() + rhs, - span, - }), - - _ => Err(ShellError::OperatorMismatch { - op_span: op, - lhs_ty: self.get_type(), - lhs_span: self.span(), - rhs_ty: rhs.get_type(), - rhs_span: rhs.span(), - }), - } - } -} - -pub struct State<'a> { - pub parser_state: &'a ParserState, -} - -#[derive(Debug)] -pub struct StackFrame { - pub vars: HashMap, - pub env_vars: HashMap, - pub parent: Option, -} - -#[derive(Clone, Debug)] -pub struct Stack(Rc>); - -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 { - 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() - } - } -} - -pub fn eval_operator( - _state: &State, - _stack: Stack, - op: &Expression, -) -> Result { +pub fn eval_operator(op: &Expression) -> Result { match op { Expression { expr: Expr::Operator(operator), @@ -238,24 +28,24 @@ pub fn eval_operator( } } -fn eval_call(state: &State, stack: Stack, call: &Call) -> Result { +fn eval_call(state: &State, call: &Call) -> Result { let decl = state.parser_state.get_decl(call.decl_id); if let Some(block_id) = decl.body { - let stack = stack.enter_scope(); + let state = state.enter_scope(); for (arg, param) in call .positional .iter() .zip(decl.signature.required_positional.iter()) { - let result = eval_expression(state, stack.clone(), arg)?; + let result = eval_expression(&state, arg)?; let var_id = param .var_id .expect("internal error: all custom parameters must have var_ids"); - stack.add_var(var_id, result); + state.add_var(var_id, result); } let block = state.parser_state.get_block(block_id); - eval_block(state, stack, block) + eval_block(&state, block) } else if decl.signature.name == "let" { let var_id = call.positional[0] .as_var() @@ -265,11 +55,11 @@ fn eval_call(state: &State, stack: Stack, call: &Call) -> Result Result Result { if val { let block = state.parser_state.get_block(then_block); - let stack = stack.enter_scope(); - eval_block(state, stack, block) + let state = state.enter_scope(); + eval_block(&state, block) } else if let Some(else_case) = 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 = stack.enter_scope(); - eval_block(state, stack, block) + let state = state.enter_scope(); + eval_block(&state, block) } else { - eval_expression(state, stack, else_expr) + eval_expression(state, else_expr) } } else { - eval_expression(state, stack, else_case) + eval_expression(state, else_case) } } else { Ok(Value::Nothing { span }) @@ -327,7 +117,7 @@ fn eval_call(state: &State, stack: Stack, call: &Call) -> Result Result Result Result Result Result Result { +pub fn eval_expression(state: &State, expr: &Expression) -> Result { match &expr.expr { Expr::Bool(b) => Ok(Value::Bool { val: *b, @@ -424,17 +210,17 @@ pub fn eval_expression( val: *f, span: expr.span, }), - Expr::Var(var_id) => stack + Expr::Var(var_id) => state .get_var(*var_id) .map_err(move |_| ShellError::VariableNotFound(expr.span)), - Expr::Call(call) => eval_call(state, stack, call), + Expr::Call(call) => eval_call(state, call), Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)), Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }), Expr::BinaryOp(lhs, op, rhs) => { let op_span = op.span; - let lhs = eval_expression(state, stack.clone(), lhs)?; - let op = eval_operator(state, stack.clone(), op)?; - let rhs = eval_expression(state, stack, rhs)?; + let lhs = eval_expression(state, lhs)?; + let op = eval_operator(op)?; + let rhs = eval_expression(state, rhs)?; match op { Operator::Plus => lhs.add(op_span, &rhs), @@ -445,8 +231,8 @@ pub fn eval_expression( Expr::Subexpression(block_id) => { let block = state.parser_state.get_block(*block_id); - let stack = stack.enter_scope(); - eval_block(state, stack, block) + let state = state.enter_scope(); + eval_block(&state, block) } Expr::Block(block_id) => Ok(Value::Block { val: *block_id, @@ -455,7 +241,7 @@ pub fn eval_expression( Expr::List(x) => { let mut output = vec![]; for expr in x { - output.push(eval_expression(state, stack.clone(), expr)?); + output.push(eval_expression(state, expr)?); } Ok(Value::List { val: output, @@ -463,7 +249,7 @@ pub fn eval_expression( }) } Expr::Table(_, _) => Err(ShellError::Unsupported(expr.span)), - Expr::Keyword(_, _, expr) => eval_expression(state, stack, expr), + Expr::Keyword(_, _, expr) => eval_expression(state, expr), Expr::String(s) => Ok(Value::String { val: s.clone(), span: expr.span, @@ -473,14 +259,14 @@ pub fn eval_expression( } } -pub fn eval_block(state: &State, stack: Stack, block: &Block) -> Result { +pub fn eval_block(state: &State, block: &Block) -> Result { let mut last = Ok(Value::Nothing { span: Span { start: 0, end: 0 }, }); for stmt in &block.stmts { if let Statement::Expression(expression) = stmt { - last = Ok(eval_expression(state, stack.clone(), expression)?); + last = Ok(eval_expression(state, expression)?); } } diff --git a/crates/nu-engine/src/lib.rs b/crates/nu-engine/src/lib.rs index 01fb48ca0c..2d0db2a8e3 100644 --- a/crates/nu-engine/src/lib.rs +++ b/crates/nu-engine/src/lib.rs @@ -1,3 +1,7 @@ mod eval; +mod state; +mod value; -pub use eval::{eval_block, eval_expression, eval_operator, ShellError, Stack, State, Value}; +pub use eval::{eval_block, eval_expression, eval_operator, ShellError}; +pub use state::{Stack, State}; +pub use value::Value; diff --git a/crates/nu-engine/src/state.rs b/crates/nu-engine/src/state.rs new file mode 100644 index 0000000000..fdbe38e7c3 --- /dev/null +++ b/crates/nu-engine/src/state.rs @@ -0,0 +1,106 @@ +use nu_parser::{ParserState, VarId}; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; + +use crate::{value::Value, ShellError}; + +pub struct State<'a> { + pub parser_state: &'a ParserState, + pub stack: Stack, +} + +impl<'a> State<'a> { + pub fn get_var(&self, var_id: VarId) -> Result { + self.stack.get_var(var_id) + } + + pub fn enter_scope(&self) -> State<'a> { + Self { + parser_state: self.parser_state, + stack: self.stack.clone().enter_scope(), + } + } + + pub fn add_var(&self, var_id: VarId, value: Value) { + 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, + pub env_vars: HashMap, + pub parent: Option, +} + +#[derive(Clone, Debug)] +pub struct Stack(Rc>); + +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 { + 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() + } + } +} diff --git a/crates/nu-engine/src/value.rs b/crates/nu-engine/src/value.rs new file mode 100644 index 0000000000..7029ca6464 --- /dev/null +++ b/crates/nu-engine/src/value.rs @@ -0,0 +1,134 @@ +use std::fmt::Display; + +use nu_parser::{BlockId, Span, Type}; + +use crate::ShellError; + +#[derive(Debug, Clone)] +pub enum Value { + Bool { val: bool, span: Span }, + Int { val: i64, span: Span }, + Float { val: f64, span: Span }, + String { val: String, span: Span }, + List { val: Vec, span: Span }, + Block { val: BlockId, span: Span }, + Nothing { span: Span }, +} + +impl Value { + pub fn as_string(&self) -> Result { + match self { + Value::String { val, .. } => Ok(val.to_string()), + _ => Err(ShellError::CantConvert("string".into(), self.span())), + } + } + + pub fn span(&self) -> Span { + match self { + Value::Bool { span, .. } => *span, + Value::Int { span, .. } => *span, + Value::Float { span, .. } => *span, + Value::String { span, .. } => *span, + Value::List { span, .. } => *span, + Value::Block { span, .. } => *span, + Value::Nothing { span, .. } => *span, + } + } + + pub fn with_span(mut self, new_span: Span) -> Value { + match &mut self { + Value::Bool { span, .. } => *span = new_span, + Value::Int { span, .. } => *span = new_span, + Value::Float { span, .. } => *span = new_span, + Value::String { span, .. } => *span = new_span, + Value::List { span, .. } => *span = new_span, + Value::Block { span, .. } => *span = new_span, + Value::Nothing { span, .. } => *span = new_span, + } + + self + } + + pub fn get_type(&self) -> Type { + match self { + Value::Bool { .. } => Type::Bool, + Value::Int { .. } => Type::Int, + Value::Float { .. } => Type::Float, + Value::String { .. } => Type::String, + Value::List { .. } => Type::List(Box::new(Type::Unknown)), // FIXME + Value::Nothing { .. } => Type::Nothing, + Value::Block { .. } => Type::Block, + } + } +} + +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => lhs == rhs, + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => lhs == rhs, + (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => lhs == rhs, + (Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => lhs == rhs, + (Value::List { val: l1, .. }, Value::List { val: l2, .. }) => l1 == l2, + (Value::Block { val: b1, .. }, Value::Block { val: b2, .. }) => b1 == b2, + _ => false, + } + } +} + +impl Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Value::Bool { val, .. } => { + write!(f, "{}", val) + } + Value::Int { val, .. } => { + write!(f, "{}", val) + } + Value::Float { val, .. } => { + write!(f, "{}", val) + } + Value::String { val, .. } => write!(f, "{}", val), + Value::List { .. } => write!(f, ""), + Value::Block { .. } => write!(f, ""), + Value::Nothing { .. } => write!(f, ""), + } + } +} + +impl Value { + pub fn add(&self, op: Span, rhs: &Value) -> Result { + let span = nu_parser::span(&[self.span(), rhs.span()]); + + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { + val: lhs + rhs, + span, + }), + (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float { + val: *lhs as f64 + *rhs, + span, + }), + (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float { + val: *lhs + *rhs as f64, + span, + }), + (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float { + val: lhs + rhs, + span, + }), + (Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String { + val: lhs.to_string() + rhs, + span, + }), + + _ => Err(ShellError::OperatorMismatch { + op_span: op, + lhs_ty: self.get_type(), + lhs_span: self.span(), + rhs_ty: rhs.get_type(), + rhs_span: rhs.span(), + }), + } + } +} diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 6d6bd480ed..a25e71ec95 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -2280,11 +2280,22 @@ impl<'a> ParserWorkingSet<'a> { let (call, call_span, _) = self.parse_internal_call(spans[0], &spans[1..], decl_id); if spans.len() >= 4 { - let alias_name = self.get_span_contents(spans[1]).to_vec(); + let alias_name = self.get_span_contents(spans[1]); + + let alias_name = if alias_name.starts_with(b"\"") + && alias_name.ends_with(b"\"") + && alias_name.len() > 1 + { + alias_name[1..(alias_name.len() - 1)].to_vec() + } else { + alias_name.to_vec() + }; let _equals = self.get_span_contents(spans[2]); let replacement = spans[3..].to_vec(); + println!("{:?} {:?}", alias_name, replacement); + self.add_alias(alias_name, replacement); } diff --git a/src/main.rs b/src/main.rs index 1b97b13e45..c22aa1227e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,11 +27,10 @@ fn main() -> std::io::Result<()> { let state = nu_engine::State { parser_state: &*parser_state.borrow(), + stack: nu_engine::Stack::new(), }; - let stack = nu_engine::Stack::new(); - - match eval_block(&state, stack, &block) { + match eval_block(&state, &block) { Ok(value) => { println!("{}", value); } @@ -90,9 +89,10 @@ fn main() -> std::io::Result<()> { let state = nu_engine::State { parser_state: &*parser_state.borrow(), + stack: stack.clone(), }; - match eval_block(&state, stack.clone(), &block) { + match eval_block(&state, &block) { Ok(value) => { println!("{}", value); }