fix handling of assignment of deep path env vars

This commit is contained in:
Devyn Cairns 2024-07-06 02:25:45 -07:00
parent 5cbc591094
commit 650cc95d94
No known key found for this signature in database
5 changed files with 53 additions and 21 deletions

View File

@ -210,6 +210,7 @@ impl BlockBuilder {
} => allocate(&[*src_dst, *path, *new_value], &[*src_dst]),
Instruction::Jump { index: _ } => Ok(()),
Instruction::BranchIf { cond, index: _ } => allocate(&[*cond], &[]),
Instruction::BranchIfEmpty { src, index: _ } => allocate(&[*src], &[*src]),
Instruction::Match {
pattern: _,
src,
@ -336,6 +337,16 @@ impl BlockBuilder {
self.branch_if(cond, usize::MAX, span)
}
/// Add a `branch-if-empty` instruction
pub(crate) fn branch_if_empty(
&mut self,
src: RegId,
index: usize,
span: Span,
) -> Result<usize, CompileError> {
self.push(Instruction::BranchIfEmpty { src, index }.into_spanned(span))
}
/// Add a `jump` instruction
pub(crate) fn jump(&mut self, index: usize, span: Span) -> Result<usize, CompileError> {
self.push(Instruction::Jump { index }.into_spanned(span))
@ -356,6 +367,7 @@ impl BlockBuilder {
match self.instructions.get_mut(instruction_index) {
Some(
Instruction::BranchIf { index, .. }
| Instruction::BranchIfEmpty { index, .. }
| Instruction::Jump { index }
| Instruction::Match { index, .. }
| Instruction::Iterate {

View File

@ -134,10 +134,7 @@ pub(crate) fn compile_assignment(
_,
) if *var_id == ENV_VARIABLE_ID => {
// This will be an assignment to an environment variable.
let Some(PathMember::String {
val: key, optional, ..
}) = path.tail.first()
else {
let Some(PathMember::String { val: key, .. }) = path.tail.first() else {
return Err(CompileError::InvalidLhsForAssignment { span: lhs.span });
};
@ -148,23 +145,26 @@ pub(crate) fn compile_assignment(
let head_reg = builder.next_register()?;
// We could use compile_load_env, but this shares the key data...
if *optional {
builder.push(
Instruction::LoadEnvOpt {
dst: head_reg,
key: key_data,
}
.into_spanned(lhs.span),
)?;
} else {
builder.push(
Instruction::LoadEnv {
dst: head_reg,
key: key_data,
}
.into_spanned(lhs.span),
)?;
}
// Always use optional, because it doesn't matter if it's already there
builder.push(
Instruction::LoadEnvOpt {
dst: head_reg,
key: key_data,
}
.into_spanned(lhs.span),
)?;
// Default to empty record so we can do further upserts
builder.branch_if_empty(
head_reg,
builder.next_instruction_index() + 1,
assignment_span,
)?;
builder.jump(builder.next_instruction_index() + 1, assignment_span)?;
builder.load_literal(
head_reg,
Literal::Record { capacity: 0 }.into_spanned(lhs.span),
)?;
// Do the upsert on the current value to incorporate rhs
compile_upsert_cell_path(

View File

@ -544,6 +544,20 @@ fn eval_instruction<D: DebugContext>(
Ok(Continue)
}
}
Instruction::BranchIfEmpty { src, index } => {
let data = ctx.take_reg(*src);
let is_empty = matches!(
data,
PipelineData::Empty | PipelineData::Value(Value::Nothing { .. }, _)
);
ctx.put_reg(*src, data);
if is_empty {
Ok(Branch(*index))
} else {
Ok(Continue)
}
}
Instruction::Match {
pattern,
src,

View File

@ -171,6 +171,9 @@ impl<'a> fmt::Display for FmtInstruction<'a> {
Instruction::BranchIf { cond, index } => {
write!(f, "{:WIDTH$} {cond}, {index}", "branch-if")
}
Instruction::BranchIfEmpty { src, index } => {
write!(f, "{:WIDTH$} {src}, {index}", "branch-if-empty")
}
Instruction::Match {
pattern,
src,

View File

@ -186,6 +186,9 @@ pub enum Instruction {
/// Branch to an offset in this block if the value of the `cond` register is a true boolean,
/// otherwise continue execution
BranchIf { cond: RegId, index: usize },
/// Branch to an offset in this block if the value of the `src` register is Empty or Nothing,
/// otherwise continue execution. The original value in `src` is preserved.
BranchIfEmpty { src: RegId, index: usize },
/// Match a pattern on `src`. If the pattern matches, branch to `index` after having set any
/// variables captured by the pattern. If the pattern doesn't match, continue execution. The
/// original value is preserved in `src` through this instruction.