diff options
author | Vincent Ambo <mail@tazj.in> | 2022-09-23T16·38+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-09-28T00·09+0000 |
commit | f40283e0985b5e16a7d67e018a16b0d52f09b90c (patch) | |
tree | ef7898a72a092cd9514d44987b266845b15c81ba /tvix/eval | |
parent | 7e9169bcf713e9e6bc0c7286dbd2c75ac5320ba4 (diff) |
refactor(tvix/eval): Factor out `bind_values` helper r/4979
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
Diffstat (limited to 'tvix/eval')
-rw-r--r-- | tvix/eval/src/compiler/bindings.rs | 102 |
1 files changed, 55 insertions, 47 deletions
diff --git a/tvix/eval/src/compiler/bindings.rs b/tvix/eval/src/compiler/bindings.rs index 4f384484a973..1bf0b79c7340 100644 --- a/tvix/eval/src/compiler/bindings.rs +++ b/tvix/eval/src/compiler/bindings.rs @@ -434,6 +434,59 @@ impl Compiler<'_> { 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 where N: ToSpan + ast::HasEntry, @@ -488,53 +541,8 @@ impl Compiler<'_> { }); } - // Third pass to place the values in the correct stack slots. - 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); - } - - // 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); - } - } + // Actually bind values and ensure they are on the stack. + self.bind_values(bindings); count } |