nushell/crates/nu-cli/src/eval_cmds.rs
Devyn Cairns 5d1eb031eb
Turn compile errors into fatal errors (#14388)
# Description

Because the IR compiler was previously optional, compile errors were not
treated as fatal errors, and were just logged like parse warnings are.
This unfortunately meant that if a user encountered a compile error,
they would see "Can't evaluate block in IR mode" as the actual error in
addition to (hopefully) logging the compile error.

This changes compile errors to be treated like parse errors so that they
show up as the last error, helping users understand what's wrong a
little bit more easily.

Fixes #14333.

# User-Facing Changes
- Shouldn't see "Can't evaluate block in IR mode"
- Should only see compile error
- No evaluation should happen

# Tests + Formatting
Didn't add any tests specifically for this, but it might be good to have
at least one that checks to ensure the compile error shows up and the
"can't evaluate" error does not.
2024-11-20 19:24:03 +08:00

104 lines
3.0 KiB
Rust

use log::info;
use nu_engine::{convert_env_values, eval_block};
use nu_parser::parse;
use nu_protocol::{
cli_error::report_compile_error,
debugger::WithoutDebug,
engine::{EngineState, Stack, StateWorkingSet},
report_parse_error, report_parse_warning, PipelineData, ShellError, Spanned, Value,
};
use std::sync::Arc;
use crate::util::print_pipeline;
#[derive(Default)]
pub struct EvaluateCommandsOpts {
pub table_mode: Option<Value>,
pub error_style: Option<Value>,
pub no_newline: bool,
}
/// Run a command (or commands) given to us by the user
pub fn evaluate_commands(
commands: &Spanned<String>,
engine_state: &mut EngineState,
stack: &mut Stack,
input: PipelineData,
opts: EvaluateCommandsOpts,
) -> Result<(), ShellError> {
let EvaluateCommandsOpts {
table_mode,
error_style,
no_newline,
} = opts;
// Handle the configured error style early
if let Some(e_style) = error_style {
match e_style.coerce_str()?.parse() {
Ok(e_style) => {
Arc::make_mut(&mut engine_state.config).error_style = e_style;
}
Err(err) => {
return Err(ShellError::GenericError {
error: "Invalid value for `--error-style`".into(),
msg: err.into(),
span: Some(e_style.span()),
help: None,
inner: vec![],
});
}
}
}
// Translate environment variables from Strings to Values
convert_env_values(engine_state, stack)?;
// Parse the source code
let (block, delta) = {
if let Some(ref t_mode) = table_mode {
Arc::make_mut(&mut engine_state.config).table.mode =
t_mode.coerce_str()?.parse().unwrap_or_default();
}
let mut working_set = StateWorkingSet::new(engine_state);
let output = parse(&mut working_set, None, commands.item.as_bytes(), false);
if let Some(warning) = working_set.parse_warnings.first() {
report_parse_warning(&working_set, warning);
}
if let Some(err) = working_set.parse_errors.first() {
report_parse_error(&working_set, err);
std::process::exit(1);
}
if let Some(err) = working_set.compile_errors.first() {
report_compile_error(&working_set, err);
std::process::exit(1);
}
(output, working_set.render())
};
// Update permanent state
engine_state.merge_delta(delta)?;
// Run the block
let pipeline = eval_block::<WithoutDebug>(engine_state, stack, &block, input)?;
if let PipelineData::Value(Value::Error { error, .. }, ..) = pipeline {
return Err(*error);
}
if let Some(t_mode) = table_mode {
Arc::make_mut(&mut engine_state.config).table.mode =
t_mode.coerce_str()?.parse().unwrap_or_default();
}
print_pipeline(engine_state, stack, pipeline, no_newline)?;
info!("evaluate {}:{}:{}", file!(), line!(), column!());
Ok(())
}