Add transitive use_ir field to Stack and add --use-ir option to nu
This commit is contained in:
parent
73b092bfdc
commit
fd0b99554d
|
@ -1,6 +1,4 @@
|
|||
use nu_engine::{
|
||||
command_prelude::*, get_eval_block_with_early_return, get_eval_ir_block, redirect_env,
|
||||
};
|
||||
use nu_engine::{command_prelude::*, get_eval_block_with_early_return, redirect_env};
|
||||
use nu_protocol::{
|
||||
engine::Closure,
|
||||
process::{ChildPipe, ChildProcess, ExitStatus},
|
||||
|
@ -94,12 +92,13 @@ impl Command for Do {
|
|||
|
||||
bind_args_to(&mut callee_stack, &block.signature, rest, head)?;
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
let eval_ir_block = get_eval_ir_block(engine_state);
|
||||
let result = if use_ir {
|
||||
eval_ir_block(engine_state, &mut callee_stack, block, input)
|
||||
} else {
|
||||
eval_block_with_early_return(engine_state, &mut callee_stack, block, input)
|
||||
};
|
||||
|
||||
// Applies to all block evaluation once set true
|
||||
if use_ir {
|
||||
caller_stack.use_ir = true;
|
||||
}
|
||||
|
||||
let result = eval_block_with_early_return(engine_state, &mut callee_stack, block, input);
|
||||
|
||||
if has_env {
|
||||
// Merge the block's environment to the current stack
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use nu_engine::{command_prelude::*, compile};
|
||||
use nu_protocol::engine::Closure;
|
||||
|
||||
|
@ -31,7 +33,15 @@ impl Command for ViewIr {
|
|||
let closure: Closure = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let block = engine_state.get_block(closure.block_id);
|
||||
let ir_block = compile(&StateWorkingSet::new(engine_state), &block)?;
|
||||
// Use the pre-compiled block if available, otherwise try to compile it
|
||||
// This helps display the actual compilation error
|
||||
let ir_block = match &block.ir_block {
|
||||
Some(ir_block) => Cow::Borrowed(ir_block),
|
||||
None => Cow::Owned(
|
||||
compile(&StateWorkingSet::new(engine_state), &block)
|
||||
.map_err(|err| err.to_shell_error(block.span))?,
|
||||
),
|
||||
};
|
||||
|
||||
let formatted = format!("{}", ir_block.display(engine_state));
|
||||
Ok(Value::string(formatted, call.head).into_pipeline_data())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use nu_protocol::{
|
||||
ast::{
|
||||
Argument, Block, Call, CellPath, Expr, Expression, ListItem, Math, Operator, PathMember,
|
||||
Argument, Block, Call, CellPath, Expr, Expression, ListItem, Operator, PathMember,
|
||||
Pipeline, PipelineRedirection, RecordItem, RedirectionSource, RedirectionTarget,
|
||||
},
|
||||
engine::StateWorkingSet,
|
||||
|
@ -12,7 +12,7 @@ const BLOCK_INPUT: RegId = RegId(0);
|
|||
|
||||
/// Compile Nushell pipeline abstract syntax tree (AST) to internal representation (IR) instructions
|
||||
/// for evaluation.
|
||||
pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock, ShellError> {
|
||||
pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock, CompileError> {
|
||||
let mut builder = BlockBuilder::new();
|
||||
|
||||
compile_block(
|
||||
|
@ -22,16 +22,13 @@ pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock,
|
|||
RedirectModes::default(),
|
||||
Some(BLOCK_INPUT),
|
||||
BLOCK_INPUT,
|
||||
)
|
||||
.map_err(|err| err.to_shell_error(block.span))?;
|
||||
)?;
|
||||
|
||||
// A complete block has to end with a `return`
|
||||
builder
|
||||
.push(
|
||||
Instruction::Return { src: BLOCK_INPUT }
|
||||
.into_spanned(block.span.unwrap_or(Span::unknown())),
|
||||
)
|
||||
.map_err(|err| err.to_shell_error(block.span))?;
|
||||
builder.push(
|
||||
Instruction::Return { src: BLOCK_INPUT }
|
||||
.into_spanned(block.span.unwrap_or(Span::unknown())),
|
||||
)?;
|
||||
|
||||
Ok(builder.finish())
|
||||
}
|
||||
|
@ -369,7 +366,7 @@ fn compile_expression(
|
|||
.into_spanned(expr.span),
|
||||
)?;
|
||||
}
|
||||
ListItem::Spread(spread_span, expr) => {
|
||||
ListItem::Spread(spread_span, _) => {
|
||||
// Spread the list using list-spread
|
||||
builder.push(
|
||||
Instruction::ListSpread {
|
||||
|
@ -795,7 +792,7 @@ fn compile_load_env(
|
|||
/// An internal compiler error, generally means a Nushell bug rather than an issue with user error
|
||||
/// since parsing and typechecking has already passed.
|
||||
#[derive(Debug)]
|
||||
enum CompileError {
|
||||
pub enum CompileError {
|
||||
RegisterOverflow,
|
||||
RegisterUninitialized(RegId),
|
||||
DataOverflow,
|
||||
|
@ -807,8 +804,8 @@ enum CompileError {
|
|||
}
|
||||
|
||||
impl CompileError {
|
||||
fn to_shell_error(self, mut span: Option<Span>) -> ShellError {
|
||||
let message = match self {
|
||||
pub fn message(&self) -> String {
|
||||
match self {
|
||||
CompileError::RegisterOverflow => format!("register overflow"),
|
||||
CompileError::RegisterUninitialized(reg_id) => {
|
||||
format!("register {reg_id} is uninitialized when used, possibly reused")
|
||||
|
@ -821,15 +818,25 @@ impl CompileError {
|
|||
}
|
||||
CompileError::Garbage => "encountered garbage, likely due to parse error".into(),
|
||||
CompileError::UnsupportedOperatorExpression => "unsupported operator expression".into(),
|
||||
CompileError::AccessEnvByInt(local_span) => {
|
||||
span = Some(local_span);
|
||||
"attempted access of $env by integer path".into()
|
||||
}
|
||||
CompileError::AccessEnvByInt(_) => "attempted access of $env by integer path".into(),
|
||||
CompileError::Todo(msg) => {
|
||||
format!("TODO: {msg}")
|
||||
}
|
||||
};
|
||||
ShellError::IrCompileError { msg: message, span }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
match self {
|
||||
CompileError::AccessEnvByInt(span) => Some(*span),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_shell_error(self, span: Option<Span>) -> ShellError {
|
||||
ShellError::IrCompileError {
|
||||
msg: self.message(),
|
||||
span: self.span().or(span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::eval_ir_block;
|
||||
#[allow(deprecated)]
|
||||
use crate::{current_dir, get_config, get_full_help};
|
||||
use nu_path::expand_path_with;
|
||||
|
@ -509,6 +510,11 @@ pub fn eval_block<D: DebugContext>(
|
|||
block: &Block,
|
||||
mut input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// Remove once IR is the default.
|
||||
if stack.use_ir {
|
||||
return eval_ir_block::<D>(engine_state, stack, block, input);
|
||||
}
|
||||
|
||||
D::enter_block(engine_state, block);
|
||||
|
||||
let num_pipelines = block.len();
|
||||
|
|
|
@ -11,8 +11,8 @@ use itertools::Itertools;
|
|||
use log::trace;
|
||||
use nu_engine::DIR_VAR_PARSER_INFO;
|
||||
use nu_protocol::{
|
||||
ast::*, engine::StateWorkingSet, eval_const::eval_constant, report_error, BlockId, DidYouMean,
|
||||
Flag, ParseError, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId,
|
||||
ast::*, engine::StateWorkingSet, eval_const::eval_constant, BlockId, DidYouMean, Flag,
|
||||
ParseError, ParseWarning, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId,
|
||||
ENV_VARIABLE_ID, IN_VARIABLE_ID,
|
||||
};
|
||||
use std::{
|
||||
|
@ -5834,12 +5834,19 @@ pub fn parse_block(
|
|||
working_set.parse_errors.extend_from_slice(&errors);
|
||||
}
|
||||
|
||||
if !is_subexpression && errors.is_empty() {
|
||||
// Do not try to compile blocks that are subexpressions, or when we've already had a parse
|
||||
// failure as that definitely will fail to compile
|
||||
if !is_subexpression && working_set.parse_errors.is_empty() {
|
||||
match nu_engine::compile(working_set, &block) {
|
||||
Ok(ir_block) => {
|
||||
block.ir_block = Some(ir_block);
|
||||
}
|
||||
Err(err) => report_error(working_set, &err),
|
||||
Err(err) => working_set
|
||||
.parse_warnings
|
||||
.push(ParseWarning::IrCompileError {
|
||||
msg: err.message(),
|
||||
span,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ pub struct Stack {
|
|||
pub register_buf_cache: RegisterBufCache,
|
||||
/// Argument stack for IR evaluation
|
||||
pub argument_stack: ArgumentStack,
|
||||
/// Set true to always use IR mode
|
||||
pub use_ir: bool,
|
||||
pub recursion_count: u64,
|
||||
pub parent_stack: Option<Arc<Stack>>,
|
||||
/// Variables that have been deleted (this is used to hide values from parent stack lookups)
|
||||
|
@ -76,6 +78,7 @@ impl Stack {
|
|||
active_overlays: vec![DEFAULT_OVERLAY_NAME.to_string()],
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
use_ir: false,
|
||||
recursion_count: 0,
|
||||
parent_stack: None,
|
||||
parent_deletions: vec![],
|
||||
|
@ -95,6 +98,7 @@ impl Stack {
|
|||
active_overlays: parent.active_overlays.clone(),
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
use_ir: parent.use_ir,
|
||||
recursion_count: parent.recursion_count,
|
||||
vars: vec![],
|
||||
parent_deletions: vec![],
|
||||
|
@ -266,6 +270,7 @@ impl Stack {
|
|||
active_overlays: self.active_overlays.clone(),
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
use_ir: self.use_ir,
|
||||
recursion_count: self.recursion_count,
|
||||
parent_stack: None,
|
||||
parent_deletions: vec![],
|
||||
|
@ -298,6 +303,7 @@ impl Stack {
|
|||
active_overlays: self.active_overlays.clone(),
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
use_ir: self.use_ir,
|
||||
recursion_count: self.recursion_count,
|
||||
parent_stack: None,
|
||||
parent_deletions: vec![],
|
||||
|
|
|
@ -14,12 +14,29 @@ pub enum ParseWarning {
|
|||
span: Span,
|
||||
url: String,
|
||||
},
|
||||
|
||||
/// An error occurred with the IR compiler.
|
||||
///
|
||||
/// ## Resolution
|
||||
///
|
||||
/// The IR compiler is in very early development, so code that can't be compiled is quite
|
||||
/// expected. If you think it should be working, please report it to us.
|
||||
#[error("internal compiler error: {msg}")]
|
||||
#[diagnostic(
|
||||
help("this is a bug, please report it at https://github.com/nushell/nushell/issues/new along with the code you were compiling if able")
|
||||
)]
|
||||
IrCompileError {
|
||||
msg: String,
|
||||
#[label = "while compiling this code"]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
impl ParseWarning {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
ParseWarning::DeprecatedWarning { span, .. } => *span,
|
||||
ParseWarning::IrCompileError { span, .. } => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ pub(crate) fn parse_commandline_args(
|
|||
let error_style: Option<Value> =
|
||||
call.get_flag(engine_state, &mut stack, "error-style")?;
|
||||
let no_newline = call.get_named_arg("no-newline");
|
||||
let use_ir = call.has_flag(engine_state, &mut stack, "use-ir")?;
|
||||
|
||||
// ide flags
|
||||
let lsp = call.has_flag(engine_state, &mut stack, "lsp")?;
|
||||
|
@ -251,6 +252,7 @@ pub(crate) fn parse_commandline_args(
|
|||
table_mode,
|
||||
error_style,
|
||||
no_newline,
|
||||
use_ir,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +294,7 @@ pub(crate) struct NushellCliArgs {
|
|||
pub(crate) ide_complete: Option<Value>,
|
||||
pub(crate) ide_check: Option<Value>,
|
||||
pub(crate) ide_ast: Option<Spanned<String>>,
|
||||
pub(crate) use_ir: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -368,6 +371,7 @@ impl Command for Nu {
|
|||
"start with an alternate environment config file",
|
||||
None,
|
||||
)
|
||||
.switch("use-ir", "EXPERIMENTAL: use the IR evaluation engine on launch", None)
|
||||
.switch(
|
||||
"lsp",
|
||||
"start nu's language server protocol",
|
||||
|
|
12
src/run.rs
12
src/run.rs
|
@ -26,6 +26,10 @@ pub(crate) fn run_commands(
|
|||
let mut stack = Stack::new();
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
if parsed_nu_cli_args.use_ir {
|
||||
stack.use_ir = true;
|
||||
}
|
||||
|
||||
// if the --no-config-file(-n) option is NOT passed, load the plugin file,
|
||||
// load the default env file or custom (depending on parsed_nu_cli_args.env_file),
|
||||
// and maybe a custom config file (depending on parsed_nu_cli_args.config_file)
|
||||
|
@ -144,6 +148,10 @@ pub(crate) fn run_file(
|
|||
trace!("run_file");
|
||||
let mut stack = Stack::new();
|
||||
|
||||
if parsed_nu_cli_args.use_ir {
|
||||
stack.use_ir = true;
|
||||
}
|
||||
|
||||
// if the --no-config-file(-n) option is NOT passed, load the plugin file,
|
||||
// load the default env file or custom (depending on parsed_nu_cli_args.env_file),
|
||||
// and maybe a custom config file (depending on parsed_nu_cli_args.config_file)
|
||||
|
@ -254,6 +262,10 @@ pub(crate) fn run_repl(
|
|||
let mut stack = Stack::new();
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
if parsed_nu_cli_args.use_ir {
|
||||
stack.use_ir = true;
|
||||
}
|
||||
|
||||
if parsed_nu_cli_args.no_config_file.is_none() {
|
||||
setup_config(
|
||||
engine_state,
|
||||
|
|
Loading…
Reference in New Issue
Block a user