refactor(tvix/eval): Factor out bind_values
helper
This is responsible for actually setting up `TrackedBinding`s on the stack, i.e. in some sense "actually compiling" values in bindings. There is no functionality change to before, i.e. this is a salami slice. Change-Id: Idb0312038e004470a7d130c020ae0fe87c55c218 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6774 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
This commit is contained in:
parent
7e9169bcf7
commit
f40283e098
1 changed files with 55 additions and 47 deletions
|
@ -434,6 +434,59 @@ impl Compiler<'_> {
|
||||||
self.scope_mut().end_scope();
|
self.scope_mut().end_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Actually binds all tracked bindings by emitting the bytecode that places
|
||||||
|
/// them in their stack slots.
|
||||||
|
fn bind_values(&mut self, bindings: Vec<TrackedBinding>) {
|
||||||
|
let mut value_indices: Vec<LocalIdx> = vec![];
|
||||||
|
|
||||||
|
for binding in bindings.into_iter() {
|
||||||
|
value_indices.push(binding.value_slot);
|
||||||
|
|
||||||
|
if let Some(key_slot) = binding.key_slot {
|
||||||
|
let span = self.scope()[key_slot.slot].span;
|
||||||
|
self.emit_constant(Value::String(key_slot.name.into()), &span);
|
||||||
|
self.scope_mut().mark_initialised(key_slot.slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
match binding.binding {
|
||||||
|
// This entry is an inherit (from) expr. The value is
|
||||||
|
// placed on the stack by selecting an attribute.
|
||||||
|
Binding::InheritFrom {
|
||||||
|
namespace,
|
||||||
|
name,
|
||||||
|
span,
|
||||||
|
} => {
|
||||||
|
// Create a thunk wrapping value (which may be one as well) to
|
||||||
|
// avoid forcing the from expr too early.
|
||||||
|
self.thunk(binding.value_slot, &namespace, move |c, n, s| {
|
||||||
|
c.compile(s, n.clone());
|
||||||
|
c.emit_force(n);
|
||||||
|
|
||||||
|
c.emit_constant(Value::String(name.into()), &span);
|
||||||
|
c.push_op(OpCode::OpAttrsSelect, &span);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binding is "just" a plain expression that needs to
|
||||||
|
// be compiled.
|
||||||
|
Binding::Plain { expr } => self.compile(binding.value_slot, expr),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any code after this point will observe the value in the
|
||||||
|
// right stack slot, so mark it as initialised.
|
||||||
|
self.scope_mut().mark_initialised(binding.value_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final pass to emit finaliser instructions if necessary.
|
||||||
|
for idx in value_indices {
|
||||||
|
if self.scope()[idx].needs_finaliser {
|
||||||
|
let stack_idx = self.scope().stack_index(idx);
|
||||||
|
let span = self.scope()[idx].span;
|
||||||
|
self.push_op(OpCode::OpFinalise(stack_idx), &span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_recursive_scope<N>(&mut self, slot: LocalIdx, kind: BindingsKind, node: &N) -> usize
|
fn compile_recursive_scope<N>(&mut self, slot: LocalIdx, kind: BindingsKind, node: &N) -> usize
|
||||||
where
|
where
|
||||||
N: ToSpan + ast::HasEntry,
|
N: ToSpan + ast::HasEntry,
|
||||||
|
@ -488,53 +541,8 @@ impl Compiler<'_> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Third pass to place the values in the correct stack slots.
|
// Actually bind values and ensure they are on the stack.
|
||||||
let mut value_indices: Vec<LocalIdx> = vec![];
|
self.bind_values(bindings);
|
||||||
for binding in bindings.into_iter() {
|
|
||||||
value_indices.push(binding.value_slot);
|
|
||||||
|
|
||||||
if let Some(key_slot) = binding.key_slot {
|
|
||||||
let span = self.scope()[key_slot.slot].span;
|
|
||||||
self.emit_constant(Value::String(key_slot.name.into()), &span);
|
|
||||||
self.scope_mut().mark_initialised(key_slot.slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
match binding.binding {
|
|
||||||
// This entry is an inherit (from) expr. The value is
|
|
||||||
// placed on the stack by selecting an attribute.
|
|
||||||
Binding::InheritFrom {
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
span,
|
|
||||||
} => {
|
|
||||||
// Create a thunk wrapping value (which may be one as well) to
|
|
||||||
// avoid forcing the from expr too early.
|
|
||||||
self.thunk(binding.value_slot, &namespace, move |c, n, s| {
|
|
||||||
c.compile(s, n.clone());
|
|
||||||
c.emit_force(n);
|
|
||||||
|
|
||||||
c.emit_constant(Value::String(name.into()), &span);
|
|
||||||
c.push_op(OpCode::OpAttrsSelect, &span);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Binding is "just" a plain expression that needs to
|
|
||||||
// be compiled.
|
|
||||||
Binding::Plain { expr } => self.compile(binding.value_slot, expr),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any code after this point will observe the value in the
|
|
||||||
// right stack slot, so mark it as initialised.
|
|
||||||
self.scope_mut().mark_initialised(binding.value_slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fourth pass to emit finaliser instructions if necessary.
|
|
||||||
for idx in value_indices {
|
|
||||||
if self.scope()[idx].needs_finaliser {
|
|
||||||
let stack_idx = self.scope().stack_index(idx);
|
|
||||||
self.push_op(OpCode::OpFinalise(stack_idx), node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue