refactor(tvix/eval): introduce Closure struct in Value type

This struct will carry the upvalue machinery in addition to the lambda
itself. For now, all lambdas are wrapped in closures (though
technically analysis of the environment can later remove innermost
Closure wrapper, but this optimisation may not be worth it).

Change-Id: If2b68549ec1ea4ab838fdc47a2181c694ac937f2
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6269
Reviewed-by: grfn <grfn@gws.fyi>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2022-08-24 22:08:26 +03:00 committed by tazjin
parent af9dca3663
commit 6ce2c666c3
5 changed files with 17 additions and 10 deletions

View file

@ -44,7 +44,7 @@ fn pure_builtins() -> Vec<Builtin> {
}),
Builtin::new("isFunction", 1, |args| {
Ok(Value::Bool(match args[0] {
Value::Lambda(_) => true,
Value::Closure(_) => true,
Value::Builtin(_) => true,
_ => false,
}))

View file

@ -23,7 +23,7 @@ use std::rc::Rc;
use crate::chunk::Chunk;
use crate::errors::{Error, ErrorKind, EvalResult};
use crate::opcode::{CodeIdx, OpCode};
use crate::value::{Lambda, Value};
use crate::value::{Closure, Lambda, Value};
use crate::warnings::{EvalWarning, WarningKind};
/// Represents the result of compiling a piece of Nix code. If
@ -822,7 +822,9 @@ impl Compiler {
crate::disassembler::disassemble_chunk(&compiled.lambda.chunk);
}
self.emit_constant(Value::Lambda(compiled.lambda));
self.emit_constant(Value::Closure(Closure {
lambda: compiled.lambda,
}));
}
fn compile_apply(&mut self, node: ast::Apply) {

View file

@ -21,3 +21,8 @@ impl Lambda {
&mut self.chunk
}
}
#[derive(Clone, Debug)]
pub struct Closure {
pub lambda: Lambda,
}

View file

@ -5,14 +5,14 @@ use std::{fmt::Display, path::PathBuf};
mod attrs;
mod builtin;
mod lambda;
mod function;
mod list;
mod string;
use crate::errors::{ErrorKind, EvalResult};
pub use attrs::NixAttrs;
pub use builtin::Builtin;
pub use lambda::Lambda;
pub use function::{Closure, Lambda};
pub use list::NixList;
pub use string::NixString;
@ -27,7 +27,7 @@ pub enum Value {
Path(PathBuf),
Attrs(Rc<NixAttrs>),
List(NixList),
Lambda(Lambda),
Closure(Closure),
Builtin(Builtin),
// Internal values that, while they technically exist at runtime,
@ -52,7 +52,7 @@ impl Value {
Value::Path(_) => "path",
Value::Attrs(_) => "set",
Value::List(_) => "list",
Value::Lambda(_) | Value::Builtin(_) => "lambda",
Value::Closure(_) | Value::Builtin(_) => "lambda",
// Internal types
Value::AttrPath(_) | Value::Blackhole | Value::NotFound => "internal",
@ -130,7 +130,7 @@ impl Display for Value {
Value::Path(p) => p.display().fmt(f),
Value::Attrs(attrs) => attrs.fmt(f),
Value::List(list) => list.fmt(f),
Value::Lambda(_) => f.write_str("lambda"), // TODO: print position
Value::Closure(_) => f.write_str("lambda"), // TODO: print position
Value::Builtin(builtin) => builtin.fmt(f),
// Nix prints floats with a maximum precision of 5 digits

View file

@ -7,7 +7,7 @@ use crate::{
chunk::Chunk,
errors::{ErrorKind, EvalResult},
opcode::OpCode,
value::{Lambda, NixAttrs, NixList, Value},
value::{Closure, Lambda, NixAttrs, NixList, Value},
};
#[cfg(feature = "disassembler")]
@ -357,7 +357,7 @@ impl VM {
OpCode::OpCall => {
let callable = self.pop();
match callable {
Value::Lambda(lambda) => self.call(lambda, 1),
Value::Closure(Closure { lambda }) => self.call(lambda, 1),
Value::Builtin(builtin) => {
let arg = self.pop();
let result = builtin.apply(arg)?;