From 02b80277496a07c8fe1d67883e1e459a21120b82 Mon Sep 17 00:00:00 2001 From: JT <547158+jntrnr@users.noreply.github.com> Date: Sat, 6 Nov 2021 18:50:33 +1300 Subject: [PATCH] Improve external output in subexprs (#294) --- crates/nu-cli/src/completions.rs | 8 +- .../src/conversions/into/filesize.rs | 2 +- crates/nu-command/src/conversions/into/int.rs | 6 +- .../nu-command/src/conversions/into/string.rs | 7 +- crates/nu-command/src/core_commands/alias.rs | 4 +- crates/nu-command/src/core_commands/def.rs | 4 +- crates/nu-command/src/core_commands/echo.rs | 6 +- .../src/core_commands/export_def.rs | 4 +- crates/nu-command/src/core_commands/for_.rs | 11 +-- crates/nu-command/src/core_commands/hide.rs | 4 +- crates/nu-command/src/core_commands/if_.rs | 12 ++- crates/nu-command/src/core_commands/let_.rs | 2 +- crates/nu-command/src/core_commands/module.rs | 4 +- .../nu-command/src/core_commands/register.rs | 4 +- crates/nu-command/src/core_commands/use_.rs | 4 +- crates/nu-command/src/date/to_timezone.rs | 2 +- crates/nu-command/src/env/let_env.rs | 2 +- crates/nu-command/src/env/with_env.rs | 12 ++- crates/nu-command/src/example_test.rs | 11 ++- crates/nu-command/src/experimental/git.rs | 4 +- .../src/experimental/git_checkout.rs | 4 +- .../src/experimental/list_git_branches.rs | 4 +- crates/nu-command/src/filesystem/cd.rs | 2 +- crates/nu-command/src/filesystem/cp.rs | 2 +- crates/nu-command/src/filesystem/mv.rs | 2 +- crates/nu-command/src/filesystem/touch.rs | 2 +- crates/nu-command/src/filters/each.rs | 10 +-- crates/nu-command/src/filters/par_each.rs | 12 +-- crates/nu-command/src/filters/where_.rs | 3 +- crates/nu-command/src/formats/from/command.rs | 4 +- crates/nu-command/src/formats/from/json.rs | 7 +- crates/nu-command/src/formats/to/command.rs | 4 +- crates/nu-command/src/formats/to/json.rs | 18 ++++- crates/nu-command/src/math/max.rs | 2 +- crates/nu-command/src/math/min.rs | 2 +- crates/nu-command/src/math/product.rs | 2 +- crates/nu-command/src/math/reducers.rs | 10 +-- crates/nu-command/src/math/sum.rs | 2 +- .../nu-command/src/strings/format/command.rs | 5 +- crates/nu-command/src/system/benchmark.rs | 8 +- crates/nu-command/src/system/run_external.rs | 13 ++-- crates/nu-command/src/viewers/griddle.rs | 4 +- crates/nu-command/src/viewers/table.rs | 4 +- crates/nu-engine/src/eval.rs | 78 +++++++++++++++++-- crates/nu-engine/src/from_value.rs | 72 ++++++++++++++--- crates/nu-parser/src/parser.rs | 3 +- crates/nu-protocol/src/pipeline_data.rs | 18 ++--- crates/nu-protocol/src/shell_error.rs | 2 +- crates/nu-protocol/src/value/mod.rs | 19 +++-- src/main.rs | 25 ++++-- 50 files changed, 320 insertions(+), 136 deletions(-) diff --git a/crates/nu-cli/src/completions.rs b/crates/nu-cli/src/completions.rs index 43f7f9222..18ac4f7ec 100644 --- a/crates/nu-cli/src/completions.rs +++ b/crates/nu-cli/src/completions.rs @@ -72,8 +72,12 @@ impl Completer for NuCompleter { parse(&mut working_set, None, custom_completion.as_bytes(), false); let mut stack = Stack::default(); - let result = - eval_block(&self.engine_state, &mut stack, &block, PipelineData::new()); + let result = eval_block( + &self.engine_state, + &mut stack, + &block, + PipelineData::new(flat.0), + ); let v: Vec<_> = match result { Ok(pd) => pd diff --git a/crates/nu-command/src/conversions/into/filesize.rs b/crates/nu-command/src/conversions/into/filesize.rs index d17ceec8f..6336c7219 100644 --- a/crates/nu-command/src/conversions/into/filesize.rs +++ b/crates/nu-command/src/conversions/into/filesize.rs @@ -131,7 +131,7 @@ pub fn action(input: &Value, span: Span) -> Value { fn int_from_string(a_string: &str, span: Span) -> Result { match a_string.parse::() { Ok(n) => Ok(n.0 as i64), - Err(_) => Err(ShellError::CantConvert("int".into(), span)), + Err(_) => Err(ShellError::CantConvert("int".into(), "string".into(), span)), } } diff --git a/crates/nu-command/src/conversions/into/int.rs b/crates/nu-command/src/conversions/into/int.rs index 5167bcfbb..8c0914c78 100644 --- a/crates/nu-command/src/conversions/into/int.rs +++ b/crates/nu-command/src/conversions/into/int.rs @@ -137,7 +137,11 @@ fn int_from_string(a_string: &str, span: Span) -> Result { Ok(n) => Ok(n), Err(_) => match a_string.parse::() { Ok(f) => Ok(f as i64), - _ => Err(ShellError::CantConvert("into int".into(), span)), + _ => Err(ShellError::CantConvert( + "into int".into(), + "string".into(), + span, + )), }, } } diff --git a/crates/nu-command/src/conversions/into/string.rs b/crates/nu-command/src/conversions/into/string.rs index 4f094926f..a5ee59716 100644 --- a/crates/nu-command/src/conversions/into/string.rs +++ b/crates/nu-command/src/conversions/into/string.rs @@ -229,11 +229,8 @@ pub fn action( span, ), }, - _ => Value::Error { - error: ShellError::CantConvert( - String::from(" into string. Probably this type is not supported yet"), - span, - ), + x => Value::Error { + error: ShellError::CantConvert(String::from("string"), x.get_type().to_string(), span), }, } } diff --git a/crates/nu-command/src/core_commands/alias.rs b/crates/nu-command/src/core_commands/alias.rs index e9c585c23..ae09d5228 100644 --- a/crates/nu-command/src/core_commands/alias.rs +++ b/crates/nu-command/src/core_commands/alias.rs @@ -28,9 +28,9 @@ impl Command for Alias { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/core_commands/def.rs b/crates/nu-command/src/core_commands/def.rs index f83e1f3ca..6632c1e73 100644 --- a/crates/nu-command/src/core_commands/def.rs +++ b/crates/nu-command/src/core_commands/def.rs @@ -29,9 +29,9 @@ impl Command for Def { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/core_commands/echo.rs b/crates/nu-command/src/core_commands/echo.rs index 064d52bdd..be7f231fb 100644 --- a/crates/nu-command/src/core_commands/echo.rs +++ b/crates/nu-command/src/core_commands/echo.rs @@ -1,9 +1,7 @@ use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EngineState, Stack}; -use nu_protocol::{ - Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, ValueStream, -}; +use nu_protocol::{Example, PipelineData, ShellError, Signature, SyntaxShape, Value, ValueStream}; #[derive(Clone)] pub struct Echo; @@ -43,7 +41,7 @@ impl Command for Echo { // When there are no elements, we echo the empty string std::cmp::Ordering::Less => PipelineData::Value(Value::String { val: "".to_string(), - span: Span::unknown(), + span: call.head, }), } }) diff --git a/crates/nu-command/src/core_commands/export_def.rs b/crates/nu-command/src/core_commands/export_def.rs index d56add47c..8ec9c33b5 100644 --- a/crates/nu-command/src/core_commands/export_def.rs +++ b/crates/nu-command/src/core_commands/export_def.rs @@ -29,9 +29,9 @@ impl Command for ExportDef { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/core_commands/for_.rs b/crates/nu-command/src/core_commands/for_.rs index 53daf287c..6435b7696 100644 --- a/crates/nu-command/src/core_commands/for_.rs +++ b/crates/nu-command/src/core_commands/for_.rs @@ -44,6 +44,7 @@ impl Command for For { call: &Call, _input: PipelineData, ) -> Result { + let head = call.head; let var_id = call.positional[0] .as_var() .expect("internal error: missing variable"); @@ -69,8 +70,8 @@ impl Command for For { stack.add_var(var_id, x); //let block = engine_state.get_block(block_id); - match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) { - Ok(pipeline_data) => pipeline_data.into_value(), + match eval_block(&engine_state, &mut stack, &block, PipelineData::new(head)) { + Ok(pipeline_data) => pipeline_data.into_value(head), Err(error) => Value::Error { error }, } }) @@ -81,8 +82,8 @@ impl Command for For { stack.add_var(var_id, x); //let block = engine_state.get_block(block_id); - match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) { - Ok(pipeline_data) => pipeline_data.into_value(), + match eval_block(&engine_state, &mut stack, &block, PipelineData::new(head)) { + Ok(pipeline_data) => pipeline_data.into_value(head), Err(error) => Value::Error { error }, } }) @@ -90,7 +91,7 @@ impl Command for For { x => { stack.add_var(var_id, x); - eval_block(&engine_state, &mut stack, &block, PipelineData::new()) + eval_block(&engine_state, &mut stack, &block, PipelineData::new(head)) } } } diff --git a/crates/nu-command/src/core_commands/hide.rs b/crates/nu-command/src/core_commands/hide.rs index 843299aba..8d28509ef 100644 --- a/crates/nu-command/src/core_commands/hide.rs +++ b/crates/nu-command/src/core_commands/hide.rs @@ -22,9 +22,9 @@ impl Command for Hide { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/core_commands/if_.rs b/crates/nu-command/src/core_commands/if_.rs index f5bc36516..dc3e8c7ad 100644 --- a/crates/nu-command/src/core_commands/if_.rs +++ b/crates/nu-command/src/core_commands/if_.rs @@ -40,9 +40,9 @@ impl Command for If { let else_case = call.positional.get(2); let result = eval_expression(engine_state, stack, cond)?; - match result { + match &result { Value::Bool { val, .. } => { - if val { + if *val { let block = engine_state.get_block(then_block); let mut stack = stack.collect_captures(&block.captures); eval_block(engine_state, &mut stack, block, input) @@ -61,10 +61,14 @@ impl Command for If { .map(|x| x.into_pipeline_data()) } } else { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } - _ => Err(ShellError::CantConvert("bool".into(), result.span()?)), + x => Err(ShellError::CantConvert( + "bool".into(), + x.get_type().to_string(), + result.span()?, + )), } } } diff --git a/crates/nu-command/src/core_commands/let_.rs b/crates/nu-command/src/core_commands/let_.rs index 7ccde47e7..5cd254a06 100644 --- a/crates/nu-command/src/core_commands/let_.rs +++ b/crates/nu-command/src/core_commands/let_.rs @@ -45,6 +45,6 @@ impl Command for Let { //println!("Adding: {:?} to {}", rhs, var_id); stack.add_var(var_id, rhs); - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/core_commands/module.rs b/crates/nu-command/src/core_commands/module.rs index 4fe16f615..3f8f12105 100644 --- a/crates/nu-command/src/core_commands/module.rs +++ b/crates/nu-command/src/core_commands/module.rs @@ -28,9 +28,9 @@ impl Command for Module { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/core_commands/register.rs b/crates/nu-command/src/core_commands/register.rs index 9578e717e..c5fee5a22 100644 --- a/crates/nu-command/src/core_commands/register.rs +++ b/crates/nu-command/src/core_commands/register.rs @@ -26,9 +26,9 @@ impl Command for Register { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/core_commands/use_.rs b/crates/nu-command/src/core_commands/use_.rs index 3b899c96e..509e95b23 100644 --- a/crates/nu-command/src/core_commands/use_.rs +++ b/crates/nu-command/src/core_commands/use_.rs @@ -22,9 +22,9 @@ impl Command for Use { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/date/to_timezone.rs b/crates/nu-command/src/date/to_timezone.rs index 0b3d50838..c00f4711e 100644 --- a/crates/nu-command/src/date/to_timezone.rs +++ b/crates/nu-command/src/date/to_timezone.rs @@ -111,7 +111,7 @@ fn _to_timezone(dt: DateTime, timezone: &Spanned, span: Spa match datetime_in_timezone(&dt, timezone.item.as_str()) { Ok(dt) => Value::Date { val: dt, span }, Err(_) => Value::Error { - error: ShellError::UnsupportedInput(String::from("invalid time zone"), Span::unknown()), + error: ShellError::UnsupportedInput(String::from("invalid time zone"), span), }, } } diff --git a/crates/nu-command/src/env/let_env.rs b/crates/nu-command/src/env/let_env.rs index 16e742f85..b67ebac1c 100644 --- a/crates/nu-command/src/env/let_env.rs +++ b/crates/nu-command/src/env/let_env.rs @@ -46,6 +46,6 @@ impl Command for LetEnv { //println!("Adding: {:?} to {}", rhs, var_id); stack.add_env_var(env_var, rhs); - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/env/with_env.rs b/crates/nu-command/src/env/with_env.rs index ae3d3a377..8d5e18c07 100644 --- a/crates/nu-command/src/env/with_env.rs +++ b/crates/nu-command/src/env/with_env.rs @@ -91,7 +91,11 @@ impl TryFrom<&Value> for EnvVar { Ok(EnvVar::Proper(s)) } } else { - Err(ShellError::CantConvert("string".into(), value.span()?)) + Err(ShellError::CantConvert( + "string".into(), + value.get_type().to_string(), + value.span()?, + )) } } } @@ -123,9 +127,10 @@ fn with_env( env.insert(k.to_string(), v.try_into()?); } } - _ => { + x => { return Err(ShellError::CantConvert( "string list or single row".into(), + x.get_type().to_string(), call.positional[1].span, )); } @@ -145,9 +150,10 @@ fn with_env( env.insert(k.clone(), v.try_into()?); } } - _ => { + x => { return Err(ShellError::CantConvert( "string list or single row".into(), + x.get_type().to_string(), call.positional[1].span, )); } diff --git a/crates/nu-command/src/example_test.rs b/crates/nu-command/src/example_test.rs index 635a5ea00..895dec4cc 100644 --- a/crates/nu-command/src/example_test.rs +++ b/crates/nu-command/src/example_test.rs @@ -2,7 +2,7 @@ use nu_engine::eval_block; use nu_parser::parse; use nu_protocol::{ engine::{Command, EngineState, Stack, StateWorkingSet}, - PipelineData, + PipelineData, Span, }; use crate::To; @@ -56,10 +56,15 @@ pub fn test_examples(cmd: impl Command + 'static) { let mut stack = Stack::new(); - match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) { + match eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(Span::unknown()), + ) { Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err), Ok(result) => { - let result = result.into_value(); + let result = result.into_value(Span::unknown()); println!("input: {}", example.example); println!("result: {:?}", result); println!("done: {:?}", start.elapsed()); diff --git a/crates/nu-command/src/experimental/git.rs b/crates/nu-command/src/experimental/git.rs index bb1463bcb..b3939116d 100644 --- a/crates/nu-command/src/experimental/git.rs +++ b/crates/nu-command/src/experimental/git.rs @@ -44,13 +44,13 @@ impl Command for Git { } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } } diff --git a/crates/nu-command/src/experimental/git_checkout.rs b/crates/nu-command/src/experimental/git_checkout.rs index 66b68c533..ba55ae6f3 100644 --- a/crates/nu-command/src/experimental/git_checkout.rs +++ b/crates/nu-command/src/experimental/git_checkout.rs @@ -59,13 +59,13 @@ impl Command for GitCheckout { } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } } diff --git a/crates/nu-command/src/experimental/list_git_branches.rs b/crates/nu-command/src/experimental/list_git_branches.rs index 7c2bd2fdc..bde67c017 100644 --- a/crates/nu-command/src/experimental/list_git_branches.rs +++ b/crates/nu-command/src/experimental/list_git_branches.rs @@ -66,10 +66,10 @@ impl Command for ListGitBranches { .into_iter() .into_pipeline_data(engine_state.ctrlc.clone())) } else { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } else { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } } diff --git a/crates/nu-command/src/filesystem/cd.rs b/crates/nu-command/src/filesystem/cd.rs index 2986413be..215ef38b6 100644 --- a/crates/nu-command/src/filesystem/cd.rs +++ b/crates/nu-command/src/filesystem/cd.rs @@ -43,6 +43,6 @@ impl Command for Cd { //FIXME: this only changes the current scope, but instead this environment variable //should probably be a block that loads the information from the state in the overlay stack.add_env_var("PWD".into(), path); - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/filesystem/cp.rs b/crates/nu-command/src/filesystem/cp.rs index 4de1af2a1..a553a8426 100644 --- a/crates/nu-command/src/filesystem/cp.rs +++ b/crates/nu-command/src/filesystem/cp.rs @@ -204,6 +204,6 @@ impl Command for Cp { } } - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/filesystem/mv.rs b/crates/nu-command/src/filesystem/mv.rs index 74a759cdd..fe5262720 100644 --- a/crates/nu-command/src/filesystem/mv.rs +++ b/crates/nu-command/src/filesystem/mv.rs @@ -130,7 +130,7 @@ impl Command for Mv { move_file(call, &entry, &destination)? } - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/filesystem/touch.rs b/crates/nu-command/src/filesystem/touch.rs index 04188d9ec..0bc66dc06 100644 --- a/crates/nu-command/src/filesystem/touch.rs +++ b/crates/nu-command/src/filesystem/touch.rs @@ -49,6 +49,6 @@ impl Command for Touch { } } - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/filters/each.rs b/crates/nu-command/src/filters/each.rs index 1e7574e1a..22a1ebaa7 100644 --- a/crates/nu-command/src/filters/each.rs +++ b/crates/nu-command/src/filters/each.rs @@ -102,8 +102,8 @@ impl Command for Each { } } - match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) { - Ok(v) => v.into_value(), + match eval_block(&engine_state, &mut stack, &block, PipelineData::new(span)) { + Ok(v) => v.into_value(span), Err(error) => Value::Error { error }, } }) @@ -136,7 +136,7 @@ impl Command for Each { } } - match eval_block(&engine_state, &mut stack, block, PipelineData::new())? { + match eval_block(&engine_state, &mut stack, block, PipelineData::new(span))? { PipelineData::Value(Value::Record { mut cols, mut vals, .. }) => { @@ -146,7 +146,7 @@ impl Command for Each { } x => { output_cols.push(col); - output_vals.push(x.into_value()); + output_vals.push(x.into_value(span)); } } } @@ -167,7 +167,7 @@ impl Command for Each { } } - eval_block(&engine_state, &mut stack, block, PipelineData::new()) + eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) } } } diff --git a/crates/nu-command/src/filters/par_each.rs b/crates/nu-command/src/filters/par_each.rs index d59983bd2..95a34ecc1 100644 --- a/crates/nu-command/src/filters/par_each.rs +++ b/crates/nu-command/src/filters/par_each.rs @@ -88,7 +88,7 @@ impl Command for ParEach { } } - match eval_block(&engine_state, &mut stack, block, PipelineData::new()) { + match eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) { Ok(v) => v, Err(error) => Value::Error { error }.into_pipeline_data(), } @@ -129,7 +129,7 @@ impl Command for ParEach { } } - match eval_block(&engine_state, &mut stack, block, PipelineData::new()) { + match eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) { Ok(v) => v, Err(error) => Value::Error { error }.into_pipeline_data(), } @@ -169,7 +169,7 @@ impl Command for ParEach { } } - match eval_block(&engine_state, &mut stack, block, PipelineData::new()) { + match eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) { Ok(v) => v, Err(error) => Value::Error { error }.into_pipeline_data(), } @@ -206,7 +206,7 @@ impl Command for ParEach { } } - match eval_block(&engine_state, &mut stack, block, PipelineData::new())? { + match eval_block(&engine_state, &mut stack, block, PipelineData::new(span))? { PipelineData::Value(Value::Record { mut cols, mut vals, .. }) => { @@ -216,7 +216,7 @@ impl Command for ParEach { } x => { output_cols.push(col); - output_vals.push(x.into_value()); + output_vals.push(x.into_value(span)); } } } @@ -237,7 +237,7 @@ impl Command for ParEach { } } - eval_block(&engine_state, &mut stack, block, PipelineData::new()) + eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) } } } diff --git a/crates/nu-command/src/filters/where_.rs b/crates/nu-command/src/filters/where_.rs index c837b47a2..593b23ff1 100644 --- a/crates/nu-command/src/filters/where_.rs +++ b/crates/nu-command/src/filters/where_.rs @@ -29,6 +29,7 @@ impl Command for Where { call: &Call, input: PipelineData, ) -> Result { + let head = call.head; let cond = call.positional[0].clone(); let ctrlc = engine_state.ctrlc.clone(); @@ -79,7 +80,7 @@ impl Command for Where { if result.is_true() { Ok(x.into_pipeline_data()) } else { - Ok(PipelineData::new()) + Ok(PipelineData::new(head)) } } } diff --git a/crates/nu-command/src/formats/from/command.rs b/crates/nu-command/src/formats/from/command.rs index 8aede1def..f8de9bd63 100644 --- a/crates/nu-command/src/formats/from/command.rs +++ b/crates/nu-command/src/formats/from/command.rs @@ -22,9 +22,9 @@ impl Command for From { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/formats/from/json.rs b/crates/nu-command/src/formats/from/json.rs index 2de433dd1..35b610e67 100644 --- a/crates/nu-command/src/formats/from/json.rs +++ b/crates/nu-command/src/formats/from/json.rs @@ -128,7 +128,11 @@ fn convert_nujson_to_value(value: &nu_json::Value, span: Span) -> Value { nu_json::Value::U64(u) => { if *u > i64::MAX as u64 { Value::Error { - error: ShellError::CantConvert("i64 sized integer".into(), span), + error: ShellError::CantConvert( + "i64 sized integer".into(), + "larger than i64".into(), + span, + ), } } else { Value::Int { @@ -151,6 +155,7 @@ fn convert_string_to_value(string_input: String, span: Span) -> Result Err(ShellError::CantConvert( "structured data from json".into(), + "string".into(), span, )), } diff --git a/crates/nu-command/src/formats/to/command.rs b/crates/nu-command/src/formats/to/command.rs index ebc5e6b8c..226b7f30e 100644 --- a/crates/nu-command/src/formats/to/command.rs +++ b/crates/nu-command/src/formats/to/command.rs @@ -22,9 +22,9 @@ impl Command for To { &self, _engine_state: &EngineState, _stack: &mut Stack, - _call: &Call, + call: &Call, _input: PipelineData, ) -> Result { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } diff --git a/crates/nu-command/src/formats/to/json.rs b/crates/nu-command/src/formats/to/json.rs index 952c029bd..ac08404e0 100644 --- a/crates/nu-command/src/formats/to/json.rs +++ b/crates/nu-command/src/formats/to/json.rs @@ -127,7 +127,11 @@ fn to_json( } .into_pipeline_data()), _ => Ok(Value::Error { - error: ShellError::CantConvert("JSON".into(), name_span), + error: ShellError::CantConvert( + "JSON".into(), + value.get_type().to_string(), + name_span, + ), } .into_pipeline_data()), } @@ -141,12 +145,20 @@ fn to_json( span: name_span, }, _ => Value::Error { - error: ShellError::CantConvert("JSON".into(), name_span), + error: ShellError::CantConvert( + "JSON".into(), + value.get_type().to_string(), + name_span, + ), }, } } else { Value::Error { - error: ShellError::CantConvert("JSON".into(), name_span), + error: ShellError::CantConvert( + "JSON".into(), + value.get_type().to_string(), + name_span, + ), } } }) diff --git a/crates/nu-command/src/math/max.rs b/crates/nu-command/src/math/max.rs index 81d146502..efe2422b0 100644 --- a/crates/nu-command/src/math/max.rs +++ b/crates/nu-command/src/math/max.rs @@ -41,7 +41,7 @@ impl Command for SubCommand { pub fn maximum(values: &[Value], head: &Span) -> Result { let max_func = reducer_for(Reduce::Maximum); - max_func(Value::nothing(), values.to_vec(), *head) + max_func(Value::nothing(*head), values.to_vec(), *head) } #[cfg(test)] diff --git a/crates/nu-command/src/math/min.rs b/crates/nu-command/src/math/min.rs index b232d1307..a59db60c2 100644 --- a/crates/nu-command/src/math/min.rs +++ b/crates/nu-command/src/math/min.rs @@ -41,7 +41,7 @@ impl Command for SubCommand { pub fn minimum(values: &[Value], head: &Span) -> Result { let min_func = reducer_for(Reduce::Minimum); - min_func(Value::nothing(), values.to_vec(), *head) + min_func(Value::nothing(*head), values.to_vec(), *head) } #[cfg(test)] diff --git a/crates/nu-command/src/math/product.rs b/crates/nu-command/src/math/product.rs index 150f0fff7..bfa2e85cb 100644 --- a/crates/nu-command/src/math/product.rs +++ b/crates/nu-command/src/math/product.rs @@ -42,7 +42,7 @@ impl Command for SubCommand { /// Calculate product of given values pub fn product(values: &[Value], head: &Span) -> Result { let product_func = reducer_for(Reduce::Product); - product_func(Value::nothing(), values.to_vec(), *head) + product_func(Value::nothing(*head), values.to_vec(), *head) } #[cfg(test)] diff --git a/crates/nu-command/src/math/reducers.rs b/crates/nu-command/src/math/reducers.rs index 400b2baa0..3a7b3273f 100644 --- a/crates/nu-command/src/math/reducers.rs +++ b/crates/nu-command/src/math/reducers.rs @@ -24,7 +24,7 @@ pub fn reducer_for(command: Reduce) -> ReducerFunction { pub fn max(data: Vec, head: Span) -> Result { let mut biggest = data .first() - .ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), Span::unknown()))? + .ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), head))? .clone(); for value in &data { @@ -48,7 +48,7 @@ pub fn max(data: Vec, head: Span) -> Result { pub fn min(data: Vec, head: Span) -> Result { let mut smallest = data .first() - .ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), Span::unknown()))? + .ok_or_else(|| ShellError::UnsupportedInput("Empty input".to_string(), head))? .clone(); for value in &data { @@ -87,9 +87,9 @@ pub fn sum(data: Vec, head: Span) -> Result { }), None => Err(ShellError::UnsupportedInput( "Empty input".to_string(), - Span::unknown(), + head, )), - _ => Ok(Value::nothing()), + _ => Ok(Value::nothing(head)), }?; for value in &data { @@ -127,7 +127,7 @@ pub fn product(data: Vec, head: Span) -> Result { "Empty input".to_string(), Span::unknown(), )), - _ => Ok(Value::nothing()), + _ => Ok(Value::nothing(head)), }?; for value in &data { diff --git a/crates/nu-command/src/math/sum.rs b/crates/nu-command/src/math/sum.rs index c749d09d7..743241aa4 100644 --- a/crates/nu-command/src/math/sum.rs +++ b/crates/nu-command/src/math/sum.rs @@ -48,7 +48,7 @@ impl Command for SubCommand { pub fn summation(values: &[Value], head: &Span) -> Result { let sum_func = reducer_for(Reduce::Summation); - sum_func(Value::nothing(), values.to_vec(), *head) + sum_func(Value::nothing(*head), values.to_vec(), *head) } #[cfg(test)] diff --git a/crates/nu-command/src/strings/format/command.rs b/crates/nu-command/src/strings/format/command.rs index 4c78e5b46..2170dd722 100644 --- a/crates/nu-command/src/strings/format/command.rs +++ b/crates/nu-command/src/strings/format/command.rs @@ -38,7 +38,7 @@ impl Command for Format { Ok(pattern) => { let string_pattern = pattern.as_string().unwrap(); let ops = extract_formatting_operations(string_pattern); - format(input, &ops) + format(input, &ops, call.head) } } } @@ -116,8 +116,9 @@ fn extract_formatting_operations(input: String) -> Vec { fn format( input_data: PipelineData, format_operations: &[FormatOperation], + span: Span, ) -> Result { - let data_as_value = input_data.into_value(); + let data_as_value = input_data.into_value(span); // We can only handle a Record or a List of Record's match data_as_value { diff --git a/crates/nu-command/src/system/benchmark.rs b/crates/nu-command/src/system/benchmark.rs index e786c4088..db9040ebd 100644 --- a/crates/nu-command/src/system/benchmark.rs +++ b/crates/nu-command/src/system/benchmark.rs @@ -39,7 +39,13 @@ impl Command for Benchmark { let mut stack = stack.collect_captures(&block.captures); let start_time = Instant::now(); - eval_block(engine_state, &mut stack, block, PipelineData::new())?.into_value(); + eval_block( + engine_state, + &mut stack, + block, + PipelineData::new(call.head), + )? + .into_value(call.head); let end_time = Instant::now(); diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index ca790b07d..a2860b9ea 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -161,9 +161,9 @@ impl ExternalCommand { }); // The ValueStream is consumed by the next expression in the pipeline - ChannelReceiver::new(rx).into_pipeline_data(ctrlc) + ChannelReceiver::new(rx, self.name.span).into_pipeline_data(ctrlc) } else { - PipelineData::new() + PipelineData::new(self.name.span) }; match child.wait() { @@ -214,11 +214,12 @@ enum Data { // It implements iterator so it can be used as a ValueStream struct ChannelReceiver { rx: mpsc::Receiver, + span: Span, } impl ChannelReceiver { - pub fn new(rx: mpsc::Receiver) -> Self { - Self { rx } + pub fn new(rx: mpsc::Receiver, span: Span) -> Self { + Self { rx, span } } } @@ -230,11 +231,11 @@ impl Iterator for ChannelReceiver { Ok(v) => match v { Data::String(s) => Some(Value::String { val: s, - span: Span::unknown(), + span: self.span, }), Data::Bytes(b) => Some(Value::Binary { val: b, - span: Span::unknown(), + span: self.span, }), }, Err(_) => None, diff --git a/crates/nu-command/src/viewers/griddle.rs b/crates/nu-command/src/viewers/griddle.rs index 07faac1c2..983a6e576 100644 --- a/crates/nu-command/src/viewers/griddle.rs +++ b/crates/nu-command/src/viewers/griddle.rs @@ -70,7 +70,7 @@ prints out the list properly."# separator_param, )) } else { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } PipelineData::Stream(stream) => { @@ -86,7 +86,7 @@ prints out the list properly."# )) } else { // dbg!(data); - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } PipelineData::Value(Value::Record { cols, vals, .. }) => { diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index bd1a432c5..cef8a3526 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -48,7 +48,7 @@ impl Command for Table { } .into_pipeline_data()) } else { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } PipelineData::Stream(stream) => { @@ -63,7 +63,7 @@ impl Command for Table { } .into_pipeline_data()) } else { - Ok(PipelineData::new()) + Ok(PipelineData::new(call.head)) } } PipelineData::Value(Value::Record { cols, vals, .. }) => { diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 9b000df58..d331ff46c 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -178,7 +178,11 @@ pub fn eval_expression( }), Expr::ValueWithUnit(e, unit) => match eval_expression(engine_state, stack, e)? { Value::Int { val, .. } => Ok(compute(val, unit.item, unit.span)), - _ => Err(ShellError::CantConvert("unit value".into(), e.span)), + x => Err(ShellError::CantConvert( + "unit value".into(), + x.get_type().to_string(), + e.span, + )), }, Expr::Range(from, next, to, operator) => { let from = if let Some(f) = from { @@ -224,7 +228,10 @@ pub fn eval_expression( Expr::RowCondition(_, expr) => eval_expression(engine_state, stack, expr), Expr::Call(call) => { // FIXME: protect this collect with ctrl-c - Ok(eval_call(engine_state, stack, call, PipelineData::new())?.into_value()) + Ok( + eval_call(engine_state, stack, call, PipelineData::new(call.head))? + .into_value(call.head), + ) } Expr::ExternalCall(name, span, args) => { // FIXME: protect this collect with ctrl-c @@ -234,10 +241,10 @@ pub fn eval_expression( name, span, args, - PipelineData::new(), + PipelineData::new(*span), true, )? - .into_value()) + .into_value(*span)) } Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }), Expr::BinaryOp(lhs, op, rhs) => { @@ -271,7 +278,10 @@ pub fn eval_expression( let block = engine_state.get_block(*block_id); // FIXME: protect this collect with ctrl-c - Ok(eval_block(engine_state, stack, block, PipelineData::new())?.into_value()) + Ok( + eval_subexpression(engine_state, stack, block, PipelineData::new(expr.span))? + .into_value(expr.span), + ) } Expr::Block(block_id) => Ok(Value::Block { val: *block_id, @@ -370,6 +380,64 @@ pub fn eval_block( Ok(input) } +pub fn eval_subexpression( + engine_state: &EngineState, + stack: &mut Stack, + block: &Block, + mut input: PipelineData, +) -> Result { + for stmt in block.stmts.iter() { + if let Statement::Pipeline(pipeline) = stmt { + for (i, elem) in pipeline.expressions.iter().enumerate() { + match elem { + Expression { + expr: Expr::Call(call), + .. + } => { + input = eval_call(engine_state, stack, call, input)?; + } + Expression { + expr: Expr::ExternalCall(name, name_span, args), + .. + } => { + input = eval_external( + engine_state, + stack, + name, + name_span, + args, + input, + false, + )?; + + if i == pipeline.expressions.len() - 1 { + // We're at the end, so drain as a string for the value + // to be used later + // FIXME: the trimming of the end probably needs to live in a better place + + let mut s = input.collect_string(); + if s.ends_with('\n') { + s.pop(); + } + input = Value::String { + val: s.to_string(), + span: *name_span, + } + .into_pipeline_data() + } + } + + elem => { + input = eval_expression(engine_state, stack, elem)?.into_pipeline_data(); + } + } + } + } + } + + Ok(input) +} + pub fn eval_variable( engine_state: &EngineState, stack: &Stack, diff --git a/crates/nu-engine/src/from_value.rs b/crates/nu-engine/src/from_value.rs index 694d9adb3..0871459e1 100644 --- a/crates/nu-engine/src/from_value.rs +++ b/crates/nu-engine/src/from_value.rs @@ -32,7 +32,11 @@ impl FromValue for Spanned { span: *span, }), - v => Err(ShellError::CantConvert("integer".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "integer".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -44,7 +48,11 @@ impl FromValue for i64 { Value::Filesize { val, .. } => Ok(*val as i64), Value::Duration { val, .. } => Ok(*val as i64), - v => Err(ShellError::CantConvert("integer".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "integer".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -61,7 +69,11 @@ impl FromValue for Spanned { span: *span, }), - v => Err(ShellError::CantConvert("float".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "float".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -71,7 +83,11 @@ impl FromValue for f64 { match v { Value::Float { val, .. } => Ok(*val), Value::Int { val, .. } => Ok(*val as f64), - v => Err(ShellError::CantConvert("float".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "float".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -109,7 +125,11 @@ impl FromValue for CellPath { span, }], }), - _ => Err(ShellError::CantConvert("cell path".into(), span)), + x => Err(ShellError::CantConvert( + "cell path".into(), + x.get_type().to_string(), + span, + )), } } } @@ -118,7 +138,11 @@ impl FromValue for bool { fn from_value(v: &Value) -> Result { match v { Value::Bool { val, .. } => Ok(*val), - v => Err(ShellError::CantConvert("bool".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "bool".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -130,7 +154,11 @@ impl FromValue for Spanned { item: *val, span: *span, }), - v => Err(ShellError::CantConvert("bool".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "bool".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -139,7 +167,11 @@ impl FromValue for DateTime { fn from_value(v: &Value) -> Result { match v { Value::Date { val, .. } => Ok(*val), - v => Err(ShellError::CantConvert("date".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "date".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -151,7 +183,11 @@ impl FromValue for Spanned> { item: *val, span: *span, }), - v => Err(ShellError::CantConvert("date".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "date".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -160,7 +196,11 @@ impl FromValue for Range { fn from_value(v: &Value) -> Result { match v { Value::Range { val, .. } => Ok((**val).clone()), - v => Err(ShellError::CantConvert("range".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "range".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -172,7 +212,11 @@ impl FromValue for Spanned { item: (**val).clone(), span: *span, }), - v => Err(ShellError::CantConvert("range".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "range".into(), + v.get_type().to_string(), + v.span()?, + )), } } } @@ -182,7 +226,11 @@ impl FromValue for Vec { match v { Value::Binary { val, .. } => Ok(val.clone()), Value::String { val, .. } => Ok(val.bytes().collect()), - v => Err(ShellError::CantConvert("binary data".into(), v.span()?)), + v => Err(ShellError::CantConvert( + "binary data".into(), + v.get_type().to_string(), + v.span()?, + )), } } } diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 4b139782b..73f0f2353 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1292,6 +1292,7 @@ pub fn parse_full_cell_path( if let Some(head) = tokens.peek() { let bytes = working_set.get_span_contents(head.span); let (head, expect_dot) = if bytes.starts_with(b"(") { + let head_span = head.span; let mut start = head.span.start; let mut end = head.span.end; @@ -1331,7 +1332,7 @@ pub fn parse_full_cell_path( ( Expression { expr: Expr::Subexpression(block_id), - span, + span: head_span, ty: Type::Unknown, // FIXME custom_completion: None, }, diff --git a/crates/nu-protocol/src/pipeline_data.rs b/crates/nu-protocol/src/pipeline_data.rs index 480a91bb5..ac5694346 100644 --- a/crates/nu-protocol/src/pipeline_data.rs +++ b/crates/nu-protocol/src/pipeline_data.rs @@ -37,16 +37,16 @@ pub enum PipelineData { } impl PipelineData { - pub fn new() -> PipelineData { - PipelineData::Value(Value::nothing()) + pub fn new(span: Span) -> PipelineData { + PipelineData::Value(Value::Nothing { span }) } - pub fn into_value(self) -> Value { + pub fn into_value(self, span: Span) -> Value { match self { PipelineData::Value(v) => v, PipelineData::Stream(s) => Value::List { vals: s.collect(), - span: Span::unknown(), // FIXME? + span, // FIXME? }, } } @@ -140,11 +140,11 @@ impl PipelineData { } } -impl Default for PipelineData { - fn default() -> Self { - PipelineData::new() - } -} +// impl Default for PipelineData { +// fn default() -> Self { +// PipelineData::new() +// } +// } pub struct PipelineIterator(PipelineData); diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index db733671d..4c55d8610 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -82,7 +82,7 @@ pub enum ShellError { #[error("Can't convert to {0}.")] #[diagnostic(code(nu::shell::cant_convert), url(docsrs))] - CantConvert(String, #[label("can't convert to {0}")] Span), + CantConvert(String, String, #[label("can't convert {1} to {0}")] Span), #[error("Division by zero.")] #[diagnostic(code(nu::shell::division_by_zero), url(docsrs))] diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 6aa3688b0..39df86cf7 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -87,7 +87,14 @@ impl Value { pub fn as_string(&self) -> Result { match self { Value::String { val, .. } => Ok(val.to_string()), - _ => Err(ShellError::CantConvert("string".into(), self.span()?)), + x => { + println!("{:?}", x); + Err(ShellError::CantConvert( + "string".into(), + x.get_type().to_string(), + self.span()?, + )) + } } } @@ -225,10 +232,8 @@ impl Value { } /// Create a new `Nothing` value - pub fn nothing() -> Value { - Value::Nothing { - span: Span::unknown(), - } + pub fn nothing(span: Span) -> Value { + Value::Nothing { span } } /// Follow a given column path into the value: for example accessing nth elements in a stream or list @@ -425,7 +430,9 @@ impl Value { impl Default for Value { fn default() -> Self { - Value::nothing() + Value::Nothing { + span: Span::unknown(), + } } } diff --git a/src/main.rs b/src/main.rs index 9d8f28ff8..05aa4127a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ use nu_parser::parse; use nu_protocol::{ ast::Call, engine::{EngineState, Stack, StateWorkingSet}, - IntoPipelineData, PipelineData, ShellError, Value, + IntoPipelineData, PipelineData, ShellError, Span, Value, }; use reedline::{Completer, CompletionActionHandler, DefaultPrompt, LineBuffer, Prompt}; @@ -126,7 +126,12 @@ fn main() -> Result<()> { stack.env_vars.insert(k, v); } - match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) { + match eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(Span::unknown()), + ) { Ok(pipeline_data) => { println!("{}", pipeline_data.collect_string()); } @@ -312,7 +317,12 @@ fn update_prompt<'prompt>( let mut stack = stack.clone(); - let evaluated_prompt = match eval_block(engine_state, &mut stack, &block, PipelineData::new()) { + let evaluated_prompt = match eval_block( + engine_state, + &mut stack, + &block, + PipelineData::new(Span::unknown()), + ) { Ok(pipeline_data) => pipeline_data.collect_string(), Err(err) => { let working_set = StateWorkingSet::new(engine_state); @@ -349,9 +359,14 @@ fn eval_source( engine_state.merge_delta(delta); - match eval_block(engine_state, stack, &block, PipelineData::new()) { + match eval_block( + engine_state, + stack, + &block, + PipelineData::new(Span::unknown()), + ) { Ok(pipeline_data) => { - if let Err(err) = print_value(pipeline_data.into_value(), engine_state) { + if let Err(err) = print_value(pipeline_data.into_value(Span::unknown()), engine_state) { let working_set = StateWorkingSet::new(engine_state); report_error(&working_set, &err);