1
0
mirror of https://github.com/nushell/nushell.git synced 2025-07-09 10:57:54 +02:00

Box ShellError in Value::Error ()

# Description

Our `ShellError` at the moment has a `std::mem::size_of<ShellError>` of
136 bytes (on AMD64). As a result `Value` directly storing the struct
also required 136 bytes (thanks to alignment requirements).

This change stores the `Value::Error` `ShellError` on the heap.

Pro:
- Value now needs just 80 bytes
- Should be 1 cacheline less (still at least 2 cachelines)

Con:
- More small heap allocations when dealing with `Value::Error`
  - More heap fragmentation
  - Potential for additional required memcopies

# Further code changes

Includes a small refactor of `try` due to a type mismatch in its large
match.

# User-Facing Changes

None for regular users.

Plugin authors may have to update their matches on `Value` if they use
`nu-protocol`

Needs benchmarking to see if there is a benefit in real world workloads.
**Update** small improvements in runtime for workloads with high volume
of values. Significant reduction in maximum resident set size, when many
values are held in memory.

# Tests + Formatting
This commit is contained in:
Stefan Holderbach
2023-03-12 09:57:27 +01:00
committed by GitHub
parent c26d91fb61
commit a52386e837
153 changed files with 648 additions and 520 deletions
crates
nu-cli
nu-cmd-lang
src
core_commands
nu-command
src
bits
bytes
charting
conversions
database
dataframe
values
nu_dataframe
date
debug
filesystem
filters
formats
hash
input_handler.rs
math
network
path
platform
strings
system
viewers
nu-engine
nu-explore
src
nu-protocol
nu_plugin_formats

@ -145,7 +145,7 @@ pub(crate) fn print_table_or_error(
if let PipelineData::Value(Value::Error { error }, ..) = &pipeline_data { if let PipelineData::Value(Value::Error { error }, ..) = &pipeline_data {
let working_set = StateWorkingSet::new(engine_state); let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, error); report_error(&working_set, &**error);
std::process::exit(1); std::process::exit(1);
} }
@ -193,7 +193,7 @@ fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, co
if let Value::Error { error } = item { if let Value::Error { error } = item {
let working_set = StateWorkingSet::new(engine_state); let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &error); report_error(&working_set, &*error);
std::process::exit(1); std::process::exit(1);
} }

@ -53,7 +53,9 @@ impl Command for NuHighlight {
span: head, span: head,
} }
} }
Err(err) => Value::Error { error: err }, Err(err) => Value::Error {
error: Box::new(err),
},
}, },
ctrlc, ctrlc,
) )

@ -1124,7 +1124,7 @@ fn run_hook_block(
eval_block_with_early_return(engine_state, &mut callee_stack, block, input, false, false)?; eval_block_with_early_return(engine_state, &mut callee_stack, block, input, false, false)?;
if let PipelineData::Value(Value::Error { error }, _) = pipeline_data { if let PipelineData::Value(Value::Error { error }, _) = pipeline_data {
return Err(error); return Err(*error);
} }
// If all went fine, preserve the environment of the called block // If all went fine, preserve the environment of the called block

@ -57,66 +57,29 @@ impl Command for Try {
let result = eval_block(engine_state, stack, try_block, input, false, false); let result = eval_block(engine_state, stack, try_block, input, false, false);
match result { match result {
Err(error) | Ok(PipelineData::Value(Value::Error { error }, ..)) => { Err(error) => {
if let nu_protocol::ShellError::Break(_) = error { let error = intercept_block_control(error)?;
return Err(error); let err_value = Value::Error {
} else if let nu_protocol::ShellError::Continue(_) = error { error: Box::new(error),
return Err(error); };
} else if let nu_protocol::ShellError::Return(_, _) = error { handle_catch(err_value, catch_block, engine_state, stack)
return Err(error);
}
if let Some(catch_block) = catch_block {
let catch_block = engine_state.get_block(catch_block.block_id);
let err_value = Value::Error { error };
// Put the error value in the positional closure var
if let Some(var) = catch_block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, err_value.clone());
}
}
eval_block(
engine_state,
stack,
catch_block,
// Make the error accessible with $in, too
err_value.into_pipeline_data(),
false,
false,
)
} else {
Ok(PipelineData::empty())
} }
Ok(PipelineData::Value(Value::Error { error }, ..)) => {
let error = intercept_block_control(*error)?;
let err_value = Value::Error {
error: Box::new(error),
};
handle_catch(err_value, catch_block, engine_state, stack)
} }
// external command may fail to run // external command may fail to run
Ok(pipeline) => { Ok(pipeline) => {
let (pipeline, external_failed) = pipeline.is_external_failed(); let (pipeline, external_failed) = pipeline.is_external_failed();
if external_failed { if external_failed {
if let Some(catch_block) = catch_block {
let catch_block = engine_state.get_block(catch_block.block_id);
if let Some(var) = catch_block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
// Because external command errors aren't "real" errors, // Because external command errors aren't "real" errors,
// (unless do -c is in effect) // (unless do -c is in effect)
// they can't be passed in as Nushell values. // they can't be passed in as Nushell values.
let err_value = Value::nothing(call.head); let err_value = Value::nothing(call.head);
stack.add_var(*var_id, err_value); handle_catch(err_value, catch_block, engine_state, stack)
}
}
eval_block(
engine_state,
stack,
catch_block,
// The same null as in the above block is set as the $in value.
Value::nothing(call.head).into_pipeline_data(),
false,
false,
)
} else {
Ok(PipelineData::empty())
}
} else { } else {
Ok(pipeline) Ok(pipeline)
} }
@ -140,6 +103,48 @@ impl Command for Try {
} }
} }
fn handle_catch(
err_value: Value,
catch_block: Option<Closure>,
engine_state: &EngineState,
stack: &mut Stack,
) -> Result<PipelineData, ShellError> {
if let Some(catch_block) = catch_block {
let catch_block = engine_state.get_block(catch_block.block_id);
// Put the error value in the positional closure var
if let Some(var) = catch_block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, err_value.clone());
}
}
eval_block(
engine_state,
stack,
catch_block,
// Make the error accessible with $in, too
err_value.into_pipeline_data(),
false,
false,
)
} else {
Ok(PipelineData::empty())
}
}
/// The flow control commands `break`/`continue`/`return` emit their own [`ShellError`] variants
/// We need to ignore those in `try` and bubble them through
///
/// `Err` when flow control to bubble up with `?`
fn intercept_block_control(error: ShellError) -> Result<ShellError, ShellError> {
match error {
nu_protocol::ShellError::Break(_) => Err(error),
nu_protocol::ShellError::Continue(_) => Err(error),
nu_protocol::ShellError::Return(_, _) => Err(error),
_ => Ok(error),
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

@ -81,12 +81,12 @@ fn operate(value: Value, target: i64, head: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -150,12 +150,12 @@ fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) ->
// Propagate errors inside the value // Propagate errors inside the value
Value::Error { .. } => other, Value::Error { .. } => other,
_ => Value::Error { _ => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
}, },
} }

@ -81,12 +81,12 @@ fn operate(value: Value, target: i64, head: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -103,7 +103,7 @@ where
match rotate_result { match rotate_result {
Ok(val) => Value::Int { val, span }, Ok(val) => Value::Int { val, span },
Err(_) => Value::Error { Err(_) => Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
"Rotate left result beyond the range of 64 bit signed number".to_string(), "Rotate left result beyond the range of 64 bit signed number".to_string(),
format!( format!(
"{val} of the specified number of bytes rotate left {bits} bits exceed limit" "{val} of the specified number of bytes rotate left {bits} bits exceed limit"
@ -111,7 +111,7 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
}, },
} }
} }
@ -137,12 +137,12 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -107,7 +107,7 @@ where
match rotate_result { match rotate_result {
Ok(val) => Value::Int { val, span }, Ok(val) => Value::Int { val, span },
Err(_) => Value::Error { Err(_) => Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
"Rotate right result beyond the range of 64 bit signed number".to_string(), "Rotate right result beyond the range of 64 bit signed number".to_string(),
format!( format!(
"{val} of the specified number of bytes rotate right {bits} bits exceed limit" "{val} of the specified number of bytes rotate right {bits} bits exceed limit"
@ -115,7 +115,7 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
}, },
} }
} }
@ -141,12 +141,12 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -115,7 +115,7 @@ where
match shift_result { match shift_result {
Ok(val) => Value::Int { val, span }, Ok(val) => Value::Int { val, span },
Err(_) => Value::Error { Err(_) => Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
"Shift left result beyond the range of 64 bit signed number".to_string(), "Shift left result beyond the range of 64 bit signed number".to_string(),
format!( format!(
"{val} of the specified number of bytes shift left {bits} bits exceed limit" "{val} of the specified number of bytes shift left {bits} bits exceed limit"
@ -123,18 +123,18 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
}, },
} }
} }
None => Value::Error { None => Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
"Shift left failed".to_string(), "Shift left failed".to_string(),
format!("{val} shift left {bits} bits failed, you may shift too many bits"), format!("{val} shift left {bits} bits failed, you may shift too many bits"),
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
}, },
} }
} }
@ -160,12 +160,12 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -105,7 +105,7 @@ where
match shift_result { match shift_result {
Ok(val) => Value::Int { val, span }, Ok(val) => Value::Int { val, span },
Err(_) => Value::Error { Err(_) => Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
"Shift right result beyond the range of 64 bit signed number".to_string(), "Shift right result beyond the range of 64 bit signed number".to_string(),
format!( format!(
"{val} of the specified number of bytes shift right {bits} bits exceed limit" "{val} of the specified number of bytes shift right {bits} bits exceed limit"
@ -113,18 +113,18 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
}, },
} }
} }
None => Value::Error { None => Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
"Shift right failed".to_string(), "Shift right failed".to_string(),
format!("{val} shift right {bits} bits failed, you may shift too many bits"), format!("{val} shift right {bits} bits failed, you may shift too many bits"),
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
}, },
} }
} }
@ -150,12 +150,12 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -80,12 +80,12 @@ fn operate(value: Value, target: i64, head: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(), exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -125,12 +125,12 @@ fn add(val: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -41,7 +41,7 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
Value::Int { val, .. } => val.to_string(), Value::Int { val, .. } => val.to_string(),
Value::String { val, .. } => val, Value::String { val, .. } => val,
// Explicitly propagate errors instead of dropping them. // Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
"Only string or list<int> ranges are supported".into(), "Only string or list<int> ranges are supported".into(),
@ -56,7 +56,7 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
Value::Int { val, .. } => val.to_string(), Value::Int { val, .. } => val.to_string(),
Value::String { val, .. } => val, Value::String { val, .. } => val,
// Explicitly propagate errors instead of dropping them. // Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
"Only string or list<int> ranges are supported".into(), "Only string or list<int> ranges are supported".into(),
@ -84,7 +84,7 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
} }
} }
// Explicitly propagate errors instead of dropping them. // Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
"could not perform subbytes".to_string(), "could not perform subbytes".to_string(),
@ -249,12 +249,12 @@ fn at(val: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }
@ -277,10 +277,10 @@ fn at_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
match start.cmp(&end) { match start.cmp(&end) {
Ordering::Equal => Value::Binary { val: vec![], span }, Ordering::Equal => Value::Binary { val: vec![], span },
Ordering::Greater => Value::Error { Ordering::Greater => Value::Error {
error: ShellError::TypeMismatch { error: Box::new(ShellError::TypeMismatch {
err_message: "End must be greater than or equal to Start".to_string(), err_message: "End must be greater than or equal to Start".to_string(),
span: arg.arg_span, span: arg.arg_span,
}, }),
}, },
Ordering::Less => Value::Binary { Ordering::Less => Value::Binary {
val: { val: {

@ -53,7 +53,7 @@ impl Command for BytesBuild {
match val { match val {
Value::Binary { mut val, .. } => output.append(&mut val), Value::Binary { mut val, .. } => output.append(&mut val),
// Explicitly propagate errors instead of dropping them. // Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
other => { other => {
return Err(ShellError::TypeMismatch { return Err(ShellError::TypeMismatch {
err_message: "only binary data arguments are supported".to_string(), err_message: "only binary data arguments are supported".to_string(),

@ -55,7 +55,7 @@ impl Command for BytesCollect {
} }
} }
// Explicitly propagate errors instead of dropping them. // Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
other => { other => {
return Err(ShellError::OnlySupportsThisInputType { return Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),

@ -93,12 +93,12 @@ fn ends_with(val: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -135,12 +135,12 @@ fn index_of(val: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -74,12 +74,12 @@ fn length(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -142,12 +142,12 @@ fn remove(val: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -133,12 +133,12 @@ fn replace(val: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -84,12 +84,12 @@ fn reverse(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -80,12 +80,12 @@ impl Command for BytesStartsWith {
// Unsupported data // Unsupported data
Ok(other) => { Ok(other) => {
return Ok(Value::Error { return Ok(Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string and binary".into(), exp_input_type: "string and binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
} }
.into_pipeline_data()); .into_pipeline_data());
} }
@ -149,12 +149,12 @@ fn starts_with(val: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(), Value::Error { .. } => val.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(), exp_input_type: "binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -79,7 +79,7 @@ impl HashableValue {
Value::Binary { val, span } => Ok(HashableValue::Binary { val, span }), Value::Binary { val, span } => Ok(HashableValue::Binary { val, span }),
// Explicitly propagate errors instead of dropping them. // Explicitly propagate errors instead of dropping them.
Value::Error { error } => Err(error), Value::Error { error } => Err(*error),
_ => Err(ShellError::UnsupportedInput( _ => Err(ShellError::UnsupportedInput(
"input value is not hashable".into(), "input value is not hashable".into(),
format!("input type: {:?}", value.get_type()), format!("input type: {:?}", value.get_type()),
@ -236,7 +236,7 @@ mod test {
}, },
Value::Nothing { span }, Value::Nothing { span },
Value::Error { Value::Error {
error: ShellError::DidYouMean("what?".to_string(), span), error: Box::new(ShellError::DidYouMean("what?".to_string(), span)),
}, },
Value::CellPath { Value::CellPath {
val: CellPath { val: CellPath {

@ -160,7 +160,7 @@ fn run_histogram(
for v in values { for v in values {
match v { match v {
// Propagate existing errors. // Propagate existing errors.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
_ => { _ => {
let t = v.get_type(); let t = v.get_type();
let span = v.expect_span(); let span = v.expect_span();
@ -198,7 +198,7 @@ fn run_histogram(
} }
} }
// Propagate existing errors. // Propagate existing errors.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
_ => continue, _ => continue,
} }
} }

@ -193,12 +193,12 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "int, filesize, float, string".into(), exp_input_type: "int, filesize, float, string".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -87,12 +87,12 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer or filesize".into(), exp_input_type: "integer or filesize".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -188,13 +188,13 @@ pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer, float, filesize, string, date, duration, binary or bool" exp_input_type: "integer, float, filesize, string, date, duration, binary or bool"
.into(), .into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -161,17 +161,19 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
}, },
Value::String { val, .. } => match string_to_boolean(val, span) { Value::String { val, .. } => match string_to_boolean(val, span) {
Ok(val) => Value::Bool { val, span }, Ok(val) => Value::Bool { val, span },
Err(error) => Value::Error { error }, Err(error) => Value::Error {
error: Box::new(error),
},
}, },
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "bool, integer, float or string".into(), exp_input_type: "bool, integer, float or string".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -209,12 +209,12 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
Value::Error { .. } => return input.clone(), Value::Error { .. } => return input.clone(),
other => { other => {
return Value::Error { return Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string and integer".into(), exp_input_type: "string and integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}; };
} }
}; };
@ -245,21 +245,21 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
Zone::East(i) => match FixedOffset::east_opt((*i as i32) * HOUR) { Zone::East(i) => match FixedOffset::east_opt((*i as i32) * HOUR) {
Some(eastoffset) => match_datetime!(eastoffset.timestamp_nanos(ts)), Some(eastoffset) => match_datetime!(eastoffset.timestamp_nanos(ts)),
None => Value::Error { None => Value::Error {
error: ShellError::DatetimeParseError(input.debug_value(), *span), error: Box::new(ShellError::DatetimeParseError(input.debug_value(), *span)),
}, },
}, },
Zone::West(i) => match FixedOffset::west_opt((*i as i32) * HOUR) { Zone::West(i) => match FixedOffset::west_opt((*i as i32) * HOUR) {
Some(westoffset) => match_datetime!(westoffset.timestamp_nanos(ts)), Some(westoffset) => match_datetime!(westoffset.timestamp_nanos(ts)),
None => Value::Error { None => Value::Error {
error: ShellError::DatetimeParseError(input.debug_value(), *span), error: Box::new(ShellError::DatetimeParseError(input.debug_value(), *span)),
}, },
}, },
Zone::Error => Value::Error { Zone::Error => Value::Error {
// This is an argument error, not an input error // This is an argument error, not an input error
error: ShellError::TypeMismatch { error: Box::new(ShellError::TypeMismatch {
err_message: "Invalid timezone or offset".to_string(), err_message: "Invalid timezone or offset".to_string(),
span: *span, span: *span,
}, }),
}, },
}, },
}; };
@ -273,7 +273,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
Ok(d) => Value::Date { val: d, span: head }, Ok(d) => Value::Date { val: d, span: head },
Err(reason) => { Err(reason) => {
Value::Error { Value::Error {
error: ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) }, error: Box::new(ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) }),
} }
} }
}, },
@ -292,12 +292,12 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(), exp_input_type: "string".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }
@ -374,7 +374,7 @@ mod tests {
#[test] #[test]
fn takes_timestamp_offset_as_int() { fn takes_timestamp_offset_as_int() {
let date_int = Value::test_int(1614434140_000000000); let date_int = Value::test_int(1_614_434_140_000_000_000);
let timezone_option = Some(Spanned { let timezone_option = Some(Spanned {
item: Zone::East(8), item: Zone::East(8),
span: Span::test_data(), span: Span::test_data(),

@ -88,12 +88,12 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
match other.parse::<f64>() { match other.parse::<f64>() {
Ok(x) => Value::float(x, head), Ok(x) => Value::float(x, head),
Err(reason) => Value::Error { Err(reason) => Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "float".to_string(), to_type: "float".to_string(),
from_type: reason.to_string(), from_type: reason.to_string(),
span: *span, span: *span,
help: None, help: None,
}, }),
}, },
} }
} }
@ -108,12 +108,12 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string, integer or bool".into(), exp_input_type: "string, integer or bool".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -174,7 +174,9 @@ fn into_duration(
Box::new(move |old| action(old, &d, float_precision, head)), Box::new(move |old| action(old, &d, float_precision, head)),
); );
if let Err(error) = r { if let Err(error) = r {
return Value::Error { error }; return Value::Error {
error: Box::new(error),
};
} }
} }
@ -430,7 +432,7 @@ fn action(
} }
} }
} }
Err(e) => Value::Error { error: e }, Err(e) => Value::Error { error: Box::new(e) },
} }
} else { } else {
input.clone() input.clone()
@ -464,34 +466,36 @@ fn action(
} }
} }
} }
Err(e) => Value::Error { error: e }, Err(e) => Value::Error { error: Box::new(e) },
} }
} else { } else {
Value::Error { Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "string".into(), to_type: "string".into(),
from_type: "duration".into(), from_type: "duration".into(),
span, span,
help: None, help: None,
}, }),
} }
} }
} else { } else {
match string_to_duration(val, span, *value_span) { match string_to_duration(val, span, *value_span) {
Ok(val) => Value::Duration { val, span }, Ok(val) => Value::Duration { val, span },
Err(error) => Value::Error { error }, Err(error) => Value::Error {
error: Box::new(error),
},
} }
} }
} }
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string or duration".into(), exp_input_type: "string or duration".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -110,19 +110,21 @@ pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
val, val,
span: value_span, span: value_span,
}, },
Err(error) => Value::Error { error }, Err(error) => Value::Error {
error: Box::new(error),
},
}, },
Value::Nothing { .. } => Value::Filesize { Value::Nothing { .. } => Value::Filesize {
val: 0, val: 0,
span: value_span, span: value_span,
}, },
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string and integer".into(), exp_input_type: "string and integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: value_span, src_span: value_span,
}, }),
}, },
} }
} else { } else {

@ -189,12 +189,12 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
Ok(v) => v, Ok(v) => v,
_ => { _ => {
return Value::Error { return Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "float".to_string(), to_type: "float".to_string(),
from_type: "integer".to_string(), from_type: "integer".to_string(),
span, span,
help: None, help: None,
}, }),
} }
} }
} }
@ -206,7 +206,9 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
if radix == 10 { if radix == 10 {
match int_from_string(val, span) { match int_from_string(val, span) {
Ok(val) => Value::Int { val, span }, Ok(val) => Value::Int { val, span },
Err(error) => Value::Error { error }, Err(error) => Value::Error {
error: Box::new(error),
},
} }
} else { } else {
convert_int(input, span, radix) convert_int(input, span, radix)
@ -232,10 +234,10 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
.unwrap() .unwrap()
{ {
Value::Error { Value::Error {
error: ShellError::IncorrectValue { error: Box::new(ShellError::IncorrectValue {
msg: "DateTime out of range for timestamp: 1677-09-21T00:12:43Z to 2262-04-11T23:47:16".to_string(), msg: "DateTime out of range for timestamp: 1677-09-21T00:12:43Z to 2262-04-11T23:47:16".to_string(),
span span
}, }),
} }
} else { } else {
Value::Int { Value::Int {
@ -269,13 +271,13 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "integer, float, filesize, date, string, binary, duration or bool" exp_input_type: "integer, float, filesize, date, string, binary, duration or bool"
.into(), .into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }
@ -292,7 +294,7 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
{ {
match int_from_string(val, head) { match int_from_string(val, head) {
Ok(x) => return Value::int(x, head), Ok(x) => return Value::int(x, head),
Err(e) => return Value::Error { error: e }, Err(e) => return Value::Error { error: Box::new(e) },
} }
} else if val.starts_with("00") { } else if val.starts_with("00") {
// It's a padded string // It's a padded string
@ -300,12 +302,12 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
Ok(n) => return Value::int(n, head), Ok(n) => return Value::int(n, head),
Err(e) => { Err(e) => {
return Value::Error { return Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "string".to_string(), to_type: "string".to_string(),
from_type: "int".to_string(), from_type: "int".to_string(),
span: head, span: head,
help: Some(e.to_string()), help: Some(e.to_string()),
}, }),
} }
} }
} }
@ -316,24 +318,24 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
Value::Error { .. } => return input.clone(), Value::Error { .. } => return input.clone(),
other => { other => {
return Value::Error { return Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string and integer".into(), exp_input_type: "string and integer".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}; };
} }
}; };
match i64::from_str_radix(i.trim(), radix) { match i64::from_str_radix(i.trim(), radix) {
Ok(n) => Value::int(n, head), Ok(n) => Value::int(n, head),
Err(_reason) => Value::Error { Err(_reason) => Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "string".to_string(), to_type: "string".to_string(),
from_type: "int".to_string(), from_type: "int".to_string(),
span: head, span: head,
help: None, help: None,
}, }),
}, },
} }
} }
@ -483,9 +485,9 @@ mod test {
} }
#[rstest] #[rstest]
#[case("2262-04-11T23:47:16+00:00", 0x7fffffff_ffffffff)] #[case("2262-04-11T23:47:16+00:00", 0x7fff_ffff_ffff_ffff)]
#[case("1970-01-01T00:00:00+00:00", 0)] #[case("1970-01-01T00:00:00+00:00", 0)]
#[case("1677-09-21T00:12:44+00:00", -0x7fffffff_ffffffff)] #[case("1677-09-21T00:12:44+00:00", -0x7fff_ffff_ffff_ffff)]
fn datetime_to_int_values_that_work( fn datetime_to_int_values_that_work(
#[case] dt_in: DateTime<FixedOffset>, #[case] dt_in: DateTime<FixedOffset>,
#[case] int_expected: i64, #[case] int_expected: i64,
@ -522,14 +524,15 @@ mod test {
}, },
Span::test_data(), Span::test_data(),
); );
if let Value::Error { if let Value::Error { error } = actual {
error: ShellError::IncorrectValue { msg: e, .. }, if let ShellError::IncorrectValue { msg: e, .. } = *error {
} = actual
{
assert!( assert!(
e.contains(err_expected), e.contains(err_expected),
"{e:?} doesn't contain {err_expected}" "{e:?} doesn't contain {err_expected}"
); );
} else {
panic!("Unexpected error variant {error:?}")
}
} else { } else {
panic!("Unexpected actual value {actual:?}") panic!("Unexpected actual value {actual:?}")
} }

@ -185,12 +185,12 @@ fn into_record(
Value::Record { cols, vals, span } => Value::Record { cols, vals, span }, Value::Record { cols, vals, span } => Value::Record { cols, vals, span },
Value::Error { .. } => input, Value::Error { .. } => input,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(), exp_input_type: "string".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: call.head, dst_span: call.head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
}; };
Ok(res.into_pipeline_data()) Ok(res.into_pipeline_data())

@ -247,28 +247,28 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
span: _, span: _,
} => Value::Error { } => Value::Error {
// Watch out for CantConvert's argument order // Watch out for CantConvert's argument order
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "string".into(), to_type: "string".into(),
from_type: "record".into(), from_type: "record".into(),
span, span,
help: Some("try using the `to nuon` command".into()), help: Some("try using the `to nuon` command".into()),
}, }),
}, },
Value::Binary { .. } => Value::Error { Value::Binary { .. } => Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "string".into(), to_type: "string".into(),
from_type: "binary".into(), from_type: "binary".into(),
span, span,
help: Some("try using the `decode` command".into()), help: Some("try using the `decode` command".into()),
}, }),
}, },
x => Value::Error { x => Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: String::from("string"), to_type: String::from("string"),
from_type: x.get_type().to_string(), from_type: x.get_type().to_string(),
span, span,
help: None, help: None,
}, }),
}, },
} }
} }

