From e52d7bc58541e38634fa5499396903f11b7e3f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Sun, 9 Jun 2024 12:15:53 +0300 Subject: [PATCH] Span ID Refactor (Step 2): Use SpanId of expressions in some places (#13102) # Description Part of https://github.com/nushell/nushell/issues/12963, step 2. This PR refactors changes the use of `expression.span` to `expression.span_id` via a new helper `Expression::span()`. A new `GetSpan` is added to abstract getting the span from both `EngineState` and `StateWorkingSet`. # User-Facing Changes `format pattern` loses the ability to use variables in the pattern, e.g., `... | format pattern 'value of {$it.name} is {$it.value}'`. This is because the command did a custom parse-eval cycle, creating spans that are not merged into the main engine state. We could clone the engine state, add Clone trait to StateDelta and merge the cloned delta to the cloned state, but IMO there is not much value from having this ability, since we have string interpolation nowadays: `... | $"value of ($in.name) is ($in.value)"`. # Tests + Formatting # After Submitting --- .../src/extra/strings/format/command.rs | 68 ++------ crates/nu-command/tests/commands/format.rs | 7 +- crates/nu-engine/src/eval.rs | 34 ++-- crates/nu-protocol/src/ast/expression.rs | 8 +- crates/nu-protocol/src/engine/engine_state.rs | 16 +- .../src/engine/state_working_set.rs | 8 +- crates/nu-protocol/src/eval_base.rs | 153 +++++++++--------- crates/nu-protocol/src/eval_const.rs | 8 +- crates/nu-protocol/src/span.rs | 5 + 9 files changed, 148 insertions(+), 159 deletions(-) diff --git a/crates/nu-cmd-extra/src/extra/strings/format/command.rs b/crates/nu-cmd-extra/src/extra/strings/format/command.rs index 1c72627779..50e89e61e3 100644 --- a/crates/nu-cmd-extra/src/extra/strings/format/command.rs +++ b/crates/nu-cmd-extra/src/extra/strings/format/command.rs @@ -1,5 +1,4 @@ -use nu_engine::{command_prelude::*, get_eval_expression}; -use nu_parser::parse_expression; +use nu_engine::command_prelude::*; use nu_protocol::{ast::PathMember, engine::StateWorkingSet, ListStream}; #[derive(Clone)] @@ -57,14 +56,7 @@ impl Command for FormatPattern { string_span.start + 1, )?; - format( - input_val, - &ops, - engine_state, - &mut working_set, - stack, - call.head, - ) + format(input_val, &ops, engine_state, call.head) } } } @@ -100,8 +92,6 @@ enum FormatOperation { FixedText(String), // raw input is something like {column1.column2} ValueFromColumn(String, Span), - // raw input is something like {$it.column1.column2} or {$var}. - ValueNeedEval(String, Span), } /// Given a pattern that is fed into the Format command, we can process it and subdivide it @@ -110,7 +100,6 @@ enum FormatOperation { /// there without any further processing. /// FormatOperation::ValueFromColumn contains the name of a column whose values will be /// formatted according to the input pattern. -/// FormatOperation::ValueNeedEval contains expression which need to eval, it has the following form: /// "$it.column1.column2" or "$variable" fn extract_formatting_operations( input: String, @@ -161,10 +150,17 @@ fn extract_formatting_operations( if !column_name.is_empty() { if column_need_eval { - output.push(FormatOperation::ValueNeedEval( - column_name.clone(), - Span::new(span_start + column_span_start, span_start + column_span_end), - )); + return Err(ShellError::GenericError { + error: "Removed functionality".into(), + msg: "The ability to use variables ($it) in `format pattern` has been removed." + .into(), + span: Some(error_span), + help: Some( + "You can use other formatting options, such as string interpolation." + .into(), + ), + inner: vec![], + }); } else { output.push(FormatOperation::ValueFromColumn( column_name.clone(), @@ -185,8 +181,6 @@ fn format( input_data: Value, format_operations: &[FormatOperation], engine_state: &EngineState, - working_set: &mut StateWorkingSet, - stack: &mut Stack, head_span: Span, ) -> Result { let data_as_value = input_data; @@ -194,13 +188,7 @@ fn format( // We can only handle a Record or a List of Records match data_as_value { Value::Record { .. } => { - match format_record( - format_operations, - &data_as_value, - engine_state, - working_set, - stack, - ) { + match format_record(format_operations, &data_as_value, engine_state) { Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)), Err(value) => Err(value), } @@ -211,13 +199,7 @@ fn format( for val in vals.iter() { match val { Value::Record { .. } => { - match format_record( - format_operations, - val, - engine_state, - working_set, - stack, - ) { + match format_record(format_operations, val, engine_state) { Ok(value) => { list.push(Value::string(value, head_span)); } @@ -256,12 +238,9 @@ fn format_record( format_operations: &[FormatOperation], data_as_value: &Value, engine_state: &EngineState, - working_set: &mut StateWorkingSet, - stack: &mut Stack, ) -> Result { let config = engine_state.get_config(); let mut output = String::new(); - let eval_expression = get_eval_expression(engine_state); for op in format_operations { match op { @@ -283,23 +262,6 @@ fn format_record( Err(se) => return Err(se), } } - FormatOperation::ValueNeedEval(_col_name, span) => { - let exp = parse_expression(working_set, &[*span]); - match working_set.parse_errors.first() { - None => { - let parsed_result = eval_expression(engine_state, stack, &exp); - if let Ok(val) = parsed_result { - output.push_str(&val.to_abbreviated_string(config)) - } - } - Some(err) => { - return Err(ShellError::TypeMismatch { - err_message: format!("expression is invalid, detail message: {err:?}"), - span: *span, - }) - } - } - } } } Ok(output) diff --git a/crates/nu-command/tests/commands/format.rs b/crates/nu-command/tests/commands/format.rs index 6b1649c8b5..6084faf1e4 100644 --- a/crates/nu-command/tests/commands/format.rs +++ b/crates/nu-command/tests/commands/format.rs @@ -37,7 +37,7 @@ fn given_fields_can_be_column_paths() { } #[test] -fn can_use_variables() { +fn cant_use_variables() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" @@ -46,7 +46,8 @@ fn can_use_variables() { "# )); - assert_eq!(actual.out, "nu is a new type of shell"); + // TODO SPAN: This has been removed during SpanId refactor + assert!(actual.err.contains("Removed functionality")); } #[test] @@ -55,7 +56,7 @@ fn error_unmatched_brace() { cwd: "tests/fixtures/formats", pipeline( r#" open cargo_sample.toml - | format pattern "{$it.package.name" + | format pattern "{package.name" "# )); diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index af051a1dc7..044bf86980 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -208,11 +208,13 @@ fn eval_external( ) -> Result { let decl_id = engine_state .find_decl("run-external".as_bytes(), &[]) - .ok_or(ShellError::ExternalNotSupported { span: head.span })?; + .ok_or(ShellError::ExternalNotSupported { + span: head.span(&engine_state), + })?; let command = engine_state.get_decl(decl_id); - let mut call = Call::new(head.span); + let mut call = Call::new(head.span(&engine_state)); call.add_positional(head.clone()); @@ -712,7 +714,7 @@ impl Eval for EvalRuntime { args: &[ExternalArgument], _: Span, ) -> Result { - let span = head.span; + let span = head.span(&engine_state); // FIXME: protect this collect with ctrl-c eval_external(engine_state, stack, head, args, PipelineData::empty())?.into_value(span) } @@ -779,9 +781,11 @@ impl Eval for EvalRuntime { let var_info = engine_state.get_var(*var_id); if var_info.mutable { stack.add_var(*var_id, rhs); - Ok(Value::nothing(lhs.span)) + Ok(Value::nothing(lhs.span(&engine_state))) } else { - Err(ShellError::AssignmentRequiresMutableVar { lhs_span: lhs.span }) + Err(ShellError::AssignmentRequiresMutableVar { + lhs_span: lhs.span(&engine_state), + }) } } Expr::FullCellPath(cell_path) => { @@ -797,7 +801,7 @@ impl Eval for EvalRuntime { // Reject attempts to assign to the entire $env if cell_path.tail.is_empty() { return Err(ShellError::CannotReplaceEnv { - span: cell_path.head.span, + span: cell_path.head.span(&engine_state), }); } @@ -837,15 +841,21 @@ impl Eval for EvalRuntime { lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?; stack.add_var(*var_id, lhs); } - Ok(Value::nothing(cell_path.head.span)) + Ok(Value::nothing(cell_path.head.span(&engine_state))) } else { - Err(ShellError::AssignmentRequiresMutableVar { lhs_span: lhs.span }) + Err(ShellError::AssignmentRequiresMutableVar { + lhs_span: lhs.span(&engine_state), + }) } } - _ => Err(ShellError::AssignmentRequiresVar { lhs_span: lhs.span }), + _ => Err(ShellError::AssignmentRequiresVar { + lhs_span: lhs.span(&engine_state), + }), } } - _ => Err(ShellError::AssignmentRequiresVar { lhs_span: lhs.span }), + _ => Err(ShellError::AssignmentRequiresVar { + lhs_span: lhs.span(&engine_state), + }), } } @@ -882,8 +892,8 @@ impl Eval for EvalRuntime { Ok(Value::string(name, span)) } - fn unreachable(expr: &Expression) -> Result { - Ok(Value::nothing(expr.span)) + fn unreachable(engine_state: &EngineState, expr: &Expression) -> Result { + Ok(Value::nothing(expr.span(&engine_state))) } } diff --git a/crates/nu-protocol/src/ast/expression.rs b/crates/nu-protocol/src/ast/expression.rs index 832bc1f438..08ecc59aaf 100644 --- a/crates/nu-protocol/src/ast/expression.rs +++ b/crates/nu-protocol/src/ast/expression.rs @@ -1,7 +1,7 @@ use crate::{ ast::{Argument, Block, Expr, ExternalArgument, ImportPattern, MatchPattern, RecordItem}, - engine::{EngineState, StateWorkingSet}, - BlockId, DeclId, Signature, Span, SpanId, Type, VarId, IN_VARIABLE_ID, + engine::StateWorkingSet, + BlockId, DeclId, GetSpan, Signature, Span, SpanId, Type, VarId, IN_VARIABLE_ID, }; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -516,7 +516,7 @@ impl Expression { } } - pub fn span(&self, engine_state: &EngineState) -> Span { - engine_state.get_span(self.span_id) + pub fn span(&self, state: &impl GetSpan) -> Span { + state.get_span(self.span_id) } } diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index e81d3360ab..3960f6d9d0 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -7,7 +7,7 @@ use crate::{ Variable, Visibility, DEFAULT_OVERLAY_NAME, }, eval_const::create_nu_constant, - BlockId, Category, Config, DeclId, FileId, HistoryConfig, Module, ModuleId, OverlayId, + BlockId, Category, Config, DeclId, FileId, GetSpan, HistoryConfig, Module, ModuleId, OverlayId, ShellError, Signature, Span, SpanId, Type, Value, VarId, VirtualPathId, }; use fancy_regex::Regex; @@ -1035,18 +1035,20 @@ impl EngineState { SpanId(self.num_spans() - 1) } + /// Find ID of a span (should be avoided if possible) + pub fn find_span_id(&self, span: Span) -> Option { + self.spans.iter().position(|sp| sp == &span).map(SpanId) + } +} + +impl<'a> GetSpan for &'a EngineState { /// Get existing span - pub fn get_span(&self, span_id: SpanId) -> Span { + fn get_span(&self, span_id: SpanId) -> Span { *self .spans .get(span_id.0) .expect("internal error: missing span") } - - /// Find ID of a span (should be avoided if possible) - pub fn find_span_id(&self, span: Span) -> Option { - self.spans.iter().position(|sp| sp == &span).map(SpanId) - } } impl Default for EngineState { diff --git a/crates/nu-protocol/src/engine/state_working_set.rs b/crates/nu-protocol/src/engine/state_working_set.rs index 31600b5eb9..af950b8321 100644 --- a/crates/nu-protocol/src/engine/state_working_set.rs +++ b/crates/nu-protocol/src/engine/state_working_set.rs @@ -4,8 +4,8 @@ use crate::{ usage::build_usage, CachedFile, Command, CommandType, EngineState, OverlayFrame, StateDelta, Variable, VirtualPath, Visibility, }, - BlockId, Category, Config, DeclId, FileId, Module, ModuleId, ParseError, ParseWarning, Span, - SpanId, Type, Value, VarId, VirtualPathId, + BlockId, Category, Config, DeclId, FileId, GetSpan, Module, ModuleId, ParseError, ParseWarning, + Span, SpanId, Type, Value, VarId, VirtualPathId, }; use core::panic; use std::{ @@ -1019,8 +1019,10 @@ impl<'a> StateWorkingSet<'a> { self.delta.spans.push(span); SpanId(num_permanent_spans + self.delta.spans.len() - 1) } +} - pub fn get_span(&self, span_id: SpanId) -> Span { +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) diff --git a/crates/nu-protocol/src/eval_base.rs b/crates/nu-protocol/src/eval_base.rs index 6a1c0d302f..2317149460 100644 --- a/crates/nu-protocol/src/eval_base.rs +++ b/crates/nu-protocol/src/eval_base.rs @@ -4,7 +4,7 @@ use crate::{ ExternalArgument, ListItem, Math, Operator, RecordItem, }, debugger::DebugContext, - Config, Range, Record, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, + Config, GetSpan, Range, Record, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, }; use std::{borrow::Cow, collections::HashMap}; @@ -12,7 +12,7 @@ use std::{borrow::Cow, collections::HashMap}; pub trait Eval { /// State that doesn't need to be mutated. /// EngineState for regular eval and StateWorkingSet for const eval - type State<'a>: Copy; + type State<'a>: Copy + GetSpan; /// State that needs to be mutated. /// This is the stack for regular eval, and unused by const eval @@ -23,17 +23,19 @@ pub trait Eval { mut_state: &mut Self::MutState, expr: &Expression, ) -> Result { + let expr_span = expr.span(&state); + match &expr.expr { - Expr::Bool(b) => Ok(Value::bool(*b, expr.span)), - Expr::Int(i) => Ok(Value::int(*i, expr.span)), - Expr::Float(f) => Ok(Value::float(*f, expr.span)), - Expr::Binary(b) => Ok(Value::binary(b.clone(), expr.span)), - Expr::Filepath(path, quoted) => Self::eval_filepath(state, mut_state, path.clone(), *quoted, expr.span), + Expr::Bool(b) => Ok(Value::bool(*b, expr_span)), + Expr::Int(i) => Ok(Value::int(*i, expr_span)), + Expr::Float(f) => Ok(Value::float(*f, expr_span)), + Expr::Binary(b) => Ok(Value::binary(b.clone(), expr_span)), + Expr::Filepath(path, quoted) => Self::eval_filepath(state, mut_state, path.clone(), *quoted, expr_span), Expr::Directory(path, quoted) => { - Self::eval_directory(state, mut_state, path.clone(), *quoted, expr.span) + Self::eval_directory(state, mut_state, path.clone(), *quoted, expr_span) } - Expr::Var(var_id) => Self::eval_var(state, mut_state, *var_id, expr.span), - Expr::CellPath(cell_path) => Ok(Value::cell_path(cell_path.clone(), expr.span)), + Expr::Var(var_id) => Self::eval_var(state, mut_state, *var_id, expr_span), + Expr::CellPath(cell_path) => Ok(Value::cell_path(cell_path.clone(), expr_span)), Expr::FullCellPath(cell_path) => { let value = Self::eval::(state, mut_state, &cell_path.head)?; @@ -45,7 +47,7 @@ pub trait Eval { value.follow_cell_path(&cell_path.tail, false) } } - Expr::DateTime(dt) => Ok(Value::date(*dt, expr.span)), + Expr::DateTime(dt) => Ok(Value::date(*dt, expr_span)), Expr::List(list) => { let mut output = vec![]; for item in list { @@ -53,11 +55,11 @@ pub trait Eval { ListItem::Item(expr) => output.push(Self::eval::(state, mut_state, expr)?), ListItem::Spread(_, expr) => match Self::eval::(state, mut_state, expr)? { Value::List { vals, .. } => output.extend(vals), - _ => return Err(ShellError::CannotSpreadAsList { span: expr.span }), + _ => return Err(ShellError::CannotSpreadAsList { span: expr_span }), }, } } - Ok(Value::list(output, expr.span)) + Ok(Value::list(output, expr_span)) } Expr::Record(items) => { let mut record = Record::new(); @@ -67,36 +69,38 @@ pub trait Eval { RecordItem::Pair(col, val) => { // avoid duplicate cols let col_name = Self::eval::(state, mut_state, col)?.coerce_into_string()?; + let col_span = col.span(&state); if let Some(orig_span) = col_names.get(&col_name) { return Err(ShellError::ColumnDefinedTwice { col_name, - second_use: col.span, + second_use: col_span, first_use: *orig_span, }); } else { - col_names.insert(col_name.clone(), col.span); + col_names.insert(col_name.clone(), col_span); record.push(col_name, Self::eval::(state, mut_state, val)?); } } RecordItem::Spread(_, inner) => { + let inner_span = inner.span(&state); match Self::eval::(state, mut_state, inner)? { Value::Record { val: inner_val, .. } => { for (col_name, val) in inner_val.into_owned() { if let Some(orig_span) = col_names.get(&col_name) { return Err(ShellError::ColumnDefinedTwice { col_name, - second_use: inner.span, + second_use: inner_span, first_use: *orig_span, }); } else { - col_names.insert(col_name.clone(), inner.span); + col_names.insert(col_name.clone(), inner_span); record.push(col_name, val); } } } _ => { return Err(ShellError::CannotSpreadAsRecord { - span: inner.span, + span: inner_span, }) } } @@ -104,7 +108,7 @@ pub trait Eval { } } - Ok(Value::record(record, expr.span)) + Ok(Value::record(record, expr_span)) } Expr::Table(table) => { let mut output_headers = vec![]; @@ -114,10 +118,11 @@ pub trait Eval { .iter() .position(|existing| existing == &header) { + let first_use = table.columns[idx].span(&state); return Err(ShellError::ColumnDefinedTwice { col_name: header, - second_use: expr.span, - first_use: table.columns[idx].span, + second_use: expr_span, + first_use, }); } else { output_headers.push(header); @@ -132,66 +137,66 @@ pub trait Eval { output_rows.push(Value::record( record, - expr.span, + expr_span, )); } - Ok(Value::list(output_rows, expr.span)) + Ok(Value::list(output_rows, expr_span)) } Expr::Keyword(kw) => Self::eval::(state, mut_state, &kw.expr), - Expr::String(s) | Expr::RawString(s) => Ok(Value::string(s.clone(), expr.span)), - Expr::Nothing => Ok(Value::nothing(expr.span)), + Expr::String(s) | Expr::RawString(s) => Ok(Value::string(s.clone(), expr_span)), + Expr::Nothing => Ok(Value::nothing(expr_span)), Expr::ValueWithUnit(value) => match Self::eval::(state, mut_state, &value.expr)? { Value::Int { val, .. } => value.unit.item.build_value(val, value.unit.span), x => Err(ShellError::CantConvert { to_type: "unit value".into(), from_type: x.get_type().to_string(), - span: value.expr.span, + span: value.expr.span(&state), help: None, }), }, - Expr::Call(call) => Self::eval_call::(state, mut_state, call, expr.span), + Expr::Call(call) => Self::eval_call::(state, mut_state, call, expr_span), Expr::ExternalCall(head, args) => { - Self::eval_external_call(state, mut_state, head, args, expr.span) + Self::eval_external_call(state, mut_state, head, args, expr_span) } Expr::Subexpression(block_id) => { - Self::eval_subexpression::(state, mut_state, *block_id, expr.span) + Self::eval_subexpression::(state, mut_state, *block_id, expr_span) } Expr::Range(range) => { let from = if let Some(f) = &range.from { Self::eval::(state, mut_state, f)? } else { - Value::nothing(expr.span) + Value::nothing(expr_span) }; let next = if let Some(s) = &range.next { Self::eval::(state, mut_state, s)? } else { - Value::nothing(expr.span) + Value::nothing(expr_span) }; let to = if let Some(t) = &range.to { Self::eval::(state, mut_state, t)? } else { - Value::nothing(expr.span) + Value::nothing(expr_span) }; Ok(Value::range( - Range::new(from, next, to, range.operator.inclusion, expr.span)?, - expr.span, + Range::new(from, next, to, range.operator.inclusion, expr_span)?, + expr_span, )) } Expr::UnaryNot(expr) => { let lhs = Self::eval::(state, mut_state, expr)?; match lhs { - Value::Bool { val, .. } => Ok(Value::bool(!val, expr.span)), + Value::Bool { val, .. } => Ok(Value::bool(!val, expr_span)), other => Err(ShellError::TypeMismatch { err_message: format!("expected bool, found {}", other.get_type()), - span: expr.span, + span: expr_span, }), } } Expr::BinaryOp(lhs, op, rhs) => { - let op_span = op.span; + let op_span = op.span(&state); let op = eval_operator(op)?; match op { @@ -200,23 +205,23 @@ pub trait Eval { match boolean { Boolean::And => { if lhs.is_false() { - Ok(Value::bool(false, expr.span)) + Ok(Value::bool(false, expr_span)) } else { let rhs = Self::eval::(state, mut_state, rhs)?; - lhs.and(op_span, &rhs, expr.span) + lhs.and(op_span, &rhs, expr_span) } } Boolean::Or => { if lhs.is_true() { - Ok(Value::bool(true, expr.span)) + Ok(Value::bool(true, expr_span)) } else { let rhs = Self::eval::(state, mut_state, rhs)?; - lhs.or(op_span, &rhs, expr.span) + lhs.or(op_span, &rhs, expr_span) } } Boolean::Xor => { let rhs = Self::eval::(state, mut_state, rhs)?; - lhs.xor(op_span, &rhs, expr.span) + lhs.xor(op_span, &rhs, expr_span) } } } @@ -225,35 +230,35 @@ pub trait Eval { let rhs = Self::eval::(state, mut_state, rhs)?; match math { - Math::Plus => lhs.add(op_span, &rhs, expr.span), - Math::Minus => lhs.sub(op_span, &rhs, expr.span), - Math::Multiply => lhs.mul(op_span, &rhs, expr.span), - Math::Divide => lhs.div(op_span, &rhs, expr.span), - Math::Append => lhs.append(op_span, &rhs, expr.span), - Math::Modulo => lhs.modulo(op_span, &rhs, expr.span), - Math::FloorDivision => lhs.floor_div(op_span, &rhs, expr.span), - Math::Pow => lhs.pow(op_span, &rhs, expr.span), + Math::Plus => lhs.add(op_span, &rhs, expr_span), + Math::Minus => lhs.sub(op_span, &rhs, expr_span), + Math::Multiply => lhs.mul(op_span, &rhs, expr_span), + Math::Divide => lhs.div(op_span, &rhs, expr_span), + Math::Append => lhs.append(op_span, &rhs, expr_span), + Math::Modulo => lhs.modulo(op_span, &rhs, expr_span), + Math::FloorDivision => lhs.floor_div(op_span, &rhs, expr_span), + Math::Pow => lhs.pow(op_span, &rhs, expr_span), } } Operator::Comparison(comparison) => { let lhs = Self::eval::(state, mut_state, lhs)?; let rhs = Self::eval::(state, mut_state, rhs)?; match comparison { - Comparison::LessThan => lhs.lt(op_span, &rhs, expr.span), - Comparison::LessThanOrEqual => lhs.lte(op_span, &rhs, expr.span), - Comparison::GreaterThan => lhs.gt(op_span, &rhs, expr.span), - Comparison::GreaterThanOrEqual => lhs.gte(op_span, &rhs, expr.span), - Comparison::Equal => lhs.eq(op_span, &rhs, expr.span), - Comparison::NotEqual => lhs.ne(op_span, &rhs, expr.span), - Comparison::In => lhs.r#in(op_span, &rhs, expr.span), - Comparison::NotIn => lhs.not_in(op_span, &rhs, expr.span), - Comparison::StartsWith => lhs.starts_with(op_span, &rhs, expr.span), - Comparison::EndsWith => lhs.ends_with(op_span, &rhs, expr.span), + Comparison::LessThan => lhs.lt(op_span, &rhs, expr_span), + Comparison::LessThanOrEqual => lhs.lte(op_span, &rhs, expr_span), + Comparison::GreaterThan => lhs.gt(op_span, &rhs, expr_span), + Comparison::GreaterThanOrEqual => lhs.gte(op_span, &rhs, expr_span), + Comparison::Equal => lhs.eq(op_span, &rhs, expr_span), + Comparison::NotEqual => lhs.ne(op_span, &rhs, expr_span), + Comparison::In => lhs.r#in(op_span, &rhs, expr_span), + Comparison::NotIn => lhs.not_in(op_span, &rhs, expr_span), + Comparison::StartsWith => lhs.starts_with(op_span, &rhs, expr_span), + Comparison::EndsWith => lhs.ends_with(op_span, &rhs, expr_span), Comparison::RegexMatch => { - Self::regex_match(state, op_span, &lhs, &rhs, false, expr.span) + Self::regex_match(state, op_span, &lhs, &rhs, false, expr_span) } Comparison::NotRegexMatch => { - Self::regex_match(state, op_span, &lhs, &rhs, true, expr.span) + Self::regex_match(state, op_span, &lhs, &rhs, true, expr_span) } } } @@ -261,20 +266,20 @@ pub trait Eval { let lhs = Self::eval::(state, mut_state, lhs)?; let rhs = Self::eval::(state, mut_state, rhs)?; match bits { - Bits::BitAnd => lhs.bit_and(op_span, &rhs, expr.span), - Bits::BitOr => lhs.bit_or(op_span, &rhs, expr.span), - Bits::BitXor => lhs.bit_xor(op_span, &rhs, expr.span), - Bits::ShiftLeft => lhs.bit_shl(op_span, &rhs, expr.span), - Bits::ShiftRight => lhs.bit_shr(op_span, &rhs, expr.span), + Bits::BitAnd => lhs.bit_and(op_span, &rhs, expr_span), + Bits::BitOr => lhs.bit_or(op_span, &rhs, expr_span), + Bits::BitXor => lhs.bit_xor(op_span, &rhs, expr_span), + Bits::ShiftLeft => lhs.bit_shl(op_span, &rhs, expr_span), + Bits::ShiftRight => lhs.bit_shr(op_span, &rhs, expr_span), } } Operator::Assignment(assignment) => Self::eval_assignment::( - state, mut_state, lhs, rhs, assignment, op_span, expr.span + state, mut_state, lhs, rhs, assignment, op_span, expr_span ), } } Expr::RowCondition(block_id) | Expr::Closure(block_id) => { - Self::eval_row_condition_or_closure(state, mut_state, *block_id, expr.span) + Self::eval_row_condition_or_closure(state, mut_state, *block_id, expr_span) } Expr::StringInterpolation(exprs) => { let config = Self::get_config(state, mut_state); @@ -283,13 +288,13 @@ pub trait Eval { .map(|expr| Self::eval::(state, mut_state, expr).map(|v| v.to_expanded_string(", ", &config))) .collect::>()?; - Ok(Value::string(str, expr.span)) + Ok(Value::string(str, expr_span)) } - Expr::Overlay(_) => Self::eval_overlay(state, expr.span), + Expr::Overlay(_) => Self::eval_overlay(state, expr_span), Expr::GlobPattern(pattern, quoted) => { // GlobPattern is similar to Filepath // But we don't want to expand path during eval time, it's required for `nu_engine::glob_from` to run correctly - Ok(Value::glob(pattern, *quoted, expr.span)) + Ok(Value::glob(pattern, *quoted, expr_span)) } Expr::MatchBlock(_) // match blocks are handled by `match` | Expr::Block(_) // blocks are handled directly by core commands @@ -297,7 +302,7 @@ pub trait Eval { | Expr::ImportPattern(_) | Expr::Signature(_) | Expr::Operator(_) - | Expr::Garbage => Self::unreachable(expr), + | Expr::Garbage => Self::unreachable(state, expr), } } @@ -378,5 +383,5 @@ pub trait Eval { fn eval_overlay(state: Self::State<'_>, span: Span) -> Result; /// For expressions that should never actually be evaluated - fn unreachable(expr: &Expression) -> Result; + fn unreachable(state: Self::State<'_>, expr: &Expression) -> Result; } diff --git a/crates/nu-protocol/src/eval_const.rs b/crates/nu-protocol/src/eval_const.rs index 4cc7e25324..08ff6fa391 100644 --- a/crates/nu-protocol/src/eval_const.rs +++ b/crates/nu-protocol/src/eval_const.rs @@ -251,7 +251,7 @@ pub fn eval_constant_with_input( Expr::Call(call) => eval_const_call(working_set, call, input), Expr::Subexpression(block_id) => { let block = working_set.get_block(*block_id); - eval_const_subexpression(working_set, block, input, expr.span) + eval_const_subexpression(working_set, block, input, expr.span(&working_set)) } _ => eval_constant(working_set, expr).map(|v| PipelineData::Value(v, None)), } @@ -379,7 +379,9 @@ impl Eval for EvalConst { Err(ShellError::NotAConstant { span }) } - fn unreachable(expr: &Expression) -> Result { - Err(ShellError::NotAConstant { span: expr.span }) + fn unreachable(working_set: &StateWorkingSet, expr: &Expression) -> Result { + Err(ShellError::NotAConstant { + span: expr.span(&working_set), + }) } } diff --git a/crates/nu-protocol/src/span.rs b/crates/nu-protocol/src/span.rs index 3d32aa4ddf..0d280eaa9d 100644 --- a/crates/nu-protocol/src/span.rs +++ b/crates/nu-protocol/src/span.rs @@ -1,7 +1,12 @@ +use crate::SpanId; use miette::SourceSpan; use serde::{Deserialize, Serialize}; use std::ops::Deref; +pub trait GetSpan { + fn get_span(&self, span_id: SpanId) -> Span; +} + /// A spanned area of interest, generic over what kind of thing is of interest #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct Spanned {