fix handling of assignment of deep path env vars
This commit is contained in:
parent
5cbc591094
commit
650cc95d94
|
@ -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 {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user