@ -217,7 +217,7 @@ fn action(
Ok(Value::Nothing { span: *span }) Ok(Value::Nothing { span: *span })
} }
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => Err(error.clone()), Value::Error { error } => Err(*error.clone()),
other => Err(ShellError::OnlySupportsThisInputType { other => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "list".into(), exp_input_type: "list".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),

@ -463,7 +463,7 @@ pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value {
Ok(v) => v, Ok(v) => v,
Err(_) => { Err(_) => {
return Value::Error { return Value::Error {
error: ShellError::NonUtf8(span), error: Box::new(ShellError::NonUtf8(span)),
} }
} }
}; };

@ -461,13 +461,13 @@ pub fn create_column(
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"The given local datetime representation is invalid." "The given local datetime representation is invalid."
.to_string(), .to_string(),
format!("timestamp is {a:?}"), format!("timestamp is {a:?}"),
span, span,
Span::unknown(), Span::unknown(),
), )),
} }
} }
}; };
@ -476,13 +476,13 @@ pub fn create_column(
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"The given local datetime representation is invalid." "The given local datetime representation is invalid."
.to_string(), .to_string(),
format!("timestamp is {a:?}"), format!("timestamp is {a:?}"),
span, span,
Span::unknown(), Span::unknown(),
), )),
} }
} }
}; };
@ -526,13 +526,13 @@ pub fn create_column(
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"The given local datetime representation is invalid." "The given local datetime representation is invalid."
.to_string(), .to_string(),
format!("timestamp is {a:?}"), format!("timestamp is {a:?}"),
span, span,
Span::unknown(), Span::unknown(),
), )),
} }
} }
}; };
@ -541,13 +541,13 @@ pub fn create_column(
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"The given local datetime representation is invalid." "The given local datetime representation is invalid."
.to_string(), .to_string(),
format!("timestamp is {a:?}"), format!("timestamp is {a:?}"),
span, span,
Span::unknown(), Span::unknown(),
), )),
} }
} }
}; };

@ -132,10 +132,10 @@ where
span, span,
}, },
Err(_) => Value::Error { Err(_) => Value::Error {
error: ShellError::TypeMismatch { error: Box::new(ShellError::TypeMismatch {
err_message: "invalid format".to_string(), err_message: "invalid format".to_string(),
span, span,
}, }),
}, },
} }
} }
@ -152,7 +152,10 @@ fn format_helper(value: Value, formatter: &str, formatter_span: Span, head_span:
} }
} }
_ => Value::Error { _ => Value::Error {
error: ShellError::DatetimeParseError(value.debug_value(), head_span), error: Box::new(ShellError::DatetimeParseError(
value.debug_value(),
head_span,
)),
}, },
} }
} }
@ -177,7 +180,7 @@ fn format_helper_rfc2822(value: Value, span: Span) -> Value {
} }
} }
_ => Value::Error { _ => Value::Error {
error: ShellError::DatetimeParseError(value.debug_value(), span), error: Box::new(ShellError::DatetimeParseError(value.debug_value(), span)),
}, },
} }
} }

@ -90,7 +90,7 @@ fn helper(value: Value, head: Span) -> Value {
span: head, span: head,
}, },
_ => Value::Error { _ => Value::Error {
error: ShellError::DatetimeParseError(value.debug_value(), head), error: Box::new(ShellError::DatetimeParseError(value.debug_value(), head)),
}, },
} }
} }

@ -156,7 +156,7 @@ fn helper(val: Value, head: Span) -> Value {
} }
Value::Date { val, span: _ } => parse_date_into_table(Ok(val), head), Value::Date { val, span: _ } => parse_date_into_table(Ok(val), head),
_ => Value::Error { _ => Value::Error {
error: DatetimeParseError(val.debug_value(), head), error: Box::new(DatetimeParseError(val.debug_value(), head)),
}, },
} }
} }

@ -161,7 +161,7 @@ fn helper(val: Value, head: Span) -> Value {
} }
Value::Date { val, span: _ } => parse_date_into_table(Ok(val), head), Value::Date { val, span: _ } => parse_date_into_table(Ok(val), head),
_ => Value::Error { _ => Value::Error {
error: DatetimeParseError(val.debug_value(), head), error: Box::new(DatetimeParseError(val.debug_value(), head)),
}, },
} }
} }

@ -128,7 +128,7 @@ fn helper(value: Value, head: Span, timezone: &Spanned<String>) -> Value {
_to_timezone(dt.with_timezone(dt.offset()), timezone, head) _to_timezone(dt.with_timezone(dt.offset()), timezone, head)
} }
_ => Value::Error { _ => Value::Error {
error: ShellError::DatetimeParseError(value.debug_value(), head), error: Box::new(ShellError::DatetimeParseError(value.debug_value(), head)),
}, },
} }
} }
@ -137,10 +137,10 @@ fn _to_timezone(dt: DateTime<FixedOffset>, timezone: &Spanned<String>, span: Spa
match datetime_in_timezone(&dt, timezone.item.as_str()) { match datetime_in_timezone(&dt, timezone.item.as_str()) {
Ok(dt) => Value::Date { val: dt, span }, Ok(dt) => Value::Date { val: dt, span },
Err(_) => Value::Error { Err(_) => Value::Error {
error: ShellError::TypeMismatch { error: Box::new(ShellError::TypeMismatch {
err_message: String::from("invalid time zone"), err_message: String::from("invalid time zone"),
span: timezone.span, span: timezone.span,
}, }),
}, },
} }
} }

@ -15,12 +15,12 @@ pub(crate) fn parse_date_from_string(
LocalResult::Single(d) => Ok(d), LocalResult::Single(d) => Ok(d),
LocalResult::Ambiguous(d, _) => Ok(d), LocalResult::Ambiguous(d, _) => Ok(d),
LocalResult::None => Err(Value::Error { LocalResult::None => Err(Value::Error {
error: ShellError::DatetimeParseError(input.to_string(), span), error: Box::new(ShellError::DatetimeParseError(input.to_string(), span)),
}), }),
} }
} }
Err(_) => Err(Value::Error { Err(_) => Err(Value::Error {
error: ShellError::DatetimeParseError(input.to_string(), span), error: Box::new(ShellError::DatetimeParseError(input.to_string(), span)),
}), }),
} }
} }

@ -279,7 +279,9 @@ fn get_expression_as_value(
) -> Value { ) -> Value {
match eval_expression(engine_state, stack, inner_expr) { match eval_expression(engine_state, stack, inner_expr) {
Ok(v) => v, Ok(v) => v,
Err(error) => Value::Error { error }, Err(error) => Value::Error {
error: Box::new(error),
},
} }
} }

@ -379,13 +379,13 @@ fn interactive_copy(
); );
if let Err(e) = interaction { if let Err(e) = interaction {
Value::Error { Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
e.to_string(), e.to_string(),
e.to_string(), e.to_string(),
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
} }
} else if !confirmed { } else if !confirmed {
let msg = format!("{:} not copied to {:}", src.display(), dst.display()); let msg = format!("{:} not copied to {:}", src.display(), dst.display());
@ -518,13 +518,13 @@ fn copy_symlink(
Ok(p) => p, Ok(p) => p,
Err(err) => { Err(err) => {
return Value::Error { return Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
err.to_string(), err.to_string(),
err.to_string(), err.to_string(),
Some(span), Some(span),
None, None,
vec![], vec![],
), )),
} }
} }
}; };
@ -551,7 +551,13 @@ fn copy_symlink(
Value::String { val: msg, span } Value::String { val: msg, span }
} }
Err(e) => Value::Error { Err(e) => Value::Error {
error: ShellError::GenericError(e.to_string(), e.to_string(), Some(span), None, vec![]), error: Box::new(ShellError::GenericError(
e.to_string(),
e.to_string(),
Some(span),
None,
vec![],
)),
}, },
} }
} }
@ -593,5 +599,7 @@ fn convert_io_error(error: std::io::Error, src: PathBuf, dst: PathBuf, span: Spa
_ => ShellError::IOErrorSpanned(message_src, span), _ => ShellError::IOErrorSpanned(message_src, span),
}; };
Value::Error { error: shell_error } Value::Error {
error: Box::new(shell_error),
}
} }

