diff --git a/Cargo.lock b/Cargo.lock index 2112588bf0..3c54213f68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,6 +162,7 @@ dependencies = [ "assert_cmd", "codespan-reporting", "nu-cli", + "nu-command", "nu-engine", "nu-parser", "nu-protocol", @@ -300,6 +301,10 @@ dependencies = [ [[package]] name = "nu-command" version = "0.1.0" +dependencies = [ + "nu-engine", + "nu-protocol", +] [[package]] name = "nu-engine" diff --git a/Cargo.toml b/Cargo.toml index 6f1ff009f8..225d8c4f8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = ["crates/nu-cli", "crates/nu-engine", "crates/nu-parser", "crates/nu-c reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" } codespan-reporting = "0.11.1" nu-cli = { path="./crates/nu-cli" } +nu-command = { path="./crates/nu-command" } nu-engine = { path="./crates/nu-engine" } nu-parser = { path="./crates/nu-parser" } nu-protocol = { path = "./crates/nu-protocol" } diff --git a/crates/nu-cli/src/default_context.rs b/crates/nu-cli/src/default_context.rs deleted file mode 100644 index 2c59c6748e..0000000000 --- a/crates/nu-cli/src/default_context.rs +++ /dev/null @@ -1,118 +0,0 @@ -use std::{cell::RefCell, rc::Rc}; - -use nu_protocol::{ - engine::{EngineState, StateWorkingSet}, - Signature, SyntaxShape, -}; - -pub fn create_default_context() -> Rc> { - let engine_state = Rc::new(RefCell::new(EngineState::new())); - let delta = { - let engine_state = engine_state.borrow(); - let mut working_set = StateWorkingSet::new(&*engine_state); - - let sig = - Signature::build("where").required("cond", SyntaxShape::RowCondition, "condition"); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("if") - .required("cond", SyntaxShape::Expression, "condition") - .required("then_block", SyntaxShape::Block, "then block") - .optional( - "else", - SyntaxShape::Keyword(b"else".to_vec(), Box::new(SyntaxShape::Expression)), - "optional else followed by else block", - ); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("let") - .required("var_name", SyntaxShape::VarWithOptType, "variable name") - .required( - "initial_value", - SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)), - "equals sign followed by value", - ); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("let-env") - .required("var_name", SyntaxShape::String, "variable name") - .required( - "initial_value", - SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::String)), - "equals sign followed by value", - ); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("alias") - .required("name", SyntaxShape::String, "name of the alias") - .required( - "initial_value", - SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)), - "equals sign followed by value", - ); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("build-string").rest(SyntaxShape::String, "list of string"); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("def") - .required("def_name", SyntaxShape::String, "definition name") - .required("params", SyntaxShape::Signature, "parameters") - .required("block", SyntaxShape::Block, "body of the definition"); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("for") - .required( - "var_name", - SyntaxShape::Variable, - "name of the looping variable", - ) - .required( - "range", - SyntaxShape::Keyword(b"in".to_vec(), Box::new(SyntaxShape::Int)), - "range of the loop", - ) - .required("block", SyntaxShape::Block, "the block to run"); - working_set.add_decl(sig.predeclare()); - - let sig = - Signature::build("benchmark").required("block", SyntaxShape::Block, "the block to run"); - working_set.add_decl(sig.predeclare()); - - // let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')); - // working_set.add_decl(sig.into()); - - // let sig = Signature::build("bar") - // .named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')) - // .switch("--rock", "rock!!", Some('r')); - // working_set.add_decl(sig.into()); - let sig = Signature::build("exit"); - working_set.add_decl(sig.predeclare()); - let sig = Signature::build("vars"); - working_set.add_decl(sig.predeclare()); - let sig = Signature::build("decls"); - working_set.add_decl(sig.predeclare()); - let sig = Signature::build("blocks"); - working_set.add_decl(sig.predeclare()); - let sig = Signature::build("stack"); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("add"); - working_set.add_decl(sig.predeclare()); - let sig = Signature::build("add it"); - working_set.add_decl(sig.predeclare()); - - let sig = Signature::build("add it together") - .required("x", SyntaxShape::Int, "x value") - .required("y", SyntaxShape::Int, "y value"); - working_set.add_decl(sig.predeclare()); - - working_set.render() - }; - - { - EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); - } - - engine_state -} diff --git a/crates/nu-cli/src/lib.rs b/crates/nu-cli/src/lib.rs index 7c2e42b92d..a8c602012b 100644 --- a/crates/nu-cli/src/lib.rs +++ b/crates/nu-cli/src/lib.rs @@ -1,7 +1,5 @@ -mod default_context; mod errors; mod syntax_highlight; -pub use default_context::create_default_context; pub use errors::{report_parsing_error, report_shell_error}; pub use syntax_highlight::NuHighlighter; diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index eaaba9db15..6cc6ae2f63 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -6,3 +6,5 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +nu-protocol = { path = "../nu-protocol" } +nu-engine = { path = "../nu-engine" } \ No newline at end of file diff --git a/crates/nu-command/src/alias.rs b/crates/nu-command/src/alias.rs new file mode 100644 index 0000000000..91beec2fda --- /dev/null +++ b/crates/nu-command/src/alias.rs @@ -0,0 +1,34 @@ +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{Signature, SyntaxShape, Value}; + +pub struct Alias; + +impl Command for Alias { + fn name(&self) -> &str { + "alias" + } + + fn usage(&self) -> &str { + "Alias a command (with optional flags) to a new name" + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("alias") + .required("name", SyntaxShape::String, "name of the alias") + .required( + "initial_value", + SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)), + "equals sign followed by value", + ) + } + + fn run( + &self, + _context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + Ok(Value::Nothing { span: call.head }) + } +} diff --git a/crates/nu-command/src/benchmark.rs b/crates/nu-command/src/benchmark.rs new file mode 100644 index 0000000000..f494da794e --- /dev/null +++ b/crates/nu-command/src/benchmark.rs @@ -0,0 +1,44 @@ +use std::time::Instant; + +use nu_engine::eval_block; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{Signature, SyntaxShape, Value}; + +pub struct Benchmark; + +impl Command for Benchmark { + fn name(&self) -> &str { + "benchmark" + } + + fn usage(&self) -> &str { + "Time the running time of a block" + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("benchmark").required("block", SyntaxShape::Block, "the block to run") + } + + fn run( + &self, + context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + let block = call.positional[0] + .as_block() + .expect("internal error: expected block"); + let engine_state = context.engine_state.borrow(); + let block = engine_state.get_block(block); + + let state = context.enter_scope(); + let start_time = Instant::now(); + eval_block(&state, block)?; + let end_time = Instant::now(); + println!("{} ms", (end_time - start_time).as_millis()); + Ok(Value::Nothing { + span: call.positional[0].span, + }) + } +} diff --git a/crates/nu-command/src/build_string.rs b/crates/nu-command/src/build_string.rs new file mode 100644 index 0000000000..1d6d5e51f5 --- /dev/null +++ b/crates/nu-command/src/build_string.rs @@ -0,0 +1,39 @@ +use nu_engine::eval_expression; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{Signature, SyntaxShape, Value}; + +pub struct BuildString; + +impl Command for BuildString { + fn name(&self) -> &str { + "build-string" + } + + fn usage(&self) -> &str { + "Create a string from the arguments." + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("build-string").rest(SyntaxShape::String, "list of string") + } + + fn run( + &self, + context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + let mut output = vec![]; + + for expr in &call.positional { + let val = eval_expression(context, expr)?; + + output.push(val.into_string()); + } + Ok(Value::String { + val: output.join(""), + span: call.head, + }) + } +} diff --git a/crates/nu-command/src/def.rs b/crates/nu-command/src/def.rs new file mode 100644 index 0000000000..25004d800d --- /dev/null +++ b/crates/nu-command/src/def.rs @@ -0,0 +1,31 @@ +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{Signature, SyntaxShape, Value}; + +pub struct Def; + +impl Command for Def { + fn name(&self) -> &str { + "def" + } + + fn usage(&self) -> &str { + "Define a custom command" + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("def") + .required("def_name", SyntaxShape::String, "definition name") + .required("params", SyntaxShape::Signature, "parameters") + .required("block", SyntaxShape::Block, "body of the definition") + } + + fn run( + &self, + _context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + Ok(Value::Nothing { span: call.head }) + } +} diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs new file mode 100644 index 0000000000..f1bb536ff0 --- /dev/null +++ b/crates/nu-command/src/default_context.rs @@ -0,0 +1,55 @@ +use std::{cell::RefCell, rc::Rc}; + +use nu_protocol::{ + engine::{EngineState, StateWorkingSet}, + Signature, SyntaxShape, +}; + +use crate::{Alias, Benchmark, BuildString, Def, For, If, Let, LetEnv}; + +pub fn create_default_context() -> Rc> { + let engine_state = Rc::new(RefCell::new(EngineState::new())); + let delta = { + let engine_state = engine_state.borrow(); + let mut working_set = StateWorkingSet::new(&*engine_state); + + let sig = + Signature::build("where").required("cond", SyntaxShape::RowCondition, "condition"); + working_set.add_decl(sig.predeclare()); + + working_set.add_decl(Box::new(If)); + + working_set.add_decl(Box::new(Let)); + + working_set.add_decl(Box::new(LetEnv)); + + working_set.add_decl(Box::new(Alias)); + + working_set.add_decl(Box::new(BuildString)); + + working_set.add_decl(Box::new(Def)); + + working_set.add_decl(Box::new(For)); + + working_set.add_decl(Box::new(Benchmark)); + + let sig = Signature::build("exit"); + working_set.add_decl(sig.predeclare()); + let sig = Signature::build("vars"); + working_set.add_decl(sig.predeclare()); + let sig = Signature::build("decls"); + working_set.add_decl(sig.predeclare()); + let sig = Signature::build("blocks"); + working_set.add_decl(sig.predeclare()); + let sig = Signature::build("stack"); + working_set.add_decl(sig.predeclare()); + + working_set.render() + }; + + { + EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); + } + + engine_state +} diff --git a/crates/nu-command/src/for_.rs b/crates/nu-command/src/for_.rs new file mode 100644 index 0000000000..8eaf393e72 --- /dev/null +++ b/crates/nu-command/src/for_.rs @@ -0,0 +1,75 @@ +use nu_engine::{eval_block, eval_expression}; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{Signature, Span, SyntaxShape, Value}; + +pub struct For; + +impl Command for For { + fn name(&self) -> &str { + "for" + } + + fn usage(&self) -> &str { + "Loop over a range" + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("for") + .required( + "var_name", + SyntaxShape::Variable, + "name of the looping variable", + ) + .required( + "range", + SyntaxShape::Keyword(b"in".to_vec(), Box::new(SyntaxShape::Int)), + "range of the loop", + ) + .required("block", SyntaxShape::Block, "the block to run") + } + + fn run( + &self, + context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + let var_id = call.positional[0] + .as_var() + .expect("internal error: missing variable"); + + let keyword_expr = call.positional[1] + .as_keyword() + .expect("internal error: missing keyword"); + let end_val = eval_expression(context, keyword_expr)?; + + let block = call.positional[2] + .as_block() + .expect("internal error: expected block"); + let engine_state = context.engine_state.borrow(); + let block = engine_state.get_block(block); + + let state = context.enter_scope(); + + let mut x = Value::Int { + val: 0, + span: Span::unknown(), + }; + + loop { + if x == end_val { + break; + } else { + state.add_var(var_id, x.clone()); + eval_block(&state, block)?; + } + if let Value::Int { ref mut val, .. } = x { + *val += 1 + } + } + Ok(Value::Nothing { + span: call.positional[0].span, + }) + } +} diff --git a/crates/nu-command/src/if_.rs b/crates/nu-command/src/if_.rs new file mode 100644 index 0000000000..4124dbc7b8 --- /dev/null +++ b/crates/nu-command/src/if_.rs @@ -0,0 +1,67 @@ +use nu_engine::{eval_block, eval_expression}; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{ShellError, Signature, SyntaxShape, Value}; + +pub struct If; + +impl Command for If { + fn name(&self) -> &str { + "if" + } + + fn usage(&self) -> &str { + "Create a variable and give it a value." + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("if") + .required("cond", SyntaxShape::Expression, "condition") + .required("then_block", SyntaxShape::Block, "then block") + .optional( + "else", + SyntaxShape::Keyword(b"else".to_vec(), Box::new(SyntaxShape::Expression)), + "optional else followed by else block", + ) + } + + fn run( + &self, + context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + let cond = &call.positional[0]; + let then_block = call.positional[1] + .as_block() + .expect("internal error: expected block"); + let else_case = call.positional.get(2); + + let result = eval_expression(context, cond)?; + match result { + Value::Bool { val, span } => { + let engine_state = context.engine_state.borrow(); + if val { + let block = engine_state.get_block(then_block); + let state = context.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 = engine_state.get_block(block_id); + let state = context.enter_scope(); + eval_block(&state, block) + } else { + eval_expression(context, else_expr) + } + } else { + eval_expression(context, else_case) + } + } else { + Ok(Value::Nothing { span }) + } + } + _ => Err(ShellError::CantConvert("bool".into(), result.span())), + } + } +} diff --git a/crates/nu-command/src/let_.rs b/crates/nu-command/src/let_.rs new file mode 100644 index 0000000000..6e3a2d2fd3 --- /dev/null +++ b/crates/nu-command/src/let_.rs @@ -0,0 +1,50 @@ +use nu_engine::eval_expression; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{Signature, SyntaxShape, Value}; + +pub struct Let; + +impl Command for Let { + fn name(&self) -> &str { + "let" + } + + fn usage(&self) -> &str { + "Create a variable and give it a value." + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("let") + .required("var_name", SyntaxShape::VarWithOptType, "variable name") + .required( + "initial_value", + SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)), + "equals sign followed by value", + ) + } + + fn run( + &self, + context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + let var_id = call.positional[0] + .as_var() + .expect("internal error: missing variable"); + + let keyword_expr = call.positional[1] + .as_keyword() + .expect("internal error: missing keyword"); + + let rhs = eval_expression(context, keyword_expr)?; + + //println!("Adding: {:?} to {}", rhs, var_id); + + context.add_var(var_id, rhs); + Ok(Value::Nothing { + span: call.positional[0].span, + }) + } +} diff --git a/crates/nu-command/src/let_env.rs b/crates/nu-command/src/let_env.rs new file mode 100644 index 0000000000..39ed4800ed --- /dev/null +++ b/crates/nu-command/src/let_env.rs @@ -0,0 +1,51 @@ +use nu_engine::eval_expression; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{Signature, SyntaxShape, Value}; + +pub struct LetEnv; + +impl Command for LetEnv { + fn name(&self) -> &str { + "let-env" + } + + fn usage(&self) -> &str { + "Create an environment variable and give it a value." + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("let-env") + .required("var_name", SyntaxShape::String, "variable name") + .required( + "initial_value", + SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::String)), + "equals sign followed by value", + ) + } + + fn run( + &self, + context: &EvaluationContext, + call: &Call, + _input: Value, + ) -> Result { + let env_var = call.positional[0] + .as_string() + .expect("internal error: missing variable"); + + let keyword_expr = call.positional[1] + .as_keyword() + .expect("internal error: missing keyword"); + + let rhs = eval_expression(context, keyword_expr)?; + let rhs = rhs.as_string()?; + + //println!("Adding: {:?} to {}", rhs, var_id); + + context.add_env_var(env_var, rhs); + Ok(Value::Nothing { + span: call.positional[0].span, + }) + } +} diff --git a/crates/nu-command/src/lib.rs b/crates/nu-command/src/lib.rs index 31e1bb209f..ab4d11b5d1 100644 --- a/crates/nu-command/src/lib.rs +++ b/crates/nu-command/src/lib.rs @@ -1,7 +1,19 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +mod alias; +mod benchmark; +mod build_string; +mod def; +mod default_context; +mod for_; +mod if_; +mod let_; +mod let_env; + +pub use alias::Alias; +pub use benchmark::Benchmark; +pub use build_string::BuildString; +pub use def::Def; +pub use default_context::create_default_context; +pub use for_::For; +pub use if_::If; +pub use let_::Let; +pub use let_env::LetEnv; diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index f173c19f5c..662bb0f057 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -1,5 +1,3 @@ -use std::time::Instant; - use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement}; use nu_protocol::engine::EvaluationContext; use nu_protocol::{IntoRowStream, IntoValueStream, ShellError, Span, Value}; @@ -14,11 +12,11 @@ pub fn eval_operator(op: &Expression) -> Result { } } -fn eval_call(state: &EvaluationContext, call: &Call) -> Result { - let engine_state = state.engine_state.borrow(); +fn eval_call(context: &EvaluationContext, call: &Call) -> Result { + let engine_state = context.engine_state.borrow(); let decl = engine_state.get_decl(call.decl_id); if let Some(block_id) = decl.get_custom_command() { - let state = state.enter_scope(); + let state = context.enter_scope(); for (arg, param) in call.positional.iter().zip( decl.signature() .required_positional @@ -35,158 +33,21 @@ fn eval_call(state: &EvaluationContext, call: &Call) -> Result { - let engine_state = state.engine_state.borrow(); - if val { - let block = engine_state.get_block(then_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 = engine_state.get_block(block_id); - let state = state.enter_scope(); - eval_block(&state, block) - } else { - eval_expression(state, else_expr) - } - } else { - eval_expression(state, else_case) - } - } else { - Ok(Value::Nothing { span }) - } - } - _ => Err(ShellError::CantConvert("bool".into(), result.span())), - } - } else if decl.signature().name == "build-string" { - let mut output = vec![]; - - for expr in &call.positional { - let val = eval_expression(state, expr)?; - - output.push(val.into_string()); - } - Ok(Value::String { - val: output.join(""), - span: call.head, - }) - } else if decl.signature().name == "benchmark" { - let block = call.positional[0] - .as_block() - .expect("internal error: expected block"); - let engine_state = state.engine_state.borrow(); - let block = engine_state.get_block(block); - - let state = state.enter_scope(); - let start_time = Instant::now(); - eval_block(&state, block)?; - let end_time = Instant::now(); - println!("{} ms", (end_time - start_time).as_millis()); - Ok(Value::Nothing { - span: call.positional[0].span, - }) - } else if decl.signature().name == "for" { - let var_id = call.positional[0] - .as_var() - .expect("internal error: missing variable"); - - let keyword_expr = call.positional[1] - .as_keyword() - .expect("internal error: missing keyword"); - let end_val = eval_expression(state, keyword_expr)?; - - let block = call.positional[2] - .as_block() - .expect("internal error: expected block"); - let engine_state = state.engine_state.borrow(); - let block = engine_state.get_block(block); - - let state = state.enter_scope(); - - let mut x = Value::Int { - val: 0, - span: Span::unknown(), - }; - - loop { - if x == end_val { - break; - } else { - state.add_var(var_id, x.clone()); - eval_block(&state, block)?; - } - if let Value::Int { ref mut val, .. } = x { - *val += 1 - } - } - Ok(Value::Nothing { - span: call.positional[0].span, - }) - } else if decl.signature().name == "vars" { - state.engine_state.borrow().print_vars(); - Ok(Value::Nothing { span: call.head }) - } else if decl.signature().name == "decls" { - state.engine_state.borrow().print_decls(); - Ok(Value::Nothing { span: call.head }) - } else if decl.signature().name == "blocks" { - state.engine_state.borrow().print_blocks(); - Ok(Value::Nothing { span: call.head }) - } else if decl.signature().name == "stack" { - state.print_stack(); - Ok(Value::Nothing { span: call.head }) - } else if decl.signature().name == "def" || decl.signature().name == "alias" { - Ok(Value::Nothing { span: call.head }) } else { - Err(ShellError::Unsupported(call.head)) + decl.run( + context, + call, + Value::Nothing { + span: Span::unknown(), + }, + ) } } -pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result { +pub fn eval_expression( + context: &EvaluationContext, + expr: &Expression, +) -> Result { match &expr.expr { Expr::Bool(b) => Ok(Value::Bool { val: *b, @@ -200,17 +61,17 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result state + Expr::Var(var_id) => context .get_var(*var_id) .map_err(move |_| ShellError::VariableNotFound(expr.span)), - Expr::Call(call) => eval_call(state, call), + Expr::Call(call) => eval_call(context, 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, lhs)?; + let lhs = eval_expression(context, lhs)?; let op = eval_operator(op)?; - let rhs = eval_expression(state, rhs)?; + let rhs = eval_expression(context, rhs)?; match op { Operator::Plus => lhs.add(op_span, &rhs), @@ -228,10 +89,10 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result { - let engine_state = state.engine_state.borrow(); + let engine_state = context.engine_state.borrow(); let block = engine_state.get_block(*block_id); - let state = state.enter_scope(); + let state = context.enter_scope(); eval_block(&state, block) } Expr::Block(block_id) => Ok(Value::Block { @@ -241,7 +102,7 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result { let mut output = vec![]; for expr in x { - output.push(eval_expression(state, expr)?); + output.push(eval_expression(context, expr)?); } Ok(Value::List { val: output.into_value_stream(), @@ -251,14 +112,14 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result { let mut output_headers = vec![]; for expr in headers { - output_headers.push(eval_expression(state, expr)?.as_string()?); + output_headers.push(eval_expression(context, expr)?.as_string()?); } let mut output_rows = vec![]; for val in vals { let mut row = vec![]; for expr in val { - row.push(eval_expression(state, expr)?); + row.push(eval_expression(context, expr)?); } output_rows.push(row); } @@ -268,7 +129,7 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result eval_expression(state, expr), + Expr::Keyword(_, _, expr) => eval_expression(context, expr), Expr::String(s) => Ok(Value::String { val: s.clone(), span: expr.span, diff --git a/crates/nu-parser/src/errors.rs b/crates/nu-parser/src/errors.rs index 5f16a34711..bcd388c279 100644 --- a/crates/nu-parser/src/errors.rs +++ b/crates/nu-parser/src/errors.rs @@ -1,5 +1,4 @@ -use nu_protocol::{engine::StateWorkingSet, Span, Type}; -use std::ops::Range; +use nu_protocol::{Span, Type}; #[derive(Debug)] pub enum ParseError { diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 12e6584df8..60a3dbb0e8 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -7,7 +7,7 @@ use crate::{ use nu_protocol::{ ast::{Block, Call, Expr, Expression, Operator, Pipeline, Statement}, engine::StateWorkingSet, - span, BlockId, DeclId, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId, + span, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId, }; #[derive(Debug, Clone)] @@ -416,9 +416,6 @@ pub fn parse_internal_call( // Parse a positional arg if there is one if let Some(positional) = signature.get_positional(positional_idx) { - //Make sure we leave enough spans for the remaining positionals - let decl = working_set.get_decl(decl_id); - let end = calculate_end_span(working_set, &signature, spans, spans_idx, positional_idx); // println!( diff --git a/crates/nu-protocol/src/engine/command.rs b/crates/nu-protocol/src/engine/command.rs index 8e8118fc8d..246985fe38 100644 --- a/crates/nu-protocol/src/engine/command.rs +++ b/crates/nu-protocol/src/engine/command.rs @@ -1,6 +1,6 @@ -use crate::{BlockId, Example, ShellError, Signature, Value}; +use crate::{ast::Call, BlockId, Example, ShellError, Signature, Value}; -use super::CommandArgs; +use super::EvaluationContext; pub trait Command { fn name(&self) -> &str; @@ -15,19 +15,12 @@ pub trait Command { "" } - fn run(&self, args: CommandArgs) -> Result; - - // fn run(&self, args: CommandArgs) -> Result { - // let context = args.context.clone(); - // let stream = self.run_with_actions(args)?; - - // Ok(Box::new(crate::evaluate::internal::InternalIterator { - // context, - // input: stream, - // leftovers: InputStream::empty(), - // }) - // .into_output_stream()) - // } + fn run( + &self, + context: &EvaluationContext, + call: &Call, + input: Value, + ) -> Result; fn is_binary(&self) -> bool { false diff --git a/crates/nu-protocol/src/engine/command_args.rs b/crates/nu-protocol/src/engine/command_args.rs deleted file mode 100644 index a9468e0118..0000000000 --- a/crates/nu-protocol/src/engine/command_args.rs +++ /dev/null @@ -1,7 +0,0 @@ -use super::{EvaluationContext, UnevaluatedCallInfo}; - -pub struct CommandArgs { - pub context: EvaluationContext, - pub call_info: UnevaluatedCallInfo, - pub input: crate::Value, -} diff --git a/crates/nu-protocol/src/engine/mod.rs b/crates/nu-protocol/src/engine/mod.rs index 68ffac9616..e6b7eb5d3d 100644 --- a/crates/nu-protocol/src/engine/mod.rs +++ b/crates/nu-protocol/src/engine/mod.rs @@ -1,11 +1,9 @@ mod call_info; mod command; -mod command_args; mod engine_state; mod evaluation_context; pub use call_info::*; pub use command::*; -pub use command_args::*; pub use engine_state::*; pub use evaluation_context::*; diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index a797ecbf4b..aa89f9474c 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -1,6 +1,9 @@ +use crate::ast::Call; use crate::engine::Command; +use crate::engine::EvaluationContext; use crate::BlockId; use crate::SyntaxShape; +use crate::Value; use crate::VarId; #[derive(Debug, Clone)] @@ -315,7 +318,12 @@ impl Command for Predeclaration { &self.signature.usage } - fn run(&self, _args: crate::engine::CommandArgs) -> Result { + fn run( + &self, + _context: &EvaluationContext, + _call: &Call, + _input: Value, + ) -> Result { panic!("Internal error: can't run a predeclaration without a body") } } @@ -338,7 +346,12 @@ impl Command for BlockCommand { &self.signature.usage } - fn run(&self, _args: crate::engine::CommandArgs) -> Result { + fn run( + &self, + _context: &EvaluationContext, + _call: &Call, + _input: Value, + ) -> Result { panic!("Internal error: can't run custom command with 'run', use block_id"); } diff --git a/src/main.rs b/src/main.rs index 030386a055..f1d595f89f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -use nu_cli::{create_default_context, report_parsing_error, report_shell_error, NuHighlighter}; +use nu_cli::{report_parsing_error, report_shell_error, NuHighlighter}; +use nu_command::create_default_context; use nu_engine::eval_block; use nu_parser::parse_file; use nu_protocol::engine::{EngineState, EvaluationContext, StateWorkingSet}; @@ -68,8 +69,19 @@ fn main() -> std::io::Result<()> { Ok(Signal::Success(s)) => { if s.trim() == "exit" { break; + } else if s.trim() == "vars" { + engine_state.borrow().print_vars(); + continue; + } else if s.trim() == "decls" { + engine_state.borrow().print_decls(); + continue; + } else if s.trim() == "blocks" { + engine_state.borrow().print_blocks(); + continue; + } else if s.trim() == "stack" { + stack.print_stack(); + continue; } - // println!("input: '{}'", s); let (block, delta) = { let engine_state = engine_state.borrow();