From f052b3313d8831e78bcc6ea4a6e034c2f3550636 Mon Sep 17 00:00:00 2001 From: JT <547158+jntrnr@users.noreply.github.com> Date: Fri, 26 Nov 2021 16:49:03 +1300 Subject: [PATCH] Move row condition to block (#368) --- crates/nu-command/src/filters/where_.rs | 26 ++-- crates/nu-command/src/formats/to/json.rs | 159 +++-------------------- crates/nu-engine/src/eval.rs | 3 +- crates/nu-parser/src/flatten.rs | 3 +- crates/nu-parser/src/parser.rs | 37 ++++-- crates/nu-protocol/src/ast/expr.rs | 2 +- crates/nu-protocol/src/ast/expression.rs | 6 +- 7 files changed, 65 insertions(+), 171 deletions(-) diff --git a/crates/nu-command/src/filters/where_.rs b/crates/nu-command/src/filters/where_.rs index e556b8fef2..c411d2fe51 100644 --- a/crates/nu-command/src/filters/where_.rs +++ b/crates/nu-command/src/filters/where_.rs @@ -1,4 +1,4 @@ -use nu_engine::eval_expression; +use nu_engine::eval_block; use nu_protocol::ast::{Call, Expr, Expression}; use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{Category, PipelineData, ShellError, Signature, SyntaxShape}; @@ -28,30 +28,34 @@ impl Command for Where { call: &Call, input: PipelineData, ) -> Result { + let span = call.head; let cond = call.positional[0].clone(); let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); - // FIXME: expensive - let mut stack = stack.clone(); - - let (var_id, cond) = match cond { + let block_id = match cond { Expression { - expr: Expr::RowCondition(var_id, expr), + expr: Expr::RowCondition(block_id), .. - } => (var_id, expr), + } => block_id, _ => return Err(ShellError::InternalError("Expected row condition".into())), }; + let block = engine_state.get_block(block_id).clone(); + let mut stack = stack.collect_captures(&block.captures); + input.filter( move |value| { - stack.add_var(var_id, value.clone()); - - let result = eval_expression(&engine_state, &mut stack, &cond); + if let Some(var) = block.signature.get_positional(0) { + if let Some(var_id) = &var.var_id { + stack.add_var(*var_id, value.clone()); + } + } + let result = eval_block(&engine_state, &mut stack, &block, PipelineData::new(span)); match result { - Ok(result) => result.is_true(), + Ok(result) => result.into_value(span).is_true(), _ => false, } }, diff --git a/crates/nu-command/src/formats/to/json.rs b/crates/nu-command/src/formats/to/json.rs index 15804f1ec3..e15b4679b7 100644 --- a/crates/nu-command/src/formats/to/json.rs +++ b/crates/nu-command/src/formats/to/json.rs @@ -1,8 +1,7 @@ use nu_protocol::ast::{Call, PathMember}; use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{ - Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, - Signature, Value, + Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Value, }; #[derive(Clone)] @@ -15,12 +14,6 @@ impl Command for ToJson { fn signature(&self) -> Signature { Signature::build("to json").category(Category::Formats) - // .named( - // "pretty", - // SyntaxShape::Int, - // "Formats the JSON text with the provided indentation setting", - // Some('p'), - // ) } fn usage(&self) -> &str { @@ -29,12 +22,12 @@ impl Command for ToJson { fn run( &self, - engine_state: &EngineState, + _engine_state: &EngineState, _stack: &mut Stack, call: &Call, input: PipelineData, ) -> Result { - to_json(engine_state, call, input) + to_json(call, input) } fn examples(&self) -> Vec { @@ -95,143 +88,23 @@ fn json_list(input: &[Value]) -> Result, ShellError> { Ok(out) } -fn to_json( - engine_state: &EngineState, - call: &Call, - input: PipelineData, -) -> Result { - let name_span = call.head; - // let pretty: Option = args.get_flag("pretty")?; +fn to_json(call: &Call, input: PipelineData) -> Result { + let span = call.head; - //let input: Vec = input.collect(); + let value = input.into_value(span); - // let to_process_input = match input.len() { - // x if x > 1 => { - // let tag = input[0].tag.clone(); - // vec![Value:: { - // value: UntaggedValue::Table(input), - // tag, - // }] - // } - // 1 => input, - // _ => vec![], - // }; - - match input { - PipelineData::Value(value) => { - let json_value = value_to_json_value(&value)?; - match nu_json::to_string(&json_value) { - Ok(serde_json_string) => Ok(Value::String { - val: serde_json_string, - span: name_span, - } - .into_pipeline_data()), - _ => Ok(Value::Error { - error: ShellError::CantConvert( - "JSON".into(), - value.get_type().to_string(), - name_span, - ), - } - .into_pipeline_data()), - } + let json_value = value_to_json_value(&value)?; + match nu_json::to_string(&json_value) { + Ok(serde_json_string) => Ok(Value::String { + val: serde_json_string, + span, } - PipelineData::Stream(stream) => Ok(stream - .map(move |value| { - if let Ok(json_value) = value_to_json_value(&value) { - match nu_json::to_string(&json_value) { - Ok(serde_json_string) => Value::String { - val: serde_json_string, - span: name_span, - }, - _ => Value::Error { - error: ShellError::CantConvert( - "JSON".into(), - value.get_type().to_string(), - name_span, - ), - }, - } - } else { - Value::Error { - error: ShellError::CantConvert( - "JSON".into(), - value.get_type().to_string(), - name_span, - ), - } - } - }) - .into_pipeline_data(engine_state.ctrlc.clone())), + .into_pipeline_data()), + _ => Ok(Value::Error { + error: ShellError::CantConvert("JSON".into(), value.get_type().to_string(), span), + } + .into_pipeline_data()), } - // input - // // .into_iter() - // .map( - // move |value| { - // let value_span = value.span().expect("non-error"); - // match value_to_json_value(&value) { - // Ok(json_value) => { - // match nu_json::to_string(&json_value) { - // Ok(serde_json_string) => { - // // if let Some(pretty_value) = &pretty { - // // let mut pretty_format_failed = true; - - // // if let Ok(pretty_u64) = pretty_value.as_u64() { - // // if let Ok(serde_json_value) = - // // serde_json::from_str::(&serde_json_string) - // // { - // // let indentation_string = " ".repeat(pretty_u64 as usize); - // // let serde_formatter = - // // serde_json::ser::PrettyFormatter::with_indent( - // // indentation_string.as_bytes(), - // // ); - // // let serde_buffer = Vec::new(); - // // let mut serde_serializer = - // // serde_json::Serializer::with_formatter( - // // serde_buffer, - // // serde_formatter, - // // ); - // // let serde_json_object = json!(serde_json_value); - - // // if let Ok(()) = - // // serde_json_object.serialize(&mut serde_serializer) - // // { - // // if let Ok(ser_json_string) = - // // String::from_utf8(serde_serializer.into_inner()) - // // { - // // pretty_format_failed = false; - // // serde_json_string = ser_json_string - // // } - // // } - // // } - // // } - - // // if pretty_format_failed { - // // return Value::error(ShellError::labeled_error( - // // "Pretty formatting failed", - // // "failed", - // // pretty_value.tag(), - // // )); - // // } - // // } - - // Value::String { - // val: serde_json_string, - // span: value_span, - // } - // } - // _ => Value::Error { - // error: ShellError::CantConvert("JSON".into(), value_span), - // }, - // } - // } - // _ => Value::Error { - // error: ShellError::CantConvert("JSON".into(), value_span), - // }, - // } - // }, - // engine_state.ctrlc.clone(), - // ) } #[cfg(test)] diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index ae1c4e9c7c..52f20c47bf 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -228,7 +228,6 @@ pub fn eval_expression( Expr::ImportPattern(_) => Ok(Value::Nothing { span: Span::unknown(), }), - Expr::RowCondition(_, expr) => eval_expression(engine_state, stack, expr), Expr::Call(call) => { // FIXME: protect this collect with ctrl-c Ok( @@ -277,7 +276,7 @@ pub fn eval_expression( Operator::Pow => lhs.pow(op_span, &rhs), } } - Expr::Subexpression(block_id) => { + Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let block = engine_state.get_block(*block_id); // FIXME: protect this collect with ctrl-c diff --git a/crates/nu-parser/src/flatten.rs b/crates/nu-parser/src/flatten.rs index 1f4ea5e754..d9a23b18e1 100644 --- a/crates/nu-parser/src/flatten.rs +++ b/crates/nu-parser/src/flatten.rs @@ -207,8 +207,7 @@ pub fn flatten_expression( Expr::String(_) => { vec![(expr.span, FlatShape::String)] } - Expr::RowCondition(_, expr) => flatten_expression(working_set, expr), - Expr::Subexpression(block_id) => { + Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { flatten_block(working_set, working_set.get_block(*block_id)) } Expr::Table(headers, cells) => { diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 120fe9fcae..ed67800ded 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1990,11 +1990,38 @@ pub fn parse_row_condition( let var_id = working_set.add_variable(b"$it".to_vec(), Type::Unknown); let (expression, err) = parse_math_expression(working_set, spans, Some(var_id)); let span = span(spans); + + let block_id = match expression.expr { + Expr::Block(block_id) => block_id, + _ => { + // We have an expression, so let's convert this into a block. + let mut block = Block::new(); + let mut pipeline = Pipeline::new(); + pipeline.expressions.push(expression); + + block.stmts.push(Statement::Pipeline(pipeline)); + + block.signature.required_positional.push(PositionalArg { + name: "$it".into(), + desc: "row condition".into(), + shape: SyntaxShape::Any, + var_id: Some(var_id), + }); + + let mut seen = vec![]; + let captures = find_captures_in_block(working_set, &block, &mut seen); + + block.captures = captures; + + working_set.add_block(block) + } + }; + ( Expression { ty: Type::Bool, span, - expr: Expr::RowCondition(var_id, Box::new(expression)), + expr: Expr::RowCondition(block_id), custom_completion: None, }, err, @@ -3481,15 +3508,9 @@ pub fn find_captures_in_expr( output.extend(&find_captures_in_expr(working_set, field_value, seen)); } } - Expr::RowCondition(var_id, expr) => { - seen.push(*var_id); - - let result = find_captures_in_expr(working_set, expr, seen); - output.extend(&result); - } Expr::Signature(_) => {} Expr::String(_) => {} - Expr::Subexpression(block_id) => { + Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let block = working_set.get_block(*block_id); let result = find_captures_in_block(working_set, block, seen); output.extend(&result); diff --git a/crates/nu-protocol/src/ast/expr.rs b/crates/nu-protocol/src/ast/expr.rs index 763347f147..bdd0c61e8d 100644 --- a/crates/nu-protocol/src/ast/expr.rs +++ b/crates/nu-protocol/src/ast/expr.rs @@ -17,7 +17,7 @@ pub enum Expr { Call(Box), ExternalCall(String, Span, Vec), Operator(Operator), - RowCondition(VarId, Box), + RowCondition(BlockId), BinaryOp(Box, Box, Box), //lhs, op, rhs Subexpression(BlockId), Block(BlockId), diff --git a/crates/nu-protocol/src/ast/expression.rs b/crates/nu-protocol/src/ast/expression.rs index 11b0ac706f..b3cf0743a7 100644 --- a/crates/nu-protocol/src/ast/expression.rs +++ b/crates/nu-protocol/src/ast/expression.rs @@ -182,10 +182,9 @@ impl Expression { } false } - Expr::RowCondition(_, expr) => expr.has_in_variable(working_set), Expr::Signature(_) => false, Expr::String(_) => false, - Expr::Subexpression(block_id) => { + Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let block = working_set.get_block(*block_id); if let Some(Statement::Pipeline(pipeline)) = block.stmts.get(0) { @@ -311,10 +310,9 @@ impl Expression { field_value.replace_in_variable(working_set, new_var_id); } } - Expr::RowCondition(_, expr) => expr.replace_in_variable(working_set, new_var_id), Expr::Signature(_) => {} Expr::String(_) => {} - Expr::Subexpression(block_id) => { + Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let block = working_set.get_block(*block_id); let new_expr = if let Some(Statement::Pipeline(pipeline)) = block.stmts.get(0) {