@ -255,10 +255,14 @@ impl Command for Ls {
); );
match entry { match entry {
Ok(value) => Some(value), Ok(value) => Some(value),
Err(err) => Some(Value::Error { error: err }), Err(err) => Some(Value::Error {
error: Box::new(err),
}),
} }
} }
Err(err) => Some(Value::Error { error: err }), Err(err) => Some(Value::Error {
error: Box::new(err),
}),
} }
} }
_ => Some(Value::Nothing { span: call_span }), _ => Some(Value::Nothing { span: call_span }),

@ -193,7 +193,9 @@ impl Command for Mv {
interactive, interactive,
); );
if let Err(error) = result { if let Err(error) = result {
Some(Value::Error { error }) Some(Value::Error {
error: Box::new(error),
})
} else if verbose { } else if verbose {
let val = match result { let val = match result {
Ok(true) => format!( Ok(true) => format!(

@ -405,13 +405,13 @@ fn rm(
if let Err(e) = result { if let Err(e) = result {
let msg = format!("Could not delete because: {e:}"); let msg = format!("Could not delete because: {e:}");
Value::Error { Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
msg, msg,
e.to_string(), e.to_string(),
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
} }
} else if verbose { } else if verbose {
let msg = if interactive && !confirmed { let msg = if interactive && !confirmed {
@ -427,25 +427,25 @@ fn rm(
} else { } else {
let msg = format!("Cannot remove {:}. try --recursive", f.to_string_lossy()); let msg = format!("Cannot remove {:}. try --recursive", f.to_string_lossy());
Value::Error { Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
msg, msg,
"cannot remove non-empty directory".into(), "cannot remove non-empty directory".into(),
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
} }
} }
} else { } else {
let msg = format!("no such file or directory: {:}", f.to_string_lossy()); let msg = format!("no such file or directory: {:}", f.to_string_lossy());
Value::Error { Value::Error {
error: ShellError::GenericError( error: Box::new(ShellError::GenericError(
msg, msg,
"no such file or directory".into(), "no such file or directory".into(),
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
), )),
} }
} }
}) })

@ -250,7 +250,7 @@ fn value_to_bytes(value: Value) -> Result<Vec<u8>, ShellError> {
Ok(val.into_bytes()) Ok(val.into_bytes())
} }
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => Err(error), Value::Error { error } => Err(*error),
other => Ok(other.as_string()?.into_bytes()), other => Ok(other.as_string()?.into_bytes()),
} }
} }
@ -376,7 +376,7 @@ fn stream_to_file(
Value::String { val, .. } => val.into_bytes(), Value::String { val, .. } => val.into_bytes(),
Value::Binary { val, .. } => val, Value::Binary { val, .. } => val,
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
other => { other => {
return Err(ShellError::OnlySupportsThisInputType { return Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "string or binary".into(), exp_input_type: "string or binary".into(),

@ -137,7 +137,7 @@ fn getcol(
.into_pipeline_data(ctrlc) .into_pipeline_data(ctrlc)
.set_metadata(metadata)), .set_metadata(metadata)),
// Propagate errors // Propagate errors
PipelineData::Value(Value::Error { error }, ..) => Err(error), PipelineData::Value(Value::Error { error }, ..) => Err(*error),
PipelineData::Value(other, ..) => Err(ShellError::OnlySupportsThisInputType { PipelineData::Value(other, ..) => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "record or table".into(), exp_input_type: "record or table".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),

@ -167,7 +167,9 @@ with 'transpose' first."#
Err(ShellError::Break(_)) => None, Err(ShellError::Break(_)) => None,
Err(error) => { Err(error) => {
let error = chain_error_with_input(error, input_span); let error = chain_error_with_input(error, input_span);
Some(Value::Error { error }) Some(Value::Error {
error: Box::new(error),
})
} }
} }
}) })
@ -187,7 +189,11 @@ with 'transpose' first."#
let x = match x { let x = match x {
Ok(x) => x, Ok(x) => x,
Err(ShellError::Break(_)) => return None, Err(ShellError::Break(_)) => return None,
Err(err) => return Some(Value::Error { error: err }), Err(err) => {
return Some(Value::Error {
error: Box::new(err),
})
}
}; };
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
@ -208,7 +214,7 @@ with 'transpose' first."#
Ok(v) => Some(v.into_value(span)), Ok(v) => Some(v.into_value(span)),
Err(ShellError::Break(_)) => None, Err(ShellError::Break(_)) => None,
Err(error) => { Err(error) => {
let error = chain_error_with_input(error, input_span); let error = Box::new(chain_error_with_input(error, input_span));
Some(Value::Error { error }) Some(Value::Error { error })
} }
} }

@ -101,7 +101,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
} }
} }
Err(error) => Some(Value::Error { Err(error) => Some(Value::Error {
error: chain_error_with_input(error, x.span()), error: Box::new(chain_error_with_input(error, x.span())),
}), }),
} }
}) })
@ -118,7 +118,11 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
let x = match x { let x = match x {
Ok(x) => x, Ok(x) => x,
Err(err) => return Some(Value::Error { error: err }), Err(err) => {
return Some(Value::Error {
error: Box::new(err),
})
}
}; };
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
@ -144,7 +148,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
} }
} }
Err(error) => Some(Value::Error { Err(error) => Some(Value::Error {
error: chain_error_with_input(error, x.span()), error: Box::new(chain_error_with_input(error, x.span())),
}), }),
} }
}) })
@ -177,7 +181,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
} }
} }
Err(error) => Some(Value::Error { Err(error) => Some(Value::Error {
error: chain_error_with_input(error, x.span()), error: Box::new(chain_error_with_input(error, x.span())),
}), }),
} }
.into_pipeline_data(ctrlc)) .into_pipeline_data(ctrlc))

@ -522,7 +522,7 @@ fn find_with_rest_and_highlight(
} }
} }
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => return Err(error), Value::Error { error } => return Err(*error),
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
"unsupported type from raw stream".into(), "unsupported type from raw stream".into(),

