Revert "Span ID Refactor (Step 2): Use SpanId of expressions in some places (…"

This reverts commit e52d7bc585.
This commit is contained in:
Darren Schroeder 2024-06-10 10:16:25 -04:00 committed by GitHub
parent af22bb8d52
commit f13127dfde
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 159 additions and 148 deletions

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*; use nu_engine::{command_prelude::*, get_eval_expression};
use nu_parser::parse_expression;
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, ListStream}; use nu_protocol::{ast::PathMember, engine::StateWorkingSet, ListStream};
#[derive(Clone)] #[derive(Clone)]
@ -56,7 +57,14 @@ impl Command for FormatPattern {
string_span.start + 1, string_span.start + 1,
)?; )?;
format(input_val, &ops, engine_state, call.head) format(
input_val,
&ops,
engine_state,
&mut working_set,
stack,
call.head,
)
} }
} }
} }
@ -92,6 +100,8 @@ enum FormatOperation {
FixedText(String), FixedText(String),
// raw input is something like {column1.column2} // raw input is something like {column1.column2}
ValueFromColumn(String, Span), 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 /// Given a pattern that is fed into the Format command, we can process it and subdivide it
@ -100,6 +110,7 @@ enum FormatOperation {
/// there without any further processing. /// there without any further processing.
/// FormatOperation::ValueFromColumn contains the name of a column whose values will be /// FormatOperation::ValueFromColumn contains the name of a column whose values will be
/// formatted according to the input pattern. /// formatted according to the input pattern.
/// FormatOperation::ValueNeedEval contains expression which need to eval, it has the following form:
/// "$it.column1.column2" or "$variable" /// "$it.column1.column2" or "$variable"
fn extract_formatting_operations( fn extract_formatting_operations(
input: String, input: String,
@ -150,17 +161,10 @@ fn extract_formatting_operations(
if !column_name.is_empty() { if !column_name.is_empty() {
if column_need_eval { if column_need_eval {
return Err(ShellError::GenericError { output.push(FormatOperation::ValueNeedEval(
error: "Removed functionality".into(), column_name.clone(),
msg: "The ability to use variables ($it) in `format pattern` has been removed." Span::new(span_start + column_span_start, span_start + column_span_end),
.into(), ));
span: Some(error_span),
help: Some(
"You can use other formatting options, such as string interpolation."
.into(),
),
inner: vec![],
});
} else { } else {
output.push(FormatOperation::ValueFromColumn( output.push(FormatOperation::ValueFromColumn(
column_name.clone(), column_name.clone(),
@ -181,6 +185,8 @@ fn format(
input_data: Value, input_data: Value,
format_operations: &[FormatOperation], format_operations: &[FormatOperation],
engine_state: &EngineState, engine_state: &EngineState,
working_set: &mut StateWorkingSet,
stack: &mut Stack,
head_span: Span, head_span: Span,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let data_as_value = input_data; let data_as_value = input_data;
@ -188,7 +194,13 @@ fn format(
// We can only handle a Record or a List of Records // We can only handle a Record or a List of Records
match data_as_value { match data_as_value {
Value::Record { .. } => { Value::Record { .. } => {
match format_record(format_operations, &data_as_value, engine_state) { match format_record(
format_operations,
&data_as_value,
engine_state,
working_set,
stack,
) {
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)), Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
Err(value) => Err(value), Err(value) => Err(value),
} }
@ -199,7 +211,13 @@ fn format(
for val in vals.iter() { for val in vals.iter() {
match val { match val {
Value::Record { .. } => { Value::Record { .. } => {
match format_record(format_operations, val, engine_state) { match format_record(
format_operations,
val,
engine_state,
working_set,
stack,
) {
Ok(value) => { Ok(value) => {
list.push(Value::string(value, head_span)); list.push(Value::string(value, head_span));
} }
@ -238,9 +256,12 @@ fn format_record(
format_operations: &[FormatOperation], format_operations: &[FormatOperation],
data_as_value: &Value, data_as_value: &Value,
engine_state: &EngineState, engine_state: &EngineState,
working_set: &mut StateWorkingSet,
stack: &mut Stack,
) -> Result<String, ShellError> { ) -> Result<String, ShellError> {
let config = engine_state.get_config(); let config = engine_state.get_config();
let mut output = String::new(); let mut output = String::new();
let eval_expression = get_eval_expression(engine_state);
for op in format_operations { for op in format_operations {
match op { match op {
@ -262,6 +283,23 @@ fn format_record(
Err(se) => return Err(se), 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) Ok(output)

View File

@ -37,7 +37,7 @@ fn given_fields_can_be_column_paths() {
} }
#[test] #[test]
fn cant_use_variables() { fn can_use_variables() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", pipeline( cwd: "tests/fixtures/formats", pipeline(
r#" r#"
@ -46,8 +46,7 @@ fn cant_use_variables() {
"# "#
)); ));
// TODO SPAN: This has been removed during SpanId refactor assert_eq!(actual.out, "nu is a new type of shell");
assert!(actual.err.contains("Removed functionality"));
} }
#[test] #[test]
@ -56,7 +55,7 @@ fn error_unmatched_brace() {
cwd: "tests/fixtures/formats", pipeline( cwd: "tests/fixtures/formats", pipeline(
r#" r#"
open cargo_sample.toml open cargo_sample.toml
| format pattern "{package.name" | format pattern "{$it.package.name"
"# "#
)); ));

View File

@ -208,13 +208,11 @@ fn eval_external(
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let decl_id = engine_state let decl_id = engine_state
.find_decl("run-external".as_bytes(), &[]) .find_decl("run-external".as_bytes(), &[])
.ok_or(ShellError::ExternalNotSupported { .ok_or(ShellError::ExternalNotSupported { span: head.span })?;
span: head.span(&engine_state),
})?;
let command = engine_state.get_decl(decl_id); let command = engine_state.get_decl(decl_id);
let mut call = Call::new(head.span(&engine_state)); let mut call = Call::new(head.span);
call.add_positional(head.clone()); call.add_positional(head.clone());
@ -714,7 +712,7 @@ impl Eval for EvalRuntime {
args: &[ExternalArgument], args: &[ExternalArgument],
_: Span, _: Span,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
let span = head.span(&engine_state); let span = head.span;
// FIXME: protect this collect with ctrl-c // FIXME: protect this collect with ctrl-c
eval_external(engine_state, stack, head, args, PipelineData::empty())?.into_value(span) eval_external(engine_state, stack, head, args, PipelineData::empty())?.into_value(span)
} }
@ -781,11 +779,9 @@ impl Eval for EvalRuntime {
let var_info = engine_state.get_var(*var_id); let var_info = engine_state.get_var(*var_id);
if var_info.mutable { if var_info.mutable {
stack.add_var(*var_id, rhs); stack.add_var(*var_id, rhs);
Ok(Value::nothing(lhs.span(&engine_state))) Ok(Value::nothing(lhs.span))
} else { } else {
Err(ShellError::AssignmentRequiresMutableVar { Err(ShellError::AssignmentRequiresMutableVar { lhs_span: lhs.span })
lhs_span: lhs.span(&engine_state),
})
} }
} }
Expr::FullCellPath(cell_path) => { Expr::FullCellPath(cell_path) => {
@ -801,7 +797,7 @@ impl Eval for EvalRuntime {
// Reject attempts to assign to the entire $env // Reject attempts to assign to the entire $env
if cell_path.tail.is_empty() { if cell_path.tail.is_empty() {
return Err(ShellError::CannotReplaceEnv { return Err(ShellError::CannotReplaceEnv {
span: cell_path.head.span(&engine_state), span: cell_path.head.span,
}); });
} }
@ -841,21 +837,15 @@ impl Eval for EvalRuntime {
lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?; lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?;
stack.add_var(*var_id, lhs); stack.add_var(*var_id, lhs);
} }
Ok(Value::nothing(cell_path.head.span(&engine_state))) Ok(Value::nothing(cell_path.head.span))
} else { } else {
Err(ShellError::AssignmentRequiresMutableVar { Err(ShellError::AssignmentRequiresMutableVar { lhs_span: lhs.span })
lhs_span: lhs.span(&engine_state),
})
} }
} }
_ => Err(ShellError::AssignmentRequiresVar { _ => Err(ShellError::AssignmentRequiresVar { lhs_span: lhs.span }),
lhs_span: lhs.span(&engine_state),
}),
} }
} }
_ => Err(ShellError::AssignmentRequiresVar { _ => Err(ShellError::AssignmentRequiresVar { lhs_span: lhs.span }),
lhs_span: lhs.span(&engine_state),
}),
} }
} }
@ -892,8 +882,8 @@ impl Eval for EvalRuntime {
Ok(Value::string(name, span)) Ok(Value::string(name, span))
} }
fn unreachable(engine_state: &EngineState, expr: &Expression) -> Result<Value, ShellError> { fn unreachable(expr: &Expression) -> Result<Value, ShellError> {
Ok(Value::nothing(expr.span(&engine_state))) Ok(Value::nothing(expr.span))
} }
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
ast::{Argument, Block, Expr, ExternalArgument, ImportPattern, MatchPattern, RecordItem}, ast::{Argument, Block, Expr, ExternalArgument, ImportPattern, MatchPattern, RecordItem},
engine::StateWorkingSet, engine::{EngineState, StateWorkingSet},
BlockId, DeclId, GetSpan, Signature, Span, SpanId, Type, VarId, IN_VARIABLE_ID, BlockId, DeclId, Signature, Span, SpanId, Type, VarId, IN_VARIABLE_ID,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
@ -516,7 +516,7 @@ impl Expression {
} }
} }
pub fn span(&self, state: &impl GetSpan) -> Span { pub fn span(&self, engine_state: &EngineState) -> Span {
state.get_span(self.span_id) engine_state.get_span(self.span_id)
} }
} }

View File

@ -7,7 +7,7 @@ use crate::{
Variable, Visibility, DEFAULT_OVERLAY_NAME, Variable, Visibility, DEFAULT_OVERLAY_NAME,
}, },
eval_const::create_nu_constant, eval_const::create_nu_constant,
BlockId, Category, Config, DeclId, FileId, GetSpan, HistoryConfig, Module, ModuleId, OverlayId, BlockId, Category, Config, DeclId, FileId, HistoryConfig, Module, ModuleId, OverlayId,
ShellError, Signature, Span, SpanId, Type, Value, VarId, VirtualPathId, ShellError, Signature, Span, SpanId, Type, Value, VarId, VirtualPathId,
}; };
use fancy_regex::Regex; use fancy_regex::Regex;
@ -1035,20 +1035,18 @@ impl EngineState {
SpanId(self.num_spans() - 1) SpanId(self.num_spans() - 1)
} }
/// Find ID of a span (should be avoided if possible)
pub fn find_span_id(&self, span: Span) -> Option<SpanId> {
self.spans.iter().position(|sp| sp == &span).map(SpanId)
}
}
impl<'a> GetSpan for &'a EngineState {
/// Get existing span /// Get existing span
fn get_span(&self, span_id: SpanId) -> Span { pub fn get_span(&self, span_id: SpanId) -> Span {
*self *self
.spans .spans
.get(span_id.0) .get(span_id.0)
.expect("internal error: missing span") .expect("internal error: missing span")
} }
/// Find ID of a span (should be avoided if possible)
pub fn find_span_id(&self, span: Span) -> Option<SpanId> {
self.spans.iter().position(|sp| sp == &span).map(SpanId)
}
} }
impl Default for EngineState { impl Default for EngineState {

View File

@ -4,8 +4,8 @@ use crate::{
usage::build_usage, CachedFile, Command, CommandType, EngineState, OverlayFrame, usage::build_usage, CachedFile, Command, CommandType, EngineState, OverlayFrame,
StateDelta, Variable, VirtualPath, Visibility, StateDelta, Variable, VirtualPath, Visibility,
}, },
BlockId, Category, Config, DeclId, FileId, GetSpan, Module, ModuleId, ParseError, ParseWarning, BlockId, Category, Config, DeclId, FileId, Module, ModuleId, ParseError, ParseWarning, Span,
Span, SpanId, Type, Value, VarId, VirtualPathId, SpanId, Type, Value, VarId, VirtualPathId,
}; };
use core::panic; use core::panic;
use std::{ use std::{
@ -1019,10 +1019,8 @@ impl<'a> StateWorkingSet<'a> {
self.delta.spans.push(span); self.delta.spans.push(span);
SpanId(num_permanent_spans + self.delta.spans.len() - 1) SpanId(num_permanent_spans + self.delta.spans.len() - 1)
} }
}
impl<'a> GetSpan for &'a StateWorkingSet<'a> { pub fn get_span(&self, span_id: SpanId) -> Span {
fn get_span(&self, span_id: SpanId) -> Span {
let num_permanent_spans = self.permanent_state.num_spans(); let num_permanent_spans = self.permanent_state.num_spans();
if span_id.0 < num_permanent_spans { if span_id.0 < num_permanent_spans {
self.permanent_state.get_span(span_id) self.permanent_state.get_span(span_id)

View File

@ -4,7 +4,7 @@ use crate::{
ExternalArgument, ListItem, Math, Operator, RecordItem, ExternalArgument, ListItem, Math, Operator, RecordItem,
}, },
debugger::DebugContext, debugger::DebugContext,
Config, GetSpan, Range, Record, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, Config, Range, Record, ShellError, Span, Value, VarId, ENV_VARIABLE_ID,
}; };
use std::{borrow::Cow, collections::HashMap}; use std::{borrow::Cow, collections::HashMap};
@ -12,7 +12,7 @@ use std::{borrow::Cow, collections::HashMap};
pub trait Eval { pub trait Eval {
/// State that doesn't need to be mutated. /// State that doesn't need to be mutated.
/// EngineState for regular eval and StateWorkingSet for const eval /// EngineState for regular eval and StateWorkingSet for const eval
type State<'a>: Copy + GetSpan; type State<'a>: Copy;
/// State that needs to be mutated. /// State that needs to be mutated.
/// This is the stack for regular eval, and unused by const eval /// This is the stack for regular eval, and unused by const eval
@ -23,19 +23,17 @@ pub trait Eval {
mut_state: &mut Self::MutState, mut_state: &mut Self::MutState,
expr: &Expression, expr: &Expression,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
let expr_span = expr.span(&state);
match &expr.expr { match &expr.expr {
Expr::Bool(b) => Ok(Value::bool(*b, expr_span)), Expr::Bool(b) => Ok(Value::bool(*b, expr.span)),
Expr::Int(i) => Ok(Value::int(*i, expr_span)), Expr::Int(i) => Ok(Value::int(*i, expr.span)),
Expr::Float(f) => Ok(Value::float(*f, expr_span)), Expr::Float(f) => Ok(Value::float(*f, expr.span)),
Expr::Binary(b) => Ok(Value::binary(b.clone(), 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::Filepath(path, quoted) => Self::eval_filepath(state, mut_state, path.clone(), *quoted, expr.span),
Expr::Directory(path, quoted) => { 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::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::CellPath(cell_path) => Ok(Value::cell_path(cell_path.clone(), expr.span)),
Expr::FullCellPath(cell_path) => { Expr::FullCellPath(cell_path) => {
let value = Self::eval::<D>(state, mut_state, &cell_path.head)?; let value = Self::eval::<D>(state, mut_state, &cell_path.head)?;
@ -47,7 +45,7 @@ pub trait Eval {
value.follow_cell_path(&cell_path.tail, false) 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) => { Expr::List(list) => {
let mut output = vec![]; let mut output = vec![];
for item in list { for item in list {
@ -55,11 +53,11 @@ pub trait Eval {
ListItem::Item(expr) => output.push(Self::eval::<D>(state, mut_state, expr)?), ListItem::Item(expr) => output.push(Self::eval::<D>(state, mut_state, expr)?),
ListItem::Spread(_, expr) => match Self::eval::<D>(state, mut_state, expr)? { ListItem::Spread(_, expr) => match Self::eval::<D>(state, mut_state, expr)? {
Value::List { vals, .. } => output.extend(vals), 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) => { Expr::Record(items) => {
let mut record = Record::new(); let mut record = Record::new();
@ -69,38 +67,36 @@ pub trait Eval {
RecordItem::Pair(col, val) => { RecordItem::Pair(col, val) => {
// avoid duplicate cols // avoid duplicate cols
let col_name = Self::eval::<D>(state, mut_state, col)?.coerce_into_string()?; let col_name = Self::eval::<D>(state, mut_state, col)?.coerce_into_string()?;
let col_span = col.span(&state);
if let Some(orig_span) = col_names.get(&col_name) { if let Some(orig_span) = col_names.get(&col_name) {
return Err(ShellError::ColumnDefinedTwice { return Err(ShellError::ColumnDefinedTwice {
col_name, col_name,
second_use: col_span, second_use: col.span,
first_use: *orig_span, first_use: *orig_span,
}); });
} else { } else {
col_names.insert(col_name.clone(), col_span); col_names.insert(col_name.clone(), col.span);
record.push(col_name, Self::eval::<D>(state, mut_state, val)?); record.push(col_name, Self::eval::<D>(state, mut_state, val)?);
} }
} }
RecordItem::Spread(_, inner) => { RecordItem::Spread(_, inner) => {
let inner_span = inner.span(&state);
match Self::eval::<D>(state, mut_state, inner)? { match Self::eval::<D>(state, mut_state, inner)? {
Value::Record { val: inner_val, .. } => { Value::Record { val: inner_val, .. } => {
for (col_name, val) in inner_val.into_owned() { for (col_name, val) in inner_val.into_owned() {
if let Some(orig_span) = col_names.get(&col_name) { if let Some(orig_span) = col_names.get(&col_name) {
return Err(ShellError::ColumnDefinedTwice { return Err(ShellError::ColumnDefinedTwice {
col_name, col_name,
second_use: inner_span, second_use: inner.span,
first_use: *orig_span, first_use: *orig_span,
}); });
} else { } else {
col_names.insert(col_name.clone(), inner_span); col_names.insert(col_name.clone(), inner.span);
record.push(col_name, val); record.push(col_name, val);
} }
} }
} }
_ => { _ => {
return Err(ShellError::CannotSpreadAsRecord { return Err(ShellError::CannotSpreadAsRecord {
span: inner_span, span: inner.span,
}) })
} }
} }
@ -108,7 +104,7 @@ pub trait Eval {
} }
} }
Ok(Value::record(record, expr_span)) Ok(Value::record(record, expr.span))
} }
Expr::Table(table) => { Expr::Table(table) => {
let mut output_headers = vec![]; let mut output_headers = vec![];
@ -118,11 +114,10 @@ pub trait Eval {
.iter() .iter()
.position(|existing| existing == &header) .position(|existing| existing == &header)
{ {
let first_use = table.columns[idx].span(&state);
return Err(ShellError::ColumnDefinedTwice { return Err(ShellError::ColumnDefinedTwice {
col_name: header, col_name: header,
second_use: expr_span, second_use: expr.span,
first_use, first_use: table.columns[idx].span,
}); });
} else { } else {
output_headers.push(header); output_headers.push(header);
@ -137,66 +132,66 @@ pub trait Eval {
output_rows.push(Value::record( output_rows.push(Value::record(
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::<D>(state, mut_state, &kw.expr), Expr::Keyword(kw) => Self::eval::<D>(state, mut_state, &kw.expr),
Expr::String(s) | Expr::RawString(s) => Ok(Value::string(s.clone(), expr_span)), Expr::String(s) | Expr::RawString(s) => Ok(Value::string(s.clone(), expr.span)),
Expr::Nothing => Ok(Value::nothing(expr_span)), Expr::Nothing => Ok(Value::nothing(expr.span)),
Expr::ValueWithUnit(value) => match Self::eval::<D>(state, mut_state, &value.expr)? { Expr::ValueWithUnit(value) => match Self::eval::<D>(state, mut_state, &value.expr)? {
Value::Int { val, .. } => value.unit.item.build_value(val, value.unit.span), Value::Int { val, .. } => value.unit.item.build_value(val, value.unit.span),
x => Err(ShellError::CantConvert { x => Err(ShellError::CantConvert {
to_type: "unit value".into(), to_type: "unit value".into(),
from_type: x.get_type().to_string(), from_type: x.get_type().to_string(),
span: value.expr.span(&state), span: value.expr.span,
help: None, help: None,
}), }),
}, },
Expr::Call(call) => Self::eval_call::<D>(state, mut_state, call, expr_span), Expr::Call(call) => Self::eval_call::<D>(state, mut_state, call, expr.span),
Expr::ExternalCall(head, args) => { 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) => { Expr::Subexpression(block_id) => {
Self::eval_subexpression::<D>(state, mut_state, *block_id, expr_span) Self::eval_subexpression::<D>(state, mut_state, *block_id, expr.span)
} }
Expr::Range(range) => { Expr::Range(range) => {
let from = if let Some(f) = &range.from { let from = if let Some(f) = &range.from {
Self::eval::<D>(state, mut_state, f)? Self::eval::<D>(state, mut_state, f)?
} else { } else {
Value::nothing(expr_span) Value::nothing(expr.span)
}; };
let next = if let Some(s) = &range.next { let next = if let Some(s) = &range.next {
Self::eval::<D>(state, mut_state, s)? Self::eval::<D>(state, mut_state, s)?
} else { } else {
Value::nothing(expr_span) Value::nothing(expr.span)
}; };
let to = if let Some(t) = &range.to { let to = if let Some(t) = &range.to {
Self::eval::<D>(state, mut_state, t)? Self::eval::<D>(state, mut_state, t)?
} else { } else {
Value::nothing(expr_span) Value::nothing(expr.span)
}; };
Ok(Value::range( Ok(Value::range(
Range::new(from, next, to, range.operator.inclusion, expr_span)?, Range::new(from, next, to, range.operator.inclusion, expr.span)?,
expr_span, expr.span,
)) ))
} }
Expr::UnaryNot(expr) => { Expr::UnaryNot(expr) => {
let lhs = Self::eval::<D>(state, mut_state, expr)?; let lhs = Self::eval::<D>(state, mut_state, expr)?;
match lhs { match lhs {
Value::Bool { val, .. } => Ok(Value::bool(!val, expr_span)), Value::Bool { val, .. } => Ok(Value::bool(!val, expr.span)),
other => Err(ShellError::TypeMismatch { other => Err(ShellError::TypeMismatch {
err_message: format!("expected bool, found {}", other.get_type()), err_message: format!("expected bool, found {}", other.get_type()),
span: expr_span, span: expr.span,
}), }),
} }
} }
Expr::BinaryOp(lhs, op, rhs) => { Expr::BinaryOp(lhs, op, rhs) => {
let op_span = op.span(&state); let op_span = op.span;
let op = eval_operator(op)?; let op = eval_operator(op)?;
match op { match op {
@ -205,23 +200,23 @@ pub trait Eval {
match boolean { match boolean {
Boolean::And => { Boolean::And => {
if lhs.is_false() { if lhs.is_false() {
Ok(Value::bool(false, expr_span)) Ok(Value::bool(false, expr.span))
} else { } else {
let rhs = Self::eval::<D>(state, mut_state, rhs)?; let rhs = Self::eval::<D>(state, mut_state, rhs)?;
lhs.and(op_span, &rhs, expr_span) lhs.and(op_span, &rhs, expr.span)
} }
} }
Boolean::Or => { Boolean::Or => {
if lhs.is_true() { if lhs.is_true() {
Ok(Value::bool(true, expr_span)) Ok(Value::bool(true, expr.span))
} else { } else {
let rhs = Self::eval::<D>(state, mut_state, rhs)?; let rhs = Self::eval::<D>(state, mut_state, rhs)?;
lhs.or(op_span, &rhs, expr_span) lhs.or(op_span, &rhs, expr.span)
} }
} }
Boolean::Xor => { Boolean::Xor => {
let rhs = Self::eval::<D>(state, mut_state, rhs)?; let rhs = Self::eval::<D>(state, mut_state, rhs)?;
lhs.xor(op_span, &rhs, expr_span) lhs.xor(op_span, &rhs, expr.span)
} }
} }
} }
@ -230,35 +225,35 @@ pub trait Eval {
let rhs = Self::eval::<D>(state, mut_state, rhs)?; let rhs = Self::eval::<D>(state, mut_state, rhs)?;
match math { match math {
Math::Plus => lhs.add(op_span, &rhs, expr_span), Math::Plus => lhs.add(op_span, &rhs, expr.span),
Math::Minus => lhs.sub(op_span, &rhs, expr_span), Math::Minus => lhs.sub(op_span, &rhs, expr.span),
Math::Multiply => lhs.mul(op_span, &rhs, expr_span), Math::Multiply => lhs.mul(op_span, &rhs, expr.span),
Math::Divide => lhs.div(op_span, &rhs, expr_span), Math::Divide => lhs.div(op_span, &rhs, expr.span),
Math::Append => lhs.append(op_span, &rhs, expr_span), Math::Append => lhs.append(op_span, &rhs, expr.span),
Math::Modulo => lhs.modulo(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::FloorDivision => lhs.floor_div(op_span, &rhs, expr.span),
Math::Pow => lhs.pow(op_span, &rhs, expr_span), Math::Pow => lhs.pow(op_span, &rhs, expr.span),
} }
} }
Operator::Comparison(comparison) => { Operator::Comparison(comparison) => {
let lhs = Self::eval::<D>(state, mut_state, lhs)?; let lhs = Self::eval::<D>(state, mut_state, lhs)?;
let rhs = Self::eval::<D>(state, mut_state, rhs)?; let rhs = Self::eval::<D>(state, mut_state, rhs)?;
match comparison { match comparison {
Comparison::LessThan => lhs.lt(op_span, &rhs, expr_span), Comparison::LessThan => lhs.lt(op_span, &rhs, expr.span),
Comparison::LessThanOrEqual => lhs.lte(op_span, &rhs, expr_span), Comparison::LessThanOrEqual => lhs.lte(op_span, &rhs, expr.span),
Comparison::GreaterThan => lhs.gt(op_span, &rhs, expr_span), Comparison::GreaterThan => lhs.gt(op_span, &rhs, expr.span),
Comparison::GreaterThanOrEqual => lhs.gte(op_span, &rhs, expr_span), Comparison::GreaterThanOrEqual => lhs.gte(op_span, &rhs, expr.span),
Comparison::Equal => lhs.eq(op_span, &rhs, expr_span), Comparison::Equal => lhs.eq(op_span, &rhs, expr.span),
Comparison::NotEqual => lhs.ne(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::In => lhs.r#in(op_span, &rhs, expr.span),
Comparison::NotIn => lhs.not_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::StartsWith => lhs.starts_with(op_span, &rhs, expr.span),
Comparison::EndsWith => lhs.ends_with(op_span, &rhs, expr_span), Comparison::EndsWith => lhs.ends_with(op_span, &rhs, expr.span),
Comparison::RegexMatch => { 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 => { Comparison::NotRegexMatch => {
Self::regex_match(state, op_span, &lhs, &rhs, true, expr_span) Self::regex_match(state, op_span, &lhs, &rhs, true, expr.span)
} }
} }
} }
@ -266,20 +261,20 @@ pub trait Eval {
let lhs = Self::eval::<D>(state, mut_state, lhs)?; let lhs = Self::eval::<D>(state, mut_state, lhs)?;
let rhs = Self::eval::<D>(state, mut_state, rhs)?; let rhs = Self::eval::<D>(state, mut_state, rhs)?;
match bits { match bits {
Bits::BitAnd => lhs.bit_and(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::BitOr => lhs.bit_or(op_span, &rhs, expr.span),
Bits::BitXor => lhs.bit_xor(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::ShiftLeft => lhs.bit_shl(op_span, &rhs, expr.span),
Bits::ShiftRight => lhs.bit_shr(op_span, &rhs, expr_span), Bits::ShiftRight => lhs.bit_shr(op_span, &rhs, expr.span),
} }
} }
Operator::Assignment(assignment) => Self::eval_assignment::<D>( Operator::Assignment(assignment) => Self::eval_assignment::<D>(
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) => { 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) => { Expr::StringInterpolation(exprs) => {
let config = Self::get_config(state, mut_state); let config = Self::get_config(state, mut_state);
@ -288,13 +283,13 @@ pub trait Eval {
.map(|expr| Self::eval::<D>(state, mut_state, expr).map(|v| v.to_expanded_string(", ", &config))) .map(|expr| Self::eval::<D>(state, mut_state, expr).map(|v| v.to_expanded_string(", ", &config)))
.collect::<Result<String, _>>()?; .collect::<Result<String, _>>()?;
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) => { Expr::GlobPattern(pattern, quoted) => {
// GlobPattern is similar to Filepath // 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 // 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::MatchBlock(_) // match blocks are handled by `match`
| Expr::Block(_) // blocks are handled directly by core commands | Expr::Block(_) // blocks are handled directly by core commands
@ -302,7 +297,7 @@ pub trait Eval {
| Expr::ImportPattern(_) | Expr::ImportPattern(_)
| Expr::Signature(_) | Expr::Signature(_)
| Expr::Operator(_) | Expr::Operator(_)
| Expr::Garbage => Self::unreachable(state, expr), | Expr::Garbage => Self::unreachable(expr),
} }
} }
@ -383,5 +378,5 @@ pub trait Eval {
fn eval_overlay(state: Self::State<'_>, span: Span) -> Result<Value, ShellError>; fn eval_overlay(state: Self::State<'_>, span: Span) -> Result<Value, ShellError>;
/// For expressions that should never actually be evaluated /// For expressions that should never actually be evaluated
fn unreachable(state: Self::State<'_>, expr: &Expression) -> Result<Value, ShellError>; fn unreachable(expr: &Expression) -> Result<Value, ShellError>;
} }

View File

@ -251,7 +251,7 @@ pub fn eval_constant_with_input(
Expr::Call(call) => eval_const_call(working_set, call, input), Expr::Call(call) => eval_const_call(working_set, call, input),
Expr::Subexpression(block_id) => { Expr::Subexpression(block_id) => {
let block = working_set.get_block(*block_id); let block = working_set.get_block(*block_id);
eval_const_subexpression(working_set, block, input, expr.span(&working_set)) eval_const_subexpression(working_set, block, input, expr.span)
} }
_ => eval_constant(working_set, expr).map(|v| PipelineData::Value(v, None)), _ => eval_constant(working_set, expr).map(|v| PipelineData::Value(v, None)),
} }
@ -379,9 +379,7 @@ impl Eval for EvalConst {
Err(ShellError::NotAConstant { span }) Err(ShellError::NotAConstant { span })
} }
fn unreachable(working_set: &StateWorkingSet, expr: &Expression) -> Result<Value, ShellError> { fn unreachable(expr: &Expression) -> Result<Value, ShellError> {
Err(ShellError::NotAConstant { Err(ShellError::NotAConstant { span: expr.span })
span: expr.span(&working_set),
})
} }
} }

View File

@ -1,12 +1,7 @@
use crate::SpanId;
use miette::SourceSpan; use miette::SourceSpan;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::Deref; 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 /// A spanned area of interest, generic over what kind of thing is of interest
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct Spanned<T> { pub struct Spanned<T> {