add compiled IR to blocks

This commit is contained in:
Devyn Cairns 2024-06-10 19:55:33 -07:00
parent a836711a22
commit 20a214a4b9
8 changed files with 68 additions and 54 deletions

View File

@ -37,7 +37,7 @@ impl Command for ViewIr {
})?; })?;
let block = engine_state.get_block(block_id); 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)); 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())

View File

@ -3,7 +3,7 @@ use nu_protocol::{
Argument, Block, Call, CellPath, Expr, Expression, Operator, Pipeline, PipelineRedirection, Argument, Block, Call, CellPath, Expr, Expression, Operator, Pipeline, PipelineRedirection,
RedirectionSource, RedirectionTarget, RedirectionSource, RedirectionTarget,
}, },
engine::EngineState, engine::StateWorkingSet,
ir::{Instruction, IrBlock, Literal, RedirectMode}, ir::{Instruction, IrBlock, Literal, RedirectMode},
IntoSpanned, OutDest, RegId, ShellError, Span, Spanned, 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 /// Compile Nushell pipeline abstract syntax tree (AST) to internal representation (IR) instructions
/// for evaluation. /// for evaluation.
pub fn compile(engine_state: &EngineState, block: &Block) -> Result<IrBlock, ShellError> { pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock, ShellError> {
let mut builder = BlockBuilder::new(); let mut builder = BlockBuilder::new();
compile_block( compile_block(
engine_state, working_set,
&mut builder, &mut builder,
block, block,
RedirectModes::default(), RedirectModes::default(),
@ -52,7 +52,7 @@ impl RedirectModes {
} }
fn compile_block( fn compile_block(
engine_state: &EngineState, working_set: &StateWorkingSet,
builder: &mut BlockBuilder, builder: &mut BlockBuilder,
block: &Block, block: &Block,
redirect_modes: RedirectModes, redirect_modes: RedirectModes,
@ -65,7 +65,7 @@ fn compile_block(
let last_index = block.pipelines.len() - 1; let last_index = block.pipelines.len() - 1;
for (index, pipeline) in block.pipelines.iter().enumerate() { for (index, pipeline) in block.pipelines.iter().enumerate() {
compile_pipeline( compile_pipeline(
engine_state, working_set,
builder, builder,
pipeline, pipeline,
span, span,
@ -97,7 +97,7 @@ fn compile_block(
} }
fn compile_pipeline( fn compile_pipeline(
engine_state: &EngineState, working_set: &StateWorkingSet,
builder: &mut BlockBuilder, builder: &mut BlockBuilder,
pipeline: &Pipeline, pipeline: &Pipeline,
fallback_span: Span, fallback_span: Span,
@ -116,7 +116,7 @@ fn compile_pipeline(
// element, then it's from whatever is passed in as the mode to use. // 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() { 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 { } else {
redirect_modes redirect_modes
.take() .take()
@ -125,7 +125,7 @@ fn compile_pipeline(
let spec_redirect_modes = match &element.redirection { let spec_redirect_modes = match &element.redirection {
Some(PipelineRedirection::Single { source, target }) => { 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 { match source {
RedirectionSource::Stdout => RedirectModes { RedirectionSource::Stdout => RedirectModes {
out: Some(mode), out: Some(mode),
@ -142,8 +142,8 @@ fn compile_pipeline(
} }
} }
Some(PipelineRedirection::Separate { out, err }) => { Some(PipelineRedirection::Separate { out, err }) => {
let out = redirection_target_to_mode(engine_state, builder, out, true)?; let out = redirection_target_to_mode(working_set, builder, out, true)?;
let err = redirection_target_to_mode(engine_state, builder, err, true)?; let err = redirection_target_to_mode(working_set, builder, err, true)?;
RedirectModes { RedirectModes {
out: Some(out), out: Some(out),
err: Some(err), err: Some(err),
@ -159,7 +159,7 @@ fn compile_pipeline(
let err_mode = spec_redirect_modes.err.or(next_redirect_modes.err); let err_mode = spec_redirect_modes.err.or(next_redirect_modes.err);
compile_expression( compile_expression(
engine_state, working_set,
builder, builder,
&element.expr, &element.expr,
RedirectModes { RedirectModes {
@ -177,7 +177,7 @@ fn compile_pipeline(
} }
fn redirection_target_to_mode( fn redirection_target_to_mode(
engine_state: &EngineState, working_set: &StateWorkingSet,
builder: &mut BlockBuilder, builder: &mut BlockBuilder,
target: &RedirectionTarget, target: &RedirectionTarget,
separate: bool, separate: bool,
@ -190,7 +190,7 @@ fn redirection_target_to_mode(
} => { } => {
let path_reg = builder.next_register()?; let path_reg = builder.next_register()?;
compile_expression( compile_expression(
engine_state, working_set,
builder, builder,
expr, expr,
RedirectModes::capture_out(*redir_span), RedirectModes::capture_out(*redir_span),
@ -213,11 +213,11 @@ fn redirection_target_to_mode(
} }
fn redirect_modes_of_expression( fn redirect_modes_of_expression(
engine_state: &EngineState, working_set: &StateWorkingSet,
expression: &Expression, expression: &Expression,
redir_span: Span, redir_span: Span,
) -> Result<RedirectModes, CompileError> { ) -> Result<RedirectModes, CompileError> {
let (out, err) = expression.expr.pipe_redirection(&engine_state); let (out, err) = expression.expr.pipe_redirection(&working_set);
Ok(RedirectModes { Ok(RedirectModes {
out: out out: out
.map(|out| out_dest_to_redirect_mode(out)) .map(|out| out_dest_to_redirect_mode(out))
@ -241,7 +241,7 @@ fn out_dest_to_redirect_mode(out_dest: OutDest) -> Result<RedirectMode, CompileE
} }
fn compile_expression( fn compile_expression(
engine_state: &EngineState, working_set: &StateWorkingSet,
builder: &mut BlockBuilder, builder: &mut BlockBuilder,
expr: &Expression, expr: &Expression,
redirect_modes: RedirectModes, redirect_modes: RedirectModes,
@ -284,7 +284,7 @@ fn compile_expression(
builder.load_nothing(out_reg)?; builder.load_nothing(out_reg)?;
} }
compile_call(engine_state, builder, &call, redirect_modes, out_reg) compile_call(working_set, builder, &call, redirect_modes, out_reg)
} }
Expr::ExternalCall(_, _) => Err(CompileError::Todo("ExternalCall")), Expr::ExternalCall(_, _) => Err(CompileError::Todo("ExternalCall")),
Expr::Operator(_) => Err(CompileError::Todo("Operator")), Expr::Operator(_) => Err(CompileError::Todo("Operator")),
@ -293,7 +293,7 @@ fn compile_expression(
Expr::BinaryOp(lhs, op, rhs) => { Expr::BinaryOp(lhs, op, rhs) => {
if let Expr::Operator(ref operator) = op.expr { if let Expr::Operator(ref operator) = op.expr {
compile_binary_op( compile_binary_op(
engine_state, working_set,
builder, builder,
&lhs, &lhs,
operator.clone().into_spanned(op.span), operator.clone().into_spanned(op.span),
@ -306,9 +306,9 @@ fn compile_expression(
} }
} }
Expr::Subexpression(block_id) => { Expr::Subexpression(block_id) => {
let block = engine_state.get_block(*block_id); let block = working_set.get_block(*block_id);
compile_block( compile_block(
engine_state, working_set,
builder, builder,
&block, &block,
redirect_modes, redirect_modes,
@ -333,7 +333,7 @@ fn compile_expression(
Expr::CellPath(path) => lit(builder, Literal::CellPath(Box::new(path.clone()))), Expr::CellPath(path) => lit(builder, Literal::CellPath(Box::new(path.clone()))),
Expr::FullCellPath(full_cell_path) => { Expr::FullCellPath(full_cell_path) => {
compile_expression( compile_expression(
engine_state, working_set,
builder, builder,
&full_cell_path.head, &full_cell_path.head,
RedirectModes::capture_out(expr.span), RedirectModes::capture_out(expr.span),
@ -368,7 +368,7 @@ fn compile_expression(
} }
fn compile_call( fn compile_call(
engine_state: &EngineState, working_set: &StateWorkingSet,
builder: &mut BlockBuilder, builder: &mut BlockBuilder,
call: &Call, call: &Call,
redirect_modes: RedirectModes, redirect_modes: RedirectModes,
@ -395,7 +395,7 @@ fn compile_call(
let arg_reg = builder.next_register()?; let arg_reg = builder.next_register()?;
compile_expression( compile_expression(
engine_state, working_set,
builder, builder,
expr, expr,
RedirectModes::capture_out(arg.span()), RedirectModes::capture_out(arg.span()),
@ -464,7 +464,7 @@ fn compile_call(
} }
fn compile_binary_op( fn compile_binary_op(
engine_state: &EngineState, working_set: &StateWorkingSet,
builder: &mut BlockBuilder, builder: &mut BlockBuilder,
lhs: &Expression, lhs: &Expression,
op: Spanned<Operator>, op: Spanned<Operator>,
@ -481,7 +481,7 @@ fn compile_binary_op(
let rhs_reg = builder.next_register()?; let rhs_reg = builder.next_register()?;
compile_expression( compile_expression(
engine_state, working_set,
builder, builder,
lhs, lhs,
RedirectModes::capture_out(op.span), RedirectModes::capture_out(op.span),
@ -489,7 +489,7 @@ fn compile_binary_op(
lhs_reg, lhs_reg,
)?; )?;
compile_expression( compile_expression(
engine_state, working_set,
builder, builder,
rhs, rhs,
RedirectModes::capture_out(op.span), RedirectModes::capture_out(op.span),

View File

@ -7,7 +7,7 @@ use nu_protocol::{
PipelineRedirection, RedirectionSource, RedirectionTarget, PipelineRedirection, RedirectionSource, RedirectionTarget,
}, },
debugger::DebugContext, debugger::DebugContext,
engine::{Closure, EngineState, Redirection, Stack}, engine::{Closure, EngineState, Redirection, Stack, StateWorkingSet},
eval_base::Eval, eval_base::Eval,
ByteStreamSource, Config, FromValue, IntoPipelineData, OutDest, PipelineData, ShellError, Span, ByteStreamSource, Config, FromValue, IntoPipelineData, OutDest, PipelineData, ShellError, Span,
Spanned, Type, Value, VarId, ENV_VARIABLE_ID, Spanned, Type, Value, VarId, ENV_VARIABLE_ID,
@ -521,7 +521,7 @@ pub fn eval_block<D: DebugContext>(
for (i, element) in elements.iter().enumerate() { for (i, element) in elements.iter().enumerate() {
let next = elements.get(i + 1).unwrap_or(last); 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::<D>( let (stdout, stderr) = eval_element_redirection::<D>(
engine_state, engine_state,
stack, stack,

View File

@ -11,9 +11,9 @@ 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, BlockId, DidYouMean, Flag, ast::*, engine::StateWorkingSet, eval_const::eval_constant, report_error, BlockId, DidYouMean,
ParseError, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId, ENV_VARIABLE_ID, Flag, ParseError, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, VarId,
IN_VARIABLE_ID, ENV_VARIABLE_ID, IN_VARIABLE_ID,
}; };
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -5676,6 +5676,15 @@ pub fn parse_block(
working_set.parse_errors.extend_from_slice(&errors); 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 block
} }

View File

@ -1,5 +1,5 @@
use super::Pipeline; 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}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -8,6 +8,8 @@ pub struct Block {
pub pipelines: Vec<Pipeline>, pub pipelines: Vec<Pipeline>,
pub captures: Vec<VarId>, pub captures: Vec<VarId>,
pub redirect_env: bool, pub redirect_env: bool,
/// The block compiled to IR instructions. Not available for subexpressions.
pub ir_block: Option<IrBlock>,
pub span: Option<Span>, // None option encodes no span to avoid using test_span() pub span: Option<Span>, // None option encodes no span to avoid using test_span()
} }
@ -22,10 +24,10 @@ impl Block {
pub fn pipe_redirection( pub fn pipe_redirection(
&self, &self,
engine_state: &EngineState, working_set: &StateWorkingSet,
) -> (Option<OutDest>, Option<OutDest>) { ) -> (Option<OutDest>, Option<OutDest>) {
if let Some(first) = self.pipelines.first() { if let Some(first) = self.pipelines.first() {
first.pipe_redirection(engine_state) first.pipe_redirection(working_set)
} else { } else {
(None, None) (None, None)
} }
@ -45,6 +47,7 @@ impl Block {
pipelines: vec![], pipelines: vec![],
captures: vec![], captures: vec![],
redirect_env: false, redirect_env: false,
ir_block: None,
span: None, span: None,
} }
} }
@ -55,6 +58,7 @@ impl Block {
pipelines: Vec::with_capacity(capacity), pipelines: Vec::with_capacity(capacity),
captures: vec![], captures: vec![],
redirect_env: false, redirect_env: false,
ir_block: None,
span: None, span: None,
} }
} }
@ -86,6 +90,7 @@ where
pipelines: pipelines.collect(), pipelines: pipelines.collect(),
captures: vec![], captures: vec![],
redirect_env: false, redirect_env: false,
ir_block: None,
span: None, span: None,
} }
} }

View File

@ -5,7 +5,9 @@ use super::{
Call, CellPath, Expression, ExternalArgument, FullCellPath, Keyword, MatchPattern, Operator, Call, CellPath, Expression, ExternalArgument, FullCellPath, Keyword, MatchPattern, Operator,
Range, Table, ValueWithUnit, 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)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Expr { pub enum Expr {
@ -55,17 +57,17 @@ const _: () = assert!(std::mem::size_of::<Expr>() <= 40);
impl Expr { impl Expr {
pub fn pipe_redirection( pub fn pipe_redirection(
&self, &self,
engine_state: &EngineState, working_set: &StateWorkingSet,
) -> (Option<OutDest>, Option<OutDest>) { ) -> (Option<OutDest>, Option<OutDest>) {
// Usages of `$in` will be wrapped by a `collect` call by the parser, // Usages of `$in` will be wrapped by a `collect` call by the parser,
// so we do not have to worry about that when considering // so we do not have to worry about that when considering
// which of the expressions below may consume pipeline output. // which of the expressions below may consume pipeline output.
match self { match self {
Expr::Call(call) => engine_state.get_decl(call.decl_id).pipe_redirection(), Expr::Call(call) => working_set.get_decl(call.decl_id).pipe_redirection(),
Expr::Subexpression(block_id) | Expr::Block(block_id) => engine_state Expr::Subexpression(block_id) | Expr::Block(block_id) => working_set
.get_block(*block_id) .get_block(*block_id)
.pipe_redirection(engine_state), .pipe_redirection(working_set),
Expr::FullCellPath(cell_path) => cell_path.head.expr.pipe_redirection(engine_state), Expr::FullCellPath(cell_path) => cell_path.head.expr.pipe_redirection(working_set),
Expr::Bool(_) Expr::Bool(_)
| Expr::Int(_) | Expr::Int(_)
| Expr::Float(_) | Expr::Float(_)

View File

@ -1,8 +1,4 @@
use crate::{ use crate::{ast::Expression, engine::StateWorkingSet, OutDest, Span};
ast::Expression,
engine::{EngineState, StateWorkingSet},
OutDest, Span,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Display; use std::fmt::Display;
@ -120,9 +116,9 @@ impl PipelineElement {
pub fn pipe_redirection( pub fn pipe_redirection(
&self, &self,
engine_state: &EngineState, working_set: &StateWorkingSet,
) -> (Option<OutDest>, Option<OutDest>) { ) -> (Option<OutDest>, Option<OutDest>) {
self.expr.expr.pipe_redirection(engine_state) self.expr.expr.pipe_redirection(working_set)
} }
} }
@ -166,10 +162,10 @@ impl Pipeline {
pub fn pipe_redirection( pub fn pipe_redirection(
&self, &self,
engine_state: &EngineState, working_set: &StateWorkingSet,
) -> (Option<OutDest>, Option<OutDest>) { ) -> (Option<OutDest>, Option<OutDest>) {
if let Some(first) = self.elements.first() { if let Some(first) = self.elements.first() {
first.pipe_redirection(engine_state) first.pipe_redirection(working_set)
} else { } else {
(None, None) (None, None)
} }

View File

@ -4,10 +4,12 @@ use crate::{
BlockId, DeclId, RegId, Span, BlockId, DeclId, RegId, Span,
}; };
use serde::{Deserialize, Serialize};
mod display; mod display;
pub use display::FmtIrBlock; pub use display::FmtIrBlock;
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IrBlock { pub struct IrBlock {
pub instructions: Vec<Instruction>, pub instructions: Vec<Instruction>,
pub spans: Vec<Span>, pub spans: Vec<Span>,
@ -25,7 +27,7 @@ impl IrBlock {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Instruction { pub enum Instruction {
/// Load a literal value into the `dst` register /// Load a literal value into the `dst` register
LoadLiteral { dst: RegId, lit: Literal }, LoadLiteral { dst: RegId, lit: Literal },
@ -76,7 +78,7 @@ pub enum Instruction {
const _: () = assert!(std::mem::size_of::<Instruction>() <= 32); const _: () = assert!(std::mem::size_of::<Instruction>() <= 32);
/// A literal value that can be embedded in an instruction. /// A literal value that can be embedded in an instruction.
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Literal { pub enum Literal {
Bool(bool), Bool(bool),
Int(i64), Int(i64),
@ -103,7 +105,7 @@ pub enum Literal {
/// piped into. /// piped into.
/// ///
/// Not setting it uses the default, determined by [`Stack`](crate::engine::Stack). /// 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 { pub enum RedirectMode {
Pipe, Pipe,
Capture, Capture,