refactor(tvix/eval): extract compiler's upvalue logic into helper
This exact same logic is reused for thunk creation. Change-Id: I731db9cc659a1f2ca87db55d58d6ff632f417812 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6342 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
parent
70b27a6080
commit
49296cebe3
1 changed files with 20 additions and 14 deletions
|
@ -657,7 +657,7 @@ impl Compiler {
|
||||||
|
|
||||||
// First pass to ensure that all identifiers are known;
|
// First pass to ensure that all identifiers are known;
|
||||||
// required for resolving recursion.
|
// required for resolving recursion.
|
||||||
let mut entries: Vec<(LocalIdx, rnix::ast::Expr)> = vec![];
|
let mut entries: Vec<(LocalIdx, ast::Expr)> = vec![];
|
||||||
for entry in node.attrpath_values() {
|
for entry in node.attrpath_values() {
|
||||||
let mut path = match normalise_ident_path(entry.attrpath().unwrap().attrs()) {
|
let mut path = match normalise_ident_path(entry.attrpath().unwrap().attrs()) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
|
@ -830,12 +830,28 @@ impl Compiler {
|
||||||
// number of operands that allow the runtime to close over the
|
// number of operands that allow the runtime to close over the
|
||||||
// upvalues and leave a blueprint in the constant index from
|
// upvalues and leave a blueprint in the constant index from
|
||||||
// which the runtime closure can be constructed.
|
// which the runtime closure can be constructed.
|
||||||
let closure_idx = self
|
let blueprint_idx = self
|
||||||
.chunk()
|
.chunk()
|
||||||
.push_constant(Value::Blueprint(Rc::new(compiled.lambda)));
|
.push_constant(Value::Blueprint(Rc::new(compiled.lambda)));
|
||||||
|
|
||||||
self.chunk().push_op(OpCode::OpClosure(closure_idx));
|
self.chunk().push_op(OpCode::OpClosure(blueprint_idx));
|
||||||
for upvalue in compiled.scope.upvalues {
|
self.emit_upvalue_data(slot, compiled.scope.upvalues);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_apply(&mut self, node: ast::Apply) {
|
||||||
|
// To call a function, we leave its arguments on the stack,
|
||||||
|
// followed by the function expression itself, and then emit a
|
||||||
|
// call instruction. This way, the stack is perfectly laid out
|
||||||
|
// to enter the function call straight away.
|
||||||
|
self.compile(None, node.argument().unwrap());
|
||||||
|
self.compile(None, node.lambda().unwrap());
|
||||||
|
self.chunk().push_op(OpCode::OpCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit the data instructions that the runtime needs to correctly
|
||||||
|
/// assemble the provided upvalues array.
|
||||||
|
fn emit_upvalue_data(&mut self, slot: Option<LocalIdx>, upvalues: Vec<Upvalue>) {
|
||||||
|
for upvalue in upvalues {
|
||||||
match upvalue {
|
match upvalue {
|
||||||
Upvalue::Local(idx) if slot.is_none() => {
|
Upvalue::Local(idx) if slot.is_none() => {
|
||||||
let stack_idx = self.scope().stack_index(idx);
|
let stack_idx = self.scope().stack_index(idx);
|
||||||
|
@ -871,16 +887,6 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_apply(&mut self, node: ast::Apply) {
|
|
||||||
// To call a function, we leave its arguments on the stack,
|
|
||||||
// followed by the function expression itself, and then emit a
|
|
||||||
// call instruction. This way, the stack is perfectly laid out
|
|
||||||
// to enter the function call straight away.
|
|
||||||
self.compile(None, node.argument().unwrap());
|
|
||||||
self.compile(None, node.lambda().unwrap());
|
|
||||||
self.chunk().push_op(OpCode::OpCall);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Emit the literal string value of an identifier. Required for
|
/// Emit the literal string value of an identifier. Required for
|
||||||
/// several operations related to attribute sets, where
|
/// several operations related to attribute sets, where
|
||||||
/// identifiers are used as string keys.
|
/// identifiers are used as string keys.
|
||||||
|
|
Loading…
Reference in a new issue