diff --git a/crates/nu-command/src/debug/view_ir.rs b/crates/nu-command/src/debug/view_ir.rs index c74203d8a0..85220a2b11 100644 --- a/crates/nu-command/src/debug/view_ir.rs +++ b/crates/nu-command/src/debug/view_ir.rs @@ -37,7 +37,7 @@ impl Command for ViewIr { })?; let block = engine_state.get_block(block_id); - let ir_block = compile(engine_state, &block)?; + let ir_block = compile(&StateWorkingSet::new(engine_state), &block)?; let formatted = format!("{}", ir_block.display(engine_state)); Ok(Value::string(formatted, call.head).into_pipeline_data()) diff --git a/crates/nu-engine/src/compile/mod.rs b/crates/nu-engine/src/compile/mod.rs index 9fe8aab591..b6ad9b61a9 100644 --- a/crates/nu-engine/src/compile/mod.rs +++ b/crates/nu-engine/src/compile/mod.rs @@ -3,7 +3,7 @@ use nu_protocol::{ Argument, Block, Call, CellPath, Expr, Expression, Operator, Pipeline, PipelineRedirection, RedirectionSource, RedirectionTarget, }, - engine::EngineState, + engine::StateWorkingSet, ir::{Instruction, IrBlock, Literal, RedirectMode}, IntoSpanned, OutDest, RegId, ShellError, Span, Spanned, }; @@ -12,11 +12,11 @@ const BLOCK_INPUT: RegId = RegId(0); /// Compile Nushell pipeline abstract syntax tree (AST) to internal representation (IR) instructions /// for evaluation. -pub fn compile(engine_state: &EngineState, block: &Block) -> Result { +pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result { let mut builder = BlockBuilder::new(); compile_block( - engine_state, + working_set, &mut builder, block, RedirectModes::default(), @@ -52,7 +52,7 @@ impl RedirectModes { } fn compile_block( - engine_state: &EngineState, + working_set: &StateWorkingSet, builder: &mut BlockBuilder, block: &Block, redirect_modes: RedirectModes, @@ -65,7 +65,7 @@ fn compile_block( let last_index = block.pipelines.len() - 1; for (index, pipeline) in block.pipelines.iter().enumerate() { compile_pipeline( - engine_state, + working_set, builder, pipeline, span, @@ -97,7 +97,7 @@ fn compile_block( } fn compile_pipeline( - engine_state: &EngineState, + working_set: &StateWorkingSet, builder: &mut BlockBuilder, pipeline: &Pipeline, fallback_span: Span, @@ -116,7 +116,7 @@ fn compile_pipeline( // element, then it's from whatever is passed in as the mode to use. let next_redirect_modes = if let Some(next_element) = iter.peek() { - redirect_modes_of_expression(engine_state, &next_element.expr, span)? + redirect_modes_of_expression(working_set, &next_element.expr, span)? } else { redirect_modes .take() @@ -125,7 +125,7 @@ fn compile_pipeline( let spec_redirect_modes = match &element.redirection { Some(PipelineRedirection::Single { source, target }) => { - let mode = redirection_target_to_mode(engine_state, builder, target, false)?; + let mode = redirection_target_to_mode(working_set, builder, target, false)?; match source { RedirectionSource::Stdout => RedirectModes { out: Some(mode), @@ -142,8 +142,8 @@ fn compile_pipeline( } } Some(PipelineRedirection::Separate { out, err }) => { - let out = redirection_target_to_mode(engine_state, builder, out, true)?; - let err = redirection_target_to_mode(engine_state, builder, err, true)?; + let out = redirection_target_to_mode(working_set, builder, out, true)?; + let err = redirection_target_to_mode(working_set, builder, err, true)?; RedirectModes { out: Some(out), err: Some(err), @@ -159,7 +159,7 @@ fn compile_pipeline( let err_mode = spec_redirect_modes.err.or(next_redirect_modes.err); compile_expression( - engine_state, + working_set, builder, &element.expr, RedirectModes { @@ -177,7 +177,7 @@ fn compile_pipeline( } fn redirection_target_to_mode( - engine_state: &EngineState, + working_set: &StateWorkingSet, builder: &mut BlockBuilder, target: &RedirectionTarget, separate: bool, @@ -190,7 +190,7 @@ fn redirection_target_to_mode( } => { let path_reg = builder.next_register()?; compile_expression( - engine_state, + working_set, builder, expr, RedirectModes::capture_out(*redir_span), @@ -213,11 +213,11 @@ fn redirection_target_to_mode( } fn redirect_modes_of_expression( - engine_state: &EngineState, + working_set: &StateWorkingSet, expression: &Expression, redir_span: Span, ) -> Result { - let (out, err) = expression.expr.pipe_redirection(&engine_state); + let (out, err) = expression.expr.pipe_redirection(&working_set); Ok(RedirectModes { out: out .map(|out| out_dest_to_redirect_mode(out)) @@ -241,7 +241,7 @@ fn out_dest_to_redirect_mode(out_dest: OutDest) -> Result Err(CompileError::Todo("ExternalCall")), Expr::Operator(_) => Err(CompileError::Todo("Operator")), @@ -293,7 +293,7 @@ fn compile_expression( Expr::BinaryOp(lhs, op, rhs) => { if let Expr::Operator(ref operator) = op.expr { compile_binary_op( - engine_state, + working_set, builder, &lhs, operator.clone().into_spanned(op.span), @@ -306,9 +306,9 @@ fn compile_expression( } } Expr::Subexpression(block_id) => { - let block = engine_state.get_block(*block_id); + let block = working_set.get_block(*block_id); compile_block( - engine_state, + working_set, builder, &block, redirect_modes, @@ -333,7 +333,7 @@ fn compile_expression( Expr::CellPath(path) => lit(builder, Literal::CellPath(Box::new(path.clone()))), Expr::FullCellPath(full_cell_path) => { compile_expression( - engine_state, + working_set, builder, &full_cell_path.head, RedirectModes::capture_out(expr.span), @@ -368,7 +368,7 @@ fn compile_expression( } fn compile_call( - engine_state: &EngineState, + working_set: &StateWorkingSet, builder: &mut BlockBuilder, call: &Call, redirect_modes: RedirectModes, @@ -395,7 +395,7 @@ fn compile_call( let arg_reg = builder.next_register()?; compile_expression( - engine_state, + working_set, builder, expr, RedirectModes::capture_out(arg.span()), @@ -464,7 +464,7 @@ fn compile_call( } fn compile_binary_op( - engine_state: &EngineState, + working_set: &StateWorkingSet, builder: &mut BlockBuilder, lhs: &Expression, op: Spanned, @@ -481,7 +481,7 @@ fn compile_binary_op( let rhs_reg = builder.next_register()?; compile_expression( - engine_state, + working_set, builder, lhs, RedirectModes::capture_out(op.span), @@ -489,7 +489,7 @@ fn compile_binary_op( lhs_reg, )?; compile_expression( - engine_state, + working_set, builder, rhs, RedirectModes::capture_out(op.span), diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index af051a1dc7..6ee7342e2e 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -7,7 +7,7 @@ use nu_protocol::{ PipelineRedirection, RedirectionSource, RedirectionTarget, }, debugger::DebugContext, - engine::{Closure, EngineState, Redirection, Stack}, + engine::{Closure, EngineState, Redirection, Stack, StateWorkingSet}, eval_base::Eval, ByteStreamSource, Config, FromValue, IntoPipelineData, OutDest, PipelineData, ShellError, Span, Spanned, Type, Value, VarId, ENV_VARIABLE_ID, @@ -521,7 +521,7 @@ pub fn eval_block( for (i, element) in elements.iter().enumerate() { let next = elements.get(i + 1).unwrap_or(last); - let (next_out, next_err) = next.pipe_redirection(engine_state); + let (next_out, next_err) = next.pipe_redirection(&StateWorkingSet::new(engine_state)); let (stdout, stderr) = eval_element_redirection::( engine_state, stack, diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 149bce8958..9c065fd263 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -11,9 +11,9 @@ use itertools::Itertools; use log::trace; use nu_engine::DIR_VAR_PARSER_INFO; use nu_protocol::{ - ast::*, engine::StateWorkingSet, eval_const::eval_constant, BlockId, DidYouMean, Flag, - ParseError, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId, ENV_VARIABLE_ID, - IN_VARIABLE_ID, + ast::*, engine::StateWorkingSet, eval_const::eval_constant, report_error, BlockId, DidYouMean, + Flag, ParseError, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId, + ENV_VARIABLE_ID, IN_VARIABLE_ID, }; use std::{ borrow::Cow, @@ -5676,6 +5676,15 @@ pub fn parse_block( working_set.parse_errors.extend_from_slice(&errors); } + if !is_subexpression { + match nu_engine::compile(working_set, &block) { + Ok(ir_block) => { + block.ir_block = Some(ir_block); + } + Err(err) => report_error(working_set, &err), + } + } + block } diff --git a/crates/nu-protocol/src/ast/block.rs b/crates/nu-protocol/src/ast/block.rs index 6e3449af26..8f62ff99ba 100644 --- a/crates/nu-protocol/src/ast/block.rs +++ b/crates/nu-protocol/src/ast/block.rs @@ -1,5 +1,5 @@ use super::Pipeline; -use crate::{engine::EngineState, OutDest, Signature, Span, Type, VarId}; +use crate::{engine::StateWorkingSet, ir::IrBlock, OutDest, Signature, Span, Type, VarId}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -8,6 +8,8 @@ pub struct Block { pub pipelines: Vec, pub captures: Vec, pub redirect_env: bool, + /// The block compiled to IR instructions. Not available for subexpressions. + pub ir_block: Option, pub span: Option, // None option encodes no span to avoid using test_span() } @@ -22,10 +24,10 @@ impl Block { pub fn pipe_redirection( &self, - engine_state: &EngineState, + working_set: &StateWorkingSet, ) -> (Option, Option) { if let Some(first) = self.pipelines.first() { - first.pipe_redirection(engine_state) + first.pipe_redirection(working_set) } else { (None, None) } @@ -45,6 +47,7 @@ impl Block { pipelines: vec![], captures: vec![], redirect_env: false, + ir_block: None, span: None, } } @@ -55,6 +58,7 @@ impl Block { pipelines: Vec::with_capacity(capacity), captures: vec![], redirect_env: false, + ir_block: None, span: None, } } @@ -86,6 +90,7 @@ where pipelines: pipelines.collect(), captures: vec![], redirect_env: false, + ir_block: None, span: None, } } diff --git a/crates/nu-protocol/src/ast/expr.rs b/crates/nu-protocol/src/ast/expr.rs index 13d9e42985..e0c5ebbb8b 100644 --- a/crates/nu-protocol/src/ast/expr.rs +++ b/crates/nu-protocol/src/ast/expr.rs @@ -5,7 +5,9 @@ use super::{ Call, CellPath, Expression, ExternalArgument, FullCellPath, Keyword, MatchPattern, Operator, Range, Table, ValueWithUnit, }; -use crate::{ast::ImportPattern, engine::EngineState, BlockId, OutDest, Signature, Span, VarId}; +use crate::{ + ast::ImportPattern, engine::StateWorkingSet, BlockId, OutDest, Signature, Span, VarId, +}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Expr { @@ -55,17 +57,17 @@ const _: () = assert!(std::mem::size_of::() <= 40); impl Expr { pub fn pipe_redirection( &self, - engine_state: &EngineState, + working_set: &StateWorkingSet, ) -> (Option, Option) { // Usages of `$in` will be wrapped by a `collect` call by the parser, // so we do not have to worry about that when considering // which of the expressions below may consume pipeline output. match self { - Expr::Call(call) => engine_state.get_decl(call.decl_id).pipe_redirection(), - Expr::Subexpression(block_id) | Expr::Block(block_id) => engine_state + Expr::Call(call) => working_set.get_decl(call.decl_id).pipe_redirection(), + Expr::Subexpression(block_id) | Expr::Block(block_id) => working_set .get_block(*block_id) - .pipe_redirection(engine_state), - Expr::FullCellPath(cell_path) => cell_path.head.expr.pipe_redirection(engine_state), + .pipe_redirection(working_set), + Expr::FullCellPath(cell_path) => cell_path.head.expr.pipe_redirection(working_set), Expr::Bool(_) | Expr::Int(_) | Expr::Float(_) diff --git a/crates/nu-protocol/src/ast/pipeline.rs b/crates/nu-protocol/src/ast/pipeline.rs index f03c016daf..3f2a216485 100644 --- a/crates/nu-protocol/src/ast/pipeline.rs +++ b/crates/nu-protocol/src/ast/pipeline.rs @@ -1,8 +1,4 @@ -use crate::{ - ast::Expression, - engine::{EngineState, StateWorkingSet}, - OutDest, Span, -}; +use crate::{ast::Expression, engine::StateWorkingSet, OutDest, Span}; use serde::{Deserialize, Serialize}; use std::fmt::Display; @@ -120,9 +116,9 @@ impl PipelineElement { pub fn pipe_redirection( &self, - engine_state: &EngineState, + working_set: &StateWorkingSet, ) -> (Option, Option) { - self.expr.expr.pipe_redirection(engine_state) + self.expr.expr.pipe_redirection(working_set) } } @@ -166,10 +162,10 @@ impl Pipeline { pub fn pipe_redirection( &self, - engine_state: &EngineState, + working_set: &StateWorkingSet, ) -> (Option, Option) { if let Some(first) = self.elements.first() { - first.pipe_redirection(engine_state) + first.pipe_redirection(working_set) } else { (None, None) } diff --git a/crates/nu-protocol/src/ir/mod.rs b/crates/nu-protocol/src/ir/mod.rs index ca0c8790bc..c860c15da0 100644 --- a/crates/nu-protocol/src/ir/mod.rs +++ b/crates/nu-protocol/src/ir/mod.rs @@ -4,10 +4,12 @@ use crate::{ BlockId, DeclId, RegId, Span, }; +use serde::{Deserialize, Serialize}; + mod display; pub use display::FmtIrBlock; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct IrBlock { pub instructions: Vec, pub spans: Vec, @@ -25,7 +27,7 @@ impl IrBlock { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum Instruction { /// Load a literal value into the `dst` register LoadLiteral { dst: RegId, lit: Literal }, @@ -76,7 +78,7 @@ pub enum Instruction { const _: () = assert!(std::mem::size_of::() <= 32); /// A literal value that can be embedded in an instruction. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum Literal { Bool(bool), Int(i64), @@ -103,7 +105,7 @@ pub enum Literal { /// piped into. /// /// Not setting it uses the default, determined by [`Stack`](crate::engine::Stack). -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum RedirectMode { Pipe, Capture,