Move Value to helpers, separate span call (#10121)

# Description

As part of the refactor to split spans off of Value, this moves to using
helper functions to create values, and using `.span()` instead of
matching span out of Value directly.

Hoping to get a few more helping hands to finish this, as there are a
lot of commands to update :)

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
Co-authored-by: WindSoilder <windsoilder@outlook.com>
This commit is contained in:
JT 2023-09-04 02:27:29 +12:00 committed by GitHub
parent af79eb2943
commit 6cdfee3573
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
372 changed files with 5811 additions and 7448 deletions

View file

@ -120,10 +120,7 @@ fn encoding_test_data(row_cnt: usize, col_cnt: usize) -> Value {
.collect(), .collect(),
); );
Value::List { Value::list(vec![record; row_cnt], Span::test_data())
vals: vec![record; row_cnt],
span: Span::test_data(),
}
} }
fn encoding_benchmarks(c: &mut Criterion) { fn encoding_benchmarks(c: &mut Criterion) {

View file

@ -102,7 +102,7 @@ impl Command for Commandline {
repl.buffer = cmd.as_string()?; repl.buffer = cmd.as_string()?;
repl.cursor_pos = repl.buffer.len(); repl.cursor_pos = repl.buffer.len();
} }
Ok(Value::Nothing { span: call.head }.into_pipeline_data()) Ok(Value::nothing(call.head).into_pipeline_data())
} else { } else {
let repl = engine_state.repl_state.lock().expect("repl state mutex"); let repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag("cursor") { if call.has_flag("cursor") {
@ -112,17 +112,9 @@ impl Command for Commandline {
.chain(std::iter::once((repl.buffer.len(), ""))) .chain(std::iter::once((repl.buffer.len(), "")))
.position(|(i, _c)| i == repl.cursor_pos) .position(|(i, _c)| i == repl.cursor_pos)
.expect("Cursor position isn't on a grapheme boundary"); .expect("Cursor position isn't on a grapheme boundary");
Ok(Value::String { Ok(Value::string(char_pos.to_string(), call.head).into_pipeline_data())
val: char_pos.to_string(),
span: call.head,
}
.into_pipeline_data())
} else { } else {
Ok(Value::String { Ok(Value::string(repl.buffer.to_string(), call.head).into_pipeline_data())
val: repl.buffer.to_string(),
span: call.head,
}
.into_pipeline_data())
} }
} }
} }

View file

@ -151,8 +151,8 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
//1. Format all the values //1. Format all the values
//2. Create a record of either short or long columns and values //2. Create a record of either short or long columns and values
let item_id_value = Value::Int { let item_id_value = Value::int(
val: match entry.id { match entry.id {
Some(id) => { Some(id) => {
let ids = id.to_string(); let ids = id.to_string();
match ids.parse::<i64>() { match ids.parse::<i64>() {
@ -162,21 +162,18 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
} }
None => 0i64, None => 0i64,
}, },
span: head, head,
}; );
let start_timestamp_value = Value::String { let start_timestamp_value = Value::string(
val: match entry.start_timestamp { match entry.start_timestamp {
Some(time) => time.to_string(), Some(time) => time.to_string(),
None => "".into(), None => "".into(),
}, },
span: head, head,
}; );
let command_value = Value::String { let command_value = Value::string(entry.command_line, head);
val: entry.command_line, let session_id_value = Value::int(
span: head, match entry.session_id {
};
let session_id_value = Value::Int {
val: match entry.session_id {
Some(sid) => { Some(sid) => {
let sids = sid.to_string(); let sids = sid.to_string();
match sids.parse::<i64>() { match sids.parse::<i64>() {
@ -186,29 +183,29 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
} }
None => 0i64, None => 0i64,
}, },
span: head, head,
}; );
let hostname_value = Value::String { let hostname_value = Value::string(
val: match entry.hostname { match entry.hostname {
Some(host) => host, Some(host) => host,
None => "".into(), None => "".into(),
}, },
span: head, head,
}; );
let cwd_value = Value::String { let cwd_value = Value::string(
val: match entry.cwd { match entry.cwd {
Some(cwd) => cwd, Some(cwd) => cwd,
None => "".into(), None => "".into(),
}, },
span: head, head,
}; );
let duration_value = Value::Duration { let duration_value = Value::duration(
val: match entry.duration { match entry.duration {
Some(d) => d.as_nanos().try_into().unwrap_or(0), Some(d) => d.as_nanos().try_into().unwrap_or(0),
None => 0, None => 0,
}, },
span: head, head,
}; );
let exit_status_value = Value::int(entry.exit_status.unwrap_or(0), head); let exit_status_value = Value::int(entry.exit_status.unwrap_or(0), head);
let index_value = Value::int(idx as i64, head); let index_value = Value::int(idx as i64, head);
if long { if long {

View file

@ -41,16 +41,16 @@ For more information on input and keybindings, check:
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
Ok(Value::String { Ok(Value::string(
val: get_full_help( get_full_help(
&Keybindings.signature(), &Keybindings.signature(),
&Keybindings.examples(), &Keybindings.examples(),
engine_state, engine_state,
stack, stack,
self.is_parser_keyword(), self.is_parser_keyword(),
), ),
span: call.head, call.head,
} )
.into_pipeline_data()) .into_pipeline_data())
} }
} }

View file

@ -53,10 +53,6 @@ impl Command for KeybindingsDefault {
}) })
.collect(); .collect();
Ok(Value::List { Ok(Value::list(records, call.head).into_pipeline_data())
vals: records,
span: call.head,
}
.into_pipeline_data())
} }
} }

View file

@ -71,11 +71,7 @@ impl Command for KeybindingsList {
.collect() .collect()
}; };
Ok(Value::List { Ok(Value::list(records, call.head).into_pipeline_data())
vals: records,
span: call.head,
}
.into_pipeline_data())
} }
} }

View file