@ -141,7 +141,7 @@ fn first_helper(
} }
} }
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => Err(error), Value::Error { error } => Err(*error),
other => Err(ShellError::OnlySupportsThisInputType { other => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "list, binary or range".into(), exp_input_type: "list, binary or range".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),

@ -154,7 +154,7 @@ enum TableInside<'a> {
fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span, all: bool) -> Vec<Value> { fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span, all: bool) -> Vec<Value> {
let tag = match item.span() { let tag = match item.span() {
Ok(x) => x, Ok(x) => x,
Err(e) => return vec![Value::Error { error: e }], Err(e) => return vec![Value::Error { error: Box::new(e) }],
}; };
let res = { let res = {
@ -172,19 +172,19 @@ fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span, all: bool) ->
Value::Error { .. } => return vec![item.clone()], Value::Error { .. } => return vec![item.clone()],
other => { other => {
return vec![Value::Error { return vec![Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "record".into(), exp_input_type: "record".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: _name_tag, dst_span: _name_tag,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}]; }];
} }
}; };
let s = match item.span() { let s = match item.span() {
Ok(x) => x, Ok(x) => x,
Err(e) => return vec![Value::Error { error: e }], Err(e) => return vec![Value::Error { error: Box::new(e) }],
}; };
let records_iterator = { let records_iterator = {
@ -229,12 +229,12 @@ fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span, all: bool) ->
if all && vals.iter().all(|f| f.as_record().is_ok()) => if all && vals.iter().all(|f| f.as_record().is_ok()) =>
{ {
if need_flatten && inner_table.is_some() { if need_flatten && inner_table.is_some() {
return vec![Value::Error{ error: ShellError::UnsupportedInput( return vec![Value::Error{ error: Box::new(ShellError::UnsupportedInput(
"can only flatten one inner list at a time. tried flattening more than one column with inner lists... but is flattened already".to_string(), "can only flatten one inner list at a time. tried flattening more than one column with inner lists... but is flattened already".to_string(),
"value originates from here".into(), "value originates from here".into(),
s, s,
*span *span
)} ))}
]; ];
} }
// it's a table (a list of record, we can flatten inner record) // it's a table (a list of record, we can flatten inner record)
@ -267,12 +267,12 @@ fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span, all: bool) ->
} }
Value::List { vals: values, span } => { Value::List { vals: values, span } => {
if need_flatten && inner_table.is_some() { if need_flatten && inner_table.is_some() {
return vec![Value::Error{ error: ShellError::UnsupportedInput( return vec![Value::Error{ error: Box::new(ShellError::UnsupportedInput(
"can only flatten one inner list at a time. tried flattening more than one column with inner lists... but is flattened already".to_string(), "can only flatten one inner list at a time. tried flattening more than one column with inner lists... but is flattened already".to_string(),
"value originates from here".into(), "value originates from here".into(),
s, s,
*span *span
)} ))}
]; ];
} }

@ -244,7 +244,7 @@ pub fn group(
Grouper::ByColumn(Some(column_name)) => { Grouper::ByColumn(Some(column_name)) => {
let block = Box::new(move |_, row: &Value| { let block = Box::new(move |_, row: &Value| {
if let Value::Error { error } = row { if let Value::Error { error } = row {
return Err(error.clone()); return Err(*error.clone());
}; };
match row.get_data_by_key(&column_name.item) { match row.get_data_by_key(&column_name.item) {
Some(group_key) => Ok(group_key.as_string()?), Some(group_key) => Ok(group_key.as_string()?),

@ -163,12 +163,12 @@ fn insert(
pd.into_value(span), pd.into_value(span),
span, span,
) { ) {
return Value::Error { error: e }; return Value::Error { error: Box::new(e) };
} }
input input
} }
Err(e) => Value::Error { error: e }, Err(e) => Value::Error { error: Box::new(e) },
} }
}, },
ctrlc, ctrlc,
@ -199,7 +199,7 @@ fn insert(
if let Err(e) = if let Err(e) =
input.insert_data_at_cell_path(&cell_path.members, replacement, span) input.insert_data_at_cell_path(&cell_path.members, replacement, span)
{ {
return Value::Error { error: e }; return Value::Error { error: Box::new(e) };
} }
input input

@ -86,7 +86,7 @@ fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellErr
// Check for and propagate errors // Check for and propagate errors
for value in input.into_iter() { for value in input.into_iter() {
if let Value::Error { error } = value { if let Value::Error { error } = value {
return Err(error); return Err(*error);
} }
count += 1 count += 1
} }

@ -112,7 +112,7 @@ impl Command for Lines {
PipelineData::Value(val, ..) => { PipelineData::Value(val, ..) => {
match val { match val {
// Propagate existing errors // Propagate existing errors
Value::Error { error } => Err(error), Value::Error { error } => Err(*error),
_ => Err(ShellError::OnlySupportsThisInputType { _ => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "string or raw data".into(), exp_input_type: "string or raw data".into(),
wrong_type: val.get_type().to_string(), wrong_type: val.get_type().to_string(),
@ -129,7 +129,9 @@ impl Command for Lines {
.enumerate() .enumerate()
.map(move |(_idx, x)| match x { .map(move |(_idx, x)| match x {
Ok(x) => x, Ok(x) => x,
Err(err) => Value::Error { error: err }, Err(err) => Value::Error {
error: Box::new(err),
},
}) })
.into_pipeline_data(ctrlc)), .into_pipeline_data(ctrlc)),
} }
@ -232,7 +234,7 @@ impl Iterator for RawStreamLinesAdapter {
self.queue.append(&mut lines); self.queue.append(&mut lines);
} }
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => return Some(Err(error)), Value::Error { error } => return Some(Err(*error)),
other => { other => {
return Some(Err(ShellError::OnlySupportsThisInputType { return Some(Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(), exp_input_type: "string".into(),

@ -125,11 +125,15 @@ repeating this process with row 1, and so on."#
span: call.head, span: call.head,
} }
} }
Err(error) => Value::Error { error }, Err(error) => Value::Error {
error: Box::new(error),
},
} }
} }
(_, None) => inp, (_, None) => inp,
(Err(error), _) => Value::Error { error }, (Err(error), _) => Value::Error {
error: Box::new(error),
},
}); });
if let Some(md) = metadata { if let Some(md) = metadata {

@ -158,9 +158,13 @@ impl Command for Move {
call.head, call.head,
) { ) {
Ok(val) => val, Ok(val) => val,
Err(error) => Value::Error { error }, Err(error) => Value::Error {
error: Box::new(error),
},
},
Err(error) => Value::Error {
error: Box::new(error),
}, },
Err(error) => Value::Error { error },
}); });
if let Some(md) = metadata { if let Some(md) = metadata {

@ -121,7 +121,7 @@ impl Command for ParEach {
) { ) {
Ok(v) => v, Ok(v) => v,
Err(error) => Value::Error { Err(error) => Value::Error {
error: chain_error_with_input(error, val_span), error: Box::new(chain_error_with_input(error, val_span)),
} }
.into_pipeline_data(), .into_pipeline_data(),
} }
@ -155,7 +155,7 @@ impl Command for ParEach {
) { ) {
Ok(v) => v, Ok(v) => v,
Err(error) => Value::Error { Err(error) => Value::Error {
error: chain_error_with_input(error, val_span), error: Box::new(chain_error_with_input(error, val_span)),
} }
.into_pipeline_data(), .into_pipeline_data(),
} }
@ -188,7 +188,7 @@ impl Command for ParEach {
) { ) {
Ok(v) => v, Ok(v) => v,
Err(error) => Value::Error { Err(error) => Value::Error {
error: chain_error_with_input(error, val_span), error: Box::new(chain_error_with_input(error, val_span)),
} }
.into_pipeline_data(), .into_pipeline_data(),
} }
@ -206,7 +206,12 @@ impl Command for ParEach {
.map(move |x| { .map(move |x| {
let x = match x { let x = match x {
Ok(x) => x, Ok(x) => x,
Err(err) => return Value::Error { error: err }.into_pipeline_data(), Err(err) => {
return Value::Error {
error: Box::new(err),
}
.into_pipeline_data()
}
}; };
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
@ -228,7 +233,10 @@ impl Command for ParEach {
redirect_stderr, redirect_stderr,
) { ) {
Ok(v) => v, Ok(v) => v,
Err(error) => Value::Error { error }.into_pipeline_data(), Err(error) => Value::Error {
error: Box::new(error),
}
.into_pipeline_data(),
} }
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()

@ -141,7 +141,7 @@ fn rename(
// check if the specified column to be renamed exists // check if the specified column to be renamed exists
if !cols.contains(&c[0]) { if !cols.contains(&c[0]) {
return Value::Error { return Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
format!( format!(
"The column '{}' does not exist in the input", "The column '{}' does not exist in the input",
&c[0] &c[0]
@ -151,7 +151,7 @@ fn rename(
specified_col_span.unwrap_or(head_span), specified_col_span.unwrap_or(head_span),
// Arrow 2 points at the input value. // Arrow 2 points at the input value.
span, span,
), )),
}; };
} }
for (idx, val) in cols.iter_mut().enumerate() { for (idx, val) in cols.iter_mut().enumerate() {
@ -177,12 +177,12 @@ fn rename(
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => item.clone(), Value::Error { .. } => item.clone(),
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "record".into(), exp_input_type: "record".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head_span, dst_span: head_span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
}, },
engine_state.ctrlc.clone(), engine_state.ctrlc.clone(),

@ -73,7 +73,7 @@ impl Command for Take {
.into_pipeline_data(ctrlc) .into_pipeline_data(ctrlc)
.set_metadata(metadata)), .set_metadata(metadata)),
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => Err(error), Value::Error { error } => Err(*error),
other => Err(ShellError::OnlySupportsThisInputType { other => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "list, binary or range".into(), exp_input_type: "list, binary or range".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),

@ -132,12 +132,12 @@ fn update(
if let Err(e) = if let Err(e) =
input.update_data_at_cell_path(&cell_path.members, pd.into_value(span)) input.update_data_at_cell_path(&cell_path.members, pd.into_value(span))
{ {
return Value::Error { error: e }; return Value::Error { error: Box::new(e) };
} }
input input
} }
Err(e) => Value::Error { error: e }, Err(e) => Value::Error { error: Box::new(e) },
} }
}, },
ctrlc, ctrlc,
@ -174,7 +174,7 @@ fn update(
let replacement = replacement.clone(); let replacement = replacement.clone();
if let Err(e) = input.update_data_at_cell_path(&cell_path.members, replacement) { if let Err(e) = input.update_data_at_cell_path(&cell_path.members, replacement) {
return Value::Error { error: e }; return Value::Error { error: Box::new(e) };
} }
input input

@ -253,7 +253,7 @@ fn process_cell(
redirect_stderr, redirect_stderr,
) { ) {
Ok(pd) => pd.into_value(span), Ok(pd) => pd.into_value(span),
Err(e) => Value::Error { error: e }, Err(e) => Value::Error { error: Box::new(e) },
} }
} }

