support calling with the redirection mode of the caller

This commit is contained in:
Devyn Cairns 2024-07-07 20:17:55 -07:00
parent 6d199fd219
commit 689cc49663
5 changed files with 32 additions and 15 deletions

View File

@ -25,20 +25,19 @@ const BLOCK_INPUT: RegId = RegId(0);
pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock, CompileError> { pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock, CompileError> {
let mut builder = BlockBuilder::new(); let mut builder = BlockBuilder::new();
let span = block.span.unwrap_or(Span::unknown());
compile_block( compile_block(
working_set, working_set,
&mut builder, &mut builder,
block, block,
RedirectModes::default(), RedirectModes::caller(span),
Some(BLOCK_INPUT), Some(BLOCK_INPUT),
BLOCK_INPUT, BLOCK_INPUT,
)?; )?;
// A complete block has to end with a `return` // A complete block has to end with a `return`
builder.push( builder.push(Instruction::Return { src: BLOCK_INPUT }.into_spanned(span))?;
Instruction::Return { src: BLOCK_INPUT }
.into_spanned(block.span.unwrap_or(Span::unknown())),
)?;
Ok(builder.finish()) Ok(builder.finish())
} }

View File

@ -21,6 +21,13 @@ impl RedirectModes {
} }
} }
pub(crate) fn caller(span: Span) -> RedirectModes {
RedirectModes {
out: Some(RedirectMode::Caller.into_spanned(span)),
err: Some(RedirectMode::Caller.into_spanned(span)),
}
}
pub(crate) fn with_pipe_out(&self, span: Span) -> Self { pub(crate) fn with_pipe_out(&self, span: Span) -> Self {
RedirectModes { RedirectModes {
out: Some(RedirectMode::Pipe.into_spanned(span)), out: Some(RedirectMode::Pipe.into_spanned(span)),

View File

@ -371,13 +371,11 @@ fn eval_instruction<D: DebugContext>(
Ok(Continue) Ok(Continue)
} }
Instruction::RedirectOut { mode } => { Instruction::RedirectOut { mode } => {
let out_dest = eval_redirection(ctx, mode, *span)?; ctx.redirect_out = eval_redirection(ctx, mode, *span, RedirectionStream::Out)?;
ctx.redirect_out = Some(out_dest);
Ok(Continue) Ok(Continue)
} }
Instruction::RedirectErr { mode } => { Instruction::RedirectErr { mode } => {
let out_dest = eval_redirection(ctx, mode, *span)?; ctx.redirect_err = eval_redirection(ctx, mode, *span, RedirectionStream::Err)?;
ctx.redirect_err = Some(out_dest);
Ok(Continue) Ok(Continue)
} }
Instruction::Call { decl_id, src_dst } => { Instruction::Call { decl_id, src_dst } => {
@ -1093,17 +1091,23 @@ fn collect(data: PipelineData, fallback_span: Span) -> Result<PipelineData, Shel
Ok(PipelineData::Value(value, metadata)) Ok(PipelineData::Value(value, metadata))
} }
enum RedirectionStream {
Out,
Err,
}
/// Set up a [`Redirection`] from a [`RedirectMode`] /// Set up a [`Redirection`] from a [`RedirectMode`]
fn eval_redirection( fn eval_redirection(
ctx: &mut EvalContext<'_>, ctx: &mut EvalContext<'_>,
mode: &RedirectMode, mode: &RedirectMode,
span: Span, span: Span,
) -> Result<Redirection, ShellError> { which: RedirectionStream,
) -> Result<Option<Redirection>, ShellError> {
match mode { match mode {
RedirectMode::Pipe => Ok(Redirection::Pipe(OutDest::Pipe)), RedirectMode::Pipe => Ok(Some(Redirection::Pipe(OutDest::Pipe))),
RedirectMode::Capture => Ok(Redirection::Pipe(OutDest::Capture)), RedirectMode::Capture => Ok(Some(Redirection::Pipe(OutDest::Capture))),
RedirectMode::Null => Ok(Redirection::Pipe(OutDest::Null)), RedirectMode::Null => Ok(Some(Redirection::Pipe(OutDest::Null))),
RedirectMode::Inherit => Ok(Redirection::Pipe(OutDest::Inherit)), RedirectMode::Inherit => Ok(Some(Redirection::Pipe(OutDest::Inherit))),
RedirectMode::File { path, append } => { RedirectMode::File { path, append } => {
let path = ctx.collect_reg(*path, span)?; let path = ctx.collect_reg(*path, span)?;
let path_expanded = let path_expanded =
@ -1118,8 +1122,12 @@ fn eval_redirection(
.create(true) .create(true)
.open(path_expanded) .open(path_expanded)
.map_err(|err| err.into_spanned(span))?; .map_err(|err| err.into_spanned(span))?;
Ok(Redirection::File(file.into())) Ok(Some(Redirection::File(file.into())))
} }
RedirectMode::Caller => Ok(match which {
RedirectionStream::Out => ctx.stack.pipe_stdout().cloned().map(Redirection::Pipe),
RedirectionStream::Err => ctx.stack.pipe_stderr().cloned().map(Redirection::Pipe),
}),
} }
} }

View File

@ -254,6 +254,7 @@ impl fmt::Display for RedirectMode {
RedirectMode::Null => write!(f, "null"), RedirectMode::Null => write!(f, "null"),
RedirectMode::Inherit => write!(f, "inherit"), RedirectMode::Inherit => write!(f, "inherit"),
RedirectMode::File { path, append } => write!(f, "file({path}, append={append})"), RedirectMode::File { path, append } => write!(f, "file({path}, append={append})"),
RedirectMode::Caller => write!(f, "caller"),
} }
} }
} }

View File

@ -300,6 +300,8 @@ pub enum RedirectMode {
path: RegId, path: RegId,
append: bool, append: bool,
}, },
/// Use the redirection mode requested by the caller, for a pre-return call.
Caller,
} }
/// Just a hack to allow `Arc<[u8]>` to be serialized and deserialized /// Just a hack to allow `Arc<[u8]>` to be serialized and deserialized