@ -74,13 +74,13 @@ impl NuCompleter {
if let Some(var_id) = pos_arg.var_id { if let Some(var_id) = pos_arg.var_id {
callee_stack.add_var( callee_stack.add_var(
var_id, var_id,
Value::List { Value::list(
vals: spans spans
.iter() .iter()
.map(|it| Value::string(it, Span::unknown())) .map(|it| Value::string(it, Span::unknown()))
.collect(), .collect(),
span: Span::unknown(), Span::unknown(),
}, ),
); );
} }
} }
@ -97,7 +97,7 @@ impl NuCompleter {
match result { match result {
Ok(pd) => { Ok(pd) => {
let value = pd.into_value(span); let value = pd.into_value(span);
if let Value::List { vals, span: _ } = value { if let Value::List { vals, .. } = value {
let result = let result =
map_value_completions(vals.iter(), Span::new(span.start, span.end), offset); map_value_completions(vals.iter(), Span::new(span.start, span.end), offset);

View file

@ -263,7 +263,7 @@ fn nested_suggestions(
output output
} }
Value::List { vals, span: _ } => { Value::List { vals, .. } => {
for column_name in get_columns(vals.as_slice()) { for column_name in get_columns(vals.as_slice()) {
output.push(Suggestion { output.push(Suggestion {
value: column_name, value: column_name,
@ -284,6 +284,7 @@ fn nested_suggestions(
fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value { fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
// Go to next sublevel // Go to next sublevel
if let Some(next_sublevel) = sublevels.clone().into_iter().next() { if let Some(next_sublevel) = sublevels.clone().into_iter().next() {
let span = val.span();
match val { match val {
Value::Record { val, .. } => { Value::Record { val, .. } => {
for item in val { for item in val {
@ -295,11 +296,9 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
} }
// Current sublevel value not found // Current sublevel value not found
return Value::Nothing { return Value::nothing(span);
span: Span::unknown(),
};
} }
Value::LazyRecord { val, span: _ } => { Value::LazyRecord { val, .. } => {
for col in val.column_names() { for col in val.column_names() {
if col.as_bytes().to_vec() == next_sublevel { if col.as_bytes().to_vec() == next_sublevel {
return recursive_value( return recursive_value(
@ -310,15 +309,13 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
} }
// Current sublevel value not found // Current sublevel value not found
return Value::Nothing { return Value::nothing(span);
span: Span::unknown(),
};
} }
Value::List { vals, span } => { Value::List { vals, .. } => {
for col in get_columns(vals.as_slice()) { for col in get_columns(vals.as_slice()) {
if col.as_bytes().to_vec() == next_sublevel { if col.as_bytes().to_vec() == next_sublevel {
return recursive_value( return recursive_value(
Value::List { vals, span } Value::list(vals, span)
.get_data_by_key(&col) .get_data_by_key(&col)
.unwrap_or_default(), .unwrap_or_default(),
sublevels.into_iter().skip(1).collect(), sublevels.into_iter().skip(1).collect(),
@ -327,9 +324,7 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
} }
// Current sublevel value not found // Current sublevel value not found
return Value::Nothing { return Value::nothing(span);
span: Span::unknown(),
};
} }
_ => return val, _ => return val,
} }

View file

@ -48,15 +48,9 @@ impl Command for NuHighlight {
Ok(line) => { Ok(line) => {
let highlights = highlighter.highlight(&line, line.len()); let highlights = highlighter.highlight(&line, line.len());
Value::String { Value::string(highlights.render_simple(), head)
val: highlights.render_simple(),
span: head,
}
} }
Err(err) => Value::Error { Err(err) => Value::error(err, head),
error: Box::new(err),
span: head,
},
}, },
ctrlc, ctrlc,
) )

View file

@ -131,8 +131,9 @@ fn add_menu(
stack: &Stack, stack: &Stack,
config: &Config, config: &Config,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
if let Value::Record { val, span } = &menu.menu_type { let span = menu.menu_type.span();
let layout = extract_value("layout", val, *span)?.into_string("", config); if let Value::Record { val, .. } = &menu.menu_type {
let layout = extract_value("layout", val, span)?.into_string("", config);
match layout.as_str() { match layout.as_str() {
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config), "columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
@ -156,7 +157,7 @@ fn add_menu(
macro_rules! add_style { macro_rules! add_style {
// first arm match add!(1,2), add!(2,3) etc // first arm match add!(1,2), add!(2,3) etc
($name:expr, $record: expr, $span:expr, $config: expr, $menu:expr, $f:expr) => { ($name:expr, $record: expr, $span:expr, $config: expr, $menu:expr, $f:expr) => {
$menu = match extract_value($name, $record, *$span) { $menu = match extract_value($name, $record, $span) {
Ok(text) => { Ok(text) => {
let style = match text { let style = match text {
Value::String { val, .. } => lookup_ansi_color_style(&val), Value::String { val, .. } => lookup_ansi_color_style(&val),
@ -178,11 +179,12 @@ pub(crate) fn add_columnar_menu(
stack: &Stack, stack: &Stack,
config: &Config, config: &Config,
) -> Result<Reedline, ShellError> { ) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
let name = menu.name.into_string("", config); let name = menu.name.into_string("", config);
let mut columnar_menu = ColumnarMenu::default().with_name(&name); let mut columnar_menu = ColumnarMenu::default().with_name(&name);
if let Value::Record { val, span } = &menu.menu_type { if let Value::Record { val, .. } = &menu.menu_type {
columnar_menu = match extract_value("columns", val, *span) { columnar_menu = match extract_value("columns", val, span) {
Ok(columns) => { Ok(columns) => {
let columns = columns.as_int()?; let columns = columns.as_int()?;
columnar_menu.with_columns(columns as u16) columnar_menu.with_columns(columns as u16)
@ -190,7 +192,7 @@ pub(crate) fn add_columnar_menu(
Err(_) => columnar_menu, Err(_) => columnar_menu,
}; };
columnar_menu = match extract_value("col_width", val, *span) { columnar_menu = match extract_value("col_width", val, span) {
Ok(col_width) => { Ok(col_width) => {
let col_width = col_width.as_int()?; let col_width = col_width.as_int()?;
columnar_menu.with_column_width(Some(col_width as usize)) columnar_menu.with_column_width(Some(col_width as usize))
@ -198,7 +200,7 @@ pub(crate) fn add_columnar_menu(
Err(_) => columnar_menu.with_column_width(None), Err(_) => columnar_menu.with_column_width(None),
}; };
columnar_menu = match extract_value("col_padding", val, *span) { columnar_menu = match extract_value("col_padding", val, span) {
Ok(col_padding) => { Ok(col_padding) => {
let col_padding = col_padding.as_int()?; let col_padding = col_padding.as_int()?;
columnar_menu.with_column_padding(col_padding as usize) columnar_menu.with_column_padding(col_padding as usize)
@ -207,7 +209,8 @@ pub(crate) fn add_columnar_menu(
}; };
} }
if let Value::Record { val, span } = &menu.style { let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
add_style!( add_style!(
"text", "text",
val, val,
@ -240,18 +243,15 @@ pub(crate) fn add_columnar_menu(
let only_buffer_difference = menu.only_buffer_difference.as_bool()?; let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
columnar_menu = columnar_menu.with_only_buffer_difference(only_buffer_difference); columnar_menu = columnar_menu.with_only_buffer_difference(only_buffer_difference);
let span = menu.source.span();
match &menu.source { match &menu.source {
Value::Nothing { .. } => { Value::Nothing { .. } => {
Ok(line_editor.with_menu(ReedlineMenu::EngineCompleter(Box::new(columnar_menu)))) Ok(line_editor.with_menu(ReedlineMenu::EngineCompleter(Box::new(columnar_menu))))
} }
Value::Closure { Value::Closure { val, captures, .. } => {
val,
captures,
span,
} => {
let menu_completer = NuMenuCompleter::new( let menu_completer = NuMenuCompleter::new(
*val, *val,
*span, span,
stack.captures_to_stack(captures), stack.captures_to_stack(captures),
engine_state, engine_state,
only_buffer_difference, only_buffer_difference,
@ -264,7 +264,7 @@ pub(crate) fn add_columnar_menu(
_ => Err(ShellError::UnsupportedConfigValue( _ => Err(ShellError::UnsupportedConfigValue(
"block or omitted value".to_string(), "block or omitted value".to_string(),
menu.source.into_abbreviated_string(config), menu.source.into_abbreviated_string(config),
menu.source.span(), span,
)), )),
} }
} }
@ -280,8 +280,9 @@ pub(crate) fn add_list_menu(
let name = menu.name.into_string("", config); let name = menu.name.into_string("", config);
let mut list_menu = ListMenu::default().with_name(&name); let mut list_menu = ListMenu::default().with_name(&name);
if let Value::Record { val, span } = &menu.menu_type { let span = menu.menu_type.span();
list_menu = match extract_value("page_size", val, *span) { if let Value::Record { val, .. } = &menu.menu_type {
list_menu = match extract_value("page_size", val, span) {
Ok(page_size) => { Ok(page_size) => {
let page_size = page_size.as_int()?; let page_size = page_size.as_int()?;
list_menu.with_page_size(page_size as usize) list_menu.with_page_size(page_size as usize)
@ -290,7 +291,8 @@ pub(crate) fn add_list_menu(
}; };
} }
if let Value::Record { val, span } = &menu.style { let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
add_style!( add_style!(
"text", "text",
val, val,
@ -323,18 +325,15 @@ pub(crate) fn add_list_menu(
let only_buffer_difference = menu.only_buffer_difference.as_bool()?; let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
list_menu = list_menu.with_only_buffer_difference(only_buffer_difference); list_menu = list_menu.with_only_buffer_difference(only_buffer_difference);
let span = menu.source.span();
match &menu.source { match &menu.source {
Value::Nothing { .. } => { Value::Nothing { .. } => {
Ok(line_editor.with_menu(ReedlineMenu::HistoryMenu(Box::new(list_menu)))) Ok(line_editor.with_menu(ReedlineMenu::HistoryMenu(Box::new(list_menu))))
} }
Value::Closure { Value::Closure { val, captures, .. } => {
val,
captures,
span,
} => {
let menu_completer = NuMenuCompleter::new( let menu_completer = NuMenuCompleter::new(
*val, *val,
*span, span,
stack.captures_to_stack(captures), stack.captures_to_stack(captures),
engine_state, engine_state,
only_buffer_difference, only_buffer_difference,
@ -363,8 +362,9 @@ pub(crate) fn add_description_menu(
let name = menu.name.into_string("", config); let name = menu.name.into_string("", config);
let mut description_menu = DescriptionMenu::default().with_name(&name); let mut description_menu = DescriptionMenu::default().with_name(&name);
if let Value::Record { val, span } = &menu.menu_type { let span = menu.menu_type.span();
description_menu = match extract_value("columns", val, *span) { if let Value::Record { val, .. } = &menu.menu_type {
description_menu = match extract_value("columns", val, span) {
Ok(columns) => { Ok(columns) => {
let columns = columns.as_int()?; let columns = columns.as_int()?;
description_menu.with_columns(columns as u16) description_menu.with_columns(columns as u16)
@ -372,7 +372,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu, Err(_) => description_menu,
}; };
description_menu = match extract_value("col_width", val, *span) { description_menu = match extract_value("col_width", val, span) {
Ok(col_width) => { Ok(col_width) => {
let col_width = col_width.as_int()?; let col_width = col_width.as_int()?;
description_menu.with_column_width(Some(col_width as usize)) description_menu.with_column_width(Some(col_width as usize))
@ -380,7 +380,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu.with_column_width(None), Err(_) => description_menu.with_column_width(None),
}; };
description_menu = match extract_value("col_padding", val, *span) { description_menu = match extract_value("col_padding", val, span) {
Ok(col_padding) => { Ok(col_padding) => {
let col_padding = col_padding.as_int()?; let col_padding = col_padding.as_int()?;
description_menu.with_column_padding(col_padding as usize) description_menu.with_column_padding(col_padding as usize)
@ -388,7 +388,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu, Err(_) => description_menu,
}; };
description_menu = match extract_value("selection_rows", val, *span) { description_menu = match extract_value("selection_rows", val, span) {
Ok(selection_rows) => { Ok(selection_rows) => {
let selection_rows = selection_rows.as_int()?; let selection_rows = selection_rows.as_int()?;
description_menu.with_selection_rows(selection_rows as u16) description_menu.with_selection_rows(selection_rows as u16)
@ -396,7 +396,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu, Err(_) => description_menu,
}; };
description_menu = match extract_value("description_rows", val, *span) { description_menu = match extract_value("description_rows", val, span) {
Ok(description_rows) => { Ok(description_rows) => {
let description_rows = description_rows.as_int()?; let description_rows = description_rows.as_int()?;
description_menu.with_description_rows(description_rows as usize) description_menu.with_description_rows(description_rows as usize)
@ -405,7 +405,8 @@ pub(crate) fn add_description_menu(
}; };
} }
if let Value::Record { val, span } = &menu.style { let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
add_style!( add_style!(
"text", "text",
val, val,
@ -438,6 +439,7 @@ pub(crate) fn add_description_menu(
let only_buffer_difference = menu.only_buffer_difference.as_bool()?; let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
description_menu = description_menu.with_only_buffer_difference(only_buffer_difference); description_menu = description_menu.with_only_buffer_difference(only_buffer_difference);
let span = menu.source.span();
match &menu.source { match &menu.source {
Value::Nothing { .. } => { Value::Nothing { .. } => {
let completer = Box::new(NuHelpCompleter::new(engine_state)); let completer = Box::new(NuHelpCompleter::new(engine_state));
@ -446,14 +448,10 @@ pub(crate) fn add_description_menu(
completer, completer,
})) }))
} }
Value::Closure { Value::Closure { val, captures, .. } => {
val,
captures,
span,
} => {
let menu_completer = NuMenuCompleter::new( let menu_completer = NuMenuCompleter::new(
*val, *val,
*span, span,
stack.captures_to_stack(captures), stack.captures_to_stack(captures),
engine_state, engine_state,
only_buffer_difference, only_buffer_difference,
@ -575,15 +573,16 @@ fn add_keybinding(
insert_keybindings: &mut Keybindings, insert_keybindings: &mut Keybindings,
normal_keybindings: &mut Keybindings, normal_keybindings: &mut Keybindings,
) -> Result<(), ShellError> { ) -> Result<(), ShellError> {
let span = mode.span();
match &mode { match &mode {
Value::String { val, span } => match val.as_str() { Value::String { val, .. } => match val.as_str() {
"emacs" => add_parsed_keybinding(emacs_keybindings, keybinding, config), "emacs" => add_parsed_keybinding(emacs_keybindings, keybinding, config),
"vi_insert" => add_parsed_keybinding(insert_keybindings, keybinding, config), "vi_insert" => add_parsed_keybinding(insert_keybindings, keybinding, config),
"vi_normal" => add_parsed_keybinding(normal_keybindings, keybinding, config), "vi_normal" => add_parsed_keybinding(normal_keybindings, keybinding, config),
m => Err(ShellError::UnsupportedConfigValue( m => Err(ShellError::UnsupportedConfigValue(
"emacs, vi_insert or vi_normal".to_string(), "emacs, vi_insert or vi_normal".to_string(),
m.to_string(), m.to_string(),
*span, span,
)), )),
}, },
Value::List { vals, .. } => { Value::List { vals, .. } => {
@ -724,13 +723,14 @@ impl<'config> EventType<'config> {
} }
fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>, ShellError> { fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>, ShellError> {
let span = value.span();
match value { match value {
Value::Record { val: record, span } => match EventType::try_from_record(record, *span)? { Value::Record { val: record, .. } => match EventType::try_from_record(record, span)? {
EventType::Send(value) => event_from_record( EventType::Send(value) => event_from_record(
value.into_string("", config).to_lowercase().as_str(), value.into_string("", config).to_lowercase().as_str(),
record, record,
config, config,
*span, span,
) )
.map(Some), .map(Some),
EventType::Edit(value) => { EventType::Edit(value) => {
@ -738,7 +738,7 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
value.into_string("", config).to_lowercase().as_str(), value.into_string("", config).to_lowercase().as_str(),
record, record,
config, config,
*span, span,
)?; )?;
Ok(Some(ReedlineEvent::Edit(vec![edit]))) Ok(Some(ReedlineEvent::Edit(vec![edit])))
} }
@ -1056,10 +1056,10 @@ mod test {
// Until event // Until event
let cols = vec!["until".to_string()]; let cols = vec!["until".to_string()];
let vals = vec![Value::List { let vals = vec![Value::list(
vals: vec![menu_event, enter_event], vec![menu_event, enter_event],
span: Span::test_data(), Span::test_data(),
}]; )];
let event = Record { cols, vals }; let event = Record { cols, vals };
let span = Span::test_data(); let span = Span::test_data();
@ -1097,10 +1097,7 @@ mod test {
let enter_event = Value::test_record(Record { cols, vals }); let enter_event = Value::test_record(Record { cols, vals });
// Multiple event // Multiple event
let event = Value::List { let event = Value::list(vec![menu_event, enter_event], Span::test_data());
vals: vec![menu_event, enter_event],
span: Span::test_data(),
};
let config = Config::default(); let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap(); let parsed_event = parse_event(&event, &config).unwrap();

View file

@ -514,24 +514,12 @@ pub fn evaluate_repl(
(path.to_string_lossy().to_string(), tokens.0[0].span) (path.to_string_lossy().to_string(), tokens.0[0].span)
}; };
stack.add_env_var( stack.add_env_var("OLDPWD".into(), Value::string(cwd.clone(), Span::unknown()));
"OLDPWD".into(),
Value::String {
val: cwd.clone(),
span: Span::unknown(),
},
);
//FIXME: this only changes the current scope, but instead this environment variable //FIXME: this only changes the current scope, but instead this environment variable
//should probably be a block that loads the information from the state in the overlay //should probably be a block that loads the information from the state in the overlay
stack.add_env_var( stack.add_env_var("PWD".into(), Value::string(path.clone(), Span::unknown()));
"PWD".into(), let cwd = Value::string(cwd, span);
Value::String {
val: path.clone(),
span: Span::unknown(),
},
);
let cwd = Value::String { val: cwd, span };
let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS"); let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS");
let mut shells = if let Some(v) = shells { let mut shells = if let Some(v) = shells {
@ -556,15 +544,12 @@ pub fn evaluate_repl(
0 0
}; };
shells[current_shell] = Value::String { val: path, span }; shells[current_shell] = Value::string(path, span);
stack.add_env_var("NUSHELL_SHELLS".into(), Value::List { vals: shells, span }); stack.add_env_var("NUSHELL_SHELLS".into(), Value::list(shells, span));
stack.add_env_var( stack.add_env_var(
"NUSHELL_LAST_SHELL".into(), "NUSHELL_LAST_SHELL".into(),
Value::Int { Value::int(last_shell as i64, span),
val: last_shell as i64,
span,
},
); );
} else if !s.trim().is_empty() { } else if !s.trim().is_empty() {
trace!("eval source: {}", s); trace!("eval source: {}", s);
@ -607,10 +592,7 @@ pub fn evaluate_repl(
stack.add_env_var( stack.add_env_var(
"CMD_DURATION_MS".into(), "CMD_DURATION_MS".into(),
Value::String { Value::string(format!("{}", cmd_duration.as_millis()), Span::unknown()),
val: format!("{}", cmd_duration.as_millis()),
span: Span::unknown(),
},
); );
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context() if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()

View file

@ -185,10 +185,7 @@ fn gather_env_vars(
continue; continue;
} }
Value::String { Value::string(bytes, *span)
val: bytes,
span: *span,
}
} else { } else {
report_capture_error( report_capture_error(
engine_state, engine_state,

View file

@ -40,33 +40,30 @@ pub fn new_engine() -> (PathBuf, String, EngineState, Stack) {
// Add pwd as env var // Add pwd as env var
stack.add_env_var( stack.add_env_var(
"PWD".to_string(), "PWD".to_string(),
Value::String { Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
val: dir_str.clone(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
); );
stack.add_env_var( stack.add_env_var(
"TEST".to_string(), "TEST".to_string(),
Value::String { Value::string(
val: "NUSHELL".to_string(), "NUSHELL".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()), nu_protocol::Span::new(0, dir_str.len()),
}, ),
); );
#[cfg(windows)] #[cfg(windows)]
stack.add_env_var( stack.add_env_var(
"Path".to_string(), "Path".to_string(),
Value::String { Value::string(
val: "c:\\some\\path;c:\\some\\other\\path".to_string(), "c:\\some\\path;c:\\some\\other\\path".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()), nu_protocol::Span::new(0, dir_str.len()),
}, ),
); );
#[cfg(not(windows))] #[cfg(not(windows))]
stack.add_env_var( stack.add_env_var(
"PATH".to_string(), "PATH".to_string(),
Value::String { Value::string(
val: "/some/path:/some/other/path".to_string(), "/some/path:/some/other/path".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()), nu_protocol::Span::new(0, dir_str.len()),
}, ),
); );
// Merge environment into the permanent state // Merge environment into the permanent state
@ -95,17 +92,14 @@ pub fn new_quote_engine() -> (PathBuf, String, EngineState, Stack) {
// Add pwd as env var // Add pwd as env var
stack.add_env_var( stack.add_env_var(
"PWD".to_string(), "PWD".to_string(),
Value::String { Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
val: dir_str.clone(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
); );
stack.add_env_var( stack.add_env_var(
"TEST".to_string(), "TEST".to_string(),
Value::String { Value::string(
val: "NUSHELL".to_string(), "NUSHELL".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()), nu_protocol::Span::new(0, dir_str.len()),
}, ),
); );
// Merge environment into the permanent state // Merge environment into the permanent state
@ -168,12 +162,7 @@ pub fn merge_input(
engine_state, engine_state,
stack, stack,
&block, &block,
PipelineData::Value( PipelineData::Value(Value::nothing(Span::unknown(),), None),
Value::Nothing {
span: Span::unknown(),
},
None
),
false, false,
false false
) )

View file

@ -84,8 +84,9 @@ pub fn eval_hook(
optional: false, optional: false,
}; };
let span = value.span();
match value { match value {
Value::String { val, span } => { Value::String { val, .. } => {
let (block, delta, vars) = { let (block, delta, vars) = {
let mut working_set = StateWorkingSet::new(engine_state); let mut working_set = StateWorkingSet::new(engine_state);
@ -113,7 +114,7 @@ pub fn eval_hook(
return Err(ShellError::UnsupportedConfigValue( return Err(ShellError::UnsupportedConfigValue(
"valid source code".into(), "valid source code".into(),
"source code with syntax errors".into(), "source code with syntax errors".into(),
*span, span,
)); ));
} }
@ -161,64 +162,56 @@ pub fn eval_hook(
} }
} }
Value::Record { .. } => { Value::Record { .. } => {
let do_run_hook = let do_run_hook = if let Ok(condition) =
if let Ok(condition) = value.clone().follow_cell_path(&[condition_path], false) { value.clone().follow_cell_path(&[condition_path], false)
match condition { {
Value::Block { let other_span = condition.span();
val: block_id, match condition {
span: block_span, Value::Block { val: block_id, .. } | Value::Closure { val: block_id, .. } => {
.. match run_hook_block(
} engine_state,
| Value::Closure { stack,
val: block_id, block_id,
span: block_span, None,
.. arguments.clone(),
} => { other_span,
match run_hook_block( ) {
engine_state, Ok(pipeline_data) => {
stack, if let PipelineData::Value(Value::Bool { val, .. }, ..) =
block_id, pipeline_data
None, {
arguments.clone(), val
block_span, } else {
) { return Err(ShellError::UnsupportedConfigValue(
Ok(pipeline_data) => { "boolean output".to_string(),
if let PipelineData::Value(Value::Bool { val, .. }, ..) = "other PipelineData variant".to_string(),
pipeline_data other_span,
{ ));
val
} else {
return Err(ShellError::UnsupportedConfigValue(
"boolean output".to_string(),
"other PipelineData variant".to_string(),
block_span,
));
}
}
Err(err) => {
return Err(err);
} }
} }
} Err(err) => {
other => { return Err(err);
return Err(ShellError::UnsupportedConfigValue( }
"block".to_string(),
format!("{}", other.get_type()),
other.span(),
));
} }
} }
} else { other => {
// always run the hook return Err(ShellError::UnsupportedConfigValue(
true "block".to_string(),
}; format!("{}", other.get_type()),
other_span,
));
}
}
} else {
// always run the hook
true
};
if do_run_hook { if do_run_hook {
match value.clone().follow_cell_path(&[code_path], false)? { let follow = value.clone().follow_cell_path(&[code_path], false)?;
Value::String { let source_span = follow.span();
val, match follow {
span: source_span, Value::String { val, .. } => {
} => {
let (block, delta, vars) = { let (block, delta, vars) = {
let mut working_set = StateWorkingSet::new(engine_state); let mut working_set = StateWorkingSet::new(engine_state);
@ -277,71 +270,41 @@ pub fn eval_hook(
stack.remove_var(*var_id); stack.remove_var(*var_id);
} }
} }
Value::Block { Value::Block { val: block_id, .. } => {
val: block_id,
span: block_span,
..
} => {
run_hook_block( run_hook_block(
engine_state, engine_state,
stack, stack,
block_id, block_id,
input, input,
arguments, arguments,
block_span, source_span,
)?; )?;
} }
Value::Closure { Value::Closure { val: block_id, .. } => {
val: block_id,
span: block_span,
..
} => {
run_hook_block( run_hook_block(
engine_state, engine_state,
stack, stack,
block_id, block_id,
input, input,
arguments, arguments,
block_span, source_span,
)?; )?;
} }
other => { other => {
return Err(ShellError::UnsupportedConfigValue( return Err(ShellError::UnsupportedConfigValue(
"block or string".to_string(), "block or string".to_string(),
format!("{}", other.get_type()), format!("{}", other.get_type()),
other.span(), source_span,
)); ));
} }
} }
} }
} }
Value::Block { Value::Block { val: block_id, .. } => {
val: block_id, output = run_hook_block(engine_state, stack, *block_id, input, arguments, span)?;
span: block_span,
..
} => {
output = run_hook_block(
engine_state,
stack,
*block_id,
input,
arguments,
*block_span,
)?;
} }
Value::Closure { Value::Closure { val: block_id, .. } => {
val: block_id, output = run_hook_block(engine_state, stack, *block_id, input, arguments, span)?;
span: block_span,
..
} => {
output = run_hook_block(
engine_state,
stack,
*block_id,
input,
arguments,
*block_span,
)?;
} }
other => { other => {
return Err(ShellError::UnsupportedConfigValue( return Err(ShellError::UnsupportedConfigValue(

View file

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

View file

@ -27,10 +27,10 @@ impl Command for ColumnsDF {
vec![Example { vec![Example {
description: "Dataframe columns", description: "Dataframe columns",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr columns", example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr columns",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_string("a"), Value::test_string("b")], vec![Value::test_string("a"), Value::test_string("b")],
span: Span::test_data(), Span::test_data(),
}), )),
}] }]
} }
@ -60,10 +60,7 @@ fn command(
.map(|v| Value::string(*v, call.head)) .map(|v| Value::string(*v, call.head))
.collect(); .collect();
let names = Value::List { let names = Value::list(names, call.head);
vals: names,
span: call.head,
};
Ok(PipelineData::Value(names, None)) Ok(PipelineData::Value(names, None))
} }

View file

@ -79,10 +79,7 @@ fn command(
.dtype(); .dtype();
let dtype_str = dtype.to_string(); let dtype_str = dtype.to_string();
dtypes.push(Value::String { dtypes.push(Value::string(dtype_str, call.head));
val: dtype_str,
span: call.head,
});
Value::string(*v, call.head) Value::string(*v, call.head)
}) })

View file

@ -66,10 +66,7 @@ impl Command for ListDF {
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
let list = Value::List { let list = Value::list(vals, call.head);
vals,
span: call.head,
};
Ok(list.into_pipeline_data()) Ok(list.into_pipeline_data())
} }

View file

@ -88,10 +88,7 @@ fn command(
let lazy = NuLazyFrame::new(false, df_sql); let lazy = NuLazyFrame::new(false, df_sql);
let eager = lazy.collect(call.head)?; let eager = lazy.collect(call.head)?;
let value = Value::CustomValue { let value = Value::custom_value(Box::new(eager), call.head);
val: Box::new(eager),
span: call.head,
};
Ok(PipelineData::Value(value, None)) Ok(PipelineData::Value(value, None))
} }

View file

@ -120,30 +120,30 @@ fn command(
let quantiles = quantiles.map(|values| { let quantiles = quantiles.map(|values| {
values values
.iter() .iter()
.map(|value| match value { .map(|value| {
Value::Float { val, span } => { let span = value.span();
if (&0.0..=&1.0).contains(&val) { match value {
Ok(*val) Value::Float { val, .. } => {
} else { if (&0.0..=&1.0).contains(&val) {
Err(ShellError::GenericError( Ok(*val)
"Incorrect value for quantile".to_string(), } else {
"value should be between 0 and 1".to_string(), Err(ShellError::GenericError(
Some(*span), "Incorrect value for quantile".to_string(),
None, "value should be between 0 and 1".to_string(),
Vec::new(), Some(span),
)) None,
Vec::new(),
))
}
} }
} Value::Error { error, .. } => Err(*error.clone()),
Value::Error { error, .. } => Err(*error.clone()), _ => Err(ShellError::GenericError(
_ => {
let span = value.span();
Err(ShellError::GenericError(
"Incorrect value for quantile".to_string(), "Incorrect value for quantile".to_string(),
"value should be a float".to_string(), "value should be a float".to_string(),
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
)) )),
} }
}) })
.collect::<Result<Vec<f64>, ShellError>>() .collect::<Result<Vec<f64>, ShellError>>()

View file

@ -78,16 +78,10 @@ fn command(
) )
})?; })?;
let file_value = Value::String { let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
Ok(PipelineData::Value( Ok(PipelineData::Value(
Value::List { Value::list(vec![file_value], call.head),
vals: vec![file_value],
span: call.head,
},
None, None,
)) ))
} }

View file

@ -108,16 +108,10 @@ fn command(
) )
})?; })?;
let file_value = Value::String { let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
Ok(PipelineData::Value( Ok(PipelineData::Value(
Value::List { Value::list(vec![file_value], call.head),
vals: vec![file_value],
span: call.head,
},
None, None,
)) ))
} }

View file

@ -124,16 +124,10 @@ fn command(
) )
})?; })?;
let file_value = Value::String { let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
Ok(PipelineData::Value( Ok(PipelineData::Value(
Value::List { Value::list(vec![file_value], call.head),
vals: vec![file_value],
span: call.head,
},
None, None,
)) ))
} }

View file

@ -81,16 +81,10 @@ fn command(
) )
})?; })?;
let file_value = Value::String { let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
Ok(PipelineData::Value( Ok(PipelineData::Value(
Value::List { Value::list(vec![file_value], call.head),
vals: vec![file_value],
span: call.head,
},
None, None,
)) ))
} }

View file

@ -57,18 +57,12 @@ impl Command for ToNu {
Example { Example {
description: "Shows head rows from dataframe", description: "Shows head rows from dataframe",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr into-nu", example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr into-nu",
result: Some(Value::List { result: Some(Value::list(vec![rec_1, rec_2], Span::test_data())),
vals: vec![rec_1, rec_2],
span: Span::test_data(),
}),
}, },
Example { Example {
description: "Shows tail rows from dataframe", description: "Shows tail rows from dataframe",
example: "[[a b]; [1 2] [5 6] [3 4]] | dfr into-df | dfr into-nu -t -n 1", example: "[[a b]; [1 2] [5 6] [3 4]] | dfr into-df | dfr into-nu -t -n 1",
result: Some(Value::List { result: Some(Value::list(vec![rec_3], Span::test_data())),
vals: vec![rec_3],
span: Span::test_data(),
}),
}, },
Example { Example {
description: "Convert a col expression into a nushell value", description: "Convert a col expression into a nushell value",
@ -119,10 +113,7 @@ fn dataframe_command(
} }
}; };
let value = Value::List { let value = Value::list(values, call.head);
vals: values,
span: call.head,
};
Ok(PipelineData::Value(value, None)) Ok(PipelineData::Value(value, None))
} }

View file

@ -78,16 +78,10 @@ fn command(
) )
})?; })?;
let file_value = Value::String { let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
Ok(PipelineData::Value( Ok(PipelineData::Value(
Value::List { Value::list(vec![file_value], call.head),
vals: vec![file_value],
span: call.head,
},
None, None,
)) ))
} }

View file

@ -132,10 +132,7 @@ fn command_eager(
if NuExpression::can_downcast(&new_column) { if NuExpression::can_downcast(&new_column) {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?; let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List { let value = Value::list(vals, call.head);
vals,
span: call.head,
};
let expressions = NuExpression::extract_exprs(value)?; let expressions = NuExpression::extract_exprs(value)?;
let lazy = NuLazyFrame::new(true, df.lazy().with_columns(&expressions)); let lazy = NuLazyFrame::new(true, df.lazy().with_columns(&expressions));
@ -179,10 +176,7 @@ fn command_lazy(
lazy: NuLazyFrame, lazy: NuLazyFrame,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?; let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List { let value = Value::list(vals, call.head);
vals,
span: call.head,
};
let expressions = NuExpression::extract_exprs(value)?; let expressions = NuExpression::extract_exprs(value)?;
let lazy: NuLazyFrame = lazy.into_polars().with_columns(&expressions).into(); let lazy: NuLazyFrame = lazy.into_polars().with_columns(&expressions).into();

View file

@ -114,10 +114,7 @@ impl Command for LazyAggregate {
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?; let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List { let value = Value::list(vals, call.head);
vals,
span: call.head,
};
let expressions = NuExpression::extract_exprs(value)?; let expressions = NuExpression::extract_exprs(value)?;
let group_by = NuLazyGroupBy::try_from_pipeline(input, call.head)?; let group_by = NuLazyGroupBy::try_from_pipeline(input, call.head)?;

View file

@ -58,10 +58,7 @@ impl Command for LazyCollect {
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
let eager = lazy.collect(call.head)?; let eager = lazy.collect(call.head)?;
let value = Value::CustomValue { let value = Value::custom_value(Box::new(eager), call.head);
val: Box::new(eager),
span: call.head,
};
Ok(PipelineData::Value(value, None)) Ok(PipelineData::Value(value, None))
} }

View file

@ -102,18 +102,21 @@ impl Command for LazyFillNA {
let column_name = column.name().to_string(); let column_name = column.name().to_string();
let values = column let values = column
.into_iter() .into_iter()
.map(|value| match value { .map(|value| {
Value::Float { val, .. } => { let span = value.span();
if val.is_nan() { match value {
fill.clone() Value::Float { val, .. } => {
} else { if val.is_nan() {
value fill.clone()
} else {
value
}
} }
Value::List { vals, .. } => {
NuDataFrame::fill_list_nan(vals, span, fill.clone())
}
_ => value,
} }
Value::List { vals, span } => {
NuDataFrame::fill_list_nan(vals, span, fill.clone())
}
_ => value,
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
Column::new(column_name, values) Column::new(column_name, values)

View file

@ -113,10 +113,7 @@ impl Command for ToLazyGroupBy {
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?; let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List { let value = Value::list(vals, call.head);
vals,
span: call.head,
};
let expressions = NuExpression::extract_exprs(value)?; let expressions = NuExpression::extract_exprs(value)?;
if expressions if expressions

View file

@ -55,10 +55,7 @@ impl Command for LazySelect {
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?; let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List { let value = Value::list(vals, call.head);
vals,
span: call.head,
};
let expressions = NuExpression::extract_exprs(value)?; let expressions = NuExpression::extract_exprs(value)?;
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;

View file

@ -105,10 +105,7 @@ impl Command for LazySortBy {
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?; let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List { let value = Value::list(vals, call.head);
vals,
span: call.head,
};
let expressions = NuExpression::extract_exprs(value)?; let expressions = NuExpression::extract_exprs(value)?;
let nulls_last = call.has_flag("nulls-last"); let nulls_last = call.has_flag("nulls-last");
let maintain_order = call.has_flag("maintain-order"); let maintain_order = call.has_flag("maintain-order");

View file

@ -41,10 +41,7 @@ impl Command for ToLazyFrame {
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_iter(input.into_iter())?; let df = NuDataFrame::try_from_iter(input.into_iter())?;
let lazy = NuLazyFrame::from_dataframe(df); let lazy = NuLazyFrame::from_dataframe(df);
let value = Value::CustomValue { let value = Value::custom_value(Box::new(lazy), call.head);
val: Box::new(lazy),
span: call.head,
};
Ok(PipelineData::Value(value, None)) Ok(PipelineData::Value(value, None))
} }

View file

@ -56,22 +56,22 @@ impl Command for AsDateTime {
NuDataFrame::try_from_columns(vec![Column::new( NuDataFrame::try_from_columns(vec![Column::new(
"datetime".to_string(), "datetime".to_string(),
vec![ vec![
Value::Date { Value::date(
val: DateTime::parse_from_str( DateTime::parse_from_str(
"2021-12-30 00:00:00 +0000", "2021-12-30 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z", "%Y-%m-%d %H:%M:%S %z",
) )
.expect("date calculation should not fail in test"), .expect("date calculation should not fail in test"),
span: Span::test_data(), Span::test_data(),
}, ),
Value::Date { Value::date(
val: DateTime::parse_from_str( DateTime::parse_from_str(
"2021-12-31 00:00:00 +0000", "2021-12-31 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z", "%Y-%m-%d %H:%M:%S %z",
) )
.expect("date calculation should not fail in test"), .expect("date calculation should not fail in test"),
span: Span::test_data(), Span::test_data(),
}, ),
], ],
)]) )])
.expect("simple df for test should not fail") .expect("simple df for test should not fail")
@ -85,22 +85,22 @@ impl Command for AsDateTime {
NuDataFrame::try_from_columns(vec![Column::new( NuDataFrame::try_from_columns(vec![Column::new(
"datetime".to_string(), "datetime".to_string(),
vec![ vec![
Value::Date { Value::date(
val: DateTime::parse_from_str( DateTime::parse_from_str(
"2021-12-30 00:00:00.123456789 +0000", "2021-12-30 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z", "%Y-%m-%d %H:%M:%S.%9f %z",
) )
.expect("date calculation should not fail in test"), .expect("date calculation should not fail in test"),
span: Span::test_data(), Span::test_data(),
}, ),
Value::Date { Value::date(
val: DateTime::parse_from_str( DateTime::parse_from_str(
"2021-12-31 00:00:00.123456789 +0000", "2021-12-31 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z", "%Y-%m-%d %H:%M:%S.%9f %z",
) )
.expect("date calculation should not fail in test"), .expect("date calculation should not fail in test"),
span: Span::test_data(), Span::test_data(),
}, ),
], ],
)]) )])
.expect("simple df for test should not fail") .expect("simple df for test should not fail")

View file

@ -123,8 +123,9 @@ fn command(
let df = NuDataFrame::try_from_pipeline(input, call.head)?; let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?; let series = df.as_series(call.head)?;
let span = value.span();
let res = match value { let res = match value {
Value::Int { val, span } => { Value::Int { val, .. } => {
let chunked = series.i64().map_err(|e| { let chunked = series.i64().map_err(|e| {
ShellError::GenericError( ShellError::GenericError(
"Error casting to i64".into(), "Error casting to i64".into(),
@ -147,7 +148,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head) NuDataFrame::try_from_series(vec![res.into_series()], call.head)
} }
Value::Float { val, span } => { Value::Float { val, .. } => {
let chunked = series.f64().map_err(|e| { let chunked = series.f64().map_err(|e| {
ShellError::GenericError( ShellError::GenericError(
"Error casting to f64".into(), "Error casting to f64".into(),
@ -170,7 +171,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head) NuDataFrame::try_from_series(vec![res.into_series()], call.head)
} }
Value::String { val, span } => { Value::String { val, .. } => {
let chunked = series.utf8().map_err(|e| { let chunked = series.utf8().map_err(|e| {
ShellError::GenericError( ShellError::GenericError(
"Error casting to string".into(), "Error casting to string".into(),
@ -204,7 +205,7 @@ fn command(
"this value cannot be set in a series of type '{}'", "this value cannot be set in a series of type '{}'",
series.dtype() series.dtype()
), ),
Some(value.span()), Some(span),
None, None,
Vec::new(), Vec::new(),
)), )),

View file

@ -105,9 +105,9 @@ fn command(
let df = NuDataFrame::try_from_pipeline(input, call.head)?; let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?; let series = df.as_series(call.head)?;
let span = value.span();
let res = match value { let res = match value {
Value::Int { val, span } => { Value::Int { val, .. } => {
let chunked = series.i64().map_err(|e| { let chunked = series.i64().map_err(|e| {
ShellError::GenericError( ShellError::GenericError(
"Error casting to i64".into(), "Error casting to i64".into(),
@ -130,7 +130,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head) NuDataFrame::try_from_series(vec![res.into_series()], call.head)
} }
Value::Float { val, span } => { Value::Float { val, .. } => {
let chunked = series.f64().map_err(|e| { let chunked = series.f64().map_err(|e| {
ShellError::GenericError( ShellError::GenericError(
"Error casting to f64".into(), "Error casting to f64".into(),
@ -153,7 +153,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head) NuDataFrame::try_from_series(vec![res.into_series()], call.head)
} }
Value::String { val, span } => { Value::String { val, .. } => {
let chunked = series.utf8().map_err(|e| { let chunked = series.utf8().map_err(|e| {
ShellError::GenericError( ShellError::GenericError(
"Error casting to string".into(), "Error casting to string".into(),
@ -185,7 +185,7 @@ fn command(
"this value cannot be set in a series of type '{}'", "this value cannot be set in a series of type '{}'",
series.dtype() series.dtype()
), ),
Some(value.span()), Some(span),
None, None,
Vec::new(), Vec::new(),
)), )),

View file

@ -267,29 +267,37 @@ pub(super) fn compute_series_single_value(
rhs_span: right.span(), rhs_span: right.span(),
}), }),
}, },
Operator::Math(Math::Divide) => match &right { Operator::Math(Math::Divide) => {
Value::Int { val, span } => { let span = right.span();
if *val == 0 { match &right {
Err(ShellError::DivisionByZero { span: *span }) Value::Int { val, .. } => {
} else { if *val == 0 {
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span) Err(ShellError::DivisionByZero { span })
} else {
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span)
}
} }
} Value::Float { val, .. } => {
Value::Float { val, span } => { if val.is_zero() {
if val.is_zero() { Err(ShellError::DivisionByZero { span })
Err(ShellError::DivisionByZero { span: *span }) } else {
} else { compute_series_decimal(
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span) &lhs,
*val,
<ChunkedArray<Float64Type>>::div,
lhs_span,
)
}
} }
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span(),
}),
} }
_ => Err(ShellError::OperatorMismatch { }
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::Equal) => match &right { Operator::Comparison(Comparison::Equal) => match &right {
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::equal, lhs_span), Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::equal, lhs_span),
Value::Float { val, .. } => { Value::Float { val, .. } => {

View file

@ -452,7 +452,7 @@ fn series_to_values(
) -> Result<Vec<Value>, ShellError> { ) -> Result<Vec<Value>, ShellError> {
match series.dtype() { match series.dtype() {
DataType::Null => { DataType::Null => {
let it = std::iter::repeat(Value::Nothing { span }); let it = std::iter::repeat(Value::nothing(span));
let values = if let Some(size) = maybe_size { let values = if let Some(size) = maybe_size {
Either::Left(it.take(size)) Either::Left(it.take(size))
} else { } else {
@ -480,11 +480,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { Some(a) => Value::int(a as i64, span),
val: a as i64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -508,11 +505,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { Some(a) => Value::int(a as i64, span),
val: a as i64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -536,11 +530,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { Some(a) => Value::int(a as i64, span),
val: a as i64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -564,11 +555,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { Some(a) => Value::int(a as i64, span),
val: a as i64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -592,11 +580,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { Some(a) => Value::int(a as i64, span),
val: a as i64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -620,11 +605,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { Some(a) => Value::int(a as i64, span),
val: a as i64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -648,11 +630,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { Some(a) => Value::int(a as i64, span),
val: a as i64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -676,8 +655,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Int { val: a, span }, Some(a) => Value::int(a, span),
None => Value::Nothing { span }, None => Value::nothing(span),
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -701,11 +680,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Float { Some(a) => Value::float(a as f64, span),
val: a as f64, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -729,8 +705,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Float { val: a, span }, Some(a) => Value::float(a, span),
None => Value::Nothing { span }, None => Value::nothing(span),
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -754,8 +730,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::Bool { val: a, span }, Some(a) => Value::bool(a, span),
None => Value::Nothing { span }, None => Value::nothing(span),
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -779,11 +755,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(a) => Value::String { Some(a) => Value::string(a.to_string(), span),
val: a.into(), None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -812,7 +785,7 @@ fn series_to_values(
} }
.map(|v| match v { .map(|v| match v {
Some(a) => a.get_value(), Some(a) => a.get_value(),
None => Value::Nothing { span }, None => Value::nothing(span),
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -850,10 +823,7 @@ fn series_to_values(
} }
}) })
.unwrap_or(vec![]); .unwrap_or(vec![]);
Value::List { Value::list(sublist, span)
vals: sublist,
span,
}
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
Ok(values) Ok(values)
@ -884,43 +854,40 @@ fn series_to_values(
let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) { let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) {
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::error(
error: Box::new(ShellError::UnsupportedInput( 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(),
)), ),
span, span,
} )
} }
}; };
// Zero length offset // Zero length offset
let offset = match FixedOffset::east_opt(0) { let offset = match FixedOffset::east_opt(0) {
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::error(
error: Box::new(ShellError::UnsupportedInput( 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(),
)), ),
span, span,
} )
} }
}; };
let datetime = let datetime =
DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset); DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset);
Value::Date { Value::date(datetime, span)
val: datetime,
span,
}
} }
None => Value::Nothing { span }, None => Value::nothing(span),
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -955,43 +922,40 @@ fn series_to_values(
let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) { let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) {
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::error(
error: Box::new(ShellError::UnsupportedInput( 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(),
)), ),
span, span,
} )
} }
}; };
// Zero length offset // Zero length offset
let offset = match FixedOffset::east_opt(0) { let offset = match FixedOffset::east_opt(0) {
Some(val) => val, Some(val) => val,
None => { None => {
return Value::Error { return Value::error(
error: Box::new(ShellError::UnsupportedInput( 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(),
)), ),
span, span,
} )
} }
}; };
let datetime = let datetime =
DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset); DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset);
Value::Date { Value::date(datetime, span)
val: datetime,
span,
}
} }
None => Value::Nothing { span }, None => Value::nothing(span),
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -1015,11 +979,8 @@ fn series_to_values(
Either::Right(it) Either::Right(it)
} }
.map(|v| match v { .map(|v| match v {
Some(nanoseconds) => Value::Duration { Some(nanoseconds) => Value::duration(nanoseconds, span),
val: nanoseconds, None => Value::nothing(span),
span,
},
None => Value::Nothing { span },
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
@ -1043,20 +1004,14 @@ mod tests {
#[test] #[test]
fn test_parsed_column_string_list() -> Result<(), Box<dyn std::error::Error>> { fn test_parsed_column_string_list() -> Result<(), Box<dyn std::error::Error>> {
let values = vec![ let values = vec![
Value::List { Value::list(
vals: vec![Value::String { vec![Value::string("bar".to_string(), Span::test_data())],
val: "bar".to_string(), Span::test_data(),
span: Span::test_data(), ),
}], Value::list(
span: Span::test_data(), vec![Value::string("baz".to_string(), Span::test_data())],
}, Span::test_data(),
Value::List { ),
vals: vec![Value::String {
val: "baz".to_string(),
span: Span::test_data(),
}],
span: Span::test_data(),
},
]; ];
let column = Column { let column = Column {
name: "foo".to_string(), name: "foo".to_string(),

View file

@ -17,10 +17,7 @@ impl CustomValue for NuDataFrame {
from_lazy: false, from_lazy: false,
}; };
Value::CustomValue { Value::custom_value(Box::new(cloned), span)
val: Box::new(cloned),
span,
}
} }
fn value_string(&self) -> String { fn value_string(&self) -> String {
@ -30,7 +27,7 @@ impl CustomValue for NuDataFrame {
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> { fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
let vals = self.print(span)?; let vals = self.print(span)?;
Ok(Value::List { vals, span }) Ok(Value::list(vals, span))
} }
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {

View file

@ -38,9 +38,7 @@ impl Display for DataFrameValue {
impl Default for DataFrameValue { impl Default for DataFrameValue {
fn default() -> Self { fn default() -> Self {
Self(Value::Nothing { Self(Value::nothing(Span::unknown()))
span: Span::unknown(),
})
} }
} }
@ -111,24 +109,15 @@ impl NuDataFrame {
} }
pub fn dataframe_into_value(dataframe: DataFrame, span: Span) -> Value { pub fn dataframe_into_value(dataframe: DataFrame, span: Span) -> Value {
Value::CustomValue { Value::custom_value(Box::new(Self::new(false, dataframe)), span)
val: Box::new(Self::new(false, dataframe)),
span,
}
} }
pub fn into_value(self, span: Span) -> Value { pub fn into_value(self, span: Span) -> Value {
if self.from_lazy { if self.from_lazy {
let lazy = NuLazyFrame::from_dataframe(self); let lazy = NuLazyFrame::from_dataframe(self);
Value::CustomValue { Value::custom_value(Box::new(lazy), span)
val: Box::new(lazy),
span,
}
} else { } else {
Value::CustomValue { Value::custom_value(Box::new(self), span)
val: Box::new(self),
span,
}
} }
} }
@ -207,16 +196,19 @@ impl NuDataFrame {
pub fn fill_list_nan(list: Vec<Value>, list_span: Span, fill: Value) -> Value { pub fn fill_list_nan(list: Vec<Value>, list_span: Span, fill: Value) -> Value {
let newlist = list let newlist = list
.into_iter() .into_iter()
.map(|value| match value { .map(|value| {
Value::Float { val, .. } => { let span = value.span();
if val.is_nan() { match value {
fill.clone() Value::Float { val, .. } => {
} else { if val.is_nan() {
value fill.clone()
} else {
value
}
} }
Value::List { vals, .. } => Self::fill_list_nan(vals, span, fill.clone()),
_ => value,
} }
Value::List { vals, span } => Self::fill_list_nan(vals, span, fill.clone()),
_ => value,
}) })
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
Value::list(newlist, list_span) Value::list(newlist, list_span)
@ -250,8 +242,9 @@ impl NuDataFrame {
} }
pub fn get_df(value: Value) -> Result<Self, ShellError> { pub fn get_df(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value { match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() { Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(df) => Ok(NuDataFrame { Some(df) => Ok(NuDataFrame {
df: df.df.clone(), df: df.df.clone(),
from_lazy: false, from_lazy: false,

View file

@ -20,15 +20,13 @@ impl NuDataFrame {
op_span: Span, op_span: Span,
right: &Value, right: &Value,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
let rhs_span = right.span();
match right { match right {
Value::CustomValue { Value::CustomValue { val: rhs, .. } => {
val: rhs,
span: rhs_span,
} => {
let rhs = rhs.as_any().downcast_ref::<NuDataFrame>().ok_or_else(|| { let rhs = rhs.as_any().downcast_ref::<NuDataFrame>().ok_or_else(|| {
ShellError::DowncastNotPossible( ShellError::DowncastNotPossible(
"Unable to create dataframe".to_string(), "Unable to create dataframe".to_string(),
*rhs_span, rhs_span,
) )
})?; })?;
@ -38,7 +36,7 @@ impl NuDataFrame {
.as_series(lhs_span) .as_series(lhs_span)
.expect("Already checked that is a series"); .expect("Already checked that is a series");
let rhs = &rhs let rhs = &rhs
.as_series(*rhs_span) .as_series(rhs_span)
.expect("Already checked that is a series"); .expect("Already checked that is a series");
if lhs.dtype() != rhs.dtype() { if lhs.dtype() != rhs.dtype() {
@ -46,7 +44,7 @@ impl NuDataFrame {
left_message: format!("datatype {}", lhs.dtype()), left_message: format!("datatype {}", lhs.dtype()),
left_span: lhs_span, left_span: lhs_span,
right_message: format!("datatype {}", lhs.dtype()), right_message: format!("datatype {}", lhs.dtype()),
right_span: *rhs_span, right_span: rhs_span,
}); });
} }
@ -55,7 +53,7 @@ impl NuDataFrame {
left_message: format!("len {}", lhs.len()), left_message: format!("len {}", lhs.len()),
left_span: lhs_span, left_span: lhs_span,
right_message: format!("len {}", rhs.len()), right_message: format!("len {}", rhs.len()),
right_span: *rhs_span, right_span: rhs_span,
}); });
} }
@ -78,7 +76,7 @@ impl NuDataFrame {
left_message: format!("rows {}", self.df.height()), left_message: format!("rows {}", self.df.height()),
left_span: lhs_span, left_span: lhs_span,
right_message: format!("rows {}", rhs.df.height()), right_message: format!("rows {}", rhs.df.height()),
right_span: *rhs_span, right_span: rhs_span,
}); });
} }

View file

@ -20,10 +20,7 @@ impl CustomValue for NuExpression {
fn clone_value(&self, span: nu_protocol::Span) -> Value { fn clone_value(&self, span: nu_protocol::Span) -> Value {
let cloned = NuExpression(self.0.clone()); let cloned = NuExpression(self.0.clone());
Value::CustomValue { Value::custom_value(Box::new(cloned), span)
val: Box::new(cloned),
span,
}
} }
fn value_string(&self) -> String { fn value_string(&self) -> String {
@ -56,16 +53,11 @@ fn compute_with_value(
op: Span, op: Span,
right: &Value, right: &Value,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
let rhs_span = right.span();
match right { match right {
Value::CustomValue { Value::CustomValue { val: rhs, .. } => {
val: rhs,
span: rhs_span,
} => {
let rhs = rhs.as_any().downcast_ref::<NuExpression>().ok_or_else(|| { let rhs = rhs.as_any().downcast_ref::<NuExpression>().ok_or_else(|| {
ShellError::DowncastNotPossible( ShellError::DowncastNotPossible("Unable to create expression".to_string(), rhs_span)
"Unable to create expression".to_string(),
*rhs_span,
)
})?; })?;
match rhs.as_ref() { match rhs.as_ref() {

View file

@ -55,15 +55,13 @@ impl From<Expr> for NuExpression {
impl NuExpression { impl NuExpression {
pub fn into_value(self, span: Span) -> Value { pub fn into_value(self, span: Span) -> Value {
Value::CustomValue { Value::custom_value(Box::new(self), span)
val: Box::new(self),
span,
}
} }
pub fn try_from_value(value: Value) -> Result<Self, ShellError> { pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value { match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() { Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(NuExpression(expr.0.clone())), Some(expr) => Ok(NuExpression(expr.0.clone())),
None => Err(ShellError::CantConvert { None => Err(ShellError::CantConvert {
to_type: "lazy expression".into(), to_type: "lazy expression".into(),
@ -277,13 +275,10 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
Expr::DtypeColumn(dtypes) => { Expr::DtypeColumn(dtypes) => {
let vals = dtypes let vals = dtypes
.iter() .iter()
.map(|d| Value::String { .map(|d| Value::string(format!("{d}"), span))
val: format!("{d}"),
span,
})
.collect(); .collect();
Ok(Value::List { vals, span }) Ok(Value::list(vals, span))
} }
Expr::Sort { expr, options } => Ok(Value::record( Expr::Sort { expr, options } => Ok(Value::record(
record! { record! {
@ -318,10 +313,7 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
} => { } => {
let by: Result<Vec<Value>, ShellError> = let by: Result<Vec<Value>, ShellError> =
by.iter().map(|b| expr_to_value(b, span)).collect(); by.iter().map(|b| expr_to_value(b, span)).collect();
let descending: Vec<Value> = descending let descending: Vec<Value> = descending.iter().map(|r| Value::bool(*r, span)).collect();
.iter()
.map(|r| Value::Bool { val: *r, span })
.collect();
Ok(Value::record( Ok(Value::record(
record! { record! {
@ -354,10 +346,7 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
Expr::Exclude(expr, excluded) => { Expr::Exclude(expr, excluded) => {
let excluded = excluded let excluded = excluded
.iter() .iter()
.map(|e| Value::String { .map(|e| Value::string(format!("{e:?}"), span))
val: format!("{e:?}"),
span,
})
.collect(); .collect();
Ok(Value::record( Ok(Value::record(

View file

@ -18,10 +18,7 @@ impl CustomValue for NuLazyFrame {
schema: self.schema.clone(), schema: self.schema.clone(),
}; };
Value::CustomValue { Value::custom_value(Box::new(cloned), span)
val: Box::new(cloned),
span,
}
} }
fn value_string(&self) -> String { fn value_string(&self) -> String {

View file

@ -90,15 +90,9 @@ impl NuLazyFrame {
pub fn into_value(self, span: Span) -> Result<Value, ShellError> { pub fn into_value(self, span: Span) -> Result<Value, ShellError> {
if self.from_eager { if self.from_eager {
let df = self.collect(span)?; let df = self.collect(span)?;
Ok(Value::CustomValue { Ok(Value::custom_value(Box::new(df), span))
val: Box::new(df),
span,
})
} else { } else {
Ok(Value::CustomValue { Ok(Value::custom_value(Box::new(self), span))
val: Box::new(self),
span,
})
} }
} }
@ -147,8 +141,9 @@ impl NuLazyFrame {
} }
pub fn get_lazy_df(value: Value) -> Result<Self, ShellError> { pub fn get_lazy_df(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value { match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() { Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(Self { Some(expr) => Ok(Self {
lazy: expr.lazy.clone(), lazy: expr.lazy.clone(),
from_eager: false, from_eager: false,

View file

@ -18,10 +18,7 @@ impl CustomValue for NuLazyGroupBy {
from_eager: self.from_eager, from_eager: self.from_eager,
}; };
Value::CustomValue { Value::custom_value(Box::new(cloned), span)
val: Box::new(cloned),
span,
}
} }
fn value_string(&self) -> String { fn value_string(&self) -> String {

View file

@ -74,10 +74,7 @@ impl From<LazyGroupBy> for NuLazyGroupBy {
impl NuLazyGroupBy { impl NuLazyGroupBy {
pub fn into_value(self, span: Span) -> Value { pub fn into_value(self, span: Span) -> Value {
Value::CustomValue { Value::custom_value(Box::new(self), span)
val: Box::new(self),
span,
}
} }
pub fn into_polars(self) -> LazyGroupBy { pub fn into_polars(self) -> LazyGroupBy {
@ -85,22 +82,21 @@ impl NuLazyGroupBy {
} }
pub fn try_from_value(value: Value) -> Result<Self, ShellError> { pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value { match value {
Value::CustomValue { val, span } => { Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<NuLazyGroupBy>() {
match val.as_any().downcast_ref::<NuLazyGroupBy>() { Some(group) => Ok(Self {
Some(group) => Ok(Self { group_by: group.group_by.clone(),
group_by: group.group_by.clone(), schema: group.schema.clone(),
schema: group.schema.clone(), from_eager: group.from_eager,
from_eager: group.from_eager, }),
}), None => Err(ShellError::CantConvert {
None => Err(ShellError::CantConvert { to_type: "lazy groupby".into(),
to_type: "lazy groupby".into(), from_type: "custom value".into(),
from_type: "custom value".into(), span,
span, help: None,
help: None, }),
}), },
}
}
x => Err(ShellError::CantConvert { x => Err(ShellError::CantConvert {
to_type: "lazy groupby".into(), to_type: "lazy groupby".into(),
from_type: x.get_type().to_string(), from_type: x.get_type().to_string(),

View file

@ -14,10 +14,7 @@ impl CustomValue for NuWhen {
fn clone_value(&self, span: nu_protocol::Span) -> Value { fn clone_value(&self, span: nu_protocol::Span) -> Value {
let cloned = self.clone(); let cloned = self.clone();
Value::CustomValue { Value::custom_value(Box::new(cloned), span)
val: Box::new(cloned),
span,
}
} }
fn value_string(&self) -> String { fn value_string(&self) -> String {
@ -25,12 +22,12 @@ impl CustomValue for NuWhen {
} }
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> { fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
let val = match self { let val: String = match self {
NuWhen::Then(_) => "whenthen".into(), NuWhen::Then(_) => "whenthen".into(),
NuWhen::ChainedThen(_) => "whenthenthen".into(), NuWhen::ChainedThen(_) => "whenthenthen".into(),
}; };
let value = Value::String { val, span }; let value = Value::string(val, span);
Ok(value) Ok(value)
} }

View file

@ -51,15 +51,13 @@ impl From<ChainedThen> for NuWhen {
impl NuWhen { impl NuWhen {
pub fn into_value(self, span: Span) -> Value { pub fn into_value(self, span: Span) -> Value {
Value::CustomValue { Value::custom_value(Box::new(self), span)
val: Box::new(self),
span,
}
} }
pub fn try_from_value(value: Value) -> Result<Self, ShellError> { pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value { match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() { Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(expr.clone()), Some(expr) => Ok(expr.clone()),
None => Err(ShellError::CantConvert { None => Err(ShellError::CantConvert {
to_type: "when expression".into(), to_type: "when expression".into(),

View file

@ -25,18 +25,21 @@ pub(crate) fn convert_columns(
let res = columns let res = columns
.into_iter() .into_iter()
.map(|value| match value { .map(|value| {
Value::String { val, span } => { let span = value.span();
col_span = span_join(&[col_span, span]); match value {
Ok(Spanned { item: val, span }) Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
Ok(Spanned { item: val, span })
}
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
} }
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
}) })
.collect::<Result<Vec<Spanned<String>>, _>>()?; .collect::<Result<Vec<Spanned<String>>, _>>()?;
@ -65,18 +68,21 @@ pub(crate) fn convert_columns_string(
let res = columns let res = columns
.into_iter() .into_iter()
.map(|value| match value { .map(|value| {
Value::String { val, span } => { let span = value.span();
col_span = span_join(&[col_span, span]); match value {
Ok(val) Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
Ok(val)
}
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
} }
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
}) })
.collect::<Result<Vec<String>, _>>()?; .collect::<Result<Vec<String>, _>>()?;

View file

@ -68,32 +68,30 @@ impl Command for BitsAnd {
Example { Example {
description: "Apply logical and to a list of numbers", description: "Apply logical and to a list of numbers",
example: "[4 3 2] | bits and 2", example: "[4 3 2] | bits and 2",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_int(0), Value::test_int(2), Value::test_int(2)], vec![Value::test_int(0), Value::test_int(2), Value::test_int(2)],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
} }
fn operate(value: Value, target: i64, head: Span) -> Value { fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => Value::Int { Value::Int { val, .. } => Value::int(val & target, span),
val: val & target,
span,
},
// 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: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -34,16 +34,16 @@ impl Command for Bits {
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
Ok(Value::String { Ok(Value::string(
val: get_full_help( get_full_help(
&Bits.signature(), &Bits.signature(),
&Bits.examples(), &Bits.examples(),
engine_state, engine_state,
stack, stack,
self.is_parser_keyword(), self.is_parser_keyword(),
), ),
span: call.head, call.head,
} )
.into_pipeline_data()) .into_pipeline_data())
} }
} }

View file

@ -71,58 +71,51 @@ impl Command for BitsInto {
Example { Example {
description: "convert a binary value into a string, padded to 8 places with 0s", description: "convert a binary value into a string, padded to 8 places with 0s",
example: "01b | into bits", example: "01b | into bits",
result: Some(Value::String { result: Some(Value::string("00000001",
val: "00000001".to_string(), Span::test_data(),
span: Span::test_data(), )),
}),
}, },
Example { Example {
description: "convert an int into a string, padded to 8 places with 0s", description: "convert an int into a string, padded to 8 places with 0s",
example: "1 | into bits", example: "1 | into bits",
result: Some(Value::String { result: Some(Value::string("00000001",
val: "00000001".to_string(), Span::test_data(),
span: Span::test_data(), )),
}),
}, },
Example { Example {
description: "convert a filesize value into a string, padded to 8 places with 0s", description: "convert a filesize value into a string, padded to 8 places with 0s",
example: "1b | into bits", example: "1b | into bits",
result: Some(Value::String { result: Some(Value::string("00000001",
val: "00000001".to_string(), Span::test_data(),
span: Span::test_data(), )),
}),
}, },
Example { Example {
description: "convert a duration value into a string, padded to 8 places with 0s", description: "convert a duration value into a string, padded to 8 places with 0s",
example: "1ns | into bits", example: "1ns | into bits",
result: Some(Value::String { result: Some(Value::string("00000001",
val: "00000001".to_string(), Span::test_data(),
span: Span::test_data(), )),
}),
}, },
Example { Example {
description: "convert a boolean value into a string, padded to 8 places with 0s", description: "convert a boolean value into a string, padded to 8 places with 0s",
example: "true | into bits", example: "true | into bits",
result: Some(Value::String { result: Some(Value::string("00000001",
val: "00000001".to_string(), Span::test_data(),
span: Span::test_data(), )),
}),
}, },
Example { Example {
description: "convert a datetime value into a string, padded to 8 places with 0s", description: "convert a datetime value into a string, padded to 8 places with 0s",
example: "2023-04-17T01:02:03 | into bits", example: "2023-04-17T01:02:03 | into bits",
result: Some(Value::String { result: Some(Value::string("01001101 01101111 01101110 00100000 01000001 01110000 01110010 00100000 00110001 00110111 00100000 00110000 00110001 00111010 00110000 00110010 00111010 00110000 00110011 00100000 00110010 00110000 00110010 00110011",
val: "01001101 01101111 01101110 00100000 01000001 01110000 01110010 00100000 00110001 00110111 00100000 00110000 00110001 00111010 00110000 00110010 00111010 00110000 00110011 00100000 00110010 00110000 00110010 00110011".to_string(), Span::test_data(),
span: Span::test_data(), )),
}),
}, },
Example { Example {
description: "convert a string into a raw binary string, padded with 0s to 8 places", description: "convert a string into a raw binary string, padded with 0s to 8 places",
example: "'nushell.sh' | into bits", example: "'nushell.sh' | into bits",
result: Some(Value::String { result: Some(Value::string("01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000",
val: "01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000".to_string(), Span::test_data(),
span: Span::test_data(), )),
}),
}, },
] ]
} }
@ -139,22 +132,16 @@ fn into_bits(
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths); let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
match input { match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary { PipelineData::ExternalStream { stdout: None, .. } => {
val: vec![], Ok(Value::binary(vec![], head).into_pipeline_data())
span: head,
} }
.into_pipeline_data()),
PipelineData::ExternalStream { PipelineData::ExternalStream {
stdout: Some(stream), stdout: Some(stream),
.. ..
} => { } => {
// TODO: in the future, we may want this to stream out, converting each to bytes // TODO: in the future, we may want this to stream out, converting each to bytes
let output = stream.into_bytes()?; let output = stream.into_bytes()?;
Ok(Value::Binary { Ok(Value::binary(output.item, head).into_pipeline_data())
val: output.item,
span: head,
}
.into_pipeline_data())
} }
_ => { _ => {
let args = Arguments { cell_paths }; let args = Arguments { cell_paths };
@ -170,40 +157,28 @@ fn convert_to_smallest_number_type(num: i64, span: Span) -> Value {
for ch in bytes { for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch)); raw_string.push_str(&format!("{:08b} ", ch));
} }
Value::String { Value::string(raw_string.trim(), span)
val: raw_string.trim().to_string(),
span,
}
} else if let Some(v) = num.to_i16() { } else if let Some(v) = num.to_i16() {
let bytes = v.to_ne_bytes(); let bytes = v.to_ne_bytes();
let mut raw_string = "".to_string(); let mut raw_string = "".to_string();
for ch in bytes { for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch)); raw_string.push_str(&format!("{:08b} ", ch));
} }
Value::String { Value::string(raw_string.trim(), span)
val: raw_string.trim().to_string(),
span,
}
} else if let Some(v) = num.to_i32() { } else if let Some(v) = num.to_i32() {
let bytes = v.to_ne_bytes(); let bytes = v.to_ne_bytes();
let mut raw_string = "".to_string(); let mut raw_string = "".to_string();
for ch in bytes { for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch)); raw_string.push_str(&format!("{:08b} ", ch));
} }
Value::String { Value::string(raw_string.trim(), span)
val: raw_string.trim().to_string(),
span,
}
} else { } else {
let bytes = num.to_ne_bytes(); let bytes = num.to_ne_bytes();
let mut raw_string = "".to_string(); let mut raw_string = "".to_string();
for ch in bytes { for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch)); raw_string.push_str(&format!("{:08b} ", ch));
} }
Value::String { Value::string(raw_string.trim(), span)
val: raw_string.trim().to_string(),
span,
}
} }
} }
@ -214,10 +189,7 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
for ch in val { for ch in val {
raw_string.push_str(&format!("{:08b} ", ch)); raw_string.push_str(&format!("{:08b} ", ch));
} }
Value::String { Value::string(raw_string.trim(), span)
val: raw_string.trim().to_string(),
span,
}
} }
Value::Int { val, .. } => convert_to_smallest_number_type(*val, span), Value::Int { val, .. } => convert_to_smallest_number_type(*val, span),
Value::Filesize { val, .. } => convert_to_smallest_number_type(*val, span), Value::Filesize { val, .. } => convert_to_smallest_number_type(*val, span),
@ -228,10 +200,7 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
for ch in raw_bytes { for ch in raw_bytes {
raw_string.push_str(&format!("{:08b} ", ch)); raw_string.push_str(&format!("{:08b} ", ch));
} }
Value::String { Value::string(raw_string.trim(), span)
val: raw_string.trim().to_string(),
span,
}
} }
Value::Bool { val, .. } => { Value::Bool { val, .. } => {
let v = <i64 as From<bool>>::from(*val); let v = <i64 as From<bool>>::from(*val);
@ -244,22 +213,19 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
for ch in bytes { for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch)); raw_string.push_str(&format!("{:08b} ", ch));
} }
Value::String { Value::string(raw_string.trim(), span)
val: raw_string.trim().to_string(),
span,
}
} }
// 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: Box::new(ShellError::OnlySupportsThisInputType { ShellError::OnlySupportsThisInputType {
exp_input_type: "integer, filesize, string, date, duration, binary or bool".into(), exp_input_type: "integer, filesize, string, date, duration, binary or bool".into(),
wrong_type: other.get_type().to_string(), wrong_type: other.get_type().to_string(),
dst_span: span, dst_span: span,
src_span: other.span(), src_span: other.span(),
}), },
span, span,
}, ),
} }
} }

View file

@ -84,50 +84,51 @@ impl Command for BitsNot {
Example { Example {
description: "Apply logical negation to a list of numbers", description: "Apply logical negation to a list of numbers",
example: "[4 3 2] | bits not", example: "[4 3 2] | bits not",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_int(140737488355323), Value::test_int(140737488355323),
Value::test_int(140737488355324), Value::test_int(140737488355324),
Value::test_int(140737488355325), Value::test_int(140737488355325),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: description:
"Apply logical negation to a list of numbers, treat input as 2 bytes number", "Apply logical negation to a list of numbers, treat input as 2 bytes number",
example: "[4 3 2] | bits not -n '2'", example: "[4 3 2] | bits not -n '2'",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_int(65531), Value::test_int(65531),
Value::test_int(65532), Value::test_int(65532),
Value::test_int(65533), Value::test_int(65533),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: description:
"Apply logical negation to a list of numbers, treat input as signed number", "Apply logical negation to a list of numbers, treat input as signed number",
example: "[4 3 2] | bits not -s", example: "[4 3 2] | bits not -s",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_int(-5), Value::test_int(-5),
Value::test_int(-4), Value::test_int(-4),
Value::test_int(-3), Value::test_int(-3),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
} }
fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) -> Value { fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => { Value::Int { val, .. } => {
if signed || val < 0 { if signed || val < 0 {
Value::Int { val: !val, span } Value::int(!val, span)
} else { } else {
use NumberBytes::*; use NumberBytes::*;
let out_val = match number_size { let out_val = match number_size {
@ -149,21 +150,21 @@ fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) ->
// This case shouldn't happen here, as it's handled before // This case shouldn't happen here, as it's handled before
Invalid => 0, Invalid => 0,
}; };
Value::Int { val: out_val, span } Value::int(out_val, span)
} }
} }
other => match other { other => match other {
// Propagate errors inside the value // Propagate errors inside the value
Value::Error { .. } => other, Value::Error { .. } => other,
_ => Value::Error { _ => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
}, },
} }
} }

View file

@ -68,32 +68,30 @@ impl Command for BitsOr {
Example { Example {
description: "Apply logical or to a list of numbers", description: "Apply logical or to a list of numbers",
example: "[8 3 2] | bits or 2", example: "[8 3 2] | bits or 2",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)], vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
} }
fn operate(value: Value, target: i64, head: Span) -> Value { fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => Value::Int { Value::Int { val, .. } => Value::int(val | target, span),
val: val | target,
span,
},
// 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: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -91,10 +91,10 @@ impl Command for BitsRol {
Example { Example {
description: "Rotate left a list of numbers with 2 bits", description: "Rotate left a list of numbers with 2 bits",
example: "[5 3 2] | bits rol 2", example: "[5 3 2] | bits rol 2",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_int(20), Value::test_int(12), Value::test_int(8)], vec![Value::test_int(20), Value::test_int(12), Value::test_int(8)],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -106,9 +106,9 @@ where
{ {
let rotate_result = i64::try_from(val.rotate_left(bits)); let rotate_result = i64::try_from(val.rotate_left(bits));
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: Box::new(ShellError::GenericError( 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"
@ -116,15 +116,16 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
)), ),
span, span,
}, ),
} }
} }
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value { fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => { Value::Int { val, .. } => {
use InputNumType::*; use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32; // let bits = (((bits % 64) + 64) % 64) as u32;
let bits = bits as u32; let bits = bits as u32;
@ -142,15 +143,15 @@ 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: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -91,14 +91,14 @@ impl Command for BitsRor {
Example { Example {
description: "Rotate right a list of numbers of one byte", description: "Rotate right a list of numbers of one byte",
example: "[15 33 92] | bits ror 2 -n '1'", example: "[15 33 92] | bits ror 2 -n '1'",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_int(195), Value::test_int(195),
Value::test_int(72), Value::test_int(72),
Value::test_int(23), Value::test_int(23),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -110,9 +110,9 @@ where
{ {
let rotate_result = i64::try_from(val.rotate_right(bits)); let rotate_result = i64::try_from(val.rotate_right(bits));
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: Box::new(ShellError::GenericError( 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"
@ -120,15 +120,16 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
)), ),
span, span,
}, ),
} }
} }
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value { fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => { Value::Int { val, .. } => {
use InputNumType::*; use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32; // let bits = (((bits % 64) + 64) % 64) as u32;
let bits = bits as u32; let bits = bits as u32;
@ -146,15 +147,15 @@ 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: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -101,10 +101,10 @@ impl Command for BitsShl {
Example { Example {
description: "Shift left a list of numbers", description: "Shift left a list of numbers",
example: "[5 3 2] | bits shl 2", example: "[5 3 2] | bits shl 2",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_int(20), Value::test_int(12), Value::test_int(8)], vec![Value::test_int(20), Value::test_int(12), Value::test_int(8)],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -118,9 +118,9 @@ where
Some(val) => { Some(val) => {
let shift_result = i64::try_from(val); let shift_result = i64::try_from(val);
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: Box::new(ShellError::GenericError( 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"
@ -128,27 +128,28 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
)), ),
span, span,
}, ),
} }
} }
None => Value::Error { None => Value::error(
error: Box::new(ShellError::GenericError( 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(),
)), ),
span, span,
}, ),
} }
} }
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value { fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => { Value::Int { val, .. } => {
use InputNumType::*; use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32; // let bits = (((bits % 64) + 64) % 64) as u32;
let bits = bits as u32; let bits = bits as u32;
@ -166,15 +167,15 @@ 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: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -91,10 +91,10 @@ impl Command for BitsShr {
Example { Example {
description: "Shift right a list of numbers", description: "Shift right a list of numbers",
example: "[15 35 2] | bits shr 2", example: "[15 35 2] | bits shr 2",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_int(3), Value::test_int(8), Value::test_int(0)], vec![Value::test_int(3), Value::test_int(8), Value::test_int(0)],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -108,9 +108,9 @@ where
Some(val) => { Some(val) => {
let shift_result = i64::try_from(val); let shift_result = i64::try_from(val);
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: Box::new(ShellError::GenericError( 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"
@ -118,27 +118,28 @@ where
Some(span), Some(span),
None, None,
Vec::new(), Vec::new(),
)), ),
span, span,
}, ),
} }
} }
None => Value::Error { None => Value::error(
error: Box::new(ShellError::GenericError( 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(),
)), ),
span, span,
}, ),
} }
} }
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value { fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => { Value::Int { val, .. } => {
use InputNumType::*; use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32; // let bits = (((bits % 64) + 64) % 64) as u32;
let bits = bits as u32; let bits = bits as u32;
@ -156,15 +157,15 @@ 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: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -67,32 +67,30 @@ impl Command for BitsXor {
Example { Example {
description: "Apply logical xor to a list of numbers", description: "Apply logical xor to a list of numbers",
example: "[8 3 2] | bits xor 2", example: "[8 3 2] | bits xor 2",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_int(10), Value::test_int(1), Value::test_int(0)], vec![Value::test_int(10), Value::test_int(1), Value::test_int(0)],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
} }
fn operate(value: Value, target: i64, head: Span) -> Value { fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value { match value {
Value::Int { val, span } => Value::Int { Value::Int { val, .. } => Value::int(val ^ target, span),
val: val ^ target,
span,
},
// 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: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -86,15 +86,15 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
Value::Filesize { val, .. } => fmt_it(*val, span), Value::Filesize { val, .. } => fmt_it(*val, span),
// 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: Box::new(ShellError::OnlySupportsThisInputType { ShellError::OnlySupportsThisInputType {
exp_input_type: "float , integer or filesize".into(), exp_input_type: "float , 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.span(), src_span: other.span(),
}), },
span, span,
}, ),
} }
} }

View file

@ -50,26 +50,20 @@ impl Command for EachWhile {
Example { Example {
example: "[1 2 3 2 1] | each while {|e| if $e < 3 { $e * 2 } }", example: "[1 2 3 2 1] | each while {|e| if $e < 3 { $e * 2 } }",
description: "Produces a list of each element before the 3, doubled", description: "Produces a list of each element before the 3, doubled",
result: Some(Value::List { result: Some(Value::list(stream_test_1, Span::test_data())),
vals: stream_test_1,
span: Span::test_data(),
}),
}, },
Example { Example {
example: r#"[1 2 stop 3 4] | each while {|e| if $e != 'stop' { $"Output: ($e)" } }"#, example: r#"[1 2 stop 3 4] | each while {|e| if $e != 'stop' { $"Output: ($e)" } }"#,
description: "Output elements until reaching 'stop'", description: "Output elements until reaching 'stop'",
result: Some(Value::List { result: Some(Value::list(stream_test_2, Span::test_data())),
vals: stream_test_2,
span: Span::test_data(),
}),
}, },
Example { Example {
example: r#"[1 2 3] | enumerate | each while {|e| if $e.item < 2 { $"value ($e.item) at ($e.index)!"} }"#, example: r#"[1 2 3] | enumerate | each while {|e| if $e.item < 2 { $"value ($e.item) at ($e.index)!"} }"#,
description: "Iterate over each element, printing the matching value and its index", description: "Iterate over each element, printing the matching value and its index",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_string("value 1 at 0!")], vec![Value::test_string("value 1 at 0!")],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -21,8 +21,9 @@ fn vertical_rotate_value(
by: Option<usize>, by: Option<usize>,
direction: VerticalDirection, direction: VerticalDirection,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
let span = value.span();
match value { match value {
Value::List { mut vals, span } => { Value::List { mut vals, .. } => {
let rotations = by.map(|n| n % vals.len()).unwrap_or(1); let rotations = by.map(|n| n % vals.len()).unwrap_or(1);
let values = vals.as_mut_slice(); let values = vals.as_mut_slice();
@ -31,10 +32,7 @@ fn vertical_rotate_value(
VerticalDirection::Down => values.rotate_right(rotations), VerticalDirection::Down => values.rotate_right(rotations),
} }
Ok(Value::List { Ok(Value::list(values.to_owned(), span))
vals: values.to_owned(),
span,
})
} }
_ => Err(ShellError::TypeMismatch { _ => Err(ShellError::TypeMismatch {
err_message: "list".to_string(), err_message: "list".to_string(),
@ -54,10 +52,10 @@ fn horizontal_rotate_value(
cells_only: bool, cells_only: bool,
direction: &HorizontalDirection, direction: &HorizontalDirection,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
let span = value.span();
match value { match value {
Value::Record { Value::Record {
val: mut record, val: mut record, ..
span,
} => { } => {
let rotations = by.map(|n| n % record.len()).unwrap_or(1); let rotations = by.map(|n| n % record.len()).unwrap_or(1);
@ -75,13 +73,13 @@ fn horizontal_rotate_value(
Ok(Value::record(record, span)) Ok(Value::record(record, span))
} }
Value::List { vals, span } => { Value::List { vals, .. } => {
let values = vals let values = vals
.into_iter() .into_iter()
.map(|value| horizontal_rotate_value(value, by, cells_only, direction)) .map(|value| horizontal_rotate_value(value, by, cells_only, direction))
.collect::<Result<Vec<Value>, ShellError>>()?; .collect::<Result<Vec<Value>, ShellError>>()?;
Ok(Value::List { vals: values, span }) Ok(Value::list(values, span))
} }
_ => Err(ShellError::TypeMismatch { _ => Err(ShellError::TypeMismatch {
err_message: "record".to_string(), err_message: "record".to_string(),

View file

@ -36,16 +36,16 @@ impl Command for Roll {
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
Ok(Value::String { Ok(Value::string(
val: get_full_help( get_full_help(
&Roll.signature(), &Roll.signature(),
&Roll.examples(), &Roll.examples(),
engine_state, engine_state,
stack, stack,
self.is_parser_keyword(), self.is_parser_keyword(),
), ),
span: call.head, call.head,
} )
.into_pipeline_data()) .into_pipeline_data())
} }
} }

View file

@ -37,8 +37,8 @@ impl Command for RollDown {
vec![Example { vec![Example {
description: "Rolls rows down of a table", description: "Rolls rows down of a table",
example: "[[a b]; [1 2] [3 4] [5 6]] | roll down", example: "[[a b]; [1 2] [3 4] [5 6]] | roll down",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: columns.clone(), cols: columns.clone(),
vals: vec![Value::test_int(5), Value::test_int(6)], vals: vec![Value::test_int(5), Value::test_int(6)],
@ -52,8 +52,8 @@ impl Command for RollDown {
vals: vec![Value::test_int(3), Value::test_int(4)], vals: vec![Value::test_int(3), Value::test_int(4)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}] }]
} }

View file

@ -59,8 +59,8 @@ impl Command for RollLeft {
Example { Example {
description: "Rolls columns of a table to the left", description: "Rolls columns of a table to the left",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll left", example: "[[a b c]; [1 2 3] [4 5 6]] | roll left",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: rotated_columns.clone(), cols: rotated_columns.clone(),
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(1)], vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(1)],
@ -70,14 +70,14 @@ impl Command for RollLeft {
vals: vec![Value::test_int(5), Value::test_int(6), Value::test_int(4)], vals: vec![Value::test_int(5), Value::test_int(6), Value::test_int(4)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Rolls columns to the left without changing column names", description: "Rolls columns to the left without changing column names",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll left --cells-only", example: "[[a b c]; [1 2 3] [4 5 6]] | roll left --cells-only",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: columns.clone(), cols: columns.clone(),
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(1)], vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(1)],
@ -87,8 +87,8 @@ impl Command for RollLeft {
vals: vec![Value::test_int(5), Value::test_int(6), Value::test_int(4)], vals: vec![Value::test_int(5), Value::test_int(6), Value::test_int(4)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -59,8 +59,8 @@ impl Command for RollRight {
Example { Example {
description: "Rolls columns to the right", description: "Rolls columns to the right",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll right", example: "[[a b c]; [1 2 3] [4 5 6]] | roll right",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: rotated_columns.clone(), cols: rotated_columns.clone(),
vals: vec![Value::test_int(3), Value::test_int(1), Value::test_int(2)], vals: vec![Value::test_int(3), Value::test_int(1), Value::test_int(2)],
@ -70,14 +70,14 @@ impl Command for RollRight {
vals: vec![Value::test_int(6), Value::test_int(4), Value::test_int(5)], vals: vec![Value::test_int(6), Value::test_int(4), Value::test_int(5)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Rolls columns to the right with fixed headers", description: "Rolls columns to the right with fixed headers",
example: "[[a b c]; [1 2 3] [4 5 6]] | roll right --cells-only", example: "[[a b c]; [1 2 3] [4 5 6]] | roll right --cells-only",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: columns.clone(), cols: columns.clone(),
vals: vec![Value::test_int(3), Value::test_int(1), Value::test_int(2)], vals: vec![Value::test_int(3), Value::test_int(1), Value::test_int(2)],
@ -87,8 +87,8 @@ impl Command for RollRight {
vals: vec![Value::test_int(6), Value::test_int(4), Value::test_int(5)], vals: vec![Value::test_int(6), Value::test_int(4), Value::test_int(5)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -37,8 +37,8 @@ impl Command for RollUp {
vec![Example { vec![Example {
description: "Rolls rows up", description: "Rolls rows up",
example: "[[a b]; [1 2] [3 4] [5 6]] | roll up", example: "[[a b]; [1 2] [3 4] [5 6]] | roll up",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: columns.clone(), cols: columns.clone(),
vals: vec![Value::test_int(3), Value::test_int(4)], vals: vec![Value::test_int(3), Value::test_int(4)],
@ -52,8 +52,8 @@ impl Command for RollUp {
vals: vec![Value::test_int(1), Value::test_int(2)], vals: vec![Value::test_int(1), Value::test_int(2)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}] }]
} }

View file

@ -38,8 +38,7 @@ impl Command for Rotate {
Example { Example {
description: "Rotate a record clockwise, producing a table (like `transpose` but with column order reversed)", description: "Rotate a record clockwise, producing a table (like `transpose` but with column order reversed)",
example: "{a:1, b:2} | rotate", example: "{a:1, b:2} | rotate",
result: Some(Value::List { result: Some(Value::list(vec![
vals: vec![
Value::test_record(Record { Value::test_record(Record {
cols: vec!["column0".to_string(), "column1".to_string()], cols: vec!["column0".to_string(), "column1".to_string()],
vals: vec![Value::test_int(1), Value::test_string("a")], vals: vec![Value::test_int(1), Value::test_string("a")],
@ -49,14 +48,14 @@ impl Command for Rotate {
vals: vec![Value::test_int(2), Value::test_string("b")], vals: vec![Value::test_int(2), Value::test_string("b")],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Rotate 2x3 table clockwise", description: "Rotate 2x3 table clockwise",
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate", example: "[[a b]; [1 2] [3 4] [5 6]] | rotate",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: vec![ cols: vec![
"column0".to_string(), "column0".to_string(),
@ -86,14 +85,14 @@ impl Command for Rotate {
], ],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Rotate table clockwise and change columns names", description: "Rotate table clockwise and change columns names",
example: "[[a b]; [1 2]] | rotate col_a col_b", example: "[[a b]; [1 2]] | rotate col_a col_b",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: vec!["col_a".to_string(), "col_b".to_string()], cols: vec!["col_a".to_string(), "col_b".to_string()],
vals: vec![Value::test_int(1), Value::test_string("a")], vals: vec![Value::test_int(1), Value::test_string("a")],
@ -103,14 +102,14 @@ impl Command for Rotate {
vals: vec![Value::test_int(2), Value::test_string("b")], vals: vec![Value::test_int(2), Value::test_string("b")],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Rotate table counter clockwise", description: "Rotate table counter clockwise",
example: "[[a b]; [1 2]] | rotate --ccw", example: "[[a b]; [1 2]] | rotate --ccw",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: vec!["column0".to_string(), "column1".to_string()], cols: vec!["column0".to_string(), "column1".to_string()],
vals: vec![Value::test_string("b"), Value::test_int(2)], vals: vec![Value::test_string("b"), Value::test_int(2)],
@ -120,14 +119,14 @@ impl Command for Rotate {
vals: vec![Value::test_string("a"), Value::test_int(1)], vals: vec![Value::test_string("a"), Value::test_int(1)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Rotate table counter-clockwise", description: "Rotate table counter-clockwise",
example: "[[a b]; [1 2] [3 4] [5 6]] | rotate --ccw", example: "[[a b]; [1 2] [3 4] [5 6]] | rotate --ccw",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: vec![ cols: vec![
"column0".to_string(), "column0".to_string(),
@ -157,14 +156,14 @@ impl Command for Rotate {
], ],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Rotate table counter-clockwise and change columns names", description: "Rotate table counter-clockwise and change columns names",
example: "[[a b]; [1 2]] | rotate --ccw col_a col_b", example: "[[a b]; [1 2]] | rotate --ccw col_a col_b",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_record(Record { Value::test_record(Record {
cols: vec!["col_a".to_string(), "col_b".to_string()], cols: vec!["col_a".to_string(), "col_b".to_string()],
vals: vec![Value::test_string("b"), Value::test_int(2)], vals: vec![Value::test_string("b"), Value::test_int(2)],
@ -174,8 +173,8 @@ impl Command for Rotate {
vals: vec![Value::test_string("a"), Value::test_int(1)], vals: vec![Value::test_string("a"), Value::test_int(1)],
}), }),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -213,6 +212,7 @@ pub fn rotate(
if !values.is_empty() { if !values.is_empty() {
for val in values.into_iter() { for val in values.into_iter() {
let span = val.span();
match val { match val {
Value::Record { val: record, .. } => { Value::Record { val: record, .. } => {
old_column_names = record.cols; old_column_names = record.cols;
@ -226,9 +226,9 @@ pub fn rotate(
new_values.push(v); new_values.push(v);
} }
} }
Value::String { val, span } => { Value::String { val, .. } => {
not_a_record = true; not_a_record = true;
new_values.push(Value::String { val, span }) new_values.push(Value::string(val, span))
} }
x => { x => {
not_a_record = true; not_a_record = true;
@ -273,16 +273,16 @@ pub fn rotate(
} }
if not_a_record { if not_a_record {
return Ok(Value::List { return Ok(Value::list(
vals: vec![Value::record( vec![Value::record(
Record { Record {
cols: new_column_names, cols: new_column_names,
vals: new_values, vals: new_values,
}, },
call.head, call.head,
)], )],
span: call.head, call.head,
} )
.into_pipeline_data() .into_pipeline_data()
.set_metadata(metadata)); .set_metadata(metadata));
} }
@ -332,12 +332,9 @@ pub fn rotate(
)) ))
} }
Ok(Value::List { Ok(Value::list(final_values, call.head)
vals: final_values, .into_pipeline_data()
span: call.head, .set_metadata(metadata))
}
.into_pipeline_data()
.set_metadata(metadata))
} }
#[cfg(test)] #[cfg(test)]

View file

@ -51,8 +51,8 @@ impl Command for UpdateCells {
$value $value
} }
}"#, }"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec![ cols: vec![
"2021-04-16".into(), "2021-04-16".into(),
"2021-06-10".into(), "2021-06-10".into(),
@ -72,8 +72,8 @@ impl Command for UpdateCells {
Value::test_string(""), Value::test_string(""),
], ],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
Example { Example {
description: "Update the zero value cells to empty strings in 2 last columns.", description: "Update the zero value cells to empty strings in 2 last columns.",
@ -87,8 +87,8 @@ impl Command for UpdateCells {
$value $value
} }
}"#, }"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec![ cols: vec![
"2021-04-16".into(), "2021-04-16".into(),
"2021-06-10".into(), "2021-06-10".into(),
@ -108,8 +108,8 @@ impl Command for UpdateCells {
Value::test_string(""), Value::test_string(""),
], ],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -191,8 +191,9 @@ impl Iterator for UpdateCellIterator {
} }
} }
let span = val.span();
match val { match val {
Value::Record { val, span } => Some(Value::record( Value::Record { val, .. } => Some(Value::record(
val.into_iter() val.into_iter()
.map(|(col, val)| match &self.columns { .map(|(col, val)| match &self.columns {
Some(cols) if !cols.contains(&col) => (col, val), Some(cols) if !cols.contains(&col) => (col, val),
@ -251,10 +252,7 @@ fn process_cell(
redirect_stderr, redirect_stderr,
) { ) {
Ok(pd) => pd.into_value(span), Ok(pd) => pd.into_value(span),
Err(e) => Value::Error { Err(e) => Value::error(e, span),
error: Box::new(e),
span,
},
} }
} }

View file

@ -288,13 +288,13 @@ fn to_html(
) )
}) })
.collect(); .collect();
return Ok(Value::List { return Ok(
vals: result, Value::list(result, head).into_pipeline_data_with_metadata(Box::new(
span: head, PipelineMetadata {
} data_source: DataSource::HtmlThemes,
.into_pipeline_data_with_metadata(Box::new(PipelineMetadata { },
data_source: DataSource::HtmlThemes, )),
}))); );
} else { } else {
let theme_span = match &theme { let theme_span = match &theme {
Some(v) => v.span, Some(v) => v.span,
@ -403,7 +403,8 @@ fn html_table(table: Vec<Value>, headers: Vec<String>, config: &Config) -> Strin
output_string.push_str("</tr></thead><tbody>"); output_string.push_str("</tr></thead><tbody>");
for row in table { for row in table {
if let Value::Record { span, .. } = row { let span = row.span();
if let Value::Record { .. } = row {
output_string.push_str("<tr>"); output_string.push_str("<tr>");
for header in &headers { for header in &headers {
let data = row.get_data_by_key(header); let data = row.get_data_by_key(header);

View file

@ -70,9 +70,10 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span, use_degrees: bool) -> Value { fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -80,29 +81,29 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
let val = val.acos(); let val = val.acos();
let val = if use_degrees { val.to_degrees() } else { val }; let val = if use_degrees { val.to_degrees() } else { val };
Value::Float { val, span } Value::float(val, span)
} else { } else {
Value::Error { Value::error(
error: Box::new(ShellError::UnsupportedInput( 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,
)), ),
span, span,
} )
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -61,38 +61,39 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
if (1.0..).contains(&val) { if (1.0..).contains(&val) {
let val = val.acosh(); let val = val.acosh();
Value::Float { val, span } Value::float(val, span)
} else { } else {
Value::Error { Value::error(
error: Box::new(ShellError::UnsupportedInput( 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,
)), ),
span, span,
} )
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -71,9 +71,10 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span, use_degrees: bool) -> Value { fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -81,29 +82,29 @@ fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
let val = val.asin(); let val = val.asin();
let val = if use_degrees { val.to_degrees() } else { val }; let val = if use_degrees { val.to_degrees() } else { val };
Value::Float { val, span } Value::float(val, span)
} else { } else {
Value::Error { Value::error(
error: Box::new(ShellError::UnsupportedInput( 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,
)), ),
span, span,
} )
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -61,26 +61,27 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
let val = val.asinh(); let val = val.asinh();
Value::Float { val, span } Value::float(val, span)
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -71,27 +71,28 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span, use_degrees: bool) -> Value { fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
let val = val.atan(); let val = val.atan();
let val = if use_degrees { val.to_degrees() } else { val }; let val = if use_degrees { val.to_degrees() } else { val };
Value::Float { val, span } Value::float(val, span)
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -61,38 +61,39 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
if (-1.0..=1.0).contains(&val) { if (-1.0..=1.0).contains(&val) {
let val = val.atanh(); let val = val.atanh();
Value::Float { val, span } Value::float(val, span)
} else { } else {
Value::Error { Value::error(
error: Box::new(ShellError::UnsupportedInput( 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,
)), ),
span: head, head,
} )
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -60,16 +60,16 @@ impl Command for SubCommand {
Example { Example {
description: "Apply the cosine to a list of angles in degrees", description: "Apply the cosine to a list of angles in degrees",
example: "[0 90 180 270 360] | math cos -d", example: "[0 90 180 270 360] | math cos -d",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_float(1f64), Value::test_float(1f64),
Value::test_float(0f64), Value::test_float(0f64),
Value::test_float(-1f64), Value::test_float(-1f64),
Value::test_float(0f64), Value::test_float(0f64),
Value::test_float(1f64), Value::test_float(1f64),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -78,29 +78,27 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span, use_degrees: bool) -> Value { fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
let val = if use_degrees { val.to_radians() } else { val }; let val = if use_degrees { val.to_radians() } else { val };
Value::Float { Value::float(val.cos(), span)
val: val.cos(),
span,
}
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -62,27 +62,26 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
Value::Float { Value::float(val.cosh(), span)
val: val.cosh(),
span,
}
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -68,27 +68,25 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
Value::Float { Value::float(val.exp(), span)
val: val.exp(),
span,
}
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -61,38 +61,39 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
if val > 0.0 { if val > 0.0 {
let val = val.ln(); let val = val.ln();
Value::Float { val, span } Value::float(val, span)
} else { } else {
Value::Error { Value::error(
error: Box::new(ShellError::UnsupportedInput( 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,
)), ),
span, span,
} )
} }
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -60,16 +60,16 @@ impl Command for SubCommand {
Example { Example {
description: "Apply the sine to a list of angles in degrees", description: "Apply the sine to a list of angles in degrees",
example: "[0 90 180 270 360] | math sin -d | math round --precision 4", example: "[0 90 180 270 360] | math sin -d | math round --precision 4",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_float(0f64), Value::test_float(0f64),
Value::test_float(1f64), Value::test_float(1f64),
Value::test_float(0f64), Value::test_float(0f64),
Value::test_float(-1f64), Value::test_float(-1f64),
Value::test_float(0f64), Value::test_float(0f64),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -78,29 +78,27 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span, use_degrees: bool) -> Value { fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
let val = if use_degrees { val.to_radians() } else { val }; let val = if use_degrees { val.to_radians() } else { val };
Value::Float { Value::float(val.sin(), span)
val: val.sin(),
span,
}
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -62,27 +62,25 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
Value::Float { Value::float(val.sinh(), span)
val: val.sinh(),
span,
}
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -60,14 +60,14 @@ impl Command for SubCommand {
Example { Example {
description: "Apply the tangent to a list of angles in degrees", description: "Apply the tangent to a list of angles in degrees",
example: "[-45 0 45] | math tan -d", example: "[-45 0 45] | math tan -d",
result: Some(Value::List { result: Some(Value::list(
vals: vec![ vec![
Value::test_float(-1f64), Value::test_float(-1f64),
Value::test_float(0f64), Value::test_float(0f64),
Value::test_float(1f64), Value::test_float(1f64),
], ],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }
@ -76,29 +76,27 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span, use_degrees: bool) -> Value { fn operate(value: Value, head: Span, use_degrees: bool) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
let val = if use_degrees { val.to_radians() } else { val }; let val = if use_degrees { val.to_radians() } else { val };
Value::Float { Value::float(val.tan(), span)
val: val.tan(),
span,
}
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -61,27 +61,25 @@ impl Command for SubCommand {
fn operate(value: Value, head: Span) -> Value { fn operate(value: Value, head: Span) -> Value {
match value { match value {
numeric @ (Value::Int { .. } | Value::Float { .. }) => { numeric @ (Value::Int { .. } | Value::Float { .. }) => {
let span = numeric.span();
let (val, span) = match numeric { let (val, span) = match numeric {
Value::Int { val, span } => (val as f64, span), Value::Int { val, .. } => (val as f64, span),
Value::Float { val, span } => (val, span), Value::Float { val, .. } => (val, span),
_ => unreachable!(), _ => unreachable!(),
}; };
Value::Float { Value::float(val.tanh(), span)
val: val.tanh(),
span,
}
} }
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { 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.span(), src_span: other.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -138,10 +138,7 @@ fn operate(
Box::new(move |old| action(old, fgs_hex, fge_hex, bgs_hex, bge_hex, head)), Box::new(move |old| action(old, fgs_hex, fge_hex, bgs_hex, bge_hex, head)),
); );
if let Err(error) = r { if let Err(error) = r {
return Value::Error { return Value::error(error, head);
error: Box::new(error),
span: head,
};
} }
} }
ret ret
@ -159,20 +156,20 @@ fn action(
bg_end: Option<Rgb>, bg_end: Option<Rgb>,
command_span: Span, command_span: Span,
) -> Value { ) -> Value {
let span = input.span();
match input { match input {
Value::String { val, span } => { Value::String { val, .. } => {
let span = *span;
match (fg_start, fg_end, bg_start, bg_end) { match (fg_start, fg_end, bg_start, bg_end) {
(None, None, None, None) => { (None, None, None, None) => {
// Error - no colors // Error - no colors
Value::Error { Value::error(
error: Box::new(ShellError::MissingParameter { ShellError::MissingParameter {
param_name: param_name:
"please supply foreground and/or background color parameters".into(), "please supply foreground and/or background color parameters".into(),
span: command_span, span: command_span,
}), },
span: command_span, span,
} )
} }
(None, None, None, Some(bg_end)) => { (None, None, None, Some(bg_end)) => {
// Error - missing bg_start, so assume black // Error - missing bg_start, so assume black
@ -294,13 +291,13 @@ fn action(
other => { other => {
let got = format!("value is {}, not string", other.get_type()); let got = format!("value is {}, not string", other.get_type());
Value::Error { Value::error(
error: Box::new(ShellError::TypeMismatch { ShellError::TypeMismatch {
err_message: got, err_message: got,
span: other.span(), span: other.span(),
}), },
span: other.span(), other.span(),
} )
} }
} }
} }

View file

@ -118,32 +118,30 @@ fn process_each_path(
for path in column_paths { for path in column_paths {
let ret = value.update_cell_path(&path.members, Box::new(|v| process_value(v, text))); let ret = value.update_cell_path(&path.members, Box::new(|v| process_value(v, text)));
if let Err(error) = ret { if let Err(error) = ret {
return Value::Error { return Value::error(error, command_span);
error: Box::new(error),
span: command_span,
};
} }
} }
value value
} }
fn process_value(value: &Value, text: &Option<String>) -> Value { fn process_value(value: &Value, text: &Option<String>) -> Value {
let span = value.span();
match value { match value {
Value::String { val, span } => { Value::String { val, .. } => {
let text = text.as_deref().unwrap_or(val.as_str()); let text = text.as_deref().unwrap_or(val.as_str());
let result = add_osc_link(text, val.as_str()); let result = add_osc_link(text, val.as_str());
Value::string(result, *span) Value::string(result, span)
} }
other => { other => {
let got = format!("value is {}, not string", other.get_type()); let got = format!("value is {}, not string", other.get_type());
Value::Error { Value::error(
error: Box::new(ShellError::TypeMismatch { ShellError::TypeMismatch {
err_message: got, err_message: got,
span: other.span(), span: other.span(),
}), },
span: other.span(), other.span(),
} )
} }
} }
} }

View file

@ -107,62 +107,60 @@ fn action(
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
Value::Binary { val, .. } => match hex_config.action_type { Value::Binary { val, .. } => match hex_config.action_type {
ActionType::Encode => Value::string(hex_encode(val.as_ref()), command_span), ActionType::Encode => Value::string(hex_encode(val.as_ref()), command_span),
ActionType::Decode => Value::Error { ActionType::Decode => Value::error(
error: Box::new(ShellError::UnsupportedInput( ShellError::UnsupportedInput(
"Binary data can only be encoded".to_string(), "Binary data can only be encoded".to_string(),
"value originates from here".into(), "value originates from here".into(),
command_span, command_span,
// This line requires the Value::Error {} match above. // This line requires the Value::Error {} match above.
input.span(), input.span(),
)), ),
span: command_span, command_span,
}, ),
}, },
Value::String { val, .. } => { Value::String { val, .. } => {
match hex_config.action_type { match hex_config.action_type {
ActionType::Encode => Value::Error { ActionType::Encode => Value::error(
error: Box::new(ShellError::UnsupportedInput( ShellError::UnsupportedInput(
"String value can only be decoded".to_string(), "String value can only be decoded".to_string(),
"value originates from here".into(), "value originates from here".into(),
command_span, command_span,
// This line requires the Value::Error {} match above. // This line requires the Value::Error {} match above.
input.span(), input.span(),
)), ),
span: command_span, command_span,
}, ),
ActionType::Decode => match hex_decode(val.as_ref()) { ActionType::Decode => match hex_decode(val.as_ref()) {
Ok(decoded_value) => Value::binary(decoded_value, command_span), Ok(decoded_value) => Value::binary(decoded_value, command_span),
Err(HexDecodingError::InvalidLength(len)) => Value::Error { Err(HexDecodingError::InvalidLength(len)) => Value::error(ShellError::GenericError(
error: Box::new(ShellError::GenericError(
"value could not be hex decoded".to_string(), "value could not be hex decoded".to_string(),
format!("invalid hex input length: {len}. The length should be even"), format!("invalid hex input length: {len}. The length should be even"),
Some(command_span), Some(command_span),
None, None,
Vec::new(), Vec::new(),
)), ),
span: command_span, command_span,
}, ),
Err(HexDecodingError::InvalidDigit(index, digit)) => Value::Error { Err(HexDecodingError::InvalidDigit(index, digit)) => Value::error(ShellError::GenericError(
error: Box::new(ShellError::GenericError(
"value could not be hex decoded".to_string(), "value could not be hex decoded".to_string(),
format!("invalid hex digit: '{digit}' at index {index}. Only 0-9, A-F, a-f are allowed in hex encoding"), format!("invalid hex digit: '{digit}' at index {index}. Only 0-9, A-F, a-f are allowed in hex encoding"),
Some(command_span), Some(command_span),
None, None,
Vec::new(), Vec::new(),
)), ),
span: command_span, command_span,
}, ),
}, },
} }
} }
other => Value::Error { other => Value::error(
error: Box::new(ShellError::TypeMismatch { ShellError::TypeMismatch {
err_message: format!("string or binary, not {}", other.get_type()), err_message: format!("string or binary, not {}", other.get_type()),
span: other.span(), span: other.span(),
}), },
span: other.span(), other.span(),
}, ),
} }
} }

View file

@ -86,10 +86,10 @@ impl Command for Format {
Example { Example {
description: "Print elements from some columns of a table", description: "Print elements from some columns of a table",
example: "[[col1, col2]; [v1, v2] [v3, v4]] | format '{col2}'", example: "[[col1, col2]; [v1, v2] [v3, v4]] | format '{col2}'",
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_string("v2"), Value::test_string("v4")], vec![Value::test_string("v2"), Value::test_string("v4")],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -73,13 +73,13 @@ impl Command for SubCommand {
Example { Example {
description: "convert a column from a table to camelCase", description: "convert a column from a table to camelCase",
example: r#"[[lang, gems]; [nu_test, 100]] | str camel-case lang"#, example: r#"[[lang, gems]; [nu_test, 100]] | str camel-case lang"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec!["lang".to_string(), "gems".to_string()], cols: vec!["lang".to_string(), "gems".to_string()],
vals: vec![Value::test_string("nuTest"), Value::test_int(100)], vals: vec![Value::test_string("nuTest"), Value::test_int(100)],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -73,13 +73,13 @@ impl Command for SubCommand {
Example { Example {
description: "convert a column from a table to kebab-case", description: "convert a column from a table to kebab-case",
example: r#"[[lang, gems]; [nuTest, 100]] | str kebab-case lang"#, example: r#"[[lang, gems]; [nuTest, 100]] | str kebab-case lang"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec!["lang".to_string(), "gems".to_string()], cols: vec!["lang".to_string(), "gems".to_string()],
vals: vec![Value::test_string("nu-test"), Value::test_int(100)], vals: vec![Value::test_string("nu-test"), Value::test_int(100)],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -57,19 +57,16 @@ where
{ {
let case_operation = args.case_operation; let case_operation = args.case_operation;
match input { match input {
Value::String { val, .. } => Value::String { Value::String { val, .. } => Value::string(case_operation(val), head),
val: case_operation(val),
span: head,
},
Value::Error { .. } => input.clone(), Value::Error { .. } => input.clone(),
_ => Value::Error { _ => Value::error(
error: Box::new(ShellError::OnlySupportsThisInputType { ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(), exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(), wrong_type: input.get_type().to_string(),
dst_span: head, dst_span: head,
src_span: input.span(), src_span: input.span(),
}), },
span: head, head,
}, ),
} }
} }

View file

@ -73,13 +73,13 @@ impl Command for SubCommand {
Example { Example {
description: "convert a column from a table to PascalCase", description: "convert a column from a table to PascalCase",
example: r#"[[lang, gems]; [nu_test, 100]] | str pascal-case lang"#, example: r#"[[lang, gems]; [nu_test, 100]] | str pascal-case lang"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec!["lang".to_string(), "gems".to_string()], cols: vec!["lang".to_string(), "gems".to_string()],
vals: vec![Value::test_string("NuTest"), Value::test_int(100)], vals: vec![Value::test_string("NuTest"), Value::test_int(100)],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -73,13 +73,13 @@ impl Command for SubCommand {
Example { Example {
description: "convert a column from a table to SCREAMING_SNAKE_CASE", description: "convert a column from a table to SCREAMING_SNAKE_CASE",
example: r#"[[lang, gems]; [nu_test, 100]] | str screaming-snake-case lang"#, example: r#"[[lang, gems]; [nu_test, 100]] | str screaming-snake-case lang"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec!["lang".to_string(), "gems".to_string()], cols: vec!["lang".to_string(), "gems".to_string()],
vals: vec![Value::test_string("NU_TEST"), Value::test_int(100)], vals: vec![Value::test_string("NU_TEST"), Value::test_int(100)],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -72,13 +72,13 @@ impl Command for SubCommand {
Example { Example {
description: "convert a column from a table to snake_case", description: "convert a column from a table to snake_case",
example: r#"[[lang, gems]; [nuTest, 100]] | str snake-case lang"#, example: r#"[[lang, gems]; [nuTest, 100]] | str snake-case lang"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec!["lang".to_string(), "gems".to_string()], cols: vec!["lang".to_string(), "gems".to_string()],
vals: vec![Value::test_string("nu_test"), Value::test_int(100)], vals: vec![Value::test_string("nu_test"), Value::test_int(100)],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -34,16 +34,16 @@ impl Command for Str {
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
Ok(Value::String { Ok(Value::string(
val: get_full_help( get_full_help(
&Str.signature(), &Str.signature(),
&Str.examples(), &Str.examples(),
engine_state, engine_state,
stack, stack,
self.is_parser_keyword(), self.is_parser_keyword(),
), ),
span: call.head, call.head,
} )
.into_pipeline_data()) .into_pipeline_data())
} }
} }

View file

@ -68,13 +68,13 @@ impl Command for SubCommand {
Example { Example {
description: "convert a column from a table to Title Case", description: "convert a column from a table to Title Case",
example: r#"[[title, count]; ['nu test', 100]] | str title-case title"#, example: r#"[[title, count]; ['nu test', 100]] | str title-case title"#,
result: Some(Value::List { result: Some(Value::list(
vals: vec![Value::test_record(Record { vec![Value::test_record(Record {
cols: vec!["title".to_string(), "count".to_string()], cols: vec!["title".to_string(), "count".to_string()],
vals: vec![Value::test_string("Nu Test"), Value::test_int(100)], vals: vec![Value::test_string("Nu Test"), Value::test_int(100)],
})], })],
span: Span::test_data(), Span::test_data(),
}), )),
}, },
] ]
} }

View file

@ -106,11 +106,7 @@ fn run(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
} }
}; };
Ok(Value::String { Ok(Value::string(description, head).into_pipeline_data())
val: description,
span: head,
}
.into_pipeline_data())
} }
#[cfg(test)] #[cfg(test)]

View file

@ -100,10 +100,7 @@ impl Command for Do {
param param
.var_id .var_id
.expect("Internal error: rest positional parameter lacks var_id"), .expect("Internal error: rest positional parameter lacks var_id"),
Value::List { Value::list(rest_items, span),
vals: rest_items,
span,
},
) )
} }
} }

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