From b322a12f586a197920942f419d3aa235550c5ba7 Mon Sep 17 00:00:00 2001 From: JT Date: Wed, 20 Oct 2021 18:58:25 +1300 Subject: [PATCH] Add more helper functions --- Cargo.lock | 1 + crates/nu-command/src/conversions/into/int.rs | 30 ++------ crates/nu-command/src/experimental/git.rs | 5 +- .../src/experimental/git_checkout.rs | 5 +- crates/nu-command/src/filters/lines.rs | 2 +- crates/nu-command/src/strings/split/chars.rs | 30 ++------ crates/nu-command/src/strings/split/column.rs | 10 +-- crates/nu-command/src/strings/split/row.rs | 5 +- crates/nu-engine/Cargo.toml | 3 +- crates/nu-engine/src/from_value.rs | 76 ++++++++----------- crates/nu-protocol/src/shell_error.rs | 4 + crates/nu-protocol/src/value/mod.rs | 48 +++++++++--- 12 files changed, 98 insertions(+), 121 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ab87af86..696b84d35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,6 +596,7 @@ dependencies = [ name = "nu-engine" version = "0.1.0" dependencies = [ + "chrono", "itertools", "nu-parser", "nu-path", diff --git a/crates/nu-command/src/conversions/into/int.rs b/crates/nu-command/src/conversions/into/int.rs index 491379c70..f53aee083 100644 --- a/crates/nu-command/src/conversions/into/int.rs +++ b/crates/nu-command/src/conversions/into/int.rs @@ -55,26 +55,17 @@ impl Command for SubCommand { Example { description: "Convert string to integer", example: "'2' | into int", - result: Some(Value::Int { - val: 2, - span: Span::unknown(), - }), + result: Some(Value::test_int(2)), }, Example { description: "Convert decimal to integer", example: "5.9 | into int", - result: Some(Value::Int { - val: 5, - span: Span::unknown(), - }), + result: Some(Value::test_int(5)), }, Example { description: "Convert decimal string to integer", example: "'5.9' | into int", - result: Some(Value::Int { - val: 5, - span: Span::unknown(), - }), + result: Some(Value::test_int(5)), }, Example { description: "Convert file size to integer", @@ -88,18 +79,9 @@ impl Command for SubCommand { description: "Convert bool to integer", example: "[$false, $true] | into int", result: Some(Value::Stream { - stream: vec![ - Value::Int { - val: 0, - span: Span::unknown(), - }, - Value::Int { - val: 1, - span: Span::unknown(), - }, - ] - .into_iter() - .into_value_stream(), + stream: vec![Value::test_int(0), Value::test_int(1)] + .into_iter() + .into_value_stream(), span: Span::unknown(), }), }, diff --git a/crates/nu-command/src/experimental/git.rs b/crates/nu-command/src/experimental/git.rs index eddb042bc..cef4a27db 100644 --- a/crates/nu-command/src/experimental/git.rs +++ b/crates/nu-command/src/experimental/git.rs @@ -34,7 +34,10 @@ impl Command for Git { Ok(val) => { let result = val.stdout; - Ok(Value::string(&String::from_utf8_lossy(&result), call.head)) + Ok(Value::String { + val: String::from_utf8_lossy(&result).to_string(), + span: call.head, + }) } Err(_err) => { // FIXME: Move this to an external signature and add better error handling diff --git a/crates/nu-command/src/experimental/git_checkout.rs b/crates/nu-command/src/experimental/git_checkout.rs index 84cd0e5d3..d25d607d7 100644 --- a/crates/nu-command/src/experimental/git_checkout.rs +++ b/crates/nu-command/src/experimental/git_checkout.rs @@ -49,7 +49,10 @@ impl Command for GitCheckout { Ok(val) => { let result = val.stdout; - Ok(Value::string(&String::from_utf8_lossy(&result), call.head)) + Ok(Value::String { + val: String::from_utf8_lossy(&result).to_string(), + span: call.head, + }) } Err(_err) => { // FIXME: Move this to an external signature and add better error handling diff --git a/crates/nu-command/src/filters/lines.rs b/crates/nu-command/src/filters/lines.rs index a6dd017a8..2a32b54ca 100644 --- a/crates/nu-command/src/filters/lines.rs +++ b/crates/nu-command/src/filters/lines.rs @@ -42,7 +42,7 @@ impl Command for Lines { let iter = lines.into_iter().filter_map(move |s| { if !s.is_empty() { - Some(Value::String { val: s, span }) + Some(Value::string(s, span)) } else { None } diff --git a/crates/nu-command/src/strings/split/chars.rs b/crates/nu-command/src/strings/split/chars.rs index b326c7864..c74dce2f1 100644 --- a/crates/nu-command/src/strings/split/chars.rs +++ b/crates/nu-command/src/strings/split/chars.rs @@ -25,26 +25,11 @@ impl Command for SubCommand { example: "'hello' | split chars", result: Some(Value::List { vals: vec![ - Value::String { - val: "h".into(), - span: Span::unknown(), - }, - Value::String { - val: "e".into(), - span: Span::unknown(), - }, - Value::String { - val: "l".into(), - span: Span::unknown(), - }, - Value::String { - val: "l".into(), - span: Span::unknown(), - }, - Value::String { - val: "o".into(), - span: Span::unknown(), - }, + Value::test_string("h"), + Value::test_string("e"), + Value::test_string("l"), + Value::test_string("l"), + Value::test_string("o"), ], span: Span::unknown(), }), @@ -74,10 +59,7 @@ fn split_chars_helper(v: &Value, name: Span) -> Vec { s.chars() .collect::>() .into_iter() - .map(move |x| Value::String { - val: x.to_string(), - span: v_span, - }) + .map(move |x| Value::string(x, v_span)) .collect() } else { vec![Value::Error { diff --git a/crates/nu-command/src/strings/split/column.rs b/crates/nu-command/src/strings/split/column.rs index c0a8e03bb..ace779bd2 100644 --- a/crates/nu-command/src/strings/split/column.rs +++ b/crates/nu-command/src/strings/split/column.rs @@ -86,18 +86,12 @@ fn split_column_helper( for (&k, v) in split_result.iter().zip(&gen_columns) { cols.push(v.to_string()); - vals.push(Value::String { - val: k.into(), - span: head, - }); + vals.push(Value::string(k, head)); } } else { for (&k, v) in split_result.iter().zip(&positional) { cols.push(v.into()); - vals.push(Value::String { - val: k.into(), - span: head, - }) + vals.push(Value::string(k, head)); } } Value::List { diff --git a/crates/nu-command/src/strings/split/row.rs b/crates/nu-command/src/strings/split/row.rs index 7f8c49a4b..afda96977 100644 --- a/crates/nu-command/src/strings/split/row.rs +++ b/crates/nu-command/src/strings/split/row.rs @@ -55,10 +55,7 @@ fn split_row_helper(v: &Value, separator: &Spanned, name: Span) -> Vec { } } -// impl FromValue for DateTime { -// fn from_value(v: &Value) -> Result { -// match v { -// Value { -// value: UntaggedValue::Primitive(Primitive::Date(d)), -// .. -// } => Ok(*d), -// Value { -// value: UntaggedValue::Row(_), -// .. -// } => { -// let mut shell_error = ShellError::type_error("date", v.spanned_type_name()); -// shell_error.notes.push( -// "Note: you can access columns using dot. eg) $it.column or (ls).column".into(), -// ); -// Err(shell_error) -// } -// v => Err(ShellError::type_error("date", v.spanned_type_name())), -// } -// } -// } +impl FromValue for DateTime { + fn from_value(v: &Value) -> Result { + match v { + Value::Date { val, .. } => Ok(*val), + v => Err(ShellError::CantConvert("date".into(), v.span()?)), + } + } +} + +impl FromValue for Spanned> { + fn from_value(v: &Value) -> Result { + match v { + Value::Date { val, span } => Ok(Spanned { + item: *val, + span: *span, + }), + v => Err(ShellError::CantConvert("date".into(), v.span()?)), + } + } +} impl FromValue for Range { fn from_value(v: &Value) -> Result { @@ -177,31 +177,15 @@ impl FromValue for Spanned { } } -// impl FromValue for Vec { -// fn from_value(v: &Value) -> Result { -// match v { -// Value { -// value: UntaggedValue::Primitive(Primitive::Binary(b)), -// .. -// } => Ok(b.clone()), -// Value { -// value: UntaggedValue::Primitive(Primitive::String(s)), -// .. -// } => Ok(s.bytes().collect()), -// Value { -// value: UntaggedValue::Row(_), -// .. -// } => { -// let mut shell_error = ShellError::type_error("binary data", v.spanned_type_name()); -// shell_error.notes.push( -// "Note: you can access columns using dot. eg) $it.column or (ls).column".into(), -// ); -// Err(shell_error) -// } -// v => Err(ShellError::type_error("binary data", v.spanned_type_name())), -// } -// } -// } +impl FromValue for Vec { + fn from_value(v: &Value) -> Result { + match v { + Value::Binary { val, .. } => Ok(val.clone()), + Value::String { val, .. } => Ok(val.bytes().collect()), + v => Err(ShellError::CantConvert("binary data".into(), v.span()?)), + } + } +} // impl FromValue for Dictionary { // fn from_value(v: &Value) -> Result { diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index 88a1880dd..befcd029f 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -19,6 +19,10 @@ pub enum ShellError { rhs_span: Span, }, + #[error("Operator overflow.")] + #[diagnostic(code(nu::shell::operator_overflow), url(docsrs))] + OperatorOverflow(String, #[label = "{0}"] Span), + #[error("Pipeline mismatch.")] #[diagnostic(code(nu::shell::pipeline_mismatch), url(docsrs))] PipelineMismatch { diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index e792e253f..976cb9b6b 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -363,13 +363,6 @@ impl Value { Ok(current) } - pub fn string(s: &str, span: Span) -> Value { - Value::String { - val: s.into(), - span, - } - } - pub fn is_true(&self) -> bool { matches!(self, Value::Bool { val: true, .. }) } @@ -438,6 +431,33 @@ impl Value { }, } } + + pub fn string(val: impl Into, span: Span) -> Value { + Value::String { + val: val.into(), + span, + } + } + + pub fn int(val: i64, span: Span) -> Value { + Value::Int { val, span } + } + + // Only use these for test data. Span::unknown() should not be used in user data + pub fn test_string(s: impl Into) -> Value { + Value::String { + val: s.into(), + span: Span::unknown(), + } + } + + // Only use these for test data. Span::unknown() should not be used in user data + pub fn test_int(val: i64) -> Value { + Value::Int { + val, + span: Span::unknown(), + } + } } impl PartialOrd for Value { @@ -528,10 +548,16 @@ impl Value { let span = span(&[self.span()?, rhs.span()?]); match (self, rhs) { - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { - val: lhs + rhs, - span, - }), + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if let Some(val) = lhs.checked_add(*rhs) { + Ok(Value::Int { val, span }) + } else { + Err(ShellError::OperatorOverflow( + "add operation overflowed".into(), + span, + )) + } + } (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float { val: *lhs as f64 + *rhs, span,