@ -154,12 +154,12 @@ fn upsert(
if let Err(e) = if let Err(e) =
input.upsert_data_at_cell_path(&cell_path.members, pd.into_value(span)) input.upsert_data_at_cell_path(&cell_path.members, pd.into_value(span))
{ {
return Value::Error { error: e }; return Value::Error { error: Box::new(e) };
} }
input input
} }
Err(e) => Value::Error { error: e }, Err(e) => Value::Error { error: Box::new(e) },
} }
}, },
ctrlc, ctrlc,
@ -195,7 +195,7 @@ fn upsert(
let replacement = replacement.clone(); let replacement = replacement.clone();
if let Err(e) = input.upsert_data_at_cell_path(&cell_path.members, replacement) { if let Err(e) = input.upsert_data_at_cell_path(&cell_path.members, replacement) {
return Value::Error { error: e }; return Value::Error { error: Box::new(e) };
} }
input input

@ -119,7 +119,7 @@ pub fn get_values<'a>(
} }
} }
} }
Value::Error { error } => return Err(error.clone()), Value::Error { error } => return Err(*error.clone()),
_ => { _ => {
return Err(ShellError::OnlySupportsThisInputType { return Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "record or table".into(), exp_input_type: "record or table".into(),
@ -176,7 +176,7 @@ fn values(
Ok(vals.into_pipeline_data(ctrlc).set_metadata(metadata)) Ok(vals.into_pipeline_data(ctrlc).set_metadata(metadata))
} }
// Propagate errors // Propagate errors
PipelineData::Value(Value::Error { error }, ..) => Err(error), PipelineData::Value(Value::Error { error }, ..) => Err(*error),
PipelineData::Value(other, ..) => Err(ShellError::OnlySupportsThisInputType { PipelineData::Value(other, ..) => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "record or table".into(), exp_input_type: "record or table".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),

@ -97,7 +97,9 @@ not supported."#
None None
} }
} }
Err(err) => Some(Value::Error { error: err }), Err(err) => Some(Value::Error {
error: Box::new(err),
}),
} }
}) })
.into_pipeline_data(ctrlc) .into_pipeline_data(ctrlc)

@ -77,7 +77,9 @@ impl Command for FromJson {
} else { } else {
match convert_string_to_value(x.to_string(), span) { match convert_string_to_value(x.to_string(), span) {
Ok(v) => Some(v), Ok(v) => Some(v),
Err(error) => Some(Value::Error { error }), Err(error) => Some(Value::Error {
error: Box::new(error),
}),
} }
} }
}) })
@ -119,12 +121,12 @@ fn convert_nujson_to_value(value: &nu_json::Value, span: Span) -> Value {
nu_json::Value::U64(u) => { nu_json::Value::U64(u) => {
if *u > i64::MAX as u64 { if *u > i64::MAX as u64 {
Value::Error { Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "i64 sized integer".into(), to_type: "i64 sized integer".into(),
from_type: "value larger than i64".into(), from_type: "value larger than i64".into(),
span, span,
help: None, help: None,
}, }),
} }
} else { } else {
Value::Int { Value::Int {

@ -93,7 +93,7 @@ fn collect_binary(input: PipelineData, span: Span) -> Result<Vec<u8>, ShellError
Some(Value::Binary { val: b, .. }) => { Some(Value::Binary { val: b, .. }) => {
bytes.extend_from_slice(&b); bytes.extend_from_slice(&b);
} }
Some(Value::Error { error }) => return Err(error), Some(Value::Error { error }) => return Err(*error),
Some(x) => { Some(x) => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
"Expected binary from pipeline".to_string(), "Expected binary from pipeline".to_string(),

@ -16,7 +16,7 @@ fn from_value_to_delimited_string(
} }
Value::List { vals, span } => table_to_delimited(vals, span, separator, config, head), Value::List { vals, span } => table_to_delimited(vals, span, separator, config, head),
// Propagate errors by explicitly matching them before the final case. // Propagate errors by explicitly matching them before the final case.
Value::Error { error } => Err(error.clone()), Value::Error { error } => Err(*error.clone()),
v => Err(make_unsupported_input_error(v, head, v.expect_span())), v => Err(make_unsupported_input_error(v, head, v.expect_span())),
} }
} }
@ -122,7 +122,7 @@ fn to_string_tagged_value(
Value::Date { val, .. } => Ok(val.to_string()), Value::Date { val, .. } => Ok(val.to_string()),
Value::Nothing { .. } => Ok(String::new()), Value::Nothing { .. } => Ok(String::new()),
// Propagate existing errors // Propagate existing errors
Value::Error { error } => Err(error.clone()), Value::Error { error } => Err(*error.clone()),
_ => Err(make_unsupported_input_error(v, head, span)), _ => Err(make_unsupported_input_error(v, head, span)),
} }
} }

@ -70,12 +70,12 @@ impl Command for ToJson {
} }
.into_pipeline_data()), .into_pipeline_data()),
_ => Ok(Value::Error { _ => Ok(Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "JSON".into(), to_type: "JSON".into(),
from_type: value.get_type().to_string(), from_type: value.get_type().to_string(),
span, span,
help: None, help: None,
}, }),
} }
.into_pipeline_data()), .into_pipeline_data()),
} }
@ -126,7 +126,7 @@ pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
), ),
Value::List { vals, .. } => nu_json::Value::Array(json_list(vals)?), Value::List { vals, .. } => nu_json::Value::Array(json_list(vals)?),
Value::Error { error } => return Err(error.clone()), Value::Error { error } => return Err(*error.clone()),
Value::Closure { .. } | Value::Block { .. } | Value::Range { .. } => nu_json::Value::Null, Value::Closure { .. } | Value::Block { .. } | Value::Range { .. } => nu_json::Value::Null,
Value::Binary { val, .. } => { Value::Binary { val, .. } => {
nu_json::Value::Array(val.iter().map(|x| nu_json::Value::U64(*x as u64)).collect()) nu_json::Value::Array(val.iter().map(|x| nu_json::Value::U64(*x as u64)).collect())

@ -101,7 +101,7 @@ pub fn value_to_string(v: &Value, span: Span) -> Result<String, ShellError> {
// FIXME: make durations use the shortest lossless representation. // FIXME: make durations use the shortest lossless representation.
Value::Duration { val, .. } => Ok(format!("{}ns", *val)), Value::Duration { val, .. } => Ok(format!("{}ns", *val)),
// Propagate existing errors // Propagate existing errors
Value::Error { error } => Err(error.clone()), Value::Error { error } => Err(*error.clone()),
// FIXME: make filesizes use the shortest lossless representation. // FIXME: make filesizes use the shortest lossless representation.
Value::Filesize { val, .. } => Ok(format!("{}b", *val)), Value::Filesize { val, .. } => Ok(format!("{}b", *val)),
Value::Float { val, .. } => { Value::Float { val, .. } => {

@ -77,7 +77,7 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellErr
toml::Value::String(code) toml::Value::String(code)
} }
Value::Nothing { .. } => toml::Value::String("<Nothing>".to_string()), Value::Nothing { .. } => toml::Value::String("<Nothing>".to_string()),
Value::Error { error } => return Err(error.clone()), Value::Error { error } => return Err(*error.clone()),
Value::Binary { val, .. } => toml::Value::Array( Value::Binary { val, .. } => toml::Value::Array(
val.iter() val.iter()
.map(|x| toml::Value::Integer(*x as i64)) .map(|x| toml::Value::Integer(*x as i64))
@ -118,12 +118,12 @@ fn toml_into_pipeline_data(
} }
.into_pipeline_data()), .into_pipeline_data()),
_ => Ok(Value::Error { _ => Ok(Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "TOML".into(), to_type: "TOML".into(),
from_type: value_type.to_string(), from_type: value_type.to_string(),
span, span,
help: None, help: None,
}, }),
} }
.into_pipeline_data()), .into_pipeline_data()),
} }
@ -137,7 +137,7 @@ fn value_to_toml_value(
match v { match v {
Value::Record { .. } => helper(engine_state, v), Value::Record { .. } => helper(engine_state, v),
// Propagate existing errors // Propagate existing errors
Value::Error { error } => Err(error.clone()), Value::Error { error } => Err(*error.clone()),
_ => Err(ShellError::UnsupportedInput( _ => Err(ShellError::UnsupportedInput(
format!("{:?} is not valid top-level TOML", v.get_type()), format!("{:?} is not valid top-level TOML", v.get_type()),
"value originates from here".into(), "value originates from here".into(),

@ -79,7 +79,7 @@ pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
Value::Block { .. } => serde_yaml::Value::Null, Value::Block { .. } => serde_yaml::Value::Null,
Value::Closure { .. } => serde_yaml::Value::Null, Value::Closure { .. } => serde_yaml::Value::Null,
Value::Nothing { .. } => serde_yaml::Value::Null, Value::Nothing { .. } => serde_yaml::Value::Null,
Value::Error { error } => return Err(error.clone()), Value::Error { error } => return Err(*error.clone()),
Value::Binary { val, .. } => serde_yaml::Value::Sequence( Value::Binary { val, .. } => serde_yaml::Value::Sequence(
val.iter() val.iter()
.map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x))) .map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x)))
@ -111,12 +111,12 @@ fn to_yaml(input: PipelineData, head: Span) -> Result<PipelineData, ShellError>
} }
.into_pipeline_data()), .into_pipeline_data()),
_ => Ok(Value::Error { _ => Ok(Value::Error {
error: ShellError::CantConvert { error: Box::new(ShellError::CantConvert {
to_type: "YAML".into(), to_type: "YAML".into(),
from_type: value.get_type().to_string(), from_type: value.get_type().to_string(),
span: head, span: head,
help: None, help: None,
}, }),
} }
.into_pipeline_data()), .into_pipeline_data()),
} }

