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::{
|
use nu_engine::{command_prelude::*, get_eval_block_with_early_return, redirect_env};
|
||||||
command_prelude::*, get_eval_block_with_early_return, get_eval_ir_block, redirect_env,
|
|
||||||
};
|
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::Closure,
|
engine::Closure,
|
||||||
process::{ChildPipe, ChildProcess, ExitStatus},
|
process::{ChildPipe, ChildProcess, ExitStatus},
|
||||||
|
@ -94,12 +92,13 @@ impl Command for Do {
|
||||||
|
|
||||||
bind_args_to(&mut callee_stack, &block.signature, rest, head)?;
|
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_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 {
|
// Applies to all block evaluation once set true
|
||||||
eval_ir_block(engine_state, &mut callee_stack, block, input)
|
if use_ir {
|
||||||
} else {
|
caller_stack.use_ir = true;
|
||||||
eval_block_with_early_return(engine_state, &mut callee_stack, block, input)
|
}
|
||||||
};
|
|
||||||
|
let result = eval_block_with_early_return(engine_state, &mut callee_stack, block, input);
|
||||||
|
|
||||||
if has_env {
|
if has_env {
|
||||||
// Merge the block's environment to the current stack
|
// 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_engine::{command_prelude::*, compile};
|
||||||
use nu_protocol::engine::Closure;
|
use nu_protocol::engine::Closure;
|
||||||
|
|
||||||
|
@ -31,7 +33,15 @@ impl Command for ViewIr {
|
||||||
let closure: Closure = call.req(engine_state, stack, 0)?;
|
let closure: Closure = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
let block = engine_state.get_block(closure.block_id);
|
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));
|
let formatted = format!("{}", ir_block.display(engine_state));
|
||||||
Ok(Value::string(formatted, call.head).into_pipeline_data())
|
Ok(Value::string(formatted, call.head).into_pipeline_data())
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{
|
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,
|
Pipeline, PipelineRedirection, RecordItem, RedirectionSource, RedirectionTarget,
|
||||||
},
|
},
|
||||||
engine::StateWorkingSet,
|
engine::StateWorkingSet,
|
||||||
|
@ -12,7 +12,7 @@ const BLOCK_INPUT: RegId = RegId(0);
|
||||||
|
|
||||||
/// Compile Nushell pipeline abstract syntax tree (AST) to internal representation (IR) instructions
|
/// Compile Nushell pipeline abstract syntax tree (AST) to internal representation (IR) instructions
|
||||||
/// for evaluation.
|
/// 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();
|
let mut builder = BlockBuilder::new();
|
||||||
|
|
||||||
compile_block(
|
compile_block(
|
||||||
|
@ -22,16 +22,13 @@ pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock,
|
||||||
RedirectModes::default(),
|
RedirectModes::default(),
|
||||||
Some(BLOCK_INPUT),
|
Some(BLOCK_INPUT),
|
||||||
BLOCK_INPUT,
|
BLOCK_INPUT,
|
||||||
)
|
)?;
|
||||||
.map_err(|err| err.to_shell_error(block.span))?;
|
|
||||||
|
|
||||||
// A complete block has to end with a `return`
|
// A complete block has to end with a `return`
|
||||||
builder
|
builder.push(
|
||||||
.push(
|
Instruction::Return { src: BLOCK_INPUT }
|
||||||
Instruction::Return { src: BLOCK_INPUT }
|
.into_spanned(block.span.unwrap_or(Span::unknown())),
|
||||||
.into_spanned(block.span.unwrap_or(Span::unknown())),
|
)?;
|
||||||
)
|
|
||||||
.map_err(|err| err.to_shell_error(block.span))?;
|
|
||||||
|
|
||||||
Ok(builder.finish())
|
Ok(builder.finish())
|
||||||
}
|
}
|
||||||
|
@ -369,7 +366,7 @@ fn compile_expression(
|
||||||
.into_spanned(expr.span),
|
.into_spanned(expr.span),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
ListItem::Spread(spread_span, expr) => {
|
ListItem::Spread(spread_span, _) => {
|
||||||
// Spread the list using list-spread
|
// Spread the list using list-spread
|
||||||
builder.push(
|
builder.push(
|
||||||
Instruction::ListSpread {
|
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
|
/// An internal compiler error, generally means a Nushell bug rather than an issue with user error
|
||||||
/// since parsing and typechecking has already passed.
|
/// since parsing and typechecking has already passed.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum CompileError {
|
pub enum CompileError {
|
||||||
RegisterOverflow,
|
RegisterOverflow,
|
||||||
RegisterUninitialized(RegId),
|
RegisterUninitialized(RegId),
|
||||||
DataOverflow,
|
DataOverflow,
|
||||||
|
@ -807,8 +804,8 @@ enum CompileError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompileError {
|
impl CompileError {
|
||||||
fn to_shell_error(self, mut span: Option<Span>) -> ShellError {
|
pub fn message(&self) -> String {
|
||||||
let message = match self {
|
match self {
|
||||||
CompileError::RegisterOverflow => format!("register overflow"),
|
CompileError::RegisterOverflow => format!("register overflow"),
|
||||||
CompileError::RegisterUninitialized(reg_id) => {
|
CompileError::RegisterUninitialized(reg_id) => {
|
||||||
format!("register {reg_id} is uninitialized when used, possibly reused")
|
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::Garbage => "encountered garbage, likely due to parse error".into(),
|
||||||
CompileError::UnsupportedOperatorExpression => "unsupported operator expression".into(),
|
CompileError::UnsupportedOperatorExpression => "unsupported operator expression".into(),
|
||||||
CompileError::AccessEnvByInt(local_span) => {
|
CompileError::AccessEnvByInt(_) => "attempted access of $env by integer path".into(),
|
||||||
span = Some(local_span);
|
|
||||||
"attempted access of $env by integer path".into()
|
|
||||||
}
|
|
||||||
CompileError::Todo(msg) => {
|
CompileError::Todo(msg) => {
|
||||||
format!("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)]
|
#[allow(deprecated)]
|
||||||
use crate::{current_dir, get_config, get_full_help};
|
use crate::{current_dir, get_config, get_full_help};
|
||||||
use nu_path::expand_path_with;
|
use nu_path::expand_path_with;
|
||||||
|
@ -509,6 +510,11 @@ pub fn eval_block<D: DebugContext>(
|
||||||
block: &Block,
|
block: &Block,
|
||||||
mut input: PipelineData,
|
mut input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> 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);
|
D::enter_block(engine_state, block);
|
||||||
|
|
||||||
let num_pipelines = block.len();
|
let num_pipelines = block.len();
|
||||||
|
|
|
@ -11,8 +11,8 @@ use itertools::Itertools;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use nu_engine::DIR_VAR_PARSER_INFO;
|
use nu_engine::DIR_VAR_PARSER_INFO;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::*, engine::StateWorkingSet, eval_const::eval_constant, report_error, BlockId, DidYouMean,
|
ast::*, engine::StateWorkingSet, eval_const::eval_constant, BlockId, DidYouMean, Flag,
|
||||||
Flag, ParseError, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId,
|
ParseError, ParseWarning, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId,
|
||||||
ENV_VARIABLE_ID, IN_VARIABLE_ID,
|
ENV_VARIABLE_ID, IN_VARIABLE_ID,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -5834,12 +5834,19 @@ pub fn parse_block(
|
||||||
working_set.parse_errors.extend_from_slice(&errors);
|
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) {
|
match nu_engine::compile(working_set, &block) {
|
||||||
Ok(ir_block) => {
|
Ok(ir_block) => {
|
||||||
block.ir_block = Some(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,
|
pub register_buf_cache: RegisterBufCache,
|
||||||
/// Argument stack for IR evaluation
|
/// Argument stack for IR evaluation
|
||||||
pub argument_stack: ArgumentStack,
|
pub argument_stack: ArgumentStack,
|
||||||
|
/// Set true to always use IR mode
|
||||||
|
pub use_ir: bool,
|
||||||
pub recursion_count: u64,
|
pub recursion_count: u64,
|
||||||
pub parent_stack: Option<Arc<Stack>>,
|
pub parent_stack: Option<Arc<Stack>>,
|
||||||
/// Variables that have been deleted (this is used to hide values from parent stack lookups)
|
/// 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()],
|
active_overlays: vec![DEFAULT_OVERLAY_NAME.to_string()],
|
||||||
register_buf_cache: RegisterBufCache::new(),
|
register_buf_cache: RegisterBufCache::new(),
|
||||||
argument_stack: ArgumentStack::new(),
|
argument_stack: ArgumentStack::new(),
|
||||||
|
use_ir: false,
|
||||||
recursion_count: 0,
|
recursion_count: 0,
|
||||||
parent_stack: None,
|
parent_stack: None,
|
||||||
parent_deletions: vec![],
|
parent_deletions: vec![],
|
||||||
|
@ -95,6 +98,7 @@ impl Stack {
|
||||||
active_overlays: parent.active_overlays.clone(),
|
active_overlays: parent.active_overlays.clone(),
|
||||||
register_buf_cache: RegisterBufCache::new(),
|
register_buf_cache: RegisterBufCache::new(),
|
||||||
argument_stack: ArgumentStack::new(),
|
argument_stack: ArgumentStack::new(),
|
||||||
|
use_ir: parent.use_ir,
|
||||||
recursion_count: parent.recursion_count,
|
recursion_count: parent.recursion_count,
|
||||||
vars: vec![],
|
vars: vec![],
|
||||||
parent_deletions: vec![],
|
parent_deletions: vec![],
|
||||||
|
@ -266,6 +270,7 @@ impl Stack {
|
||||||
active_overlays: self.active_overlays.clone(),
|
active_overlays: self.active_overlays.clone(),
|
||||||
register_buf_cache: RegisterBufCache::new(),
|
register_buf_cache: RegisterBufCache::new(),
|
||||||
argument_stack: ArgumentStack::new(),
|
argument_stack: ArgumentStack::new(),
|
||||||
|
use_ir: self.use_ir,
|
||||||
recursion_count: self.recursion_count,
|
recursion_count: self.recursion_count,
|
||||||
parent_stack: None,
|
parent_stack: None,
|
||||||
parent_deletions: vec![],
|
parent_deletions: vec![],
|
||||||
|
@ -298,6 +303,7 @@ impl Stack {
|
||||||
active_overlays: self.active_overlays.clone(),
|
active_overlays: self.active_overlays.clone(),
|
||||||
register_buf_cache: RegisterBufCache::new(),
|
register_buf_cache: RegisterBufCache::new(),
|
||||||
argument_stack: ArgumentStack::new(),
|
argument_stack: ArgumentStack::new(),
|
||||||
|
use_ir: self.use_ir,
|
||||||
recursion_count: self.recursion_count,
|
recursion_count: self.recursion_count,
|
||||||
parent_stack: None,
|
parent_stack: None,
|
||||||
parent_deletions: vec![],
|
parent_deletions: vec![],
|
||||||
|
|
|
@ -14,12 +14,29 @@ pub enum ParseWarning {
|
||||||
span: Span,
|
span: Span,
|
||||||
url: String,
|
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 {
|
impl ParseWarning {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
ParseWarning::DeprecatedWarning { span, .. } => *span,
|
ParseWarning::DeprecatedWarning { span, .. } => *span,
|
||||||
|
ParseWarning::IrCompileError { span, .. } => *span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ pub(crate) fn parse_commandline_args(
|
||||||
let error_style: Option<Value> =
|
let error_style: Option<Value> =
|
||||||
call.get_flag(engine_state, &mut stack, "error-style")?;
|
call.get_flag(engine_state, &mut stack, "error-style")?;
|
||||||
let no_newline = call.get_named_arg("no-newline");
|
let no_newline = call.get_named_arg("no-newline");
|
||||||
|
let use_ir = call.has_flag(engine_state, &mut stack, "use-ir")?;
|
||||||
|
|
||||||
// ide flags
|
// ide flags
|
||||||
let lsp = call.has_flag(engine_state, &mut stack, "lsp")?;
|
let lsp = call.has_flag(engine_state, &mut stack, "lsp")?;
|
||||||
|
@ -251,6 +252,7 @@ pub(crate) fn parse_commandline_args(
|
||||||
table_mode,
|
table_mode,
|
||||||
error_style,
|
error_style,
|
||||||
no_newline,
|
no_newline,
|
||||||
|
use_ir,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,6 +294,7 @@ pub(crate) struct NushellCliArgs {
|
||||||
pub(crate) ide_complete: Option<Value>,
|
pub(crate) ide_complete: Option<Value>,
|
||||||
pub(crate) ide_check: Option<Value>,
|
pub(crate) ide_check: Option<Value>,
|
||||||
pub(crate) ide_ast: Option<Spanned<String>>,
|
pub(crate) ide_ast: Option<Spanned<String>>,
|
||||||
|
pub(crate) use_ir: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -368,6 +371,7 @@ impl Command for Nu {
|
||||||
"start with an alternate environment config file",
|
"start with an alternate environment config file",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
.switch("use-ir", "EXPERIMENTAL: use the IR evaluation engine on launch", None)
|
||||||
.switch(
|
.switch(
|
||||||
"lsp",
|
"lsp",
|
||||||
"start nu's language server protocol",
|
"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 mut stack = Stack::new();
|
||||||
let start_time = std::time::Instant::now();
|
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,
|
// 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),
|
// 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)
|
// 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");
|
trace!("run_file");
|
||||||
let mut stack = Stack::new();
|
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,
|
// 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),
|
// 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)
|
// 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 mut stack = Stack::new();
|
||||||
let start_time = std::time::Instant::now();
|
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() {
|
if parsed_nu_cli_args.no_config_file.is_none() {
|
||||||
setup_config(
|
setup_config(
|
||||||
engine_state,
|
engine_state,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user