Add commands

This commit is contained in:
JT 2021-09-03 10:58:15 +12:00
parent 94687a7603
commit 7c8504ea24
23 changed files with 536 additions and 324 deletions

5
Cargo.lock generated
View file

@ -162,6 +162,7 @@ dependencies = [
"assert_cmd", "assert_cmd",
"codespan-reporting", "codespan-reporting",
"nu-cli", "nu-cli",
"nu-command",
"nu-engine", "nu-engine",
"nu-parser", "nu-parser",
"nu-protocol", "nu-protocol",
@ -300,6 +301,10 @@ dependencies = [
[[package]] [[package]]
name = "nu-command" name = "nu-command"
version = "0.1.0" version = "0.1.0"
dependencies = [
"nu-engine",
"nu-protocol",
]
[[package]] [[package]]
name = "nu-engine" name = "nu-engine"

View file

@ -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" } reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" }
codespan-reporting = "0.11.1" codespan-reporting = "0.11.1"
nu-cli = { path="./crates/nu-cli" } nu-cli = { path="./crates/nu-cli" }
nu-command = { path="./crates/nu-command" }
nu-engine = { path="./crates/nu-engine" } nu-engine = { path="./crates/nu-engine" }
nu-parser = { path="./crates/nu-parser" } nu-parser = { path="./crates/nu-parser" }
nu-protocol = { path = "./crates/nu-protocol" } nu-protocol = { path = "./crates/nu-protocol" }

View file

@ -1,118 +0,0 @@
use std::{cell::RefCell, rc::Rc};
use nu_protocol::{
engine::{EngineState, StateWorkingSet},
Signature, SyntaxShape,
};
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
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
}

View file

@ -1,7 +1,5 @@
mod default_context;
mod errors; mod errors;
mod syntax_highlight; mod syntax_highlight;
pub use default_context::create_default_context;
pub use errors::{report_parsing_error, report_shell_error}; pub use errors::{report_parsing_error, report_shell_error};
pub use syntax_highlight::NuHighlighter; pub use syntax_highlight::NuHighlighter;

View file

@ -6,3 +6,5 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
nu-protocol = { path = "../nu-protocol" }
nu-engine = { path = "../nu-engine" }

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
}
}

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
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,
})
}
}

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
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,
})
}
}

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
}
}

View file

@ -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<RefCell<EngineState>> {
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
}

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
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,
})
}
}

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
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())),
}
}
}

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
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,
})
}
}

View file

@ -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<nu_protocol::Value, nu_protocol::ShellError> {
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,
})
}
}

View file

@ -1,7 +1,19 @@
#[cfg(test)] mod alias;
mod tests { mod benchmark;
#[test] mod build_string;
fn it_works() { mod def;
assert_eq!(2 + 2, 4); 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;

View file

@ -1,5 +1,3 @@
use std::time::Instant;
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement}; use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement};
use nu_protocol::engine::EvaluationContext; use nu_protocol::engine::EvaluationContext;
use nu_protocol::{IntoRowStream, IntoValueStream, ShellError, Span, Value}; use nu_protocol::{IntoRowStream, IntoValueStream, ShellError, Span, Value};
@ -14,11 +12,11 @@ pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
} }
} }
fn eval_call(state: &EvaluationContext, call: &Call) -> Result<Value, ShellError> { fn eval_call(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
let engine_state = state.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let decl = engine_state.get_decl(call.decl_id); let decl = engine_state.get_decl(call.decl_id);
if let Some(block_id) = decl.get_custom_command() { 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( for (arg, param) in call.positional.iter().zip(
decl.signature() decl.signature()
.required_positional .required_positional
@ -35,158 +33,21 @@ fn eval_call(state: &EvaluationContext, call: &Call) -> Result<Value, ShellError
let engine_state = state.engine_state.borrow(); let engine_state = state.engine_state.borrow();
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
eval_block(&state, block) eval_block(&state, block)
} else if decl.signature().name == "let" {
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(state, keyword_expr)?;
//println!("Adding: {:?} to {}", rhs, var_id);
state.add_var(var_id, rhs);
Ok(Value::Nothing {
span: call.positional[0].span,
})
} else if decl.signature().name == "let-env" {
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(state, keyword_expr)?;
let rhs = rhs.as_string()?;
//println!("Adding: {:?} to {}", rhs, var_id);
state.add_env_var(env_var, rhs);
Ok(Value::Nothing {
span: call.positional[0].span,
})
} else if decl.signature().name == "if" {
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(state, cond)?;
match result {
Value::Bool { val, span } => {
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 { } else {
Err(ShellError::Unsupported(call.head)) decl.run(
context,
call,
Value::Nothing {
span: Span::unknown(),
},
)
} }
} }
pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result<Value, ShellError> { pub fn eval_expression(
context: &EvaluationContext,
expr: &Expression,
) -> Result<Value, ShellError> {
match &expr.expr { match &expr.expr {
Expr::Bool(b) => Ok(Value::Bool { Expr::Bool(b) => Ok(Value::Bool {
val: *b, val: *b,
@ -200,17 +61,17 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result<V
val: *f, val: *f,
span: expr.span, span: expr.span,
}), }),
Expr::Var(var_id) => state Expr::Var(var_id) => context
.get_var(*var_id) .get_var(*var_id)
.map_err(move |_| ShellError::VariableNotFound(expr.span)), .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::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }), Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
Expr::BinaryOp(lhs, op, rhs) => { Expr::BinaryOp(lhs, op, rhs) => {
let op_span = op.span; let op_span = op.span;
let lhs = eval_expression(state, lhs)?; let lhs = eval_expression(context, lhs)?;
let op = eval_operator(op)?; let op = eval_operator(op)?;
let rhs = eval_expression(state, rhs)?; let rhs = eval_expression(context, rhs)?;
match op { match op {
Operator::Plus => lhs.add(op_span, &rhs), Operator::Plus => lhs.add(op_span, &rhs),
@ -228,10 +89,10 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result<V
} }
Expr::Subexpression(block_id) => { Expr::Subexpression(block_id) => {
let engine_state = state.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(*block_id); let block = engine_state.get_block(*block_id);
let state = state.enter_scope(); let state = context.enter_scope();
eval_block(&state, block) eval_block(&state, block)
} }
Expr::Block(block_id) => Ok(Value::Block { Expr::Block(block_id) => Ok(Value::Block {
@ -241,7 +102,7 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result<V
Expr::List(x) => { Expr::List(x) => {
let mut output = vec![]; let mut output = vec![];
for expr in x { for expr in x {
output.push(eval_expression(state, expr)?); output.push(eval_expression(context, expr)?);
} }
Ok(Value::List { Ok(Value::List {
val: output.into_value_stream(), val: output.into_value_stream(),
@ -251,14 +112,14 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result<V
Expr::Table(headers, vals) => { Expr::Table(headers, vals) => {
let mut output_headers = vec![]; let mut output_headers = vec![];
for expr in headers { 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![]; let mut output_rows = vec![];
for val in vals { for val in vals {
let mut row = vec![]; let mut row = vec![];
for expr in val { for expr in val {
row.push(eval_expression(state, expr)?); row.push(eval_expression(context, expr)?);
} }
output_rows.push(row); output_rows.push(row);
} }
@ -268,7 +129,7 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result<V
span: expr.span, span: expr.span,
}) })
} }
Expr::Keyword(_, _, expr) => eval_expression(state, expr), Expr::Keyword(_, _, expr) => eval_expression(context, expr),
Expr::String(s) => Ok(Value::String { Expr::String(s) => Ok(Value::String {
val: s.clone(), val: s.clone(),
span: expr.span, span: expr.span,

View file

@ -1,5 +1,4 @@
use nu_protocol::{engine::StateWorkingSet, Span, Type}; use nu_protocol::{Span, Type};
use std::ops::Range;
#[derive(Debug)] #[derive(Debug)]
pub enum ParseError { pub enum ParseError {

View file

@ -7,7 +7,7 @@ use crate::{
use nu_protocol::{ use nu_protocol::{
ast::{Block, Call, Expr, Expression, Operator, Pipeline, Statement}, ast::{Block, Call, Expr, Expression, Operator, Pipeline, Statement},
engine::StateWorkingSet, engine::StateWorkingSet,
span, BlockId, DeclId, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId, span, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -416,9 +416,6 @@ pub fn parse_internal_call(
// Parse a positional arg if there is one // Parse a positional arg if there is one
if let Some(positional) = signature.get_positional(positional_idx) { 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); let end = calculate_end_span(working_set, &signature, spans, spans_idx, positional_idx);
// println!( // println!(

View file

@ -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 { pub trait Command {
fn name(&self) -> &str; fn name(&self) -> &str;
@ -15,19 +15,12 @@ pub trait Command {
"" ""
} }
fn run(&self, args: CommandArgs) -> Result<Value, ShellError>; fn run(
&self,
// fn run(&self, args: CommandArgs) -> Result<InputStream, ShellError> { context: &EvaluationContext,
// let context = args.context.clone(); call: &Call,
// let stream = self.run_with_actions(args)?; input: Value,
) -> Result<Value, ShellError>;
// Ok(Box::new(crate::evaluate::internal::InternalIterator {
// context,
// input: stream,
// leftovers: InputStream::empty(),
// })
// .into_output_stream())
// }
fn is_binary(&self) -> bool { fn is_binary(&self) -> bool {
false false

View file

@ -1,7 +0,0 @@
use super::{EvaluationContext, UnevaluatedCallInfo};
pub struct CommandArgs {
pub context: EvaluationContext,
pub call_info: UnevaluatedCallInfo,
pub input: crate::Value,
}

View file

@ -1,11 +1,9 @@
mod call_info; mod call_info;
mod command; mod command;
mod command_args;
mod engine_state; mod engine_state;
mod evaluation_context; mod evaluation_context;
pub use call_info::*; pub use call_info::*;
pub use command::*; pub use command::*;
pub use command_args::*;
pub use engine_state::*; pub use engine_state::*;
pub use evaluation_context::*; pub use evaluation_context::*;

View file

@ -1,6 +1,9 @@
use crate::ast::Call;
use crate::engine::Command; use crate::engine::Command;
use crate::engine::EvaluationContext;
use crate::BlockId; use crate::BlockId;
use crate::SyntaxShape; use crate::SyntaxShape;
use crate::Value;
use crate::VarId; use crate::VarId;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -315,7 +318,12 @@ impl Command for Predeclaration {
&self.signature.usage &self.signature.usage
} }
fn run(&self, _args: crate::engine::CommandArgs) -> Result<crate::Value, crate::ShellError> { fn run(
&self,
_context: &EvaluationContext,
_call: &Call,
_input: Value,
) -> Result<crate::Value, crate::ShellError> {
panic!("Internal error: can't run a predeclaration without a body") panic!("Internal error: can't run a predeclaration without a body")
} }
} }
@ -338,7 +346,12 @@ impl Command for BlockCommand {
&self.signature.usage &self.signature.usage
} }
fn run(&self, _args: crate::engine::CommandArgs) -> Result<crate::Value, crate::ShellError> { fn run(
&self,
_context: &EvaluationContext,
_call: &Call,
_input: Value,
) -> Result<crate::Value, crate::ShellError> {
panic!("Internal error: can't run custom command with 'run', use block_id"); panic!("Internal error: can't run custom command with 'run', use block_id");
} }

View file

@ -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_engine::eval_block;
use nu_parser::parse_file; use nu_parser::parse_file;
use nu_protocol::engine::{EngineState, EvaluationContext, StateWorkingSet}; use nu_protocol::engine::{EngineState, EvaluationContext, StateWorkingSet};
@ -68,8 +69,19 @@ fn main() -> std::io::Result<()> {
Ok(Signal::Success(s)) => { Ok(Signal::Success(s)) => {
if s.trim() == "exit" { if s.trim() == "exit" {
break; 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 (block, delta) = {
let engine_state = engine_state.borrow(); let engine_state = engine_state.borrow();