Add row conditions

This commit is contained in:
JT
2021-09-10 09:47:20 +12:00
parent b821b14987
commit bb6781a3b1
11 changed files with 195 additions and 22 deletions

View File

@ -5,7 +5,9 @@ use nu_protocol::{
Signature, SyntaxShape,
};
use crate::{Alias, Benchmark, BuildString, Def, Do, Each, For, If, Length, Let, LetEnv};
use crate::{
where_::Where, Alias, Benchmark, BuildString, Def, Do, Each, For, If, Length, Let, LetEnv,
};
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
let engine_state = Rc::new(RefCell::new(EngineState::new()));
@ -33,6 +35,8 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
working_set.add_decl(Box::new(Each));
working_set.add_decl(Box::new(Where));
working_set.add_decl(Box::new(Do));
working_set.add_decl(Box::new(Benchmark));

View File

@ -11,7 +11,7 @@ impl Command for If {
}
fn usage(&self) -> &str {
"Create a variable and give it a value."
"Conditionally run a block."
}
fn signature(&self) -> nu_protocol::Signature {

View File

@ -10,6 +10,7 @@ mod if_;
mod length;
mod let_;
mod let_env;
mod where_;
pub use alias::Alias;
pub use benchmark::Benchmark;

View File

@ -0,0 +1,92 @@
use nu_engine::eval_expression;
use nu_protocol::ast::{Call, Expr, Expression};
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{IntoValueStream, ShellError, Signature, SyntaxShape, Value};
pub struct Where;
impl Command for Where {
fn name(&self) -> &str {
"where"
}
fn usage(&self) -> &str {
"Filter values based on a condition."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("where").required("cond", SyntaxShape::RowCondition, "condition")
}
fn run(
&self,
context: &EvaluationContext,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let cond = call.positional[0].clone();
let context = context.enter_scope();
let (var_id, cond) = match cond {
Expression {
expr: Expr::RowCondition(var_id, expr),
..
} => (var_id, expr),
_ => return Err(ShellError::InternalError("Expected row condition".into())),
};
match input {
Value::Stream { stream, span } => {
let output_stream = stream
.filter(move |value| {
context.add_var(var_id, value.clone());
let result = eval_expression(&context, &cond);
match result {
Ok(result) => result.is_true(),
_ => false,
}
})
.into_value_stream();
Ok(Value::Stream {
stream: output_stream,
span,
})
}
Value::List { vals, span } => {
let output_stream = vals
.into_iter()
.filter(move |value| {
context.add_var(var_id, value.clone());
let result = eval_expression(&context, &cond);
match result {
Ok(result) => result.is_true(),
_ => false,
}
})
.into_value_stream();
Ok(Value::Stream {
stream: output_stream,
span,
})
}
x => {
context.add_var(var_id, x.clone());
let result = eval_expression(&context, &cond)?;
if result.is_true() {
Ok(x)
} else {
Ok(Value::Nothing { span: call.head })
}
}
}
}
}