@ -111,16 +111,20 @@ where
other => { other => {
let span = match input.span() { let span = match input.span() {
Ok(span) => span, Ok(span) => span,
Err(error) => return Value::Error { error }, Err(error) => {
return Value::Error {
error: Box::new(error),
}
}
}; };
return Value::Error { return Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string or binary".into(), exp_input_type: "string or binary".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}; };
} }
}; };

@ -76,7 +76,9 @@ where
}), }),
); );
if let Err(error) = r { if let Err(error) = r {
return Value::Error { error }; return Value::Error {
error: Box::new(error),
};
} }
} }
v v

@ -68,12 +68,12 @@ fn abs_helper(val: Value, head: Span) -> Value {
}, },
Value::Error { .. } => val, Value::Error { .. } => val,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -77,23 +77,23 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
Value::Float { val, span } Value::Float { val, span }
} else { } else {
Value::Error { Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"'arccos' undefined for values outside the closed interval [-1, 1].".into(), "'arccos' undefined for values outside the closed interval [-1, 1].".into(),
"value originates from here".into(), "value originates from here".into(),
head, head,
span, span,
), )),
} }
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -67,23 +67,23 @@ fn operate(value: Value, head: Span) -> Value {
Value::Float { val, span } Value::Float { val, span }
} else { } else {
Value::Error { Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"'arccosh' undefined for values below 1.".into(), "'arccosh' undefined for values below 1.".into(),
"value originates from here".into(), "value originates from here".into(),
head, head,
span, span,
), )),
} }
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -78,23 +78,23 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
Value::Float { val, span } Value::Float { val, span }
} else { } else {
Value::Error { Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"'arcsin' undefined for values outside the closed interval [-1, 1].".into(), "'arcsin' undefined for values outside the closed interval [-1, 1].".into(),
"value originates from here".into(), "value originates from here".into(),
head, head,
span, span,
), )),
} }
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -67,12 +67,12 @@ fn operate(value: Value, head: Span) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -78,12 +78,12 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -67,23 +67,23 @@ fn operate(value: Value, head: Span) -> Value {
Value::Float { val, span } Value::Float { val, span }
} else { } else {
Value::Error { Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"'arctanh' undefined for values outside the open interval (-1, 1).".into(), "'arctanh' undefined for values outside the open interval (-1, 1).".into(),
"value originates from here".into(), "value originates from here".into(),
head, head,
span, span,
), )),
} }
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -64,12 +64,12 @@ fn operate(value: Value, head: Span) -> Value {
}, },
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -88,12 +88,12 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -69,12 +69,12 @@ fn operate(value: Value, head: Span) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -64,12 +64,12 @@ fn operate(value: Value, head: Span) -> Value {
}, },
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -67,23 +67,23 @@ fn operate(value: Value, head: Span) -> Value {
Value::Float { val, span } Value::Float { val, span }
} else { } else {
Value::Error { Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"'ln' undefined for values outside the open interval (0, Inf).".into(), "'ln' undefined for values outside the open interval (0, Inf).".into(),
"value originates from here".into(), "value originates from here".into(),
head, head,
span, span,
), )),
} }
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -96,13 +96,13 @@ fn operate(value: Value, head: Span, base: f64) -> Value {
if val <= 0.0 { if val <= 0.0 {
return Value::Error { return Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
"'math log' undefined for values outside the open interval (0, Inf)." "'math log' undefined for values outside the open interval (0, Inf)."
.into(), .into(),
"value originates from here".into(), "value originates from here".into(),
head, head,
span, span,
), )),
}; };
} }
// Specialize for better precision/performance // Specialize for better precision/performance
@ -118,12 +118,12 @@ fn operate(value: Value, head: Span, base: f64) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -132,7 +132,7 @@ pub fn mode(values: &[Value], _span: Span, head: &Span) -> Result<Value, ShellEr
Value::Filesize { val, .. } => { Value::Filesize { val, .. } => {
Ok(HashableType::new(val.to_ne_bytes(), NumberTypes::Filesize)) Ok(HashableType::new(val.to_ne_bytes(), NumberTypes::Filesize))
} }
Value::Error { error } => Err(error.clone()), Value::Error { error } => Err(*error.clone()),
other => Err(ShellError::UnsupportedInput( other => Err(ShellError::UnsupportedInput(
"Unable to give a result with this input".to_string(), "Unable to give a result with this input".to_string(),
"value originates from here".into(), "value originates from here".into(),

@ -112,7 +112,7 @@ pub fn sum(data: Vec<Value>, span: Span, head: Span) -> Result<Value, ShellError
| Value::Duration { .. } => { | Value::Duration { .. } => {
acc = acc.add(head, value, head)?; acc = acc.add(head, value, head)?;
} }
Value::Error { error } => return Err(error.clone()), Value::Error { error } => return Err(*error.clone()),
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
"Attempted to compute the sum of a value that cannot be summed".to_string(), "Attempted to compute the sum of a value that cannot be summed".to_string(),
@ -145,7 +145,7 @@ pub fn product(data: Vec<Value>, span: Span, head: Span) -> Result<Value, ShellE
Value::Int { .. } | Value::Float { .. } => { Value::Int { .. } | Value::Float { .. } => {
acc = acc.mul(head, value, head)?; acc = acc.mul(head, value, head)?;
} }
Value::Error { error } => return Err(error.clone()), Value::Error { error } => return Err(*error.clone()),
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
"Attempted to compute the product of a value that cannot be multiplied" "Attempted to compute the product of a value that cannot be multiplied"

@ -95,12 +95,12 @@ fn operate(value: Value, head: Span, precision: Option<i64>) -> Value {
Value::Int { .. } => value, Value::Int { .. } => value,
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -88,12 +88,12 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -69,12 +69,12 @@ fn operate(value: Value, head: Span) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

@ -73,24 +73,24 @@ fn operate(value: Value, head: Span) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }
fn error_negative_sqrt(head: Span, span: Span) -> Value { fn error_negative_sqrt(head: Span, span: Span) -> Value {
Value::Error { Value::Error {
error: ShellError::UnsupportedInput( error: Box::new(ShellError::UnsupportedInput(
String::from("Can't square root a negative number"), String::from("Can't square root a negative number"),
"value originates from here".into(), "value originates from here".into(),
head, head,
span, span,
), )),
} }
} }

@ -86,12 +86,12 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "numeric".into(), exp_input_type: "numeric".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: other.expect_span(), src_span: other.expect_span(),
}, }),
}, },
} }
} }

Some files were not shown because too many files have changed in this diff Show More