Add Span merging functions (#12511)

# Description
This PR adds a few functions to `Span` for merging spans together:
- `Span::append`: merges two spans that are known to be in order.
- `Span::concat`: returns a span that encompasses all the spans in a
slice. The spans must be in order.
- `Span::merge`: merges two spans (no order necessary).
- `Span::merge_many`: merges an iterator of spans into a single span (no
order necessary).

These are meant to replace the free-standing `nu_protocol::span`
function.

The spans in a `LiteCommand` (the `parts`) should always be in order
based on the lite parser and lexer. So, the parser code sees the most
usage of `Span::append` and `Span::concat` where the order is known. In
other code areas, `Span::merge` and `Span::merge_many` are used since
the order between spans is often not known.
This commit is contained in:
Ian Manske 2024-05-16 22:34:49 +00:00 committed by GitHub
parent 2a09dccc11
commit aec41f3df0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 305 additions and 241 deletions

View File

@ -1,7 +1,7 @@
use super::{operations::Axis, NuDataFrame};
use nu_protocol::{
ast::{Boolean, Comparison, Math, Operator},
span, ShellError, Span, Spanned, Value,
ShellError, Span, Spanned, Value,
};
use num::Zero;
use polars::prelude::{
@ -17,7 +17,7 @@ pub(super) fn between_dataframes(
right: &Value,
rhs: &NuDataFrame,
) -> Result<Value, ShellError> {
let operation_span = span(&[left.span(), right.span()]);
let operation_span = Span::merge(left.span(), right.span());
match operator.item {
Operator::Math(Math::Plus) => match lhs.append_df(rhs, Axis::Row, operation_span) {
Ok(df) => Ok(df.into_value(operation_span)),
@ -40,7 +40,7 @@ pub(super) fn compute_between_series(
right: &Value,
rhs: &Series,
) -> Result<Value, ShellError> {
let operation_span = span(&[left.span(), right.span()]);
let operation_span = Span::merge(left.span(), right.span());
match operator.item {
Operator::Math(Math::Plus) => {
let mut res = lhs + rhs;

View File

@ -1,4 +1,4 @@
use nu_protocol::{span as span_join, ShellError, Span, Spanned, Value};
use nu_protocol::{ShellError, Span, Spanned, Value};
// Default value used when selecting rows from dataframe
pub const DEFAULT_ROWS: usize = 5;
@ -27,7 +27,7 @@ pub(crate) fn convert_columns(
let span = value.span();
match value {
Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
col_span = col_span.merge(span);
Ok(Spanned { item: val, span })
}
_ => Err(ShellError::GenericError {
@ -68,7 +68,7 @@ pub(crate) fn convert_columns_string(
let span = value.span();
match value {
Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
col_span = col_span.merge(span);
Ok(val)
}
_ => Err(ShellError::GenericError {

View File

@ -2,7 +2,6 @@ use crate::help::{help_aliases, help_commands, help_modules};
use fancy_regex::Regex;
use nu_ansi_term::Style;
use nu_engine::command_prelude::*;
use nu_protocol::span;
use nu_utils::IgnoreCaseExt;
#[derive(Clone)]
@ -97,9 +96,8 @@ You can also learn more at https://www.nushell.sh/book/"#;
span: _,
}) = result
{
let rest_spans: Vec<Span> = rest.iter().map(|arg| arg.span).collect();
Err(ShellError::NotFound {
span: span(&rest_spans),
span: Span::merge_many(rest.iter().map(|s| s.span)),
})
} else {
result

View File

@ -1,7 +1,6 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, scope::ScopeData};
use nu_protocol::span;
#[derive(Clone)]
pub struct HelpAliases;
@ -110,13 +109,13 @@ pub fn help_aliases(
let Some(alias) = engine_state.find_decl(name.as_bytes(), &[]) else {
return Err(ShellError::AliasNotFound {
span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
span: Span::merge_many(rest.iter().map(|s| s.span)),
});
};
let Some(alias) = engine_state.get_decl(alias).as_alias() else {
return Err(ShellError::AliasNotFound {
span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
span: Span::merge_many(rest.iter().map(|s| s.span)),
});
};

View File

@ -1,7 +1,6 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, get_full_help};
use nu_protocol::span;
#[derive(Clone)]
pub struct HelpCommands;
@ -104,7 +103,7 @@ pub fn help_commands(
)
} else {
Err(ShellError::CommandNotFound {
span: span(&[rest[0].span, rest[rest.len() - 1].span]),
span: Span::merge_many(rest.iter().map(|s| s.span)),
})
}
}

View File

@ -1,7 +1,6 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, get_full_help, scope::ScopeData};
use nu_protocol::span;
#[derive(Clone)]
pub struct HelpExterns;
@ -124,7 +123,7 @@ pub fn help_externs(
)
} else {
Err(ShellError::CommandNotFound {
span: span(&[rest[0].span, rest[rest.len() - 1].span]),
span: Span::merge_many(rest.iter().map(|s| s.span)),
})
}
}

View File

@ -1,7 +1,7 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, scope::ScopeData};
use nu_protocol::{span, DeclId};
use nu_protocol::DeclId;
#[derive(Clone)]
pub struct HelpModules;
@ -117,7 +117,7 @@ pub fn help_modules(
let Some(module_id) = engine_state.find_module(name.as_bytes(), &[]) else {
return Err(ShellError::ModuleNotFoundAtRuntime {
mod_name: name,
span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
span: Span::merge_many(rest.iter().map(|s| s.span)),
});
};

View File

@ -1,5 +1,4 @@
use nu_engine::command_prelude::*;
use nu_protocol::span;
use std::io::IsTerminal as _;
#[derive(Clone)]
@ -57,12 +56,9 @@ impl Command for IsTerminal {
});
}
_ => {
let spans: Vec<_> = call.arguments.iter().map(|arg| arg.span()).collect();
let span = span(&spans);
return Err(ShellError::IncompatibleParametersSingle {
msg: "Only one stream may be checked".into(),
span,
span: Span::merge_many(call.arguments.iter().map(|arg| arg.span())),
});
}
};

View File

@ -1,5 +1,4 @@
use nu_engine::command_prelude::*;
use nu_protocol::span;
use std::process::{Command as CommandSys, Stdio};
#[derive(Clone)]
@ -96,7 +95,7 @@ impl Command for Kill {
})?
.span,
right_message: "signal".to_string(),
right_span: span(&[
right_span: Span::merge(
call.get_named_arg("signal")
.ok_or_else(|| ShellError::GenericError {
error: "Flag error".into(),
@ -107,7 +106,7 @@ impl Command for Kill {
})?
.span,
signal_span,
]),
),
});
}
cmd.arg("-9");

View File

@ -15,8 +15,8 @@ use nu_protocol::{
},
engine::{StateWorkingSet, DEFAULT_OVERLAY_NAME},
eval_const::eval_constant,
span, Alias, BlockId, DeclId, Module, ModuleId, ParseError, PositionalArg,
ResolvedImportPattern, Span, Spanned, SyntaxShape, Type, Value, VarId,
Alias, BlockId, DeclId, Module, ModuleId, ParseError, PositionalArg, ResolvedImportPattern,
Span, Spanned, SyntaxShape, Type, Value, VarId,
};
use std::{
collections::{HashMap, HashSet},
@ -77,14 +77,14 @@ pub const UNALIASABLE_PARSER_KEYWORDS: &[&[u8]] = &[
/// Check whether spans start with a parser keyword that can be aliased
pub fn is_unaliasable_parser_keyword(working_set: &StateWorkingSet, spans: &[Span]) -> bool {
// try two words
if let (Some(span1), Some(span2)) = (spans.first(), spans.get(1)) {
let cmd_name = working_set.get_span_contents(span(&[*span1, *span2]));
if let (Some(&span1), Some(&span2)) = (spans.first(), spans.get(1)) {
let cmd_name = working_set.get_span_contents(Span::append(span1, span2));
return UNALIASABLE_PARSER_KEYWORDS.contains(&cmd_name);
}
// try one word
if let Some(span1) = spans.first() {
let cmd_name = working_set.get_span_contents(*span1);
if let Some(&span1) = spans.first() {
let cmd_name = working_set.get_span_contents(span1);
UNALIASABLE_PARSER_KEYWORDS.contains(&cmd_name)
} else {
false
@ -254,7 +254,7 @@ pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
if working_set.get_span_contents(spans[0]) != b"for" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'for' function".into(),
span(spans),
Span::concat(spans),
));
return garbage(spans[0]);
}
@ -270,7 +270,7 @@ pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
None => {
working_set.error(ParseError::UnknownState(
"internal error: for declaration not found".into(),
span(spans),
Span::concat(spans),
));
return garbage(spans[0]);
}
@ -281,7 +281,7 @@ pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
working_set.exit_scope();
let call_span = span(spans);
let call_span = Span::concat(spans);
let decl = working_set.get_decl(decl_id);
let sig = decl.signature();
@ -395,7 +395,7 @@ pub fn parse_def(
if def_call != b"def" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for def function".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
}
@ -411,7 +411,7 @@ pub fn parse_def(
None => {
working_set.error(ParseError::UnknownState(
"internal error: def declaration not found".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
}
@ -442,8 +442,12 @@ pub fn parse_def(
}
let starting_error_count = working_set.parse_errors.len();
let ParsedInternalCall { call, output } =
parse_internal_call(working_set, span(command_spans), rest_spans, decl_id);
let ParsedInternalCall { call, output } = parse_internal_call(
working_set,
Span::concat(command_spans),
rest_spans,
decl_id,
);
// This is to preserve the order of the errors so that
// the check errors below come first
let mut new_errors = working_set.parse_errors[starting_error_count..].to_vec();
@ -451,7 +455,7 @@ pub fn parse_def(
working_set.exit_scope();
let call_span = span(spans);
let call_span = Span::concat(spans);
let decl = working_set.get_decl(decl_id);
let sig = decl.signature();
@ -673,7 +677,7 @@ pub fn parse_extern(
if extern_call != b"extern" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for extern command".into(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
}
@ -689,7 +693,7 @@ pub fn parse_extern(
None => {
working_set.error(ParseError::UnknownState(
"internal error: def declaration not found".into(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
}
@ -709,11 +713,15 @@ pub fn parse_extern(
}
}
let ParsedInternalCall { call, .. } =
parse_internal_call(working_set, span(command_spans), rest_spans, decl_id);
let ParsedInternalCall { call, .. } = parse_internal_call(
working_set,
Span::concat(command_spans),
rest_spans,
decl_id,
);
working_set.exit_scope();
let call_span = span(spans);
let call_span = Span::concat(spans);
//let decl = working_set.get_decl(decl_id);
//let sig = decl.signature();
@ -824,8 +832,9 @@ fn check_alias_name<'a>(working_set: &mut StateWorkingSet, spans: &'a [Span]) ->
None
} else if spans.len() < command_len + 3 {
if working_set.get_span_contents(spans[command_len]) == b"=" {
let name =
String::from_utf8_lossy(working_set.get_span_contents(span(&spans[..command_len])));
let name = String::from_utf8_lossy(
working_set.get_span_contents(Span::concat(&spans[..command_len])),
);
working_set.error(ParseError::AssignmentMismatch(
format!("{name} missing name"),
"missing name".into(),
@ -836,8 +845,9 @@ fn check_alias_name<'a>(working_set: &mut StateWorkingSet, spans: &'a [Span]) ->
None
}
} else if working_set.get_span_contents(spans[command_len + 1]) != b"=" {
let name =
String::from_utf8_lossy(working_set.get_span_contents(span(&spans[..command_len])));
let name = String::from_utf8_lossy(
working_set.get_span_contents(Span::concat(&spans[..command_len])),
);
working_set.error(ParseError::AssignmentMismatch(
format!("{name} missing sign"),
"missing equal sign".into(),
@ -868,7 +878,7 @@ pub fn parse_alias(
if name != b"alias" {
working_set.error(ParseError::InternalError(
"Alias statement unparsable".into(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
}
@ -890,7 +900,12 @@ pub fn parse_alias(
call: alias_call,
output,
..
} = parse_internal_call(working_set, span(command_spans), rest_spans, decl_id);
} = parse_internal_call(
working_set,
Span::concat(command_spans),
rest_spans,
decl_id,
);
working_set
.parse_errors
@ -902,7 +917,7 @@ pub fn parse_alias(
let alias_pipeline = Pipeline::from_vec(vec![Expression {
expr: Expr::Call(alias_call.clone()),
span: span(spans),
span: Span::concat(spans),
ty: output,
custom_completion: None,
}]);
@ -914,7 +929,7 @@ pub fn parse_alias(
let Some(alias_name_expr) = alias_call.positional_nth(0) else {
working_set.error(ParseError::UnknownState(
"Missing positional after call check".to_string(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
};
@ -1090,7 +1105,7 @@ pub fn parse_alias(
} else if spans.len() < 4 {
working_set.error(ParseError::IncorrectValue(
"Incomplete alias".into(),
span(&spans[..split_id]),
Span::concat(&spans[..split_id]),
"incomplete alias".into(),
));
}
@ -1100,7 +1115,7 @@ pub fn parse_alias(
working_set.error(ParseError::InternalError(
"Alias statement unparsable".into(),
span(spans),
Span::concat(spans),
));
garbage_pipeline(spans)
@ -1111,7 +1126,7 @@ pub fn parse_export_in_block(
working_set: &mut StateWorkingSet,
lite_command: &LiteCommand,
) -> Pipeline {
let call_span = span(&lite_command.parts);
let call_span = Span::concat(&lite_command.parts);
let full_name = if lite_command.parts.len() > 1 {
let sub = working_set.get_span_contents(lite_command.parts[1]);
@ -1139,7 +1154,7 @@ pub fn parse_export_in_block(
if full_name == "export" {
lite_command.parts[0]
} else {
span(&lite_command.parts[0..2])
Span::concat(&lite_command.parts[0..2])
},
if full_name == "export" {
&lite_command.parts[1..]
@ -1169,7 +1184,7 @@ pub fn parse_export_in_block(
} else {
working_set.error(ParseError::UnknownState(
format!("internal error: '{full_name}' declaration not found",),
span(&lite_command.parts),
Span::concat(&lite_command.parts),
));
return garbage_pipeline(&lite_command.parts);
};
@ -1213,7 +1228,7 @@ pub fn parse_export_in_module(
if working_set.get_span_contents(*sp) != b"export" {
working_set.error(ParseError::UnknownState(
"expected export statement".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), vec![]);
}
@ -1222,7 +1237,7 @@ pub fn parse_export_in_module(
} else {
working_set.error(ParseError::UnknownState(
"got empty input for parsing export statement".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), vec![]);
};
@ -1280,12 +1295,12 @@ pub fn parse_export_in_module(
if let Some(Expr::Call(def_call)) = pipeline.elements.first().map(|e| &e.expr.expr)
{
call.clone_from(def_call);
call.head = span(&spans[0..=1]);
call.head = Span::concat(&spans[0..=1]);
call.decl_id = export_def_decl_id;
} else {
working_set.error(ParseError::InternalError(
"unexpected output from parsing a definition".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
};
@ -1316,12 +1331,12 @@ pub fn parse_export_in_module(
if let Some(Expr::Call(def_call)) = pipeline.elements.first().map(|e| &e.expr.expr)
{
call.clone_from(def_call);
call.head = span(&spans[0..=1]);
call.head = Span::concat(&spans[0..=1]);
call.decl_id = export_def_decl_id;
} else {
working_set.error(ParseError::InternalError(
"unexpected output from parsing a definition".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
};
@ -1341,7 +1356,7 @@ pub fn parse_export_in_module(
} else {
working_set.error(ParseError::InternalError(
"failed to find added declaration".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
}
@ -1373,12 +1388,12 @@ pub fn parse_export_in_module(
{
call.clone_from(alias_call);
call.head = span(&spans[0..=1]);
call.head = Span::concat(&spans[0..=1]);
call.decl_id = export_alias_decl_id;
} else {
working_set.error(ParseError::InternalError(
"unexpected output from parsing a definition".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
};
@ -1398,7 +1413,7 @@ pub fn parse_export_in_module(
} else {
working_set.error(ParseError::InternalError(
"failed to find added alias".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
}
@ -1428,12 +1443,12 @@ pub fn parse_export_in_module(
{
call.clone_from(use_call);
call.head = span(&spans[0..=1]);
call.head = Span::concat(&spans[0..=1]);
call.decl_id = export_use_decl_id;
} else {
working_set.error(ParseError::InternalError(
"unexpected output from parsing a definition".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
};
@ -1460,12 +1475,12 @@ pub fn parse_export_in_module(
{
call.clone_from(module_call);
call.head = span(&spans[0..=1]);
call.head = Span::concat(&spans[0..=1]);
call.decl_id = export_module_decl_id;
} else {
working_set.error(ParseError::InternalError(
"unexpected output from parsing a definition".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
};
@ -1486,7 +1501,7 @@ pub fn parse_export_in_module(
"failed to find added module '{}'",
String::from_utf8_lossy(module_name)
),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
}
}
@ -1511,12 +1526,12 @@ pub fn parse_export_in_module(
{
call.clone_from(def_call);
call.head = span(&spans[0..=1]);
call.head = Span::concat(&spans[0..=1]);
call.decl_id = export_const_decl_id;
} else {
working_set.error(ParseError::InternalError(
"unexpected output from parsing a definition".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
};
@ -1538,7 +1553,7 @@ pub fn parse_export_in_module(
} else {
working_set.error(ParseError::InternalError(
"failed to find added variable".into(),
span(&spans[1..]),
Span::concat(&spans[1..]),
));
}
}
@ -1567,7 +1582,7 @@ pub fn parse_export_in_module(
(
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]),
@ -1582,7 +1597,7 @@ pub fn parse_export_env(
if !spans.is_empty() && working_set.get_span_contents(spans[0]) != b"export-env" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'export-env' command".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
}
@ -1590,7 +1605,7 @@ pub fn parse_export_env(
if spans.len() < 2 {
working_set.error(ParseError::MissingPositional(
"block".into(),
span(spans),
Span::concat(spans),
"export-env <block>".into(),
));
return (garbage_pipeline(spans), None);
@ -1602,7 +1617,7 @@ pub fn parse_export_env(
parse_internal_call(working_set, spans[0], &[spans[1]], decl_id);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
let call_span = Span::concat(spans);
let starting_error_count = working_set.parse_errors.len();
check_call(working_set, call_span, &decl.signature(), &call);
@ -1628,7 +1643,7 @@ pub fn parse_export_env(
None => {
working_set.error(ParseError::UnknownState(
"internal error: 'export-env' declaration not found".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
}
@ -1647,14 +1662,14 @@ pub fn parse_export_env(
} else {
working_set.error(ParseError::UnknownState(
"internal error: 'export-env' block is missing".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
};
let pipeline = Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]);
@ -2050,11 +2065,15 @@ pub fn parse_module(
Some(decl_id) => {
let (command_spans, rest_spans) = spans.split_at(split_id);
let ParsedInternalCall { call, output } =
parse_internal_call(working_set, span(command_spans), rest_spans, decl_id);
let ParsedInternalCall { call, output } = parse_internal_call(
working_set,
Span::concat(command_spans),
rest_spans,
decl_id,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
let call_span = Span::concat(spans);
let starting_error_count = working_set.parse_errors.len();
check_call(working_set, call_span, &decl.signature(), &call);
@ -2080,7 +2099,7 @@ pub fn parse_module(
None => {
working_set.error(ParseError::UnknownState(
"internal error: 'module' or 'export module' declaration not found".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
}
@ -2112,14 +2131,14 @@ pub fn parse_module(
} else {
working_set.error(ParseError::UnknownState(
"internal error: name not a string".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
}
} else {
working_set.error(ParseError::UnknownState(
"internal error: missing positional".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
};
@ -2151,7 +2170,7 @@ pub fn parse_module(
if spans.len() < split_id + 2 {
working_set.error(ParseError::UnknownState(
"Expected structure: module <name> or module <name> <block>".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), None);
@ -2199,7 +2218,7 @@ pub fn parse_module(
.expect("internal error: missing module command");
let call = Box::new(Call {
head: span(&spans[..split_id]),
head: Span::concat(&spans[..split_id]),
decl_id: module_decl_id,
arguments: vec![
Argument::Positional(module_name_or_path_expr),
@ -2211,7 +2230,7 @@ pub fn parse_module(
(
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]),
@ -2236,7 +2255,7 @@ pub fn parse_use(
if use_call != b"use" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'use' command".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), vec![]);
}
@ -2244,7 +2263,7 @@ pub fn parse_use(
if working_set.get_span_contents(name_span) != b"use" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'use' command".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), vec![]);
}
@ -2258,11 +2277,15 @@ pub fn parse_use(
Some(decl_id) => {
let (command_spans, rest_spans) = spans.split_at(split_id);
let ParsedInternalCall { call, output } =
parse_internal_call(working_set, span(command_spans), rest_spans, decl_id);
let ParsedInternalCall { call, output } = parse_internal_call(
working_set,
Span::concat(command_spans),
rest_spans,
decl_id,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
let call_span = Span::concat(spans);
let starting_error_count = working_set.parse_errors.len();
check_call(working_set, call_span, &decl.signature(), &call);
@ -2288,7 +2311,7 @@ pub fn parse_use(
None => {
working_set.error(ParseError::UnknownState(
"internal error: 'use' declaration not found".into(),
span(spans),
Span::concat(spans),
));
return (garbage_pipeline(spans), vec![]);
}
@ -2418,7 +2441,7 @@ pub fn parse_use(
// Create a new Use command call to pass the import pattern as parser info
let import_pattern_expr = Expression {
expr: Expr::ImportPattern(Box::new(import_pattern)),
span: span(args_spans),
span: Span::concat(args_spans),
ty: Type::Any,
custom_completion: None,
};
@ -2429,7 +2452,7 @@ pub fn parse_use(
(
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]),
@ -2443,7 +2466,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
if working_set.get_span_contents(spans[0]) != b"hide" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'hide' command".into(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
}
@ -2458,7 +2481,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
let call_span = Span::concat(spans);
let starting_error_count = working_set.parse_errors.len();
check_call(working_set, call_span, &decl.signature(), &call);
@ -2481,7 +2504,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
None => {
working_set.error(ParseError::UnknownState(
"internal error: 'hide' declaration not found".into(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
}
@ -2602,7 +2625,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
// Create a new Use command call to pass the new import pattern
let import_pattern_expr = Expression {
expr: Expr::ImportPattern(Box::new(import_pattern)),
span: span(args_spans),
span: Span::concat(args_spans),
ty: Type::Any,
custom_completion: None,
};
@ -2612,14 +2635,14 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}])
} else {
working_set.error(ParseError::UnknownState(
"Expected structure: hide <name>".into(),
span(spans),
Span::concat(spans),
));
garbage_pipeline(spans)
}
@ -2975,7 +2998,7 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
// let x = 'f', = at least start from index 2
if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
let (tokens, parse_error) = lex(
working_set.get_span_contents(nu_protocol::span(&spans[(span.0 + 1)..])),
working_set.get_span_contents(Span::concat(&spans[(span.0 + 1)..])),
spans[span.0 + 1].start,
&[],
&[],
@ -2986,7 +3009,7 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
working_set.error(parse_error)
}
let rvalue_span = nu_protocol::span(&spans[(span.0 + 1)..]);
let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
let rvalue_block = parse_block(working_set, &tokens, rvalue_span, false, true);
let output_type = rvalue_block.output_type();
@ -3025,7 +3048,7 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
working_set.error(ParseError::TypeMismatch(
explicit_type.clone(),
rhs_type.clone(),
nu_protocol::span(&spans[(span.0 + 1)..]),
Span::concat(&spans[(span.0 + 1)..]),
));
}
}
@ -3045,7 +3068,7 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: nu_protocol::span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]);
@ -3057,20 +3080,20 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: nu_protocol::span(spans),
span: Span::concat(spans),
ty: output,
custom_completion: None,
}]);
} else {
working_set.error(ParseError::UnknownState(
"internal error: let or const statements not found in core language".into(),
span(spans),
Span::concat(spans),
))
}
working_set.error(ParseError::UnknownState(
"internal error: let or const statement unparsable".into(),
span(spans),
Span::concat(spans),
));
garbage_pipeline(spans)
@ -3134,7 +3157,7 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin
working_set.error(ParseError::TypeMismatch(
explicit_type.clone(),
rhs_type.clone(),
nu_protocol::span(&spans[(span.0 + 1)..]),
Span::concat(&spans[(span.0 + 1)..]),
));
}
}
@ -3155,7 +3178,7 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin
working_set.error(ParseError::TypeMismatch(
explicit_type.clone(),
const_type.clone(),
nu_protocol::span(&spans[(span.0 + 1)..]),
Span::concat(&spans[(span.0 + 1)..]),
));
}
let val_span = value.span();
@ -3191,7 +3214,7 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: nu_protocol::span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]);
@ -3203,20 +3226,20 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: nu_protocol::span(spans),
span: Span::concat(spans),
ty: output,
custom_completion: None,
}]);
} else {
working_set.error(ParseError::UnknownState(
"internal error: let or const statements not found in core language".into(),
span(spans),
Span::concat(spans),
))
}
working_set.error(ParseError::UnknownState(
"internal error: let or const statement unparsable".into(),
span(spans),
Span::concat(spans),
));
garbage_pipeline(spans)
@ -3239,7 +3262,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
// mut x = 'f', = at least start from index 2
if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
let (tokens, parse_error) = lex(
working_set.get_span_contents(nu_protocol::span(&spans[(span.0 + 1)..])),
working_set.get_span_contents(Span::concat(&spans[(span.0 + 1)..])),
spans[span.0 + 1].start,
&[],
&[],
@ -3250,7 +3273,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
working_set.error(parse_error);
}
let rvalue_span = nu_protocol::span(&spans[(span.0 + 1)..]);
let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
let rvalue_block = parse_block(working_set, &tokens, rvalue_span, false, true);
let output_type = rvalue_block.output_type();
@ -3290,7 +3313,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
working_set.error(ParseError::TypeMismatch(
explicit_type.clone(),
rhs_type.clone(),
nu_protocol::span(&spans[(span.0 + 1)..]),
Span::concat(&spans[(span.0 + 1)..]),
));
}
}
@ -3310,7 +3333,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: nu_protocol::span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]);
@ -3322,20 +3345,20 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: nu_protocol::span(spans),
span: Span::concat(spans),
ty: output,
custom_completion: None,
}]);
} else {
working_set.error(ParseError::UnknownState(
"internal error: let or const statements not found in core language".into(),
span(spans),
Span::concat(spans),
))
}
working_set.error(ParseError::UnknownState(
"internal error: let or const statement unparsable".into(),
span(spans),
Span::concat(spans),
));
garbage_pipeline(spans)
@ -3375,7 +3398,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman
if is_help {
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: output,
custom_completion: None,
}]);
@ -3388,10 +3411,10 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman
let val = match eval_constant(working_set, &expr) {
Ok(val) => val,
Err(err) => {
working_set.error(err.wrap(working_set, span(&spans[1..])));
working_set.error(err.wrap(working_set, Span::concat(&spans[1..])));
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(&spans[1..]),
span: Span::concat(&spans[1..]),
ty: Type::Any,
custom_completion: None,
}]);
@ -3401,10 +3424,10 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman
let filename = match val.coerce_into_string() {
Ok(s) => s,
Err(err) => {
working_set.error(err.wrap(working_set, span(&spans[1..])));
working_set.error(err.wrap(working_set, Span::concat(&spans[1..])));
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(&spans[1..]),
span: Span::concat(&spans[1..]),
ty: Type::Any,
custom_completion: None,
}]);
@ -3450,7 +3473,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call_with_block),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]);
@ -3461,7 +3484,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman
}
return Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}]);
@ -3469,7 +3492,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman
}
working_set.error(ParseError::UnknownState(
"internal error: source statement unparsable".into(),
span(spans),
Span::concat(spans),
));
garbage_pipeline(spans)
}
@ -3480,18 +3503,18 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
if !spans.is_empty() && working_set.get_span_contents(spans[0]) != b"where" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'where' command".into(),
span(spans),
Span::concat(spans),
));
return garbage(span(spans));
return garbage(Span::concat(spans));
}
if spans.len() < 2 {
working_set.error(ParseError::MissingPositional(
"row condition".into(),
span(spans),
Span::concat(spans),
"where <row_condition>".into(),
));
return garbage(span(spans));
return garbage(Span::concat(spans));
}
let call = match working_set.find_decl(b"where") {
@ -3500,13 +3523,13 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
let call_span = Span::concat(spans);
let starting_error_count = working_set.parse_errors.len();
check_call(working_set, call_span, &decl.signature(), &call);
let Ok(is_help) = has_flag_const(working_set, &call, "help") else {
return garbage(span(spans));
return garbage(Span::concat(spans));
};
if starting_error_count != working_set.parse_errors.len() || is_help {
@ -3523,15 +3546,15 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
None => {
working_set.error(ParseError::UnknownState(
"internal error: 'where' declaration not found".into(),
span(spans),
Span::concat(spans),
));
return garbage(span(spans));
return garbage(Span::concat(spans));
}
};
Expression {
expr: Expr::Call(call),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}
@ -3574,7 +3597,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm
if working_set.get_span_contents(spans[0]) != b"register" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'register' function".into(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
}
@ -3590,7 +3613,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm
None => {
working_set.error(ParseError::UnknownState(
"internal error: Register declaration not found".into(),
span(spans),
Span::concat(spans),
));
return garbage_pipeline(spans);
}
@ -3599,7 +3622,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm
parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
let call_span = Span::concat(spans);
let starting_error_count = working_set.parse_errors.len();
check_call(working_set, call_span, &decl.signature(), &call);

View File

@ -11,7 +11,7 @@ use itertools::Itertools;
use log::trace;
use nu_engine::DIR_VAR_PARSER_INFO;
use nu_protocol::{
ast::*, engine::StateWorkingSet, eval_const::eval_constant, span, BlockId, DidYouMean, Flag,
ast::*, engine::StateWorkingSet, eval_const::eval_constant, BlockId, DidYouMean, Flag,
ParseError, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId, ENV_VARIABLE_ID,
IN_VARIABLE_ID,
};
@ -27,7 +27,7 @@ pub fn garbage(span: Span) -> Expression {
}
pub fn garbage_pipeline(spans: &[Span]) -> Pipeline {
Pipeline::from_vec(vec![garbage(span(spans))])
Pipeline::from_vec(vec![garbage(Span::concat(spans))])
}
fn is_identifier_byte(b: u8) -> bool {
@ -298,7 +298,7 @@ pub fn parse_external_call(working_set: &mut StateWorkingSet, spans: &[Span]) ->
Expression {
expr: Expr::ExternalCall(head, args),
span: span(spans),
span: Span::concat(spans),
ty: Type::Any,
custom_completion: None,
}
@ -1057,7 +1057,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
if spans.is_empty() {
working_set.error(ParseError::UnknownState(
"Encountered command with zero spans".into(),
span(spans),
Span::concat(spans),
));
return garbage(head);
}
@ -1119,9 +1119,9 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
working_set.error(ParseError::UnknownState(
"Incomplete statement".into(),
span(spans),
Span::concat(spans),
));
return garbage(span(spans));
return garbage(Span::concat(spans));
}
}
@ -1149,7 +1149,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
return Expression {
expr: Expr::ExternalCall(head, final_args.into()),
span: span(spans),
span: Span::concat(spans),
ty: ty.clone(),
custom_completion: *custom_completion,
};
@ -1157,7 +1157,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
trace!("parsing: alias of internal call");
parse_internal_call(
working_set,
span(&spans[cmd_start..pos]),
Span::concat(&spans[cmd_start..pos]),
&spans[pos..],
decl_id,
)
@ -1166,7 +1166,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
trace!("parsing: internal call");
parse_internal_call(
working_set,
span(&spans[cmd_start..pos]),
Span::concat(&spans[cmd_start..pos]),
&spans[pos..],
decl_id,
)
@ -1174,7 +1174,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
Expression {
expr: Expr::Call(parsed_call.call),
span: span(spans),
span: Span::concat(spans),
ty: parsed_call.output,
custom_completion: None,
}
@ -2797,9 +2797,9 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
let Some(head_span) = spans.first() else {
working_set.error(ParseError::WrongImportPattern(
"needs at least one component of import pattern".to_string(),
span(spans),
Span::concat(spans),
));
return garbage(span(spans));
return garbage(Span::concat(spans));
};
let head_expr = parse_value(working_set, *head_span, &SyntaxShape::Any);
@ -2808,13 +2808,13 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
Ok(val) => match val.coerce_into_string() {
Ok(s) => (working_set.find_module(s.as_bytes()), s.into_bytes()),
Err(err) => {
working_set.error(err.wrap(working_set, span(spans)));
return garbage(span(spans));
working_set.error(err.wrap(working_set, Span::concat(spans)));
return garbage(Span::concat(spans));
}
},
Err(err) => {
working_set.error(err.wrap(working_set, span(spans)));
return garbage(span(spans));
working_set.error(err.wrap(working_set, Span::concat(spans)));
return garbage(Span::concat(spans));
}
};
@ -2894,7 +2894,7 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
working_set.error(ParseError::ExportNotFound(result.span));
return Expression {
expr: Expr::ImportPattern(Box::new(import_pattern)),
span: span(spans),
span: Span::concat(spans),
ty: Type::List(Box::new(Type::String)),
custom_completion: None,
};
@ -2914,7 +2914,7 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
Expression {
expr: Expr::ImportPattern(Box::new(import_pattern)),
span: span(&spans[1..]),
span: Span::concat(&spans[1..]),
ty: Type::List(Box::new(Type::String)),
custom_completion: None,
}
@ -2948,7 +2948,7 @@ pub fn parse_var_with_opt_type(
*spans_idx += 1;
// signature like record<a: int b: int> is broken into multiple spans due to
// whitespaces. Collect the rest into one span and work on it
let full_span = span(&spans[*spans_idx..]);
let full_span = Span::concat(&spans[*spans_idx..]);
let type_bytes = working_set.get_span_contents(full_span).to_vec();
let (tokens, parse_error) =
@ -2976,7 +2976,7 @@ pub fn parse_var_with_opt_type(
(
Expression {
expr: Expr::VarDecl(id),
span: span(&spans[span_beginning..*spans_idx + 1]),
span: Span::concat(&spans[span_beginning..*spans_idx + 1]),
ty: ty.clone(),
custom_completion: None,
},
@ -3019,7 +3019,7 @@ pub fn parse_var_with_opt_type(
let id = working_set.add_variable(
var_name,
span(&spans[*spans_idx..*spans_idx + 1]),
Span::concat(&spans[*spans_idx..*spans_idx + 1]),
Type::Any,
mutable,
);
@ -3067,7 +3067,7 @@ pub fn parse_input_output_types(
working_set: &mut StateWorkingSet,
spans: &[Span],
) -> Vec<(Type, Type)> {
let mut full_span = span(spans);
let mut full_span = Span::concat(spans);
let mut bytes = working_set.get_span_contents(full_span);
@ -3145,7 +3145,7 @@ pub fn parse_full_signature(working_set: &mut StateWorkingSet, spans: &[Span]) -
} = &mut arg_signature
{
sig.input_output_types = input_output_types;
expr_span.end = span(&spans[1..]).end;
expr_span.end = Span::concat(&spans[1..]).end;
}
arg_signature
} else {
@ -3154,9 +3154,9 @@ pub fn parse_full_signature(working_set: &mut StateWorkingSet, spans: &[Span]) -
}
pub fn parse_row_condition(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
let var_id = working_set.add_variable(b"$it".to_vec(), span(spans), Type::Any, false);
let var_id = working_set.add_variable(b"$it".to_vec(), Span::concat(spans), Type::Any, false);
let expression = parse_math_expression(working_set, spans, Some(var_id));
let span = span(spans);
let span = Span::concat(spans);
let block_id = match expression.expr {
Expr::Block(block_id) => block_id,
@ -5060,7 +5060,7 @@ pub fn parse_math_expression(
working_set.error(err);
}
let op_span = span(&[lhs.span, rhs.span]);
let op_span = Span::append(lhs.span, rhs.span);
expr_stack.push(Expression {
expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
span: op_span,
@ -5096,7 +5096,7 @@ pub fn parse_math_expression(
working_set.error(err)
}
let binary_op_span = span(&[lhs.span, rhs.span]);
let binary_op_span = Span::append(lhs.span, rhs.span);
expr_stack.push(Expression {
expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
span: binary_op_span,
@ -5167,7 +5167,7 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
if pos == spans.len() {
working_set.error(ParseError::UnknownCommand(spans[0]));
return garbage(span(spans));
return garbage(Span::concat(spans));
}
let output = if is_math_expression_like(working_set, spans[pos]) {
@ -5262,13 +5262,13 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
let arguments = vec![
Argument::Positional(Expression {
expr: Expr::Record(env_vars),
span: span(&spans[..pos]),
span: Span::concat(&spans[..pos]),
ty: Type::Any,
custom_completion: None,
}),
Argument::Positional(Expression {
expr: Expr::Closure(block_id),
span: span(&spans[pos..]),
span: Span::concat(&spans[pos..]),
ty: Type::Closure,
custom_completion: None,
}),
@ -5284,7 +5284,7 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
Expression {
expr,
custom_completion: None,
span: span(spans),
span: Span::concat(spans),
ty,
}
} else {
@ -5636,7 +5636,7 @@ pub fn parse_pipeline(
// if the 'let' is complete enough, use it, if not, fall through for now
if new_command.parts.len() > 3 {
let rhs_span = nu_protocol::span(&new_command.parts[3..]);
let rhs_span = Span::concat(&new_command.parts[3..]);
new_command.parts.truncate(3);
new_command.parts.push(rhs_span);

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::{span, ModuleId, Span, VarId};
use crate::{ModuleId, Span, VarId};
use std::collections::HashSet;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -12,17 +12,22 @@ pub enum ImportPatternMember {
impl ImportPatternMember {
pub fn span(&self) -> Span {
let mut spans = vec![];
match self {
ImportPatternMember::Glob { span } => spans.push(*span),
ImportPatternMember::Name { name: _, span } => spans.push(*span),
ImportPatternMember::Glob { span } | ImportPatternMember::Name { span, .. } => *span,
ImportPatternMember::List { names } => {
for (_, span) in names {
spans.push(*span);
}
let first = names
.first()
.map(|&(_, span)| span)
.unwrap_or(Span::unknown());
let last = names
.last()
.map(|&(_, span)| span)
.unwrap_or(Span::unknown());
Span::append(first, last)
}
}
span(&spans)
}
}
@ -59,13 +64,13 @@ impl ImportPattern {
}
pub fn span(&self) -> Span {
let mut spans = vec![self.head.span];
for member in &self.members {
spans.push(member.span());
}
span(&spans)
Span::append(
self.head.span,
self.members
.last()
.map(ImportPatternMember::span)
.unwrap_or(self.head.span),
)
}
pub fn with_hidden(self, hidden: HashSet<Vec<u8>>) -> Self {

View File

@ -1,7 +1,6 @@
use std::ops::Deref;
use miette::SourceSpan;
use serde::{Deserialize, Serialize};
use std::ops::Deref;
/// A spanned area of interest, generic over what kind of thing is of interest
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
@ -74,77 +73,123 @@ impl<T> IntoSpanned for T {
/// Spans are a global offset across all seen files, which are cached in the engine's state. The start and
/// end offset together make the inclusive start/exclusive end pair for where to underline to highlight
/// a given point of interest.
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl From<Span> for SourceSpan {
fn from(s: Span) -> Self {
Self::new(s.start.into(), s.end - s.start)
}
}
impl Span {
pub fn new(start: usize, end: usize) -> Span {
pub fn new(start: usize, end: usize) -> Self {
debug_assert!(
end >= start,
"Can't create a Span whose end < start, start={start}, end={end}"
);
Span { start, end }
Self { start, end }
}
pub const fn unknown() -> Span {
Span { start: 0, end: 0 }
pub const fn unknown() -> Self {
Self { start: 0, end: 0 }
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub const fn test_data() -> Span {
pub const fn test_data() -> Self {
Self::unknown()
}
pub fn offset(&self, offset: usize) -> Span {
Span::new(self.start - offset, self.end - offset)
pub fn offset(&self, offset: usize) -> Self {
Self::new(self.start - offset, self.end - offset)
}
pub fn contains(&self, pos: usize) -> bool {
pos >= self.start && pos < self.end
self.start <= pos && pos < self.end
}
pub fn contains_span(&self, span: Span) -> bool {
span.start >= self.start && span.end <= self.end
pub fn contains_span(&self, span: Self) -> bool {
self.start <= span.start && span.end <= self.end
}
/// Point to the space just past this span, useful for missing
/// values
pub fn past(&self) -> Span {
Span {
/// Point to the space just past this span, useful for missing values
pub fn past(&self) -> Self {
Self {
start: self.end,
end: self.end,
}
}
/// Returns the minimal [`Span`] that encompasses both of the given spans.
///
/// The two `Spans` can overlap in the middle,
/// but must otherwise be in order by satisfying:
/// - `self.start <= after.start`
/// - `self.end <= after.end`
///
/// If this is not guaranteed to be the case, use [`Span::merge`] instead.
pub fn append(self, after: Self) -> Self {
debug_assert!(
self.start <= after.start && self.end <= after.end,
"Can't merge two Spans that are not in order"
);
Self {
start: self.start,
end: after.end,
}
}
/// Returns the minimal [`Span`] that encompasses both of the given spans.
///
/// The spans need not be in order or have any relationship.
///
/// [`Span::append`] is slightly more efficient if the spans are known to be in order.
pub fn merge(self, other: Self) -> Self {
Self {
start: usize::min(self.start, other.start),
end: usize::max(self.end, other.end),
}
}
/// Returns the minimal [`Span`] that encompasses all of the spans in the given slice.
///
/// The spans are assumed to be in order, that is, all consecutive spans must satisfy:
/// - `spans[i].start <= spans[i + 1].start`
/// - `spans[i].end <= spans[i + 1].end`
///
/// (Two consecutive spans can overlap as long as the above is true.)
///
/// Use [`Span::merge_many`] if the spans are not known to be in order.
pub fn concat(spans: &[Self]) -> Self {
// TODO: enable assert below
// debug_assert!(!spans.is_empty());
debug_assert!(spans.windows(2).all(|spans| {
let &[a, b] = spans else {
return false;
};
a.start <= b.start && a.end <= b.end
}));
Self {
start: spans.first().map(|s| s.start).unwrap_or(0),
end: spans.last().map(|s| s.end).unwrap_or(0),
}
}
/// Returns the minimal [`Span`] that encompasses all of the spans in the given iterator.
///
/// The spans need not be in order or have any relationship.
///
/// [`Span::concat`] is more efficient if the spans are known to be in order.
pub fn merge_many(spans: impl IntoIterator<Item = Self>) -> Self {
spans
.into_iter()
.reduce(Self::merge)
.unwrap_or(Self::unknown())
}
}
/// Used when you have a slice of spans of at least size 1
pub fn span(spans: &[Span]) -> Span {
let length = spans.len();
//TODO debug_assert!(length > 0, "expect spans > 0");
if length == 0 {
Span::unknown()
} else if length == 1 {
spans[0]
} else {
let end = spans
.iter()
.map(|s| s.end)
.max()
.expect("Must be an end. Length > 0");
Span::new(spans[0].start, end)
impl From<Span> for SourceSpan {
fn from(s: Span) -> Self {
Self::new(s.start.into(), s.end - s.start)
}
}

View File

@ -1,7 +1,7 @@
use super::{operations::Axis, NuDataFrame};
use nu_protocol::{
ast::{Boolean, Comparison, Math, Operator},
span, ShellError, Span, Spanned, Value,
ShellError, Span, Spanned, Value,
};
use num::Zero;
use polars::prelude::{
@ -17,9 +17,10 @@ pub(super) fn between_dataframes(
right: &Value,
rhs: &NuDataFrame,
) -> Result<NuDataFrame, ShellError> {
let operation_span = span(&[left.span(), right.span()]);
match operator.item {
Operator::Math(Math::Plus) => lhs.append_df(rhs, Axis::Row, operation_span),
Operator::Math(Math::Plus) => {
lhs.append_df(rhs, Axis::Row, Span::merge(left.span(), right.span()))
}
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
@ -37,7 +38,7 @@ pub(super) fn compute_between_series(
right: &Value,
rhs: &Series,
) -> Result<NuDataFrame, ShellError> {
let operation_span = span(&[left.span(), right.span()]);
let operation_span = Span::merge(left.span(), right.span());
match operator.item {
Operator::Math(Math::Plus) => {
let mut res = lhs + rhs;

View File

@ -1,4 +1,4 @@
use nu_protocol::{span as span_join, ShellError, Span, Spanned, Value};
use nu_protocol::{ShellError, Span, Spanned, Value};
// Default value used when selecting rows from dataframe
pub const DEFAULT_ROWS: usize = 5;
@ -20,8 +20,8 @@ pub(crate) fn convert_columns(
span: Some(span),
help: None,
inner: vec![],
})
.map(|v| v.span())?;
})?
.span();
let res = columns
.into_iter()
@ -29,7 +29,7 @@ pub(crate) fn convert_columns(
let span = value.span();
match value {
Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
col_span = col_span.merge(span);
Ok(Spanned { item: val, span })
}
_ => Err(ShellError::GenericError {
@ -70,7 +70,7 @@ pub(crate) fn convert_columns_string(
let span = value.span();
match value {
Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
col_span = col_span.merge(span);
Ok(val)
}
_ => Err(ShellError::GenericError {