refactor(tvix/eval): return a lambda from the compiler

Changes the internal compiler plumbing to not just return a chunk of
code, but the same chunk wrapped inside of a lambda value.

This is one more step towards compiling runtime lambdas.

Change-Id: If0035f8e65a2970c5ae123fc068a2396e1d8fd72
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6240
Tested-by: BuildkiteCI
Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
Vincent Ambo 2022-08-23 22:54:25 +03:00 committed by tazjin
parent 4715f9a3a0
commit 6f31c895ff
5 changed files with 28 additions and 16 deletions

View file

@ -1,7 +1,7 @@
use crate::opcode::{CodeIdx, ConstantIdx, OpCode}; use crate::opcode::{CodeIdx, ConstantIdx, OpCode};
use crate::value::Value; use crate::value::Value;
#[derive(Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct Chunk { pub struct Chunk {
pub code: Vec<OpCode>, pub code: Vec<OpCode>,
pub constants: Vec<Value>, pub constants: Vec<Value>,

View file

@ -21,14 +21,14 @@ use std::path::{Path, PathBuf};
use crate::chunk::Chunk; use crate::chunk::Chunk;
use crate::errors::{Error, ErrorKind, EvalResult}; use crate::errors::{Error, ErrorKind, EvalResult};
use crate::opcode::{CodeIdx, OpCode}; use crate::opcode::{CodeIdx, OpCode};
use crate::value::Value; use crate::value::{Lambda, Value};
use crate::warnings::{EvalWarning, WarningKind}; use crate::warnings::{EvalWarning, WarningKind};
/// Represents the result of compiling a piece of Nix code. If /// Represents the result of compiling a piece of Nix code. If
/// compilation was successful, the resulting bytecode can be passed /// compilation was successful, the resulting bytecode can be passed
/// to the VM. /// to the VM.
pub struct CompilationResult { pub struct CompilationResult {
pub chunk: Chunk, pub lambda: Lambda,
pub warnings: Vec<EvalWarning>, pub warnings: Vec<EvalWarning>,
pub errors: Vec<Error>, pub errors: Vec<Error>,
} }
@ -90,7 +90,7 @@ struct Scope {
} }
struct Compiler { struct Compiler {
chunk: Chunk, lambda: Lambda,
scope: Scope, scope: Scope,
warnings: Vec<EvalWarning>, warnings: Vec<EvalWarning>,
@ -102,7 +102,8 @@ struct Compiler {
// structures of the compiler. // structures of the compiler.
impl Compiler { impl Compiler {
fn chunk(&mut self) -> &mut Chunk { fn chunk(&mut self) -> &mut Chunk {
&mut self.chunk std::rc::Rc::<Chunk>::get_mut(self.lambda.chunk())
.expect("compiler flaw: long-lived chunk reference")
} }
fn emit_constant(&mut self, value: Value) { fn emit_constant(&mut self, value: Value) {
@ -910,7 +911,7 @@ pub fn compile(expr: ast::Expr, location: Option<PathBuf>) -> EvalResult<Compila
let mut c = Compiler { let mut c = Compiler {
root_dir, root_dir,
chunk: Chunk::default(), lambda: Lambda::new_anonymous(),
warnings: vec![], warnings: vec![],
errors: vec![], errors: vec![],
scope: Default::default(), scope: Default::default(),
@ -919,7 +920,7 @@ pub fn compile(expr: ast::Expr, location: Option<PathBuf>) -> EvalResult<Compila
c.compile(expr); c.compile(expr);
Ok(CompilationResult { Ok(CompilationResult {
chunk: c.chunk, lambda: c.lambda,
warnings: c.warnings, warnings: c.warnings,
errors: c.errors, errors: c.errors,
}) })

View file

@ -31,7 +31,7 @@ pub fn interpret(code: &str, location: Option<PathBuf>) -> EvalResult<Value> {
let result = crate::compiler::compile(root_expr, location)?; let result = crate::compiler::compile(root_expr, location)?;
#[cfg(feature = "disassembler")] #[cfg(feature = "disassembler")]
crate::disassembler::disassemble_chunk(&result.chunk); crate::disassembler::disassemble_chunk(&result.lambda.chunk);
for warning in result.warnings { for warning in result.warnings {
eprintln!( eprintln!(
@ -49,5 +49,5 @@ pub fn interpret(code: &str, location: Option<PathBuf>) -> EvalResult<Value> {
return Err(err.clone()); return Err(err.clone());
} }
crate::vm::run_chunk(result.chunk) crate::vm::run_lambda(result.lambda)
} }

View file

@ -3,10 +3,21 @@ use std::rc::Rc;
use crate::chunk::Chunk; use crate::chunk::Chunk;
use super::NixString;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Lambda { pub struct Lambda {
name: Option<NixString>, // name: Option<NixString>,
chunk: Rc<Chunk>, pub(crate) chunk: Rc<Chunk>,
}
impl Lambda {
pub fn new_anonymous() -> Self {
Lambda {
// name: None,
chunk: Default::default(),
}
}
pub fn chunk(&mut self) -> &mut Rc<Chunk> {
&mut self.chunk
}
} }

View file

@ -7,7 +7,7 @@ use crate::{
chunk::Chunk, chunk::Chunk,
errors::{ErrorKind, EvalResult}, errors::{ErrorKind, EvalResult},
opcode::OpCode, opcode::OpCode,
value::{NixAttrs, NixList, Value}, value::{Lambda, NixAttrs, NixList, Value},
}; };
#[cfg(feature = "disassembler")] #[cfg(feature = "disassembler")]
@ -365,9 +365,9 @@ impl VM {
} }
} }
pub fn run_chunk(chunk: Chunk) -> EvalResult<Value> { pub fn run_lambda(lambda: Lambda) -> EvalResult<Value> {
let mut vm = VM { let mut vm = VM {
chunk, chunk: Rc::<Chunk>::try_unwrap(lambda.chunk).unwrap(),
ip: 0, ip: 0,
stack: vec![], stack: vec![],
with_stack: vec![], with_stack: vec![],