Revert "Span ID Refactor (Step 2): Make Call SpanId-friendly (#13268)" (#13292)

This reverts commit 0cfd5fbece.

The original PR messed up syntax higlighting of aliases and causes
panics of completion in the presence of alias.

<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

you can also mention related issues, PRs or discussions!
-->

# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
Jakub Žádník 2024-07-04 00:02:13 +03:00 committed by GitHub
parent ca7a2ae1d6
commit 3fae77209a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 296 additions and 468 deletions

View file

@ -62,7 +62,7 @@ impl Command for KeybindingsList {
.collect() .collect()
} else { } else {
call.named_iter() call.named_iter()
.flat_map(|(argument, _, _, _)| get_records(argument.item.as_str(), call.head)) .flat_map(|(argument, _, _)| get_records(argument.item.as_str(), call.head))
.collect() .collect()
}; };

View file

@ -7,7 +7,7 @@ use nu_protocol::{
ast::{Argument, Call, Expr, Expression}, ast::{Argument, Call, Expr, Expression},
debugger::WithoutDebug, debugger::WithoutDebug,
engine::{Stack, StateWorkingSet}, engine::{Stack, StateWorkingSet},
PipelineData, Span, Spanned, Type, Value, PipelineData, Span, Type, Value,
}; };
use nu_utils::IgnoreCaseExt; use nu_utils::IgnoreCaseExt;
use std::collections::HashMap; use std::collections::HashMap;
@ -53,8 +53,7 @@ impl Completer for CustomCompletion {
&Call { &Call {
decl_id: self.decl_id, decl_id: self.decl_id,
head: span, head: span,
arguments: Spanned { arguments: vec![
item: vec![
Argument::Positional(Expression::new_unknown( Argument::Positional(Expression::new_unknown(
Expr::String(self.line.clone()), Expr::String(self.line.clone()),
Span::unknown(), Span::unknown(),
@ -66,8 +65,6 @@ impl Completer for CustomCompletion {
Type::Int, Type::Int,
)), )),
], ],
span: Span::unknown(),
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}, },
PipelineData::empty(), PipelineData::empty(),

View file

@ -400,7 +400,7 @@ fn find_matching_block_end_in_expr(
} }
} }
Expr::Call(call) => call.arguments.item.iter().find_map(|arg| { Expr::Call(call) => call.arguments.iter().find_map(|arg| {
arg.expr().and_then(|expr| { arg.expr().and_then(|expr| {
find_matching_block_end_in_expr( find_matching_block_end_in_expr(
line, line,

View file

@ -49,7 +49,7 @@ impl Command for BytesBuild {
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let mut output = vec![]; let mut output = vec![];
for val in call.rest_iter_flattened(&engine_state, 0, |expr| { for val in call.rest_iter_flattened(0, |expr| {
let eval_expression = get_eval_expression(engine_state); let eval_expression = get_eval_expression(engine_state);
eval_expression(engine_state, stack, expr) eval_expression(engine_state, stack, expr)
})? { })? {

View file

@ -111,11 +111,11 @@ fn get_arguments(
) -> Vec<Value> { ) -> Vec<Value> {
let mut arg_value = vec![]; let mut arg_value = vec![];
let span = Span::test_data(); let span = Span::test_data();
for arg in &call.arguments.item { for arg in &call.arguments {
match arg { match arg {
// I think the second argument to Argument::Named is the short name, but I'm not really sure. // I think the second argument to Argument::Named is the short name, but I'm not really sure.
// Please fix it if it's wrong. :) // Please fix it if it's wrong. :)
Argument::Named((name, short, opt_expr, _)) => { Argument::Named((name, short, opt_expr)) => {
let arg_type = "named"; let arg_type = "named";
let arg_value_name = name.item.clone(); let arg_value_name = name.item.clone();
let arg_value_name_span_start = name.span.start as i64; let arg_value_name_span_start = name.span.start as i64;

View file

@ -104,7 +104,7 @@ confusing the id/parent_id hierarchy. The --expr flag is helpful for investigati
collect_values, collect_values,
collect_exprs, collect_exprs,
collect_lines, collect_lines,
call.span(&engine_state), call.span(),
); );
let lock_err = |_| ShellError::GenericError { let lock_err = |_| ShellError::GenericError {
@ -125,12 +125,12 @@ confusing the id/parent_id hierarchy. The --expr flag is helpful for investigati
let pipeline_data = result?; let pipeline_data = result?;
// Collect the output // Collect the output
let _ = pipeline_data.into_value(call.span(&engine_state)); let _ = pipeline_data.into_value(call.span());
Ok(engine_state Ok(engine_state
.deactivate_debugger() .deactivate_debugger()
.map_err(lock_err)? .map_err(lock_err)?
.report(engine_state, call.span(&engine_state))? .report(engine_state, call.span())?
.into_pipeline_data()) .into_pipeline_data())
} }

View file

@ -177,12 +177,7 @@ impl Command for Open {
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
eval_block(engine_state, stack, block, stream) eval_block(engine_state, stack, block, stream)
} else { } else {
decl.run( decl.run(engine_state, stack, &Call::new(call_span), stream)
engine_state,
stack,
&Call::new(call_span, call.arguments_span()),
stream,
)
}; };
output.push(command_output.map_err(|inner| { output.push(command_output.map_err(|inner| {
ShellError::GenericError{ ShellError::GenericError{

View file

@ -398,7 +398,7 @@ fn convert_to_extension(
let eval_block = get_eval_block(engine_state); let eval_block = get_eval_block(engine_state);
eval_block(engine_state, stack, block, input) eval_block(engine_state, stack, block, input)
} else { } else {
decl.run(engine_state, stack, &Call::new(span, span.past()), input) decl.run(engine_state, stack, &Call::new(span), input)
} }
} else { } else {
Ok(input) Ok(input)

View file

@ -103,7 +103,7 @@ pub fn get_rest_for_glob_pattern(
let mut output = vec![]; let mut output = vec![];
let eval_expression = get_eval_expression(engine_state); let eval_expression = get_eval_expression(engine_state);
for result in call.rest_iter_flattened(&engine_state, starting_pos, |expr| { for result in call.rest_iter_flattened(starting_pos, |expr| {
let result = eval_expression(engine_state, stack, expr); let result = eval_expression(engine_state, stack, expr);
match result { match result {
Err(e) => Err(e), Err(e) => Err(e),

View file

@ -141,7 +141,7 @@ fn from_csv(
} else { } else {
return Err(ShellError::NonUtf8Custom { return Err(ShellError::NonUtf8Custom {
msg: "separator should be a single char or a 4-byte unicode".into(), msg: "separator should be a single char or a 4-byte unicode".into(),
span: call.span(&engine_state), span: call.span(),
}); });
} }
} }

View file

@ -3,7 +3,6 @@ use nu_color_config::StyleComputer;
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::ast::{Expr, Expression}; use nu_protocol::ast::{Expr, Expression};
use nu_protocol::engine::UNKNOWN_SPAN_ID;
use std::collections::VecDeque; use std::collections::VecDeque;
#[derive(Clone)] #[derive(Clone)]
@ -144,7 +143,7 @@ pub fn cal(
style_computer, style_computer,
)?; )?;
let mut table_no_index = Call::new(Span::unknown(), Span::unknown()); let mut table_no_index = Call::new(Span::unknown());
table_no_index.add_named(( table_no_index.add_named((
Spanned { Spanned {
item: "index".to_string(), item: "index".to_string(),
@ -156,7 +155,6 @@ pub fn cal(
Span::unknown(), Span::unknown(),
Type::Bool, Type::Bool,
)), )),
UNKNOWN_SPAN_ID,
)); ));
let cal_table_output = let cal_table_output =

View file

@ -412,7 +412,7 @@ fn display(help: &str, engine_state: &EngineState, stack: &mut Stack, span: Span
let result = decl.run( let result = decl.run(
engine_state, engine_state,
stack, stack,
&Call::new(span, span.past()), &Call::new(span),
Value::string(item, Span::unknown()).into_pipeline_data(), Value::string(item, Span::unknown()).into_pipeline_data(),
); );

View file

@ -547,7 +547,7 @@ fn transform_response_using_content_type(
Some(converter_id) => engine_state.get_decl(converter_id).run( Some(converter_id) => engine_state.get_decl(converter_id).run(
engine_state, engine_state,
stack, stack,
&Call::new(span, span.past()), &Call::new(span),
output, output,
), ),
None => Ok(output), None => Ok(output),

View file

@ -58,12 +58,7 @@ impl Command for IsTerminal {
_ => { _ => {
return Err(ShellError::IncompatibleParametersSingle { return Err(ShellError::IncompatibleParametersSingle {
msg: "Only one stream may be checked".into(), msg: "Only one stream may be checked".into(),
span: Span::merge_many( span: Span::merge_many(call.arguments.iter().map(|arg| arg.span())),
call.arguments
.item
.iter()
.map(|arg| arg.span(&engine_state)),
),
}); });
} }
}; };

View file

@ -375,12 +375,8 @@ fn write_pipeline_data(
Arc::make_mut(&mut engine_state.config).use_ansi_coloring = false; Arc::make_mut(&mut engine_state.config).use_ansi_coloring = false;
// Invoke the `table` command. // Invoke the `table` command.
let output = crate::Table.run( let output =
&engine_state, crate::Table.run(&engine_state, &mut stack, &Call::new(Span::unknown()), data)?;
&mut stack,
&Call::new(Span::unknown(), Span::unknown()),
data,
)?;
// Write the output. // Write the output.
for value in output { for value in output {

View file

@ -127,7 +127,7 @@ impl Command for Table {
return Ok(val.into_pipeline_data()); return Ok(val.into_pipeline_data());
} }
let cfg = parse_table_config(engine_state, call, engine_state, stack)?; let cfg = parse_table_config(call, engine_state, stack)?;
let input = CmdInput::new(engine_state, stack, call, input); let input = CmdInput::new(engine_state, stack, call, input);
// reset vt processing, aka ansi because illbehaved externals can break it // reset vt processing, aka ansi because illbehaved externals can break it
@ -247,7 +247,6 @@ impl TableConfig {
} }
fn parse_table_config( fn parse_table_config(
engine_state: &EngineState,
call: &Call, call: &Call,
state: &EngineState, state: &EngineState,
stack: &mut Stack, stack: &mut Stack,
@ -270,9 +269,9 @@ fn parse_table_config(
flatten_separator, flatten_separator,
}, },
}; };
let theme = get_theme_flag(engine_state, call, state, stack)? let theme =
.unwrap_or_else(|| get_config(state, stack).table_mode); get_theme_flag(call, state, stack)?.unwrap_or_else(|| get_config(state, stack).table_mode);
let index = get_index_flag(engine_state, call, state, stack)?; let index = get_index_flag(call, state, stack)?;
let term_width = get_width_param(width_param); let term_width = get_width_param(width_param);
@ -286,7 +285,6 @@ fn parse_table_config(
} }
fn get_index_flag( fn get_index_flag(
engine_state: &EngineState,
call: &Call, call: &Call,
state: &EngineState, state: &EngineState,
stack: &mut Stack, stack: &mut Stack,
@ -310,7 +308,7 @@ fn get_index_flag(
Err(ShellError::UnsupportedInput { Err(ShellError::UnsupportedInput {
msg: String::from("got a negative integer"), msg: String::from("got a negative integer"),
input: val.to_string(), input: val.to_string(),
msg_span: call.span(&engine_state), msg_span: call.span(),
input_span: internal_span, input_span: internal_span,
}) })
} else { } else {
@ -321,14 +319,13 @@ fn get_index_flag(
_ => Err(ShellError::CantConvert { _ => Err(ShellError::CantConvert {
to_type: String::from("index"), to_type: String::from("index"),
from_type: String::new(), from_type: String::new(),
span: call.span(&engine_state), span: call.span(),
help: Some(String::from("supported values: [bool, int, nothing]")), help: Some(String::from("supported values: [bool, int, nothing]")),
}), }),
} }
} }
fn get_theme_flag( fn get_theme_flag(
engine_state: &EngineState,
call: &Call, call: &Call,
state: &EngineState, state: &EngineState,
stack: &mut Stack, stack: &mut Stack,
@ -338,7 +335,7 @@ fn get_theme_flag(
TableMode::from_str(&theme).map_err(|err| ShellError::CantConvert { TableMode::from_str(&theme).map_err(|err| ShellError::CantConvert {
to_type: String::from("theme"), to_type: String::from("theme"),
from_type: String::from("string"), from_type: String::from("string"),
span: call.span(&engine_state), span: call.span(),
help: Some(format!("{}, but found '{}'.", err, theme)), help: Some(format!("{}, but found '{}'.", err, theme)),
}) })
}) })

View file

@ -113,7 +113,7 @@ impl CallExt for Call {
let stack = &mut stack.use_call_arg_out_dest(); let stack = &mut stack.use_call_arg_out_dest();
let mut output = vec![]; let mut output = vec![];
for result in self.rest_iter_flattened(&engine_state, starting_pos, |expr| { for result in self.rest_iter_flattened(starting_pos, |expr| {
eval_expression::<WithoutDebug>(engine_state, stack, expr) eval_expression::<WithoutDebug>(engine_state, stack, expr)
})? { })? {
output.push(FromValue::from_value(result)?); output.push(FromValue::from_value(result)?);

View file

@ -48,7 +48,7 @@ fn nu_highlight_string(code_string: &str, engine_state: &EngineState, stack: &mu
if let Ok(output) = decl.run( if let Ok(output) = decl.run(
engine_state, engine_state,
stack, stack,
&Call::new(Span::unknown(), Span::unknown()), &Call::new(Span::unknown()),
Value::string(code_string, Span::unknown()).into_pipeline_data(), Value::string(code_string, Span::unknown()).into_pipeline_data(),
) { ) {
let result = output.into_value(Span::unknown()); let result = output.into_value(Span::unknown());
@ -241,10 +241,7 @@ fn get_documentation(
&Call { &Call {
decl_id, decl_id,
head: span, head: span,
arguments: Spanned { arguments: vec![],
item: vec![],
span: span.past(),
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}, },
PipelineData::Value(Value::list(vals, span), None), PipelineData::Value(Value::list(vals, span), None),
@ -276,7 +273,7 @@ fn get_documentation(
match decl.run( match decl.run(
engine_state, engine_state,
stack, stack,
&Call::new(Span::unknown(), Span::unknown()), &Call::new(Span::unknown()),
Value::string(example.example, Span::unknown()).into_pipeline_data(), Value::string(example.example, Span::unknown()).into_pipeline_data(),
) { ) {
Ok(output) => { Ok(output) => {
@ -299,7 +296,7 @@ fn get_documentation(
} }
if let Some(result) = &example.result { if let Some(result) = &example.result {
let mut table_call = Call::new(Span::unknown(), Span::unknown()); let mut table_call = Call::new(Span::unknown());
if example.example.ends_with("--collapse") { if example.example.ends_with("--collapse") {
// collapse the result // collapse the result
table_call.add_named(( table_call.add_named((
@ -309,7 +306,6 @@ fn get_documentation(
}, },
None, None,
None, None,
UNKNOWN_SPAN_ID,
)) ))
} else { } else {
// expand the result // expand the result
@ -320,7 +316,6 @@ fn get_documentation(
}, },
None, None,
None, None,
UNKNOWN_SPAN_ID,
)) ))
} }
let table = engine_state let table = engine_state
@ -373,17 +368,13 @@ fn get_ansi_color_for_component_or_default(
// Call ansi command using argument // Call ansi command using argument
if let Some(argument) = argument_opt { if let Some(argument) = argument_opt {
if let Some(decl_id) = engine_state.find_decl(b"ansi", &[]) { if let Some(decl_id) = engine_state.find_decl(b"ansi", &[]) {
let arg_span = argument.span(&engine_state);
if let Ok(result) = eval_call::<WithoutDebug>( if let Ok(result) = eval_call::<WithoutDebug>(
engine_state, engine_state,
caller_stack, caller_stack,
&Call { &Call {
decl_id, decl_id,
head: span, head: span,
arguments: Spanned { arguments: vec![argument],
item: vec![argument],
span: arg_span,
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}, },
PipelineData::Empty, PipelineData::Empty,

View file

@ -26,7 +26,7 @@ pub fn eval_call<D: DebugContext>(
} }
let decl = engine_state.get_decl(call.decl_id); let decl = engine_state.get_decl(call.decl_id);
if !decl.is_known_external() && call.named_iter().any(|(flag, _, _, _)| flag.item == "help") { if !decl.is_known_external() && call.named_iter().any(|(flag, _, _)| flag.item == "help") {
let help = get_full_help(decl, engine_state, caller_stack); let help = get_full_help(decl, engine_state, caller_stack);
Ok(Value::string(help, call.head).into_pipeline_data()) Ok(Value::string(help, call.head).into_pipeline_data())
} else if let Some(block_id) = decl.block_id() { } else if let Some(block_id) = decl.block_id() {
@ -100,7 +100,6 @@ pub fn eval_call<D: DebugContext>(
let mut rest_items = vec![]; let mut rest_items = vec![];
for result in call.rest_iter_flattened( for result in call.rest_iter_flattened(
&engine_state,
decl.signature().required_positional.len() decl.signature().required_positional.len()
+ decl.signature().optional_positional.len(), + decl.signature().optional_positional.len(),
|expr| eval_expression::<D>(engine_state, caller_stack, expr), |expr| eval_expression::<D>(engine_state, caller_stack, expr),
@ -214,16 +213,8 @@ fn eval_external(
})?; })?;
let command = engine_state.get_decl(decl_id); let command = engine_state.get_decl(decl_id);
let spans: Vec<Span> = args
.iter()
.map(|arg| match arg {
ExternalArgument::Regular(expr) | ExternalArgument::Spread(expr) => {
expr.span(&engine_state)
}
})
.collect();
let mut call = Call::new(head.span(&engine_state), Span::concat(&spans)); let mut call = Call::new(head.span(&engine_state));
call.add_positional(head.clone()); call.add_positional(head.clone());

View file

@ -252,7 +252,7 @@ fn flatten_expression_into(
} }
let arg_start = output.len(); let arg_start = output.len();
for arg in &call.arguments.item { for arg in &call.arguments {
match arg { match arg {
Argument::Positional(positional) | Argument::Unknown(positional) => { Argument::Positional(positional) | Argument::Unknown(positional) => {
flatten_expression_into(working_set, positional, output) flatten_expression_into(working_set, positional, output)

View file

@ -43,7 +43,7 @@ impl Command for KnownExternal {
let command = engine_state.get_decl(decl_id); let command = engine_state.get_decl(decl_id);
let mut extern_call = Call::new(head_span, call.arguments_span()); let mut extern_call = Call::new(head_span);
let extern_name = if let Some(name_bytes) = engine_state.find_decl_name(call.decl_id, &[]) { let extern_name = if let Some(name_bytes) = engine_state.find_decl_name(call.decl_id, &[]) {
String::from_utf8_lossy(name_bytes) String::from_utf8_lossy(name_bytes)
@ -78,7 +78,7 @@ impl Command for KnownExternal {
)); ));
} }
for arg in &call.arguments.item { for arg in &call.arguments {
match arg { match arg {
Argument::Positional(positional) => extern_call.add_positional(positional.clone()), Argument::Positional(positional) => extern_call.add_positional(positional.clone()),
Argument::Named(named) => { Argument::Named(named) => {

View file

@ -21,9 +21,8 @@ pub use nu_protocol::parser_path::*;
pub use parse_keywords::*; pub use parse_keywords::*;
pub use parser::{ pub use parser::{
is_math_expression_like, named_arg_span, parse, parse_block, parse_expression, is_math_expression_like, parse, parse_block, parse_expression, parse_external_call,
parse_external_call, parse_unit_value, trim_quotes, trim_quotes_str, unescape_unquote_string, parse_unit_value, trim_quotes, trim_quotes_str, unescape_unquote_string, DURATION_UNIT_GROUPS,
DURATION_UNIT_GROUPS,
}; };
#[cfg(feature = "plugin")] #[cfg(feature = "plugin")]

View file

@ -123,8 +123,8 @@ pub fn parse_keyword(working_set: &mut StateWorkingSet, lite_command: &LiteComma
// Apply parse keyword side effects // Apply parse keyword side effects
let cmd = working_set.get_decl(call.decl_id); let cmd = working_set.get_decl(call.decl_id);
// check help flag first. // check help flag first.
if call.named_iter().any(|(flag, _, _, _)| flag.item == "help") { if call.named_iter().any(|(flag, _, _)| flag.item == "help") {
let call_span = call.span(working_set); let call_span = call.span();
return Pipeline::from_vec(vec![Expression::new( return Pipeline::from_vec(vec![Expression::new(
working_set, working_set,
Expr::Call(call), Expr::Call(call),
@ -1056,7 +1056,7 @@ pub fn parse_alias(
// First from comments, if any are present // First from comments, if any are present
false => working_set.build_usage(&lite_command.comments), false => working_set.build_usage(&lite_command.comments),
// Then from the command itself // Then from the command itself
true => match alias_call.arguments.item.get(1) { true => match alias_call.arguments.get(1) {
Some(Argument::Positional(Expression { Some(Argument::Positional(Expression {
expr: Expr::Keyword(kw), expr: Expr::Keyword(kw),
.. ..
@ -1258,10 +1258,7 @@ pub fn parse_export_in_module(
let mut call = Box::new(Call { let mut call = Box::new(Call {
head: spans[0], head: spans[0],
decl_id: export_decl_id, decl_id: export_decl_id,
arguments: Spanned { arguments: vec![],
item: vec![],
span: spans[0].past(),
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}); });
@ -2266,21 +2263,13 @@ pub fn parse_module(
.find_decl(b"module") .find_decl(b"module")
.expect("internal error: missing module command"); .expect("internal error: missing module command");
let args_span = Span::concat(&[
module_name_or_path_expr.span(working_set),
block_expr.span(working_set),
]);
let call = Box::new(Call { let call = Box::new(Call {
head: Span::concat(&spans[..split_id]), head: Span::concat(&spans[..split_id]),
decl_id: module_decl_id, decl_id: module_decl_id,
arguments: Spanned { arguments: vec![
item: vec![
Argument::Positional(module_name_or_path_expr), Argument::Positional(module_name_or_path_expr),
Argument::Positional(block_expr), Argument::Positional(block_expr),
], ],
span: args_span,
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}); });
@ -2712,7 +2701,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand)
} }
pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline { pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
let call_span = call.span(working_set); let call_span = call.span();
let (overlay_name, _) = if let Some(expr) = call.positional_nth(0) { let (overlay_name, _) = if let Some(expr) = call.positional_nth(0) {
match eval_constant(working_set, expr) { match eval_constant(working_set, expr) {
@ -2761,7 +2750,7 @@ pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box<Call>) ->
} }
pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline { pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
let call_span = call.span(working_set); let call_span = call.span();
let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) { let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
match eval_constant(working_set, expr) { match eval_constant(working_set, expr) {
@ -2984,7 +2973,7 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box<Call>) ->
} }
pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline { pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
let call_span = call.span(working_set); let call_span = call.span();
let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) { let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
match eval_constant(working_set, expr) { match eval_constant(working_set, expr) {
@ -3124,16 +3113,10 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
} }
} }
let args_span =
Span::concat(&[lvalue.span(working_set), rvalue.span(working_set)]);
let call = Box::new(Call { let call = Box::new(Call {
decl_id, decl_id,
head: spans[0], head: spans[0],
arguments: Spanned { arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
item: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
span: args_span,
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}); });
@ -3276,16 +3259,10 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin
} }
} }
let args_span =
Span::concat(&[lvalue.span(working_set), rvalue.span(working_set)]);
let call = Box::new(Call { let call = Box::new(Call {
decl_id, decl_id,
head: spans[0], head: spans[0],
arguments: Spanned { arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
item: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
span: args_span,
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}); });
@ -3401,16 +3378,10 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
} }
} }
let args_span =
Span::concat(&[lvalue.span(working_set), rvalue.span(working_set)]);
let call = Box::new(Call { let call = Box::new(Call {
decl_id, decl_id,
head: spans[0], head: spans[0],
arguments: Spanned { arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
item: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
span: args_span,
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
}); });
@ -3913,8 +3884,8 @@ pub fn parse_plugin_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> P
let plugin_config = call let plugin_config = call
.named_iter() .named_iter()
.find(|(arg_name, _, _, _)| arg_name.item == "plugin-config") .find(|(arg_name, _, _)| arg_name.item == "plugin-config")
.map(|(_, _, expr, _)| { .map(|(_, _, expr)| {
let expr = expr let expr = expr
.as_ref() .as_ref()
.expect("--plugin-config arg should have been checked already"); .expect("--plugin-config arg should have been checked already");
@ -3990,7 +3961,7 @@ pub fn parse_plugin_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> P
working_set.error(err); working_set.error(err);
} }
let call_span = call.span(working_set); let call_span = call.span();
Pipeline::from_vec(vec![Expression::new( Pipeline::from_vec(vec![Expression::new(
working_set, working_set,
@ -4176,6 +4147,6 @@ fn detect_params_in_name(
/// Run has_flag_const and push possible error to working_set /// Run has_flag_const and push possible error to working_set
fn has_flag_const(working_set: &mut StateWorkingSet, call: &Call, name: &str) -> Result<bool, ()> { fn has_flag_const(working_set: &mut StateWorkingSet, call: &Call, name: &str) -> Result<bool, ()> {
call.has_flag_const(working_set, name).map_err(|err| { call.has_flag_const(working_set, name).map_err(|err| {
working_set.error(err.wrap(working_set, call.span(working_set))); working_set.error(err.wrap(working_set, call.span()));
}) })
} }

View file

@ -160,7 +160,7 @@ pub(crate) fn check_call(
call: &Call, call: &Call,
) { ) {
// Allow the call to pass if they pass in the help flag // Allow the call to pass if they pass in the help flag
if call.named_iter().any(|(n, _, _, _)| n.item == "help") { if call.named_iter().any(|(n, _, _)| n.item == "help") {
return; return;
} }
@ -180,7 +180,7 @@ pub(crate) fn check_call(
if let Some(last) = call.positional_iter().last() { if let Some(last) = call.positional_iter().last() {
working_set.error(ParseError::MissingPositional( working_set.error(ParseError::MissingPositional(
argument.name.clone(), argument.name.clone(),
Span::new(last.span(working_set).end, last.span(working_set).end), Span::new(last.span.end, last.span.end),
sig.call_signature(), sig.call_signature(),
)); ));
return; return;
@ -199,7 +199,7 @@ pub(crate) fn check_call(
if let Some(last) = call.positional_iter().last() { if let Some(last) = call.positional_iter().last() {
working_set.error(ParseError::MissingPositional( working_set.error(ParseError::MissingPositional(
missing.name.clone(), missing.name.clone(),
Span::new(last.span(working_set).end, last.span(working_set).end), Span::new(last.span.end, last.span.end),
sig.call_signature(), sig.call_signature(),
)) ))
} else { } else {
@ -211,10 +211,7 @@ pub(crate) fn check_call(
} }
} else { } else {
for req_flag in sig.named.iter().filter(|x| x.required) { for req_flag in sig.named.iter().filter(|x| x.required) {
if call if call.named_iter().all(|(n, _, _)| n.item != req_flag.long) {
.named_iter()
.all(|(n, _, _, _)| n.item != req_flag.long)
{
working_set.error(ParseError::MissingRequiredFlag( working_set.error(ParseError::MissingRequiredFlag(
req_flag.long.clone(), req_flag.long.clone(),
command, command,
@ -489,19 +486,18 @@ fn ensure_flag_arg_type(
arg_shape: &SyntaxShape, arg_shape: &SyntaxShape,
long_name_span: Span, long_name_span: Span,
) -> (Spanned<String>, Expression) { ) -> (Spanned<String>, Expression) {
let arg_span = arg.span(working_set);
if !type_compatible(&arg.ty, &arg_shape.to_type()) { if !type_compatible(&arg.ty, &arg_shape.to_type()) {
working_set.error(ParseError::TypeMismatch( working_set.error(ParseError::TypeMismatch(
arg_shape.to_type(), arg_shape.to_type(),
arg.ty, arg.ty,
arg_span, arg.span,
)); ));
( (
Spanned { Spanned {
item: arg_name, item: arg_name,
span: long_name_span, span: long_name_span,
}, },
Expression::garbage(working_set, arg_span), Expression::garbage(working_set, arg.span),
) )
} else { } else {
( (
@ -920,25 +916,6 @@ pub struct ParsedInternalCall {
pub output: Type, pub output: Type,
} }
// moved from call.rs since span creation must be done at parse time now
pub fn named_arg_span(
working_set: &StateWorkingSet,
named: &Spanned<String>,
short: &Option<Spanned<String>>,
expr: &Option<Expression>,
) -> Span {
let start = named.span.start;
let end = if let Some(expr) = expr {
expr.span(&working_set).end
} else if let Some(short) = short {
short.span.end
} else {
named.span.end
};
Span::new(start, end)
}
pub fn parse_internal_call( pub fn parse_internal_call(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
command_span: Span, command_span: Span,
@ -947,7 +924,7 @@ pub fn parse_internal_call(
) -> ParsedInternalCall { ) -> ParsedInternalCall {
trace!("parsing: internal call (decl id: {})", decl_id); trace!("parsing: internal call (decl id: {})", decl_id);
let mut call = Call::new(command_span, Span::concat(spans)); let mut call = Call::new(command_span);
call.decl_id = decl_id; call.decl_id = decl_id;
call.head = command_span; call.head = command_span;
let _ = working_set.add_span(call.head); let _ = working_set.add_span(call.head);
@ -1025,9 +1002,7 @@ pub fn parse_internal_call(
call.add_unknown(arg); call.add_unknown(arg);
} else { } else {
let named_span = named_arg_span(working_set, &long_name, &None, &arg); call.add_named((long_name, None, arg));
let named_span_id = working_set.add_span(named_span);
call.add_named((long_name, None, arg, named_span_id));
} }
spans_idx += 1; spans_idx += 1;
@ -1078,30 +1053,27 @@ pub fn parse_internal_call(
if flag.long.is_empty() { if flag.long.is_empty() {
if let Some(short) = flag.short { if let Some(short) = flag.short {
let named = Spanned { call.add_named((
Spanned {
item: String::new(), item: String::new(),
span: spans[spans_idx], span: spans[spans_idx],
}; },
let short = Some(Spanned { Some(Spanned {
item: short.to_string(), item: short.to_string(),
span: spans[spans_idx], span: spans[spans_idx],
}); }),
let expr = Some(arg); Some(arg),
let named_span = ));
named_arg_span(working_set, &named, &short, &expr);
let named_span_id = working_set.add_span(named_span);
call.add_named((named, short, expr, named_span_id));
} }
} else { } else {
let named = Spanned { call.add_named((
Spanned {
item: flag.long.clone(), item: flag.long.clone(),
span: spans[spans_idx], span: spans[spans_idx],
}; },
let short = None; None,
let expr = Some(arg); Some(arg),
let named_span = named_arg_span(working_set, &named, &short, &expr); ));
let named_span_id = working_set.add_span(named_span);
call.add_named((named, short, expr, named_span_id));
} }
spans_idx += 1; spans_idx += 1;
} else { } else {
@ -1112,29 +1084,27 @@ pub fn parse_internal_call(
} }
} else if flag.long.is_empty() { } else if flag.long.is_empty() {
if let Some(short) = flag.short { if let Some(short) = flag.short {
let named = Spanned { call.add_named((
Spanned {
item: String::new(), item: String::new(),
span: spans[spans_idx], span: spans[spans_idx],
}; },
let short = Some(Spanned { Some(Spanned {
item: short.to_string(), item: short.to_string(),
span: spans[spans_idx], span: spans[spans_idx],
}); }),
let expr = None; None,
let named_span = named_arg_span(working_set, &named, &short, &expr); ));
let named_span_id = working_set.add_span(named_span);
call.add_named((named, short, expr, named_span_id));
} }
} else { } else {
let named = Spanned { call.add_named((
Spanned {
item: flag.long.clone(), item: flag.long.clone(),
span: spans[spans_idx], span: spans[spans_idx],
}; },
let short = None; None,
let expr = None; None,
let named_span = named_arg_span(working_set, &named, &short, &expr); ));
let named_span_id = working_set.add_span(named_span);
call.add_named((named, short, expr, named_span_id));
} }
} }
} }
@ -1214,13 +1184,12 @@ pub fn parse_internal_call(
); );
let arg = if !type_compatible(&positional.shape.to_type(), &arg.ty) { let arg = if !type_compatible(&positional.shape.to_type(), &arg.ty) {
let arg_ty = arg.ty.clone();
working_set.error(ParseError::TypeMismatch( working_set.error(ParseError::TypeMismatch(
positional.shape.to_type(), positional.shape.to_type(),
arg_ty, arg.ty,
arg.span(working_set), arg.span,
)); ));
Expression::garbage(working_set, arg.span(working_set)) Expression::garbage(working_set, arg.span)
} else { } else {
arg arg
}; };
@ -1342,7 +1311,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
trace!("parsing: alias of external call"); trace!("parsing: alias of external call");
let mut head = head.clone(); let mut head = head.clone();
head.span_id = working_set.add_span(spans[0]); // replacing the spans preserves syntax highlighting head.span = spans[0]; // replacing the spans preserves syntax highlighting
let mut final_args = args.clone().into_vec(); let mut final_args = args.clone().into_vec();
for arg_span in &spans[1..] { for arg_span in &spans[1..] {
@ -3037,15 +3006,13 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
for item in list { for item in list {
match item { match item {
ListItem::Item(expr) => { ListItem::Item(expr) => {
let contents = let contents = working_set.get_span_contents(expr.span);
working_set.get_span_contents(expr.span(working_set)); output.push((trim_quotes(contents).to_vec(), expr.span));
output
.push((trim_quotes(contents).to_vec(), expr.span(working_set)));
} }
ListItem::Spread(_, spread) => { ListItem::Spread(_, spread) => {
working_set.error(ParseError::WrongImportPattern( working_set.error(ParseError::WrongImportPattern(
"cannot spread in an import pattern".into(), "cannot spread in an import pattern".into(),
spread.span(working_set), spread.span,
)) ))
} }
} }
@ -3055,7 +3022,7 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
.members .members
.push(ImportPatternMember::List { names: output }); .push(ImportPatternMember::List { names: output });
} else { } else {
working_set.error(ParseError::ExportNotFound(result.span(working_set))); working_set.error(ParseError::ExportNotFound(result.span));
return Expression::new( return Expression::new(
working_set, working_set,
Expr::ImportPattern(Box::new(import_pattern)), Expr::ImportPattern(Box::new(import_pattern)),
@ -3812,7 +3779,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
format!( format!(
"expected default value to be `{var_type}`" "expected default value to be `{var_type}`"
), ),
expression.span(working_set), expression.span,
), ),
) )
} }
@ -3825,7 +3792,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
Some(constant) Some(constant)
} else { } else {
working_set.error(ParseError::NonConstantDefaultValue( working_set.error(ParseError::NonConstantDefaultValue(
expression.span(working_set), expression.span,
)); ));
None None
}; };
@ -3839,7 +3806,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
working_set.error(ParseError::AssignmentMismatch( working_set.error(ParseError::AssignmentMismatch(
"Rest parameter was given a default value".into(), "Rest parameter was given a default value".into(),
"can't have default value".into(), "can't have default value".into(),
expression.span(working_set), expression.span,
)) ))
} }
Arg::Flag { Arg::Flag {
@ -3852,7 +3819,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
}, },
type_annotated, type_annotated,
} => { } => {
let expression_span = expression.span(working_set); let expression_span = expression.span;
*default_value = if let Ok(value) = *default_value = if let Ok(value) =
eval_constant(working_set, &expression) eval_constant(working_set, &expression)
@ -4098,7 +4065,7 @@ fn parse_table_row(
list.into_iter() list.into_iter()
.map(|item| match item { .map(|item| match item {
ListItem::Item(expr) => Ok(expr), ListItem::Item(expr) => Ok(expr),
ListItem::Spread(_, spread) => Err(spread.span(working_set)), ListItem::Spread(_, spread) => Err(spread.span),
}) })
.collect::<Result<_, _>>() .collect::<Result<_, _>>()
.map(|exprs| (exprs, span)) .map(|exprs| (exprs, span))
@ -4173,7 +4140,7 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr
} }
Ordering::Greater => { Ordering::Greater => {
let span = { let span = {
let start = list[head.len()].span(working_set).start; let start = list[head.len()].span.start;
let end = span.end; let end = span.end;
Span::new(start, end) Span::new(start, end)
}; };
@ -4212,7 +4179,7 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr
}; };
let ty = if working_set.parse_errors.len() == errors { let ty = if working_set.parse_errors.len() == errors {
let (ty, errs) = table_type(working_set, &head, &rows); let (ty, errs) = table_type(&head, &rows);
working_set.parse_errors.extend(errs); working_set.parse_errors.extend(errs);
ty ty
} else { } else {
@ -4227,11 +4194,7 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr
Expression::new(working_set, Expr::Table(table), span, ty) Expression::new(working_set, Expr::Table(table), span, ty)
} }
fn table_type( fn table_type(head: &[Expression], rows: &[Vec<Expression>]) -> (Type, Vec<ParseError>) {
working_set: &StateWorkingSet,
head: &[Expression],
rows: &[Vec<Expression>],
) -> (Type, Vec<ParseError>) {
let mut errors = vec![]; let mut errors = vec![];
let mut rows = rows.to_vec(); let mut rows = rows.to_vec();
let mut mk_ty = || -> Type { let mut mk_ty = || -> Type {
@ -4261,7 +4224,7 @@ fn table_type(
if let Some(str) = expr.as_string() { if let Some(str) = expr.as_string() {
str str
} else { } else {
errors.push(mk_error(expr.span(&working_set))); errors.push(mk_error(expr.span));
String::from("{ column }") String::from("{ column }")
} }
}) })
@ -5152,7 +5115,7 @@ pub fn parse_math_expression(
working_set.error(err); working_set.error(err);
} }
let op_span = Span::append(lhs.span(working_set), rhs.span(working_set)); let op_span = Span::append(lhs.span, rhs.span);
expr_stack.push(Expression::new( expr_stack.push(Expression::new(
working_set, working_set,
Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
@ -5188,7 +5151,7 @@ pub fn parse_math_expression(
working_set.error(err) working_set.error(err)
} }
let binary_op_span = Span::append(lhs.span(working_set), rhs.span(working_set)); let binary_op_span = Span::append(lhs.span, rhs.span);
expr_stack.push(Expression::new( expr_stack.push(Expression::new(
working_set, working_set,
Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
@ -5369,10 +5332,7 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
let expr = Expr::Call(Box::new(Call { let expr = Expr::Call(Box::new(Call {
head: Span::unknown(), head: Span::unknown(),
decl_id, decl_id,
arguments: Spanned { arguments,
item: arguments,
span: Span::concat(spans),
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
})); }));
@ -6134,7 +6094,7 @@ pub fn discover_captures_in_expr(
} }
} }
for arg in &call.arguments.item { for arg in &call.arguments {
match arg { match arg {
Argument::Named(named) => { Argument::Named(named) => {
if let Some(arg) = &named.2 { if let Some(arg) = &named.2 {
@ -6289,7 +6249,7 @@ pub fn discover_captures_in_expr(
} }
Expr::Var(var_id) => { Expr::Var(var_id) => {
if (*var_id > ENV_VARIABLE_ID || *var_id == IN_VARIABLE_ID) && !seen.contains(var_id) { if (*var_id > ENV_VARIABLE_ID || *var_id == IN_VARIABLE_ID) && !seen.contains(var_id) {
output.push((*var_id, expr.span(&working_set))); output.push((*var_id, expr.span));
} }
} }
Expr::VarDecl(var_id) => { Expr::VarDecl(var_id) => {
@ -6334,7 +6294,7 @@ fn wrap_element_with_collect(
} }
fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) -> Expression { fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) -> Expression {
let span = expr.span(working_set); let span = expr.span;
if let Some(decl_id) = working_set.find_decl(b"collect") { if let Some(decl_id) = working_set.find_decl(b"collect") {
let mut output = vec![]; let mut output = vec![];
@ -6364,15 +6324,14 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
Type::Any, Type::Any,
))); )));
let named = Spanned { output.push(Argument::Named((
Spanned {
item: "keep-env".to_string(), item: "keep-env".to_string(),
span: Span::unknown(), span: Span::new(0, 0),
}; },
let short = None; None,
let expr = None; None,
let named_span = named_arg_span(working_set, &named, &short, &expr); )));
let named_span_id = working_set.add_span(named_span);
output.push(Argument::Named((named, short, expr, named_span_id)));
// The containing, synthetic call to `collect`. // The containing, synthetic call to `collect`.
// We don't want to have a real span as it will confuse flattening // We don't want to have a real span as it will confuse flattening
@ -6380,11 +6339,8 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
Expression::new( Expression::new(
working_set, working_set,
Expr::Call(Box::new(Call { Expr::Call(Box::new(Call {
head: Span::unknown(), head: Span::new(0, 0),
arguments: Spanned { arguments: output,
item: output,
span: Span::unknown(),
},
decl_id, decl_id,
parser_info: HashMap::new(), parser_info: HashMap::new(),
})), })),

View file

@ -598,12 +598,9 @@ pub fn parse_call_short_flag_batch_arg_allowed() {
if let Expr::Call(call) = &element.expr.expr { if let Expr::Call(call) = &element.expr.expr {
assert_eq!(call.decl_id, 0); assert_eq!(call.decl_id, 0);
assert_eq!(call.arguments.item.len(), 2); assert_eq!(call.arguments.len(), 2);
matches!(call.arguments.item[0], Argument::Named((_, None, None, _))); matches!(call.arguments[0], Argument::Named((_, None, None)));
matches!( matches!(call.arguments[1], Argument::Named((_, None, Some(_))));
call.arguments.item[1],
Argument::Named((_, None, Some(_), _))
);
} }
} }
@ -2153,7 +2150,7 @@ mod input_types {
assert!(pipeline.elements[3].redirection.is_none()); assert!(pipeline.elements[3].redirection.is_none());
match &pipeline.elements[3].expr.expr { match &pipeline.elements[3].expr.expr {
Expr::Call(call) => { Expr::Call(call) => {
let arg = &call.arguments.item[0]; let arg = &call.arguments[0];
match arg { match arg {
Argument::Positional(a) => match &a.expr { Argument::Positional(a) => match &a.expr {
Expr::FullCellPath(path) => match &path.head.expr { Expr::FullCellPath(path) => match &path.head.expr {
@ -2350,92 +2347,3 @@ mod operator {
); );
} }
} }
#[cfg(test)]
mod test {
use nu_parser::named_arg_span;
use nu_protocol::ast::{Argument, Call, Expression};
use nu_protocol::engine::{EngineState, StateWorkingSet};
use nu_protocol::{Span, Spanned};
#[test]
fn argument_span_named() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let named_span = Span::new(2, 3);
let short_span = Span::new(5, 7);
let expr_span = Span::new(11, 13);
let _ = working_set.add_span(named_span);
let _ = working_set.add_span(short_span);
let _ = working_set.add_span(expr_span);
let named = Spanned {
item: "named".to_string(),
span: named_span,
};
let short = Spanned {
item: "short".to_string(),
span: short_span,
};
let expr = Expression::garbage(&mut working_set, expr_span);
let arg_span = named_arg_span(&working_set, &named, &None, &None);
assert_eq!(Span::new(2, 3), arg_span);
let arg_span = named_arg_span(&working_set, &named, &Some(short.clone()), &None);
assert_eq!(Span::new(2, 7), arg_span);
let arg_span = named_arg_span(&working_set, &named, &None, &Some(expr.clone()));
assert_eq!(Span::new(2, 13), arg_span);
let arg_span = named_arg_span(
&working_set,
&named,
&Some(short.clone()),
&Some(expr.clone()),
);
assert_eq!(Span::new(2, 13), arg_span);
}
#[test]
fn argument_span_positional() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let span = Span::new(2, 3);
let _ = working_set.add_span(span);
let expr = Expression::garbage(&mut working_set, span);
let arg = Argument::Positional(expr);
assert_eq!(span, arg.span(&working_set));
}
#[test]
fn argument_span_unknown() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let span = Span::new(2, 3);
let _ = working_set.add_span(span);
let expr = Expression::garbage(&mut working_set, span);
let arg = Argument::Unknown(expr);
assert_eq!(span, arg.span(&working_set));
}
#[test]
fn call_arguments_span() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let arg1_span = Span::new(2, 3);
let arg2_span = Span::new(5, 7);
let mut call = Call::new(Span::new(0, 1), Span::concat(&[arg1_span, arg2_span]));
call.add_positional(Expression::garbage(&mut working_set, arg1_span));
call.add_positional(Expression::garbage(&mut working_set, arg2_span));
assert_eq!(Span::new(2, 7), call.arguments_span());
}
}

View file

@ -34,12 +34,11 @@ impl EvaluatedCall {
stack: &mut Stack, stack: &mut Stack,
eval_expression_fn: fn(&EngineState, &mut Stack, &Expression) -> Result<Value, ShellError>, eval_expression_fn: fn(&EngineState, &mut Stack, &Expression) -> Result<Value, ShellError>,
) -> Result<Self, ShellError> { ) -> Result<Self, ShellError> {
let positional = call.rest_iter_flattened(&engine_state, 0, |expr| { let positional =
eval_expression_fn(engine_state, stack, expr) call.rest_iter_flattened(0, |expr| eval_expression_fn(engine_state, stack, expr))?;
})?;
let mut named = Vec::with_capacity(call.named_len()); let mut named = Vec::with_capacity(call.named_len());
for (string, _, expr, _) in call.named_iter() { for (string, _, expr) in call.named_iter() {
let value = match expr { let value = match expr {
None => None, None => None,
Some(expr) => Some(eval_expression_fn(engine_state, stack, expr)?), Some(expr) => Some(eval_expression_fn(engine_state, stack, expr)?),

View file

@ -4,47 +4,42 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
ast::Expression, engine::StateWorkingSet, eval_const::eval_constant, DeclId, FromValue, ast::Expression, engine::StateWorkingSet, eval_const::eval_constant, DeclId, FromValue,
GetSpan, ShellError, Span, SpanId, Spanned, Value, ShellError, Span, Spanned, Value,
}; };
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Argument { pub enum Argument {
Positional(Expression), Positional(Expression),
Named( Named((Spanned<String>, Option<Spanned<String>>, Option<Expression>)),
(
Spanned<String>,
Option<Spanned<String>>,
Option<Expression>,
SpanId,
),
),
Unknown(Expression), // unknown argument used in "fall-through" signatures Unknown(Expression), // unknown argument used in "fall-through" signatures
Spread(Expression), // a list spread to fill in rest arguments Spread(Expression), // a list spread to fill in rest arguments
} }
impl Argument { impl Argument {
pub fn span_id(&self) -> SpanId {
match self {
Argument::Positional(e) => e.span_id,
Argument::Named((_, _, _, span_id)) => *span_id,
Argument::Unknown(e) => e.span_id,
Argument::Spread(e) => e.span_id,
}
}
/// The span for an argument /// The span for an argument
pub fn span(&self, state: &impl GetSpan) -> Span { pub fn span(&self) -> Span {
match self { match self {
Argument::Positional(e) => e.span(state), Argument::Positional(e) => e.span,
Argument::Named((_, _, _, span_id)) => state.get_span(*span_id), Argument::Named((named, short, expr)) => {
Argument::Unknown(e) => e.span(state), let start = named.span.start;
Argument::Spread(e) => e.span(state), let end = if let Some(expr) = expr {
expr.span.end
} else if let Some(short) = short {
short.span.end
} else {
named.span.end
};
Span::new(start, end)
}
Argument::Unknown(e) => e.span,
Argument::Spread(e) => e.span,
} }
} }
pub fn expr(&self) -> Option<&Expression> { pub fn expr(&self) -> Option<&Expression> {
match self { match self {
Argument::Named((_, _, expr, _)) => expr.as_ref(), Argument::Named((_, _, expr)) => expr.as_ref(),
Argument::Positional(expr) | Argument::Unknown(expr) | Argument::Spread(expr) => { Argument::Positional(expr) | Argument::Unknown(expr) | Argument::Spread(expr) => {
Some(expr) Some(expr)
} }
@ -63,20 +58,17 @@ pub struct Call {
/// identifier of the declaration to call /// identifier of the declaration to call
pub decl_id: DeclId, pub decl_id: DeclId,
pub head: Span, pub head: Span,
pub arguments: Spanned<Vec<Argument>>, pub arguments: Vec<Argument>,
/// this field is used by the parser to pass additional command-specific information /// this field is used by the parser to pass additional command-specific information
pub parser_info: HashMap<String, Expression>, pub parser_info: HashMap<String, Expression>,
} }
impl Call { impl Call {
pub fn new(head: Span, args_span: Span) -> Call { pub fn new(head: Span) -> Call {
Self { Self {
decl_id: 0, decl_id: 0,
head, head,
arguments: Spanned { arguments: vec![],
item: vec![],
span: args_span,
},
parser_info: HashMap::new(), parser_info: HashMap::new(),
} }
} }
@ -88,20 +80,23 @@ impl Call {
/// If there are one or more arguments the span encompasses the start of the first argument to /// If there are one or more arguments the span encompasses the start of the first argument to
/// end of the last argument /// end of the last argument
pub fn arguments_span(&self) -> Span { pub fn arguments_span(&self) -> Span {
self.arguments.span let past = self.head.past();
let start = self
.arguments
.first()
.map(|a| a.span())
.unwrap_or(past)
.start;
let end = self.arguments.last().map(|a| a.span()).unwrap_or(past).end;
Span::new(start, end)
} }
pub fn named_iter( pub fn named_iter(
&self, &self,
) -> impl Iterator< ) -> impl Iterator<Item = &(Spanned<String>, Option<Spanned<String>>, Option<Expression>)> {
Item = &( self.arguments.iter().filter_map(|arg| match arg {
Spanned<String>,
Option<Spanned<String>>,
Option<Expression>,
SpanId,
),
> {
self.arguments.item.iter().filter_map(|arg| match arg {
Argument::Named(named) => Some(named), Argument::Named(named) => Some(named),
Argument::Positional(_) => None, Argument::Positional(_) => None,
Argument::Unknown(_) => None, Argument::Unknown(_) => None,
@ -111,15 +106,9 @@ impl Call {
pub fn named_iter_mut( pub fn named_iter_mut(
&mut self, &mut self,
) -> impl Iterator< ) -> impl Iterator<Item = &mut (Spanned<String>, Option<Spanned<String>>, Option<Expression>)>
Item = &mut ( {
Spanned<String>, self.arguments.iter_mut().filter_map(|arg| match arg {
Option<Spanned<String>>,
Option<Expression>,
SpanId,
),
> {
self.arguments.item.iter_mut().filter_map(|arg| match arg {
Argument::Named(named) => Some(named), Argument::Named(named) => Some(named),
Argument::Positional(_) => None, Argument::Positional(_) => None,
Argument::Unknown(_) => None, Argument::Unknown(_) => None,
@ -133,31 +122,25 @@ impl Call {
pub fn add_named( pub fn add_named(
&mut self, &mut self,
named: ( named: (Spanned<String>, Option<Spanned<String>>, Option<Expression>),
Spanned<String>,
Option<Spanned<String>>,
Option<Expression>,
SpanId,
),
) { ) {
self.arguments.item.push(Argument::Named(named)); self.arguments.push(Argument::Named(named));
} }
pub fn add_positional(&mut self, positional: Expression) { pub fn add_positional(&mut self, positional: Expression) {
self.arguments.item.push(Argument::Positional(positional)); self.arguments.push(Argument::Positional(positional));
} }
pub fn add_unknown(&mut self, unknown: Expression) { pub fn add_unknown(&mut self, unknown: Expression) {
self.arguments.item.push(Argument::Unknown(unknown)); self.arguments.push(Argument::Unknown(unknown));
} }
pub fn add_spread(&mut self, args: Expression) { pub fn add_spread(&mut self, args: Expression) {
self.arguments.item.push(Argument::Spread(args)); self.arguments.push(Argument::Spread(args));
} }
pub fn positional_iter(&self) -> impl Iterator<Item = &Expression> { pub fn positional_iter(&self) -> impl Iterator<Item = &Expression> {
self.arguments self.arguments
.item
.iter() .iter()
.take_while(|arg| match arg { .take_while(|arg| match arg {
Argument::Spread(_) => false, // Don't include positional arguments given to rest parameter Argument::Spread(_) => false, // Don't include positional arguments given to rest parameter
@ -185,7 +168,6 @@ impl Call {
// todo maybe rewrite to be more elegant or something // todo maybe rewrite to be more elegant or something
let args = self let args = self
.arguments .arguments
.item
.iter() .iter()
.filter_map(|arg| match arg { .filter_map(|arg| match arg {
Argument::Named(_) => None, Argument::Named(_) => None,
@ -276,9 +258,9 @@ impl Call {
) -> Result<Vec<T>, ShellError> { ) -> Result<Vec<T>, ShellError> {
let mut output = vec![]; let mut output = vec![];
for result in self.rest_iter_flattened(&working_set, starting_pos, |expr| { for result in
eval_constant(working_set, expr) self.rest_iter_flattened(starting_pos, |expr| eval_constant(working_set, expr))?
})? { {
output.push(FromValue::from_value(result)?); output.push(FromValue::from_value(result)?);
} }
@ -287,7 +269,6 @@ impl Call {
pub fn rest_iter_flattened<F>( pub fn rest_iter_flattened<F>(
&self, &self,
state: &impl GetSpan,
start: usize, start: usize,
mut eval: F, mut eval: F,
) -> Result<Vec<Value>, ShellError> ) -> Result<Vec<Value>, ShellError>
@ -301,11 +282,7 @@ impl Call {
if spread { if spread {
match result { match result {
Value::List { mut vals, .. } => output.append(&mut vals), Value::List { mut vals, .. } => output.append(&mut vals),
_ => { _ => return Err(ShellError::CannotSpreadAsList { span: expr.span }),
return Err(ShellError::CannotSpreadAsList {
span: expr.span(state),
})
}
} }
} else { } else {
output.push(result); output.push(result);
@ -333,23 +310,23 @@ impl Call {
} }
} }
pub fn span(&self, state: &impl GetSpan) -> Span { pub fn span(&self) -> Span {
let mut span = self.head; let mut span = self.head;
for positional in self.positional_iter() { for positional in self.positional_iter() {
if positional.span(state).end > span.end { if positional.span.end > span.end {
span.end = positional.span(state).end; span.end = positional.span.end;
} }
} }
for (named, _, val, _) in self.named_iter() { for (named, _, val) in self.named_iter() {
if named.span.end > span.end { if named.span.end > span.end {
span.end = named.span.end; span.end = named.span.end;
} }
if let Some(val) = &val { if let Some(val) = &val {
if val.span(state).end > span.end { if val.span.end > span.end {
span.end = val.span(state).end; span.end = val.span.end;
} }
} }
} }
@ -357,3 +334,77 @@ impl Call {
span span
} }
} }
#[cfg(test)]
mod test {
use super::*;
use crate::engine::EngineState;
#[test]
fn argument_span_named() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let named = Spanned {
item: "named".to_string(),
span: Span::new(2, 3),
};
let short = Spanned {
item: "short".to_string(),
span: Span::new(5, 7),
};
let expr = Expression::garbage(&mut working_set, Span::new(11, 13));
let arg = Argument::Named((named.clone(), None, None));
assert_eq!(Span::new(2, 3), arg.span());
let arg = Argument::Named((named.clone(), Some(short.clone()), None));
assert_eq!(Span::new(2, 7), arg.span());
let arg = Argument::Named((named.clone(), None, Some(expr.clone())));
assert_eq!(Span::new(2, 13), arg.span());
let arg = Argument::Named((named.clone(), Some(short.clone()), Some(expr.clone())));
assert_eq!(Span::new(2, 13), arg.span());
}
#[test]
fn argument_span_positional() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let span = Span::new(2, 3);
let expr = Expression::garbage(&mut working_set, span);
let arg = Argument::Positional(expr);
assert_eq!(span, arg.span());
}
#[test]
fn argument_span_unknown() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let span = Span::new(2, 3);
let expr = Expression::garbage(&mut working_set, span);
let arg = Argument::Unknown(expr);
assert_eq!(span, arg.span());
}
#[test]
fn call_arguments_span() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let mut call = Call::new(Span::new(0, 1));
call.add_positional(Expression::garbage(&mut working_set, Span::new(2, 3)));
call.add_positional(Expression::garbage(&mut working_set, Span::new(5, 7)));
assert_eq!(Span::new(2, 7), call.arguments_span());
}
}

View file

@ -173,7 +173,7 @@ impl Expression {
Expr::Binary(_) => false, Expr::Binary(_) => false,
Expr::Bool(_) => false, Expr::Bool(_) => false,
Expr::Call(call) => { Expr::Call(call) => {
for arg in &call.arguments.item { for arg in &call.arguments {
match arg { match arg {
Argument::Positional(expr) Argument::Positional(expr)
| Argument::Unknown(expr) | Argument::Unknown(expr)
@ -366,7 +366,7 @@ impl Expression {
if replaced.contains_span(call.head) { if replaced.contains_span(call.head) {
call.head = new_span; call.head = new_span;
} }
for arg in call.arguments.item.iter_mut() { for arg in call.arguments.iter_mut() {
match arg { match arg {
Argument::Positional(expr) Argument::Positional(expr)
| Argument::Unknown(expr) | Argument::Unknown(expr)

View file

@ -1023,34 +1023,18 @@ impl<'a> StateWorkingSet<'a> {
impl<'a> GetSpan for &'a StateWorkingSet<'a> { impl<'a> GetSpan for &'a StateWorkingSet<'a> {
fn get_span(&self, span_id: SpanId) -> Span { fn get_span(&self, span_id: SpanId) -> Span {
get_span(self, span_id) let num_permanent_spans = self.permanent_state.num_spans();
}
}
impl<'a> GetSpan for &'a mut StateWorkingSet<'a> {
fn get_span(&self, span_id: SpanId) -> Span {
get_span(self, span_id)
}
}
impl<'a> GetSpan for StateWorkingSet<'a> {
fn get_span(&self, span_id: SpanId) -> Span {
get_span(self, span_id)
}
}
fn get_span(working_set: &StateWorkingSet, span_id: SpanId) -> Span {
let num_permanent_spans = working_set.permanent_state.num_spans();
if span_id.0 < num_permanent_spans { if span_id.0 < num_permanent_spans {
working_set.permanent_state.get_span(span_id) self.permanent_state.get_span(span_id)
} else { } else {
*working_set *self
.delta .delta
.spans .spans
.get(span_id.0 - num_permanent_spans) .get(span_id.0 - num_permanent_spans)
.expect("internal error: missing span") .expect("internal error: missing span")
} }
} }
}
impl<'a> miette::SourceCode for &StateWorkingSet<'a> { impl<'a> miette::SourceCode for &StateWorkingSet<'a> {
fn read_span<'b>( fn read_span<'b>(

View file

@ -301,7 +301,7 @@ fn eval_const_call(
return Err(ShellError::NotAConstCommand { span: call.head }); return Err(ShellError::NotAConstCommand { span: call.head });
} }
if !decl.is_known_external() && call.named_iter().any(|(flag, _, _, _)| flag.item == "help") { if !decl.is_known_external() && call.named_iter().any(|(flag, _, _)| flag.item == "help") {
// It would require re-implementing get_full_help() for const evaluation. Assuming that // It would require re-implementing get_full_help() for const evaluation. Assuming that
// getting help messages at parse-time is rare enough, we can simply disallow it. // getting help messages at parse-time is rare enough, we can simply disallow it.
return Err(ShellError::NotAConstHelp { span: call.head }); return Err(ShellError::NotAConstHelp { span: call.head });

View file

@ -567,7 +567,7 @@ impl PipelineData {
if command.block_id().is_some() { if command.block_id().is_some() {
self.write_all_and_flush(engine_state, no_newline, to_stderr) self.write_all_and_flush(engine_state, no_newline, to_stderr)
} else { } else {
let call = Call::new(Span::unknown(), Span::unknown()); let call = Call::new(Span::new(0, 0));
let table = command.run(engine_state, stack, &call, self)?; let table = command.run(engine_state, stack, &call, self)?;
table.write_all_and_flush(engine_state, no_newline, to_stderr) table.write_all_and_flush(engine_state, no_newline, to_stderr)
} }