mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
Span ID Refactor (Step 2): Make Call SpanId-friendly (#13268)
<!-- 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. --> Part of https://github.com/nushell/nushell/issues/12963, step 2. This PR refactors Call and related argument structures to remove their dependency on `Expression::span` which will be removed in the future. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> Should be none. If you see some error messages that look broken, please report. # 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:
parent
9b63e17072
commit
0cfd5fbece
31 changed files with 468 additions and 296 deletions
|
@ -62,7 +62,7 @@ impl Command for KeybindingsList {
|
|||
.collect()
|
||||
} else {
|
||||
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()
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use nu_protocol::{
|
|||
ast::{Argument, Call, Expr, Expression},
|
||||
debugger::WithoutDebug,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
PipelineData, Span, Type, Value,
|
||||
PipelineData, Span, Spanned, Type, Value,
|
||||
};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use std::collections::HashMap;
|
||||
|
@ -51,18 +51,21 @@ impl Completer for CustomCompletion {
|
|||
&Call {
|
||||
decl_id: self.decl_id,
|
||||
head: span,
|
||||
arguments: vec![
|
||||
Argument::Positional(Expression::new_unknown(
|
||||
Expr::String(self.line.clone()),
|
||||
Span::unknown(),
|
||||
Type::String,
|
||||
)),
|
||||
Argument::Positional(Expression::new_unknown(
|
||||
Expr::Int(line_pos as i64),
|
||||
Span::unknown(),
|
||||
Type::Int,
|
||||
)),
|
||||
],
|
||||
arguments: Spanned {
|
||||
item: vec![
|
||||
Argument::Positional(Expression::new_unknown(
|
||||
Expr::String(self.line.clone()),
|
||||
Span::unknown(),
|
||||
Type::String,
|
||||
)),
|
||||
Argument::Positional(Expression::new_unknown(
|
||||
Expr::Int(line_pos as i64),
|
||||
Span::unknown(),
|
||||
Type::Int,
|
||||
)),
|
||||
],
|
||||
span: Span::unknown(),
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
},
|
||||
PipelineData::empty(),
|
||||
|
|
|
@ -400,7 +400,7 @@ fn find_matching_block_end_in_expr(
|
|||
}
|
||||
}
|
||||
|
||||
Expr::Call(call) => call.arguments.iter().find_map(|arg| {
|
||||
Expr::Call(call) => call.arguments.item.iter().find_map(|arg| {
|
||||
arg.expr().and_then(|expr| {
|
||||
find_matching_block_end_in_expr(
|
||||
line,
|
||||
|
|
|
@ -49,7 +49,7 @@ impl Command for BytesBuild {
|
|||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let mut output = vec![];
|
||||
for val in call.rest_iter_flattened(0, |expr| {
|
||||
for val in call.rest_iter_flattened(&engine_state, 0, |expr| {
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
eval_expression(engine_state, stack, expr)
|
||||
})? {
|
||||
|
|
|
@ -111,11 +111,11 @@ fn get_arguments(
|
|||
) -> Vec<Value> {
|
||||
let mut arg_value = vec![];
|
||||
let span = Span::test_data();
|
||||
for arg in &call.arguments {
|
||||
for arg in &call.arguments.item {
|
||||
match arg {
|
||||
// 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. :)
|
||||
Argument::Named((name, short, opt_expr)) => {
|
||||
Argument::Named((name, short, opt_expr, _)) => {
|
||||
let arg_type = "named";
|
||||
let arg_value_name = name.item.clone();
|
||||
let arg_value_name_span_start = name.span.start as i64;
|
||||
|
|
|
@ -104,7 +104,7 @@ confusing the id/parent_id hierarchy. The --expr flag is helpful for investigati
|
|||
collect_values,
|
||||
collect_exprs,
|
||||
collect_lines,
|
||||
call.span(),
|
||||
call.span(&engine_state),
|
||||
);
|
||||
|
||||
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?;
|
||||
|
||||
// Collect the output
|
||||
let _ = pipeline_data.into_value(call.span());
|
||||
let _ = pipeline_data.into_value(call.span(&engine_state));
|
||||
|
||||
Ok(engine_state
|
||||
.deactivate_debugger()
|
||||
.map_err(lock_err)?
|
||||
.report(engine_state, call.span())?
|
||||
.report(engine_state, call.span(&engine_state))?
|
||||
.into_pipeline_data())
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,12 @@ impl Command for Open {
|
|||
let block = engine_state.get_block(block_id);
|
||||
eval_block(engine_state, stack, block, stream)
|
||||
} else {
|
||||
decl.run(engine_state, stack, &Call::new(call_span), stream)
|
||||
decl.run(
|
||||
engine_state,
|
||||
stack,
|
||||
&Call::new(call_span, call.arguments_span()),
|
||||
stream,
|
||||
)
|
||||
};
|
||||
output.push(command_output.map_err(|inner| {
|
||||
ShellError::GenericError{
|
||||
|
|
|
@ -398,7 +398,7 @@ fn convert_to_extension(
|
|||
let eval_block = get_eval_block(engine_state);
|
||||
eval_block(engine_state, stack, block, input)
|
||||
} else {
|
||||
decl.run(engine_state, stack, &Call::new(span), input)
|
||||
decl.run(engine_state, stack, &Call::new(span, span.past()), input)
|
||||
}
|
||||
} else {
|
||||
Ok(input)
|
||||
|
|
|
@ -103,7 +103,7 @@ pub fn get_rest_for_glob_pattern(
|
|||
let mut output = vec![];
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
|
||||
for result in call.rest_iter_flattened(starting_pos, |expr| {
|
||||
for result in call.rest_iter_flattened(&engine_state, starting_pos, |expr| {
|
||||
let result = eval_expression(engine_state, stack, expr);
|
||||
match result {
|
||||
Err(e) => Err(e),
|
||||
|
|
|
@ -141,7 +141,7 @@ fn from_csv(
|
|||
} else {
|
||||
return Err(ShellError::NonUtf8Custom {
|
||||
msg: "separator should be a single char or a 4-byte unicode".into(),
|
||||
span: call.span(),
|
||||
span: call.span(&engine_state),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use nu_color_config::StyleComputer;
|
|||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::ast::{Expr, Expression};
|
||||
|
||||
use nu_protocol::engine::UNKNOWN_SPAN_ID;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -143,7 +144,7 @@ pub fn cal(
|
|||
style_computer,
|
||||
)?;
|
||||
|
||||
let mut table_no_index = Call::new(Span::unknown());
|
||||
let mut table_no_index = Call::new(Span::unknown(), Span::unknown());
|
||||
table_no_index.add_named((
|
||||
Spanned {
|
||||
item: "index".to_string(),
|
||||
|
@ -155,6 +156,7 @@ pub fn cal(
|
|||
Span::unknown(),
|
||||
Type::Bool,
|
||||
)),
|
||||
UNKNOWN_SPAN_ID,
|
||||
));
|
||||
|
||||
let cal_table_output =
|
||||
|
|
|
@ -412,7 +412,7 @@ fn display(help: &str, engine_state: &EngineState, stack: &mut Stack, span: Span
|
|||
let result = decl.run(
|
||||
engine_state,
|
||||
stack,
|
||||
&Call::new(span),
|
||||
&Call::new(span, span.past()),
|
||||
Value::string(item, Span::unknown()).into_pipeline_data(),
|
||||
);
|
||||
|
||||
|
|
|
@ -547,7 +547,7 @@ fn transform_response_using_content_type(
|
|||
Some(converter_id) => engine_state.get_decl(converter_id).run(
|
||||
engine_state,
|
||||
stack,
|
||||
&Call::new(span),
|
||||
&Call::new(span, span.past()),
|
||||
output,
|
||||
),
|
||||
None => Ok(output),
|
||||
|
|
|
@ -58,7 +58,12 @@ impl Command for IsTerminal {
|
|||
_ => {
|
||||
return Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "Only one stream may be checked".into(),
|
||||
span: Span::merge_many(call.arguments.iter().map(|arg| arg.span())),
|
||||
span: Span::merge_many(
|
||||
call.arguments
|
||||
.item
|
||||
.iter()
|
||||
.map(|arg| arg.span(&engine_state)),
|
||||
),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -375,8 +375,12 @@ fn write_pipeline_data(
|
|||
Arc::make_mut(&mut engine_state.config).use_ansi_coloring = false;
|
||||
|
||||
// Invoke the `table` command.
|
||||
let output =
|
||||
crate::Table.run(&engine_state, &mut stack, &Call::new(Span::unknown()), data)?;
|
||||
let output = crate::Table.run(
|
||||
&engine_state,
|
||||
&mut stack,
|
||||
&Call::new(Span::unknown(), Span::unknown()),
|
||||
data,
|
||||
)?;
|
||||
|
||||
// Write the output.
|
||||
for value in output {
|
||||
|
|
|
@ -127,7 +127,7 @@ impl Command for Table {
|
|||
return Ok(val.into_pipeline_data());
|
||||
}
|
||||
|
||||
let cfg = parse_table_config(call, engine_state, stack)?;
|
||||
let cfg = parse_table_config(engine_state, call, engine_state, stack)?;
|
||||
let input = CmdInput::new(engine_state, stack, call, input);
|
||||
|
||||
// reset vt processing, aka ansi because illbehaved externals can break it
|
||||
|
@ -247,6 +247,7 @@ impl TableConfig {
|
|||
}
|
||||
|
||||
fn parse_table_config(
|
||||
engine_state: &EngineState,
|
||||
call: &Call,
|
||||
state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
|
@ -269,9 +270,9 @@ fn parse_table_config(
|
|||
flatten_separator,
|
||||
},
|
||||
};
|
||||
let theme =
|
||||
get_theme_flag(call, state, stack)?.unwrap_or_else(|| get_config(state, stack).table_mode);
|
||||
let index = get_index_flag(call, state, stack)?;
|
||||
let theme = get_theme_flag(engine_state, call, state, stack)?
|
||||
.unwrap_or_else(|| get_config(state, stack).table_mode);
|
||||
let index = get_index_flag(engine_state, call, state, stack)?;
|
||||
|
||||
let term_width = get_width_param(width_param);
|
||||
|
||||
|
@ -285,6 +286,7 @@ fn parse_table_config(
|
|||
}
|
||||
|
||||
fn get_index_flag(
|
||||
engine_state: &EngineState,
|
||||
call: &Call,
|
||||
state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
|
@ -308,7 +310,7 @@ fn get_index_flag(
|
|||
Err(ShellError::UnsupportedInput {
|
||||
msg: String::from("got a negative integer"),
|
||||
input: val.to_string(),
|
||||
msg_span: call.span(),
|
||||
msg_span: call.span(&engine_state),
|
||||
input_span: internal_span,
|
||||
})
|
||||
} else {
|
||||
|
@ -319,13 +321,14 @@ fn get_index_flag(
|
|||
_ => Err(ShellError::CantConvert {
|
||||
to_type: String::from("index"),
|
||||
from_type: String::new(),
|
||||
span: call.span(),
|
||||
span: call.span(&engine_state),
|
||||
help: Some(String::from("supported values: [bool, int, nothing]")),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_theme_flag(
|
||||
engine_state: &EngineState,
|
||||
call: &Call,
|
||||
state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
|
@ -335,7 +338,7 @@ fn get_theme_flag(
|
|||
TableMode::from_str(&theme).map_err(|err| ShellError::CantConvert {
|
||||
to_type: String::from("theme"),
|
||||
from_type: String::from("string"),
|
||||
span: call.span(),
|
||||
span: call.span(&engine_state),
|
||||
help: Some(format!("{}, but found '{}'.", err, theme)),
|
||||
})
|
||||
})
|
||||
|
|
|
@ -113,7 +113,7 @@ impl CallExt for Call {
|
|||
let stack = &mut stack.use_call_arg_out_dest();
|
||||
let mut output = vec![];
|
||||
|
||||
for result in self.rest_iter_flattened(starting_pos, |expr| {
|
||||
for result in self.rest_iter_flattened(&engine_state, starting_pos, |expr| {
|
||||
eval_expression::<WithoutDebug>(engine_state, stack, expr)
|
||||
})? {
|
||||
output.push(FromValue::from_value(result)?);
|
||||
|
|
|
@ -48,7 +48,7 @@ fn nu_highlight_string(code_string: &str, engine_state: &EngineState, stack: &mu
|
|||
if let Ok(output) = decl.run(
|
||||
engine_state,
|
||||
stack,
|
||||
&Call::new(Span::unknown()),
|
||||
&Call::new(Span::unknown(), Span::unknown()),
|
||||
Value::string(code_string, Span::unknown()).into_pipeline_data(),
|
||||
) {
|
||||
let result = output.into_value(Span::unknown());
|
||||
|
@ -241,7 +241,10 @@ fn get_documentation(
|
|||
&Call {
|
||||
decl_id,
|
||||
head: span,
|
||||
arguments: vec![],
|
||||
arguments: Spanned {
|
||||
item: vec![],
|
||||
span: span.past(),
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
},
|
||||
PipelineData::Value(Value::list(vals, span), None),
|
||||
|
@ -273,7 +276,7 @@ fn get_documentation(
|
|||
match decl.run(
|
||||
engine_state,
|
||||
stack,
|
||||
&Call::new(Span::unknown()),
|
||||
&Call::new(Span::unknown(), Span::unknown()),
|
||||
Value::string(example.example, Span::unknown()).into_pipeline_data(),
|
||||
) {
|
||||
Ok(output) => {
|
||||
|
@ -296,7 +299,7 @@ fn get_documentation(
|
|||
}
|
||||
|
||||
if let Some(result) = &example.result {
|
||||
let mut table_call = Call::new(Span::unknown());
|
||||
let mut table_call = Call::new(Span::unknown(), Span::unknown());
|
||||
if example.example.ends_with("--collapse") {
|
||||
// collapse the result
|
||||
table_call.add_named((
|
||||
|
@ -306,6 +309,7 @@ fn get_documentation(
|
|||
},
|
||||
None,
|
||||
None,
|
||||
UNKNOWN_SPAN_ID,
|
||||
))
|
||||
} else {
|
||||
// expand the result
|
||||
|
@ -316,6 +320,7 @@ fn get_documentation(
|
|||
},
|
||||
None,
|
||||
None,
|
||||
UNKNOWN_SPAN_ID,
|
||||
))
|
||||
}
|
||||
let table = engine_state
|
||||
|
@ -368,13 +373,17 @@ fn get_ansi_color_for_component_or_default(
|
|||
// Call ansi command using argument
|
||||
if let Some(argument) = argument_opt {
|
||||
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>(
|
||||
engine_state,
|
||||
caller_stack,
|
||||
&Call {
|
||||
decl_id,
|
||||
head: span,
|
||||
arguments: vec![argument],
|
||||
arguments: Spanned {
|
||||
item: vec![argument],
|
||||
span: arg_span,
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
},
|
||||
PipelineData::Empty,
|
||||
|
|
|
@ -26,7 +26,7 @@ pub fn eval_call<D: DebugContext>(
|
|||
}
|
||||
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);
|
||||
Ok(Value::string(help, call.head).into_pipeline_data())
|
||||
} else if let Some(block_id) = decl.block_id() {
|
||||
|
@ -100,6 +100,7 @@ pub fn eval_call<D: DebugContext>(
|
|||
let mut rest_items = vec![];
|
||||
|
||||
for result in call.rest_iter_flattened(
|
||||
&engine_state,
|
||||
decl.signature().required_positional.len()
|
||||
+ decl.signature().optional_positional.len(),
|
||||
|expr| eval_expression::<D>(engine_state, caller_stack, expr),
|
||||
|
@ -213,8 +214,16 @@ fn eval_external(
|
|||
})?;
|
||||
|
||||
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));
|
||||
let mut call = Call::new(head.span(&engine_state), Span::concat(&spans));
|
||||
|
||||
call.add_positional(head.clone());
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ fn flatten_expression_into(
|
|||
}
|
||||
|
||||
let arg_start = output.len();
|
||||
for arg in &call.arguments {
|
||||
for arg in &call.arguments.item {
|
||||
match arg {
|
||||
Argument::Positional(positional) | Argument::Unknown(positional) => {
|
||||
flatten_expression_into(working_set, positional, output)
|
||||
|
|
|
@ -43,7 +43,7 @@ impl Command for KnownExternal {
|
|||
|
||||
let command = engine_state.get_decl(decl_id);
|
||||
|
||||
let mut extern_call = Call::new(head_span);
|
||||
let mut extern_call = Call::new(head_span, call.arguments_span());
|
||||
|
||||
let extern_name = if let Some(name_bytes) = engine_state.find_decl_name(call.decl_id, &[]) {
|
||||
String::from_utf8_lossy(name_bytes)
|
||||
|
@ -78,7 +78,7 @@ impl Command for KnownExternal {
|
|||
));
|
||||
}
|
||||
|
||||
for arg in &call.arguments {
|
||||
for arg in &call.arguments.item {
|
||||
match arg {
|
||||
Argument::Positional(positional) => extern_call.add_positional(positional.clone()),
|
||||
Argument::Named(named) => {
|
||||
|
|
|
@ -21,8 +21,9 @@ pub use nu_protocol::parser_path::*;
|
|||
pub use parse_keywords::*;
|
||||
|
||||
pub use parser::{
|
||||
is_math_expression_like, parse, parse_block, parse_expression, parse_external_call,
|
||||
parse_unit_value, trim_quotes, trim_quotes_str, unescape_unquote_string, DURATION_UNIT_GROUPS,
|
||||
is_math_expression_like, named_arg_span, parse, parse_block, parse_expression,
|
||||
parse_external_call, parse_unit_value, trim_quotes, trim_quotes_str, unescape_unquote_string,
|
||||
DURATION_UNIT_GROUPS,
|
||||
};
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
|
|
|
@ -123,8 +123,8 @@ pub fn parse_keyword(working_set: &mut StateWorkingSet, lite_command: &LiteComma
|
|||
// Apply parse keyword side effects
|
||||
let cmd = working_set.get_decl(call.decl_id);
|
||||
// check help flag first.
|
||||
if call.named_iter().any(|(flag, _, _)| flag.item == "help") {
|
||||
let call_span = call.span();
|
||||
if call.named_iter().any(|(flag, _, _, _)| flag.item == "help") {
|
||||
let call_span = call.span(working_set);
|
||||
return Pipeline::from_vec(vec![Expression::new(
|
||||
working_set,
|
||||
Expr::Call(call),
|
||||
|
@ -1056,7 +1056,7 @@ pub fn parse_alias(
|
|||
// First from comments, if any are present
|
||||
false => working_set.build_usage(&lite_command.comments),
|
||||
// Then from the command itself
|
||||
true => match alias_call.arguments.get(1) {
|
||||
true => match alias_call.arguments.item.get(1) {
|
||||
Some(Argument::Positional(Expression {
|
||||
expr: Expr::Keyword(kw),
|
||||
..
|
||||
|
@ -1258,7 +1258,10 @@ pub fn parse_export_in_module(
|
|||
let mut call = Box::new(Call {
|
||||
head: spans[0],
|
||||
decl_id: export_decl_id,
|
||||
arguments: vec![],
|
||||
arguments: Spanned {
|
||||
item: vec![],
|
||||
span: spans[0].past(),
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
|
@ -2263,13 +2266,21 @@ pub fn parse_module(
|
|||
.find_decl(b"module")
|
||||
.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 {
|
||||
head: Span::concat(&spans[..split_id]),
|
||||
decl_id: module_decl_id,
|
||||
arguments: vec![
|
||||
Argument::Positional(module_name_or_path_expr),
|
||||
Argument::Positional(block_expr),
|
||||
],
|
||||
arguments: Spanned {
|
||||
item: vec![
|
||||
Argument::Positional(module_name_or_path_expr),
|
||||
Argument::Positional(block_expr),
|
||||
],
|
||||
span: args_span,
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
|
@ -2701,7 +2712,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 {
|
||||
let call_span = call.span();
|
||||
let call_span = call.span(working_set);
|
||||
|
||||
let (overlay_name, _) = if let Some(expr) = call.positional_nth(0) {
|
||||
match eval_constant(working_set, expr) {
|
||||
|
@ -2750,7 +2761,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 {
|
||||
let call_span = call.span();
|
||||
let call_span = call.span(working_set);
|
||||
|
||||
let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
|
||||
match eval_constant(working_set, expr) {
|
||||
|
@ -2973,7 +2984,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 {
|
||||
let call_span = call.span();
|
||||
let call_span = call.span(working_set);
|
||||
|
||||
let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
|
||||
match eval_constant(working_set, expr) {
|
||||
|
@ -3113,10 +3124,16 @@ 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 {
|
||||
decl_id,
|
||||
head: spans[0],
|
||||
arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
|
||||
arguments: Spanned {
|
||||
item: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
|
||||
span: args_span,
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
|
@ -3259,10 +3276,16 @@ 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 {
|
||||
decl_id,
|
||||
head: spans[0],
|
||||
arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
|
||||
arguments: Spanned {
|
||||
item: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
|
||||
span: args_span,
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
|
@ -3378,10 +3401,16 @@ 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 {
|
||||
decl_id,
|
||||
head: spans[0],
|
||||
arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
|
||||
arguments: Spanned {
|
||||
item: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
|
||||
span: args_span,
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
|
@ -3884,8 +3913,8 @@ pub fn parse_plugin_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> P
|
|||
|
||||
let plugin_config = call
|
||||
.named_iter()
|
||||
.find(|(arg_name, _, _)| arg_name.item == "plugin-config")
|
||||
.map(|(_, _, expr)| {
|
||||
.find(|(arg_name, _, _, _)| arg_name.item == "plugin-config")
|
||||
.map(|(_, _, expr, _)| {
|
||||
let expr = expr
|
||||
.as_ref()
|
||||
.expect("--plugin-config arg should have been checked already");
|
||||
|
@ -3961,7 +3990,7 @@ pub fn parse_plugin_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> P
|
|||
working_set.error(err);
|
||||
}
|
||||
|
||||
let call_span = call.span();
|
||||
let call_span = call.span(working_set);
|
||||
|
||||
Pipeline::from_vec(vec![Expression::new(
|
||||
working_set,
|
||||
|
@ -4147,6 +4176,6 @@ fn detect_params_in_name(
|
|||
/// 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, ()> {
|
||||
call.has_flag_const(working_set, name).map_err(|err| {
|
||||
working_set.error(err.wrap(working_set, call.span()));
|
||||
working_set.error(err.wrap(working_set, call.span(working_set)));
|
||||
})
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ pub(crate) fn check_call(
|
|||
call: &Call,
|
||||
) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ pub(crate) fn check_call(
|
|||
if let Some(last) = call.positional_iter().last() {
|
||||
working_set.error(ParseError::MissingPositional(
|
||||
argument.name.clone(),
|
||||
Span::new(last.span.end, last.span.end),
|
||||
Span::new(last.span(working_set).end, last.span(working_set).end),
|
||||
sig.call_signature(),
|
||||
));
|
||||
return;
|
||||
|
@ -199,7 +199,7 @@ pub(crate) fn check_call(
|
|||
if let Some(last) = call.positional_iter().last() {
|
||||
working_set.error(ParseError::MissingPositional(
|
||||
missing.name.clone(),
|
||||
Span::new(last.span.end, last.span.end),
|
||||
Span::new(last.span(working_set).end, last.span(working_set).end),
|
||||
sig.call_signature(),
|
||||
))
|
||||
} else {
|
||||
|
@ -211,7 +211,10 @@ pub(crate) fn check_call(
|
|||
}
|
||||
} else {
|
||||
for req_flag in sig.named.iter().filter(|x| x.required) {
|
||||
if call.named_iter().all(|(n, _, _)| n.item != req_flag.long) {
|
||||
if call
|
||||
.named_iter()
|
||||
.all(|(n, _, _, _)| n.item != req_flag.long)
|
||||
{
|
||||
working_set.error(ParseError::MissingRequiredFlag(
|
||||
req_flag.long.clone(),
|
||||
command,
|
||||
|
@ -486,18 +489,19 @@ fn ensure_flag_arg_type(
|
|||
arg_shape: &SyntaxShape,
|
||||
long_name_span: Span,
|
||||
) -> (Spanned<String>, Expression) {
|
||||
let arg_span = arg.span(working_set);
|
||||
if !type_compatible(&arg.ty, &arg_shape.to_type()) {
|
||||
working_set.error(ParseError::TypeMismatch(
|
||||
arg_shape.to_type(),
|
||||
arg.ty,
|
||||
arg.span,
|
||||
arg_span,
|
||||
));
|
||||
(
|
||||
Spanned {
|
||||
item: arg_name,
|
||||
span: long_name_span,
|
||||
},
|
||||
Expression::garbage(working_set, arg.span),
|
||||
Expression::garbage(working_set, arg_span),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
|
@ -916,6 +920,25 @@ pub struct ParsedInternalCall {
|
|||
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(
|
||||
working_set: &mut StateWorkingSet,
|
||||
command_span: Span,
|
||||
|
@ -924,7 +947,7 @@ pub fn parse_internal_call(
|
|||
) -> ParsedInternalCall {
|
||||
trace!("parsing: internal call (decl id: {})", decl_id);
|
||||
|
||||
let mut call = Call::new(command_span);
|
||||
let mut call = Call::new(command_span, Span::concat(spans));
|
||||
call.decl_id = decl_id;
|
||||
call.head = command_span;
|
||||
let _ = working_set.add_span(call.head);
|
||||
|
@ -1002,7 +1025,9 @@ pub fn parse_internal_call(
|
|||
|
||||
call.add_unknown(arg);
|
||||
} else {
|
||||
call.add_named((long_name, None, arg));
|
||||
let named_span = named_arg_span(working_set, &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;
|
||||
|
@ -1053,27 +1078,30 @@ pub fn parse_internal_call(
|
|||
|
||||
if flag.long.is_empty() {
|
||||
if let Some(short) = flag.short {
|
||||
call.add_named((
|
||||
Spanned {
|
||||
item: String::new(),
|
||||
span: spans[spans_idx],
|
||||
},
|
||||
Some(Spanned {
|
||||
item: short.to_string(),
|
||||
span: spans[spans_idx],
|
||||
}),
|
||||
Some(arg),
|
||||
));
|
||||
let named = Spanned {
|
||||
item: String::new(),
|
||||
span: spans[spans_idx],
|
||||
};
|
||||
let short = Some(Spanned {
|
||||
item: short.to_string(),
|
||||
span: spans[spans_idx],
|
||||
});
|
||||
let expr = 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 {
|
||||
call.add_named((
|
||||
Spanned {
|
||||
item: flag.long.clone(),
|
||||
span: spans[spans_idx],
|
||||
},
|
||||
None,
|
||||
Some(arg),
|
||||
));
|
||||
let named = Spanned {
|
||||
item: flag.long.clone(),
|
||||
span: spans[spans_idx],
|
||||
};
|
||||
let short = None;
|
||||
let expr = 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;
|
||||
} else {
|
||||
|
@ -1084,27 +1112,29 @@ pub fn parse_internal_call(
|
|||
}
|
||||
} else if flag.long.is_empty() {
|
||||
if let Some(short) = flag.short {
|
||||
call.add_named((
|
||||
Spanned {
|
||||
item: String::new(),
|
||||
span: spans[spans_idx],
|
||||
},
|
||||
Some(Spanned {
|
||||
item: short.to_string(),
|
||||
span: spans[spans_idx],
|
||||
}),
|
||||
None,
|
||||
));
|
||||
let named = Spanned {
|
||||
item: String::new(),
|
||||
span: spans[spans_idx],
|
||||
};
|
||||
let short = Some(Spanned {
|
||||
item: short.to_string(),
|
||||
span: spans[spans_idx],
|
||||
});
|
||||
let expr = 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 {
|
||||
call.add_named((
|
||||
Spanned {
|
||||
item: flag.long.clone(),
|
||||
span: spans[spans_idx],
|
||||
},
|
||||
None,
|
||||
None,
|
||||
));
|
||||
let named = Spanned {
|
||||
item: flag.long.clone(),
|
||||
span: spans[spans_idx],
|
||||
};
|
||||
let short = None;
|
||||
let expr = 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1184,12 +1214,13 @@ pub fn parse_internal_call(
|
|||
);
|
||||
|
||||
let arg = if !type_compatible(&positional.shape.to_type(), &arg.ty) {
|
||||
let arg_ty = arg.ty.clone();
|
||||
working_set.error(ParseError::TypeMismatch(
|
||||
positional.shape.to_type(),
|
||||
arg.ty,
|
||||
arg.span,
|
||||
arg_ty,
|
||||
arg.span(working_set),
|
||||
));
|
||||
Expression::garbage(working_set, arg.span)
|
||||
Expression::garbage(working_set, arg.span(working_set))
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
|
@ -1311,7 +1342,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span)
|
|||
trace!("parsing: alias of external call");
|
||||
|
||||
let mut head = head.clone();
|
||||
head.span = spans[0]; // replacing the spans preserves syntax highlighting
|
||||
head.span_id = working_set.add_span(spans[0]); // replacing the spans preserves syntax highlighting
|
||||
|
||||
let mut final_args = args.clone().into_vec();
|
||||
for arg_span in &spans[1..] {
|
||||
|
@ -3006,13 +3037,15 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
|
|||
for item in list {
|
||||
match item {
|
||||
ListItem::Item(expr) => {
|
||||
let contents = working_set.get_span_contents(expr.span);
|
||||
output.push((trim_quotes(contents).to_vec(), expr.span));
|
||||
let contents =
|
||||
working_set.get_span_contents(expr.span(working_set));
|
||||
output
|
||||
.push((trim_quotes(contents).to_vec(), expr.span(working_set)));
|
||||
}
|
||||
ListItem::Spread(_, spread) => {
|
||||
working_set.error(ParseError::WrongImportPattern(
|
||||
"cannot spread in an import pattern".into(),
|
||||
spread.span,
|
||||
spread.span(working_set),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -3022,7 +3055,7 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -
|
|||
.members
|
||||
.push(ImportPatternMember::List { names: output });
|
||||
} else {
|
||||
working_set.error(ParseError::ExportNotFound(result.span));
|
||||
working_set.error(ParseError::ExportNotFound(result.span(working_set)));
|
||||
return Expression::new(
|
||||
working_set,
|
||||
Expr::ImportPattern(Box::new(import_pattern)),
|
||||
|
@ -3779,7 +3812,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
|
|||
format!(
|
||||
"expected default value to be `{var_type}`"
|
||||
),
|
||||
expression.span,
|
||||
expression.span(working_set),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -3792,7 +3825,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
|
|||
Some(constant)
|
||||
} else {
|
||||
working_set.error(ParseError::NonConstantDefaultValue(
|
||||
expression.span,
|
||||
expression.span(working_set),
|
||||
));
|
||||
None
|
||||
};
|
||||
|
@ -3806,7 +3839,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
|
|||
working_set.error(ParseError::AssignmentMismatch(
|
||||
"Rest parameter was given a default value".into(),
|
||||
"can't have default value".into(),
|
||||
expression.span,
|
||||
expression.span(working_set),
|
||||
))
|
||||
}
|
||||
Arg::Flag {
|
||||
|
@ -3819,7 +3852,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
|
|||
},
|
||||
type_annotated,
|
||||
} => {
|
||||
let expression_span = expression.span;
|
||||
let expression_span = expression.span(working_set);
|
||||
|
||||
*default_value = if let Ok(value) =
|
||||
eval_constant(working_set, &expression)
|
||||
|
@ -4065,7 +4098,7 @@ fn parse_table_row(
|
|||
list.into_iter()
|
||||
.map(|item| match item {
|
||||
ListItem::Item(expr) => Ok(expr),
|
||||
ListItem::Spread(_, spread) => Err(spread.span),
|
||||
ListItem::Spread(_, spread) => Err(spread.span(working_set)),
|
||||
})
|
||||
.collect::<Result<_, _>>()
|
||||
.map(|exprs| (exprs, span))
|
||||
|
@ -4140,7 +4173,7 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr
|
|||
}
|
||||
Ordering::Greater => {
|
||||
let span = {
|
||||
let start = list[head.len()].span.start;
|
||||
let start = list[head.len()].span(working_set).start;
|
||||
let end = span.end;
|
||||
Span::new(start, end)
|
||||
};
|
||||
|
@ -4179,7 +4212,7 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr
|
|||
};
|
||||
|
||||
let ty = if working_set.parse_errors.len() == errors {
|
||||
let (ty, errs) = table_type(&head, &rows);
|
||||
let (ty, errs) = table_type(working_set, &head, &rows);
|
||||
working_set.parse_errors.extend(errs);
|
||||
ty
|
||||
} else {
|
||||
|
@ -4194,7 +4227,11 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr
|
|||
Expression::new(working_set, Expr::Table(table), span, ty)
|
||||
}
|
||||
|
||||
fn table_type(head: &[Expression], rows: &[Vec<Expression>]) -> (Type, Vec<ParseError>) {
|
||||
fn table_type(
|
||||
working_set: &StateWorkingSet,
|
||||
head: &[Expression],
|
||||
rows: &[Vec<Expression>],
|
||||
) -> (Type, Vec<ParseError>) {
|
||||
let mut errors = vec![];
|
||||
let mut rows = rows.to_vec();
|
||||
let mut mk_ty = || -> Type {
|
||||
|
@ -4224,7 +4261,7 @@ fn table_type(head: &[Expression], rows: &[Vec<Expression>]) -> (Type, Vec<Parse
|
|||
if let Some(str) = expr.as_string() {
|
||||
str
|
||||
} else {
|
||||
errors.push(mk_error(expr.span));
|
||||
errors.push(mk_error(expr.span(&working_set)));
|
||||
String::from("{ column }")
|
||||
}
|
||||
})
|
||||
|
@ -5115,7 +5152,7 @@ pub fn parse_math_expression(
|
|||
working_set.error(err);
|
||||
}
|
||||
|
||||
let op_span = Span::append(lhs.span, rhs.span);
|
||||
let op_span = Span::append(lhs.span(working_set), rhs.span(working_set));
|
||||
expr_stack.push(Expression::new(
|
||||
working_set,
|
||||
Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
|
||||
|
@ -5151,7 +5188,7 @@ pub fn parse_math_expression(
|
|||
working_set.error(err)
|
||||
}
|
||||
|
||||
let binary_op_span = Span::append(lhs.span, rhs.span);
|
||||
let binary_op_span = Span::append(lhs.span(working_set), rhs.span(working_set));
|
||||
expr_stack.push(Expression::new(
|
||||
working_set,
|
||||
Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
|
||||
|
@ -5332,7 +5369,10 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
|
|||
let expr = Expr::Call(Box::new(Call {
|
||||
head: Span::unknown(),
|
||||
decl_id,
|
||||
arguments,
|
||||
arguments: Spanned {
|
||||
item: arguments,
|
||||
span: Span::concat(spans),
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
}));
|
||||
|
||||
|
@ -6094,7 +6134,7 @@ pub fn discover_captures_in_expr(
|
|||
}
|
||||
}
|
||||
|
||||
for arg in &call.arguments {
|
||||
for arg in &call.arguments.item {
|
||||
match arg {
|
||||
Argument::Named(named) => {
|
||||
if let Some(arg) = &named.2 {
|
||||
|
@ -6249,7 +6289,7 @@ pub fn discover_captures_in_expr(
|
|||
}
|
||||
Expr::Var(var_id) => {
|
||||
if (*var_id > ENV_VARIABLE_ID || *var_id == IN_VARIABLE_ID) && !seen.contains(var_id) {
|
||||
output.push((*var_id, expr.span));
|
||||
output.push((*var_id, expr.span(&working_set)));
|
||||
}
|
||||
}
|
||||
Expr::VarDecl(var_id) => {
|
||||
|
@ -6294,7 +6334,7 @@ fn wrap_element_with_collect(
|
|||
}
|
||||
|
||||
fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) -> Expression {
|
||||
let span = expr.span;
|
||||
let span = expr.span(working_set);
|
||||
|
||||
if let Some(decl_id) = working_set.find_decl(b"collect") {
|
||||
let mut output = vec![];
|
||||
|
@ -6324,14 +6364,15 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
|
|||
Type::Any,
|
||||
)));
|
||||
|
||||
output.push(Argument::Named((
|
||||
Spanned {
|
||||
item: "keep-env".to_string(),
|
||||
span: Span::new(0, 0),
|
||||
},
|
||||
None,
|
||||
None,
|
||||
)));
|
||||
let named = Spanned {
|
||||
item: "keep-env".to_string(),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let short = None;
|
||||
let expr = 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`.
|
||||
// We don't want to have a real span as it will confuse flattening
|
||||
|
@ -6339,8 +6380,11 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
|
|||
Expression::new(
|
||||
working_set,
|
||||
Expr::Call(Box::new(Call {
|
||||
head: Span::new(0, 0),
|
||||
arguments: output,
|
||||
head: Span::unknown(),
|
||||
arguments: Spanned {
|
||||
item: output,
|
||||
span: Span::unknown(),
|
||||
},
|
||||
decl_id,
|
||||
parser_info: HashMap::new(),
|
||||
})),
|
||||
|
|
|
@ -598,9 +598,12 @@ pub fn parse_call_short_flag_batch_arg_allowed() {
|
|||
|
||||
if let Expr::Call(call) = &element.expr.expr {
|
||||
assert_eq!(call.decl_id, 0);
|
||||
assert_eq!(call.arguments.len(), 2);
|
||||
matches!(call.arguments[0], Argument::Named((_, None, None)));
|
||||
matches!(call.arguments[1], Argument::Named((_, None, Some(_))));
|
||||
assert_eq!(call.arguments.item.len(), 2);
|
||||
matches!(call.arguments.item[0], Argument::Named((_, None, None, _)));
|
||||
matches!(
|
||||
call.arguments.item[1],
|
||||
Argument::Named((_, None, Some(_), _))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2150,7 +2153,7 @@ mod input_types {
|
|||
assert!(pipeline.elements[3].redirection.is_none());
|
||||
match &pipeline.elements[3].expr.expr {
|
||||
Expr::Call(call) => {
|
||||
let arg = &call.arguments[0];
|
||||
let arg = &call.arguments.item[0];
|
||||
match arg {
|
||||
Argument::Positional(a) => match &a.expr {
|
||||
Expr::FullCellPath(path) => match &path.head.expr {
|
||||
|
@ -2347,3 +2350,92 @@ 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,11 +34,12 @@ impl EvaluatedCall {
|
|||
stack: &mut Stack,
|
||||
eval_expression_fn: fn(&EngineState, &mut Stack, &Expression) -> Result<Value, ShellError>,
|
||||
) -> Result<Self, ShellError> {
|
||||
let positional =
|
||||
call.rest_iter_flattened(0, |expr| eval_expression_fn(engine_state, stack, expr))?;
|
||||
let positional = call.rest_iter_flattened(&engine_state, 0, |expr| {
|
||||
eval_expression_fn(engine_state, stack, expr)
|
||||
})?;
|
||||
|
||||
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 {
|
||||
None => None,
|
||||
Some(expr) => Some(eval_expression_fn(engine_state, stack, expr)?),
|
||||
|
|
|
@ -4,42 +4,47 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{
|
||||
ast::Expression, engine::StateWorkingSet, eval_const::eval_constant, DeclId, FromValue,
|
||||
ShellError, Span, Spanned, Value,
|
||||
GetSpan, ShellError, Span, SpanId, Spanned, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Argument {
|
||||
Positional(Expression),
|
||||
Named((Spanned<String>, Option<Spanned<String>>, Option<Expression>)),
|
||||
Named(
|
||||
(
|
||||
Spanned<String>,
|
||||
Option<Spanned<String>>,
|
||||
Option<Expression>,
|
||||
SpanId,
|
||||
),
|
||||
),
|
||||
Unknown(Expression), // unknown argument used in "fall-through" signatures
|
||||
Spread(Expression), // a list spread to fill in rest arguments
|
||||
}
|
||||
|
||||
impl Argument {
|
||||
/// The span for an argument
|
||||
pub fn span(&self) -> Span {
|
||||
pub fn span_id(&self) -> SpanId {
|
||||
match self {
|
||||
Argument::Positional(e) => e.span,
|
||||
Argument::Named((named, short, expr)) => {
|
||||
let start = named.span.start;
|
||||
let end = if let Some(expr) = expr {
|
||||
expr.span.end
|
||||
} else if let Some(short) = short {
|
||||
short.span.end
|
||||
} else {
|
||||
named.span.end
|
||||
};
|
||||
Argument::Positional(e) => e.span_id,
|
||||
Argument::Named((_, _, _, span_id)) => *span_id,
|
||||
Argument::Unknown(e) => e.span_id,
|
||||
Argument::Spread(e) => e.span_id,
|
||||
}
|
||||
}
|
||||
|
||||
Span::new(start, end)
|
||||
}
|
||||
Argument::Unknown(e) => e.span,
|
||||
Argument::Spread(e) => e.span,
|
||||
/// The span for an argument
|
||||
pub fn span(&self, state: &impl GetSpan) -> Span {
|
||||
match self {
|
||||
Argument::Positional(e) => e.span(state),
|
||||
Argument::Named((_, _, _, span_id)) => state.get_span(*span_id),
|
||||
Argument::Unknown(e) => e.span(state),
|
||||
Argument::Spread(e) => e.span(state),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr(&self) -> Option<&Expression> {
|
||||
match self {
|
||||
Argument::Named((_, _, expr)) => expr.as_ref(),
|
||||
Argument::Named((_, _, expr, _)) => expr.as_ref(),
|
||||
Argument::Positional(expr) | Argument::Unknown(expr) | Argument::Spread(expr) => {
|
||||
Some(expr)
|
||||
}
|
||||
|
@ -58,17 +63,20 @@ pub struct Call {
|
|||
/// identifier of the declaration to call
|
||||
pub decl_id: DeclId,
|
||||
pub head: Span,
|
||||
pub arguments: Vec<Argument>,
|
||||
pub arguments: Spanned<Vec<Argument>>,
|
||||
/// this field is used by the parser to pass additional command-specific information
|
||||
pub parser_info: HashMap<String, Expression>,
|
||||
}
|
||||
|
||||
impl Call {
|
||||
pub fn new(head: Span) -> Call {
|
||||
pub fn new(head: Span, args_span: Span) -> Call {
|
||||
Self {
|
||||
decl_id: 0,
|
||||
head,
|
||||
arguments: vec![],
|
||||
arguments: Spanned {
|
||||
item: vec![],
|
||||
span: args_span,
|
||||
},
|
||||
parser_info: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
@ -80,23 +88,20 @@ impl Call {
|
|||
/// If there are one or more arguments the span encompasses the start of the first argument to
|
||||
/// end of the last argument
|
||||
pub fn arguments_span(&self) -> 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)
|
||||
self.arguments.span
|
||||
}
|
||||
|
||||
pub fn named_iter(
|
||||
&self,
|
||||
) -> impl Iterator<Item = &(Spanned<String>, Option<Spanned<String>>, Option<Expression>)> {
|
||||
self.arguments.iter().filter_map(|arg| match arg {
|
||||
) -> impl Iterator<
|
||||
Item = &(
|
||||
Spanned<String>,
|
||||
Option<Spanned<String>>,
|
||||
Option<Expression>,
|
||||
SpanId,
|
||||
),
|
||||
> {
|
||||
self.arguments.item.iter().filter_map(|arg| match arg {
|
||||
Argument::Named(named) => Some(named),
|
||||
Argument::Positional(_) => None,
|
||||
Argument::Unknown(_) => None,
|
||||
|
@ -106,9 +111,15 @@ impl Call {
|
|||
|
||||
pub fn named_iter_mut(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = &mut (Spanned<String>, Option<Spanned<String>>, Option<Expression>)>
|
||||
{
|
||||
self.arguments.iter_mut().filter_map(|arg| match arg {
|
||||
) -> impl Iterator<
|
||||
Item = &mut (
|
||||
Spanned<String>,
|
||||
Option<Spanned<String>>,
|
||||
Option<Expression>,
|
||||
SpanId,
|
||||
),
|
||||
> {
|
||||
self.arguments.item.iter_mut().filter_map(|arg| match arg {
|
||||
Argument::Named(named) => Some(named),
|
||||
Argument::Positional(_) => None,
|
||||
Argument::Unknown(_) => None,
|
||||
|
@ -122,25 +133,31 @@ impl Call {
|
|||
|
||||
pub fn add_named(
|
||||
&mut self,
|
||||
named: (Spanned<String>, Option<Spanned<String>>, Option<Expression>),
|
||||
named: (
|
||||
Spanned<String>,
|
||||
Option<Spanned<String>>,
|
||||
Option<Expression>,
|
||||
SpanId,
|
||||
),
|
||||
) {
|
||||
self.arguments.push(Argument::Named(named));
|
||||
self.arguments.item.push(Argument::Named(named));
|
||||
}
|
||||
|
||||
pub fn add_positional(&mut self, positional: Expression) {
|
||||
self.arguments.push(Argument::Positional(positional));
|
||||
self.arguments.item.push(Argument::Positional(positional));
|
||||
}
|
||||
|
||||
pub fn add_unknown(&mut self, unknown: Expression) {
|
||||
self.arguments.push(Argument::Unknown(unknown));
|
||||
self.arguments.item.push(Argument::Unknown(unknown));
|
||||
}
|
||||
|
||||
pub fn add_spread(&mut self, args: Expression) {
|
||||
self.arguments.push(Argument::Spread(args));
|
||||
self.arguments.item.push(Argument::Spread(args));
|
||||
}
|
||||
|
||||
pub fn positional_iter(&self) -> impl Iterator<Item = &Expression> {
|
||||
self.arguments
|
||||
.item
|
||||
.iter()
|
||||
.take_while(|arg| match arg {
|
||||
Argument::Spread(_) => false, // Don't include positional arguments given to rest parameter
|
||||
|
@ -168,6 +185,7 @@ impl Call {
|
|||
// todo maybe rewrite to be more elegant or something
|
||||
let args = self
|
||||
.arguments
|
||||
.item
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
Argument::Named(_) => None,
|
||||
|
@ -258,9 +276,9 @@ impl Call {
|
|||
) -> Result<Vec<T>, ShellError> {
|
||||
let mut output = vec![];
|
||||
|
||||
for result in
|
||||
self.rest_iter_flattened(starting_pos, |expr| eval_constant(working_set, expr))?
|
||||
{
|
||||
for result in self.rest_iter_flattened(&working_set, starting_pos, |expr| {
|
||||
eval_constant(working_set, expr)
|
||||
})? {
|
||||
output.push(FromValue::from_value(result)?);
|
||||
}
|
||||
|
||||
|
@ -269,6 +287,7 @@ impl Call {
|
|||
|
||||
pub fn rest_iter_flattened<F>(
|
||||
&self,
|
||||
state: &impl GetSpan,
|
||||
start: usize,
|
||||
mut eval: F,
|
||||
) -> Result<Vec<Value>, ShellError>
|
||||
|
@ -282,7 +301,11 @@ impl Call {
|
|||
if spread {
|
||||
match result {
|
||||
Value::List { mut vals, .. } => output.append(&mut vals),
|
||||
_ => return Err(ShellError::CannotSpreadAsList { span: expr.span }),
|
||||
_ => {
|
||||
return Err(ShellError::CannotSpreadAsList {
|
||||
span: expr.span(state),
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
output.push(result);
|
||||
|
@ -310,23 +333,23 @@ impl Call {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
pub fn span(&self, state: &impl GetSpan) -> Span {
|
||||
let mut span = self.head;
|
||||
|
||||
for positional in self.positional_iter() {
|
||||
if positional.span.end > span.end {
|
||||
span.end = positional.span.end;
|
||||
if positional.span(state).end > span.end {
|
||||
span.end = positional.span(state).end;
|
||||
}
|
||||
}
|
||||
|
||||
for (named, _, val) in self.named_iter() {
|
||||
for (named, _, val, _) in self.named_iter() {
|
||||
if named.span.end > span.end {
|
||||
span.end = named.span.end;
|
||||
}
|
||||
|
||||
if let Some(val) = &val {
|
||||
if val.span.end > span.end {
|
||||
span.end = val.span.end;
|
||||
if val.span(state).end > span.end {
|
||||
span.end = val.span(state).end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -334,77 +357,3 @@ impl Call {
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ impl Expression {
|
|||
Expr::Binary(_) => false,
|
||||
Expr::Bool(_) => false,
|
||||
Expr::Call(call) => {
|
||||
for arg in &call.arguments {
|
||||
for arg in &call.arguments.item {
|
||||
match arg {
|
||||
Argument::Positional(expr)
|
||||
| Argument::Unknown(expr)
|
||||
|
@ -366,7 +366,7 @@ impl Expression {
|
|||
if replaced.contains_span(call.head) {
|
||||
call.head = new_span;
|
||||
}
|
||||
for arg in call.arguments.iter_mut() {
|
||||
for arg in call.arguments.item.iter_mut() {
|
||||
match arg {
|
||||
Argument::Positional(expr)
|
||||
| Argument::Unknown(expr)
|
||||
|
|
|
@ -1023,16 +1023,32 @@ impl<'a> StateWorkingSet<'a> {
|
|||
|
||||
impl<'a> GetSpan for &'a StateWorkingSet<'a> {
|
||||
fn get_span(&self, span_id: SpanId) -> Span {
|
||||
let num_permanent_spans = self.permanent_state.num_spans();
|
||||
if span_id.0 < num_permanent_spans {
|
||||
self.permanent_state.get_span(span_id)
|
||||
} else {
|
||||
*self
|
||||
.delta
|
||||
.spans
|
||||
.get(span_id.0 - num_permanent_spans)
|
||||
.expect("internal error: missing span")
|
||||
}
|
||||
get_span(self, span_id)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
working_set.permanent_state.get_span(span_id)
|
||||
} else {
|
||||
*working_set
|
||||
.delta
|
||||
.spans
|
||||
.get(span_id.0 - num_permanent_spans)
|
||||
.expect("internal error: missing span")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -301,7 +301,7 @@ fn eval_const_call(
|
|||
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
|
||||
// getting help messages at parse-time is rare enough, we can simply disallow it.
|
||||
return Err(ShellError::NotAConstHelp { span: call.head });
|
||||
|
|
|
@ -567,7 +567,7 @@ impl PipelineData {
|
|||
if command.block_id().is_some() {
|
||||
self.write_all_and_flush(engine_state, no_newline, to_stderr)
|
||||
} else {
|
||||
let call = Call::new(Span::new(0, 0));
|
||||
let call = Call::new(Span::unknown(), Span::unknown());
|
||||
let table = command.run(engine_state, stack, &call, self)?;
|
||||
table.write_all_and_flush(engine_state, no_newline, to_stderr)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue