add specific error for match guard bool

This commit is contained in:
Devyn Cairns 2024-07-08 20:13:50 -07:00
parent f026a07fe3
commit 6a8169e8ba
5 changed files with 40 additions and 20 deletions

View File

@ -227,6 +227,7 @@ impl BlockBuilder {
src,
index: _,
} => allocate(&[*src], &[*src]),
Instruction::CheckMatchGuard { src } => allocate(&[*src], &[*src]),
Instruction::Iterate {
dst,
stream,

View File

@ -149,6 +149,7 @@ pub(crate) fn compile_match(
// drop %match_reg
// jump END
// PAT1: %guard_reg <- <guard_expr>
// check-match-guard %guard_reg
// not %guard_reg
// branch-if %guard_reg, MATCH2
// drop %match_reg
@ -224,6 +225,8 @@ pub(crate) fn compile_match(
None,
guard_reg,
)?;
builder
.push(Instruction::CheckMatchGuard { src: guard_reg }.into_spanned(guard.span))?;
builder.push(Instruction::Not { src_dst: guard_reg }.into_spanned(guard.span))?;
// Branch to the next match instruction if the branch fails to match
builder.push(

View File

@ -116,6 +116,12 @@ impl<'a> EvalContext<'a> {
self.registers[reg_id.0 as usize] = new_value;
}
/// Borrow the contents of a register.
#[inline]
fn borrow_reg(&self, reg_id: RegId) -> &PipelineData {
&self.registers[reg_id.0 as usize]
}
/// Replace the contents of a register with `Empty` and then return the value that it contained
#[inline]
fn take_reg(&mut self, reg_id: RegId) -> PipelineData {
@ -422,24 +428,20 @@ fn eval_instruction<D: DebugContext>(
ctx.redirect_err = eval_redirection(ctx, mode, *span, RedirectionStream::Err)?;
Ok(Continue)
}
Instruction::CheckErrRedirected { src } => {
let data = ctx.take_reg(*src);
match &data {
PipelineData::ByteStream(stream, _)
if matches!(stream.source(), ByteStreamSource::Child(_)) =>
{
ctx.put_reg(*src, data);
Ok(Continue)
}
_ => Err(ShellError::GenericError {
error: "Can't redirect stderr of internal command output".into(),
msg: "piping stderr only works on external commands".into(),
span: Some(*span),
help: None,
inner: vec![],
}),
Instruction::CheckErrRedirected { src } => match ctx.borrow_reg(*src) {
PipelineData::ByteStream(stream, _)
if matches!(stream.source(), ByteStreamSource::Child(_)) =>
{
Ok(Continue)
}
}
_ => Err(ShellError::GenericError {
error: "Can't redirect stderr of internal command output".into(),
msg: "piping stderr only works on external commands".into(),
span: Some(*span),
help: None,
inner: vec![],
}),
},
Instruction::OpenFile {
file_num,
path,
@ -656,12 +658,10 @@ fn eval_instruction<D: DebugContext>(
}
}
Instruction::BranchIfEmpty { src, index } => {
let data = ctx.take_reg(*src);
let is_empty = matches!(
data,
ctx.borrow_reg(*src),
PipelineData::Empty | PipelineData::Value(Value::Nothing { .. }, _)
);
ctx.put_reg(*src, data);
if is_empty {
Ok(Branch(*index))
@ -688,6 +688,16 @@ fn eval_instruction<D: DebugContext>(
Ok(Continue)
}
}
Instruction::CheckMatchGuard { src } => {
if matches!(
ctx.borrow_reg(*src),
PipelineData::Value(Value::Bool { .. }, _)
) {
Ok(Continue)
} else {
Err(ShellError::MatchGuardNotBool { span: *span })
}
}
Instruction::Iterate {
dst,
stream,

View File

@ -216,6 +216,9 @@ impl<'a> fmt::Display for FmtInstruction<'a> {
};
write!(f, "{:WIDTH$} ({pattern}), {src}, {index}", "match")
}
Instruction::CheckMatchGuard { src } => {
write!(f, "{:WIDTH$} {src}", "check-match-guard")
}
Instruction::Iterate {
dst,
stream,

View File

@ -223,6 +223,9 @@ pub enum Instruction {
src: RegId,
index: usize,
},
/// Check that a match guard is a boolean, throwing
/// [`MatchGuardNotBool`](crate::ShellError::MatchGuardNotBool) if it isn't. Preserves `src`.
CheckMatchGuard { src: RegId },
/// Iterate on register `stream`, putting the next value in `dst` if present, or jumping to
/// `end_index` if the iterator is finished
Iterate {