change the return keyword to return-early, use ShellError::Return :(
This commit is contained in:
parent
f50e22597c
commit
36faabd36d
|
@ -241,6 +241,7 @@ impl BlockBuilder {
|
||||||
Instruction::OnErrorInto { index: _, dst } => allocate(&[], &[*dst]),
|
Instruction::OnErrorInto { index: _, dst } => allocate(&[], &[*dst]),
|
||||||
Instruction::PopErrorHandler => Ok(()),
|
Instruction::PopErrorHandler => Ok(()),
|
||||||
Instruction::CheckExternalFailed { dst, src } => allocate(&[*src], &[*dst, *src]),
|
Instruction::CheckExternalFailed { dst, src } => allocate(&[*src], &[*dst, *src]),
|
||||||
|
Instruction::ReturnEarly { src } => allocate(&[*src], &[]),
|
||||||
Instruction::Return { src } => allocate(&[*src], &[]),
|
Instruction::Return { src } => allocate(&[*src], &[]),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -844,7 +844,7 @@ pub(crate) fn compile_continue(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile a call to `return` as a `return` instruction.
|
/// Compile a call to `return` as a `return-early` instruction.
|
||||||
///
|
///
|
||||||
/// This is not strictly necessary, but it is more efficient.
|
/// This is not strictly necessary, but it is more efficient.
|
||||||
pub(crate) fn compile_return(
|
pub(crate) fn compile_return(
|
||||||
|
@ -857,7 +857,7 @@ pub(crate) fn compile_return(
|
||||||
// Pseudocode:
|
// Pseudocode:
|
||||||
//
|
//
|
||||||
// %io_reg <- <arg_expr>
|
// %io_reg <- <arg_expr>
|
||||||
// return %io_reg
|
// return-early %io_reg
|
||||||
if let Some(arg_expr) = call.positional_nth(0) {
|
if let Some(arg_expr) = call.positional_nth(0) {
|
||||||
compile_expression(
|
compile_expression(
|
||||||
working_set,
|
working_set,
|
||||||
|
@ -871,7 +871,9 @@ pub(crate) fn compile_return(
|
||||||
builder.load_empty(io_reg)?;
|
builder.load_empty(io_reg)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.push(Instruction::Return { src: io_reg }.into_spanned(call.head))?;
|
// TODO: It would be nice if this could be `return` instead, but there is a little bit of
|
||||||
|
// behaviour remaining that still depends on `ShellError::Return`
|
||||||
|
builder.push(Instruction::ReturnEarly { src: io_reg }.into_spanned(call.head))?;
|
||||||
|
|
||||||
// io_reg is supposed to remain allocated
|
// io_reg is supposed to remain allocated
|
||||||
builder.load_empty(io_reg)?;
|
builder.load_empty(io_reg)?;
|
||||||
|
|
|
@ -210,6 +210,14 @@ fn eval_ir_block_impl<D: DebugContext>(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(
|
||||||
|
err @ (ShellError::Return { .. }
|
||||||
|
| ShellError::Continue { .. }
|
||||||
|
| ShellError::Break { .. }),
|
||||||
|
) => {
|
||||||
|
// These block control related errors should be passed through
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let Some(error_handler) = ctx.stack.error_handlers.pop(ctx.error_handler_base) {
|
if let Some(error_handler) = ctx.stack.error_handlers.pop(ctx.error_handler_base) {
|
||||||
// If an error handler is set, branch there
|
// If an error handler is set, branch there
|
||||||
|
@ -739,6 +747,13 @@ fn eval_instruction<D: DebugContext>(
|
||||||
ctx.put_reg(*dst, Value::bool(failed, *span).into_pipeline_data());
|
ctx.put_reg(*dst, Value::bool(failed, *span).into_pipeline_data());
|
||||||
Ok(Continue)
|
Ok(Continue)
|
||||||
}
|
}
|
||||||
|
Instruction::ReturnEarly { src } => {
|
||||||
|
let val = ctx.collect_reg(*src, *span)?;
|
||||||
|
Err(ShellError::Return {
|
||||||
|
span: *span,
|
||||||
|
value: Box::new(val),
|
||||||
|
})
|
||||||
|
}
|
||||||
Instruction::Return { src } => Ok(Return(*src)),
|
Instruction::Return { src } => Ok(Return(*src)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ fn ir_call_to_extern_call(
|
||||||
} => {
|
} => {
|
||||||
let name_arg = engine::Argument::Positional {
|
let name_arg = engine::Argument::Positional {
|
||||||
span: *span,
|
span: *span,
|
||||||
val: Value::string(known_external_option_name(&data, *name, *short), *span),
|
val: Value::string(known_external_option_name(data, *name, *short), *span),
|
||||||
ast: None,
|
ast: None,
|
||||||
};
|
};
|
||||||
extern_call.add_argument(stack, name_arg);
|
extern_call.add_argument(stack, name_arg);
|
||||||
|
@ -182,7 +182,7 @@ fn ir_call_to_extern_call(
|
||||||
} => {
|
} => {
|
||||||
let name_arg = engine::Argument::Positional {
|
let name_arg = engine::Argument::Positional {
|
||||||
span: *span,
|
span: *span,
|
||||||
val: Value::string(known_external_option_name(&data, *name, *short), *span),
|
val: Value::string(known_external_option_name(data, *name, *short), *span),
|
||||||
ast: None,
|
ast: None,
|
||||||
};
|
};
|
||||||
let val_arg = engine::Argument::Positional {
|
let val_arg = engine::Argument::Positional {
|
||||||
|
|
|
@ -240,6 +240,9 @@ impl<'a> fmt::Display for FmtInstruction<'a> {
|
||||||
Instruction::CheckExternalFailed { dst, src } => {
|
Instruction::CheckExternalFailed { dst, src } => {
|
||||||
write!(f, "{:WIDTH$} {dst}, {src}", "check-external-failed")
|
write!(f, "{:WIDTH$} {dst}, {src}", "check-external-failed")
|
||||||
}
|
}
|
||||||
|
Instruction::ReturnEarly { src } => {
|
||||||
|
write!(f, "{:WIDTH$} {src}", "return-early")
|
||||||
|
}
|
||||||
Instruction::Return { src } => {
|
Instruction::Return { src } => {
|
||||||
write!(f, "{:WIDTH$} {src}", "return")
|
write!(f, "{:WIDTH$} {src}", "return")
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,6 +248,10 @@ pub enum Instruction {
|
||||||
/// Check if an external command failed. Boolean value into `dst`. `src` is preserved, but it
|
/// Check if an external command failed. Boolean value into `dst`. `src` is preserved, but it
|
||||||
/// does require waiting for the command to exit.
|
/// does require waiting for the command to exit.
|
||||||
CheckExternalFailed { dst: RegId, src: RegId },
|
CheckExternalFailed { dst: RegId, src: RegId },
|
||||||
|
/// Return early from the block, raising a `ShellError::Return` instead.
|
||||||
|
///
|
||||||
|
/// Collecting the value is unavoidable.
|
||||||
|
ReturnEarly { src: RegId },
|
||||||
/// Return from the block with the value in the register
|
/// Return from the block with the value in the register
|
||||||
Return { src: RegId },
|
Return { src: RegId },
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user