mirror of
https://github.com/nushell/nushell.git
synced 2025-06-30 22:50:14 +02: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:
@ -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(),
|
||||
})),
|
||||
|
Reference in New Issue
Block a user