mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
Add commands
This commit is contained in:
parent
94687a7603
commit
7c8504ea24
23 changed files with 536 additions and 324 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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" }
|
34
crates/nu-command/src/alias.rs
Normal file
34
crates/nu-command/src/alias.rs
Normal 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 })
|
||||
}
|
||||
}
|
44
crates/nu-command/src/benchmark.rs
Normal file
44
crates/nu-command/src/benchmark.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
39
crates/nu-command/src/build_string.rs
Normal file
39
crates/nu-command/src/build_string.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
31
crates/nu-command/src/def.rs
Normal file
31
crates/nu-command/src/def.rs
Normal 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 })
|
||||
}
|
||||
}
|
55
crates/nu-command/src/default_context.rs
Normal file
55
crates/nu-command/src/default_context.rs
Normal 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
|
||||
}
|
75
crates/nu-command/src/for_.rs
Normal file
75
crates/nu-command/src/for_.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
67
crates/nu-command/src/if_.rs
Normal file
67
crates/nu-command/src/if_.rs
Normal 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())),
|
||||
}
|
||||
}
|
||||
}
|
50
crates/nu-command/src/let_.rs
Normal file
50
crates/nu-command/src/let_.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
51
crates/nu-command/src/let_env.rs
Normal file
51
crates/nu-command/src/let_env.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<Operator, ShellError> {
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_call(state: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
|
||||
let engine_state = state.engine_state.borrow();
|
||||
fn eval_call(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
|
||||
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<Value, ShellError
|
|||
let engine_state = state.engine_state.borrow();
|
||||
let block = engine_state.get_block(block_id);
|
||||
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,
|
||||
decl.run(
|
||||
context,
|
||||
call,
|
||||
Value::Nothing {
|
||||
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))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
Expr::Bool(b) => Ok(Value::Bool {
|
||||
val: *b,
|
||||
|
@ -200,17 +61,17 @@ pub fn eval_expression(state: &EvaluationContext, expr: &Expression) -> Result<V
|
|||
val: *f,
|
||||
span: expr.span,
|
||||
}),
|
||||
Expr::Var(var_id) => 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<V
|
|||
}
|
||||
|
||||
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 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<V
|
|||
Expr::List(x) => {
|
||||
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<V
|
|||
Expr::Table(headers, vals) => {
|
||||
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<V
|
|||
span: expr.span,
|
||||
})
|
||||
}
|
||||
Expr::Keyword(_, _, expr) => eval_expression(state, expr),
|
||||
Expr::Keyword(_, _, expr) => eval_expression(context, expr),
|
||||
Expr::String(s) => Ok(Value::String {
|
||||
val: s.clone(),
|
||||
span: expr.span,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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<Value, ShellError>;
|
||||
|
||||
// fn run(&self, args: CommandArgs) -> Result<InputStream, ShellError> {
|
||||
// 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<Value, ShellError>;
|
||||
|
||||
fn is_binary(&self) -> bool {
|
||||
false
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
use super::{EvaluationContext, UnevaluatedCallInfo};
|
||||
|
||||
pub struct CommandArgs {
|
||||
pub context: EvaluationContext,
|
||||
pub call_info: UnevaluatedCallInfo,
|
||||
pub input: crate::Value,
|
||||
}
|
|
@ -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::*;
|
||||
|
|
|
@ -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<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")
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +346,12 @@ impl Command for BlockCommand {
|
|||
&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");
|
||||
}
|
||||
|
||||
|
|
16
src/main.rs
16
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();
|
||||
|
|
Loading…
Reference in a new issue