From aec41f3df0561a43c89163174842241866b0fa19 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Thu, 16 May 2024 22:34:49 +0000 Subject: [PATCH] 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. --- .../values/nu_dataframe/between_values.rs | 6 +- .../src/dataframe/values/utils.rs | 6 +- crates/nu-command/src/help/help_.rs | 4 +- crates/nu-command/src/help/help_aliases.rs | 5 +- crates/nu-command/src/help/help_commands.rs | 3 +- crates/nu-command/src/help/help_externs.rs | 3 +- crates/nu-command/src/help/help_modules.rs | 4 +- crates/nu-command/src/platform/is_terminal.rs | 6 +- crates/nu-command/src/platform/kill.rs | 5 +- crates/nu-parser/src/parse_keywords.rs | 263 ++++++++++-------- crates/nu-parser/src/parser.rs | 64 ++--- crates/nu-protocol/src/ast/import_pattern.rs | 35 ++- crates/nu-protocol/src/span.rs | 123 +++++--- .../values/nu_dataframe/between_values.rs | 9 +- .../src/dataframe/values/utils.rs | 10 +- 15 files changed, 305 insertions(+), 241 deletions(-) diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/between_values.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/between_values.rs index fab201cf9a..74a484825a 100644 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/between_values.rs +++ b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/between_values.rs @@ -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 { - 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 { - 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; diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/utils.rs b/crates/nu-cmd-dataframe/src/dataframe/values/utils.rs index 3ccf2e6d77..0dc43399a3 100644 --- a/crates/nu-cmd-dataframe/src/dataframe/values/utils.rs +++ b/crates/nu-cmd-dataframe/src/dataframe/values/utils.rs @@ -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 { diff --git a/crates/nu-command/src/help/help_.rs b/crates/nu-command/src/help/help_.rs index 819d3c7dd9..9835a20ad0 100644 --- a/crates/nu-command/src/help/help_.rs +++ b/crates/nu-command/src/help/help_.rs @@ -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 = 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 diff --git a/crates/nu-command/src/help/help_aliases.rs b/crates/nu-command/src/help/help_aliases.rs index 2cc7c7f073..da03fa6398 100644 --- a/crates/nu-command/src/help/help_aliases.rs +++ b/crates/nu-command/src/help/help_aliases.rs @@ -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::>()), + 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::>()), + span: Span::merge_many(rest.iter().map(|s| s.span)), }); }; diff --git a/crates/nu-command/src/help/help_commands.rs b/crates/nu-command/src/help/help_commands.rs index bc508b249b..bc0fd92d92 100644 --- a/crates/nu-command/src/help/help_commands.rs +++ b/crates/nu-command/src/help/help_commands.rs @@ -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)), }) } } diff --git a/crates/nu-command/src/help/help_externs.rs b/crates/nu-command/src/help/help_externs.rs index 624a8d8060..22fb4a303c 100644 --- a/crates/nu-command/src/help/help_externs.rs +++ b/crates/nu-command/src/help/help_externs.rs @@ -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)), }) } } diff --git a/crates/nu-command/src/help/help_modules.rs b/crates/nu-command/src/help/help_modules.rs index f2ddf55f1d..690968251b 100644 --- a/crates/nu-command/src/help/help_modules.rs +++ b/crates/nu-command/src/help/help_modules.rs @@ -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::>()), + span: Span::merge_many(rest.iter().map(|s| s.span)), }); }; diff --git a/crates/nu-command/src/platform/is_terminal.rs b/crates/nu-command/src/platform/is_terminal.rs index 770fa45289..c67329e839 100644 --- a/crates/nu-command/src/platform/is_terminal.rs +++ b/crates/nu-command/src/platform/is_terminal.rs @@ -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())), }); } }; diff --git a/crates/nu-command/src/platform/kill.rs b/crates/nu-command/src/platform/kill.rs index 59486cf1ad..2e47ee8c78 100644 --- a/crates/nu-command/src/platform/kill.rs +++ b/crates/nu-command/src/platform/kill.rs @@ -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"); diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 381a86d19e..015873e69a 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -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 ".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 or module ".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 ".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 ".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); diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 0f72132d10..bd09f5b52a 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -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 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); diff --git a/crates/nu-protocol/src/ast/import_pattern.rs b/crates/nu-protocol/src/ast/import_pattern.rs index 2af08087a9..893dd9897b 100644 --- a/crates/nu-protocol/src/ast/import_pattern.rs +++ b/crates/nu-protocol/src/ast/import_pattern.rs @@ -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>) -> Self { diff --git a/crates/nu-protocol/src/span.rs b/crates/nu-protocol/src/span.rs index 7bc13997a1..3d32aa4ddf 100644 --- a/crates/nu-protocol/src/span.rs +++ b/crates/nu-protocol/src/span.rs @@ -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 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 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) -> 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 for SourceSpan { + fn from(s: Span) -> Self { + Self::new(s.start.into(), s.end - s.start) } } diff --git a/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs b/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs index df0854ffee..a47197bde8 100644 --- a/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs +++ b/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs @@ -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 { - 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 { - 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; diff --git a/crates/nu_plugin_polars/src/dataframe/values/utils.rs b/crates/nu_plugin_polars/src/dataframe/values/utils.rs index f77870114b..88ce8a4656 100644 --- a/crates/nu_plugin_polars/src/dataframe/values/utils.rs +++ b/crates/nu_plugin_polars/src/dataframe/values/utils.rs @@ -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 {