about summary refs log tree commit diff
path: root/tvix/eval/src/compiler.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-23T22·54+0300
committertazjin <tazjin@tvl.su>2022-09-01T21·56+0000
commit269788086ec7cfabe70734b9be840efa87bd3f28 (patch)
treed8739de84b6a2c792d0b0693074f9096df197897 /tvix/eval/src/compiler.rs
parentfc865eb157380fa5d2c779bd0cc207b73a514572 (diff)
feat(tvix/eval): compile lambda definitions r/4581
Compiles lambda definitions of the simple form (i.e. without formals
arguments) and emits them as constants like any other value.

This does not yet implement actually invoking these functions in the VM.

Change-Id: Ie1e0a13220b68c1728be229b875f0992e685c5ef
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6247
Tested-by: BuildkiteCI
Reviewed-by: grfn <grfn@gws.fyi>
Diffstat (limited to 'tvix/eval/src/compiler.rs')
-rw-r--r--tvix/eval/src/compiler.rs41
1 files changed, 40 insertions, 1 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs
index bbf97ccaedf0..bb751e4f92a1 100644
--- a/tvix/eval/src/compiler.rs
+++ b/tvix/eval/src/compiler.rs
@@ -160,13 +160,13 @@ impl Compiler {
             ast::Expr::LetIn(let_in) => self.compile_let_in(let_in),
             ast::Expr::Ident(ident) => self.compile_ident(ident),
             ast::Expr::With(with) => self.compile_with(with),
+            ast::Expr::Lambda(lambda) => self.compile_lambda(lambda),
 
             // Parenthesized expressions are simply unwrapped, leaving
             // their value on the stack.
             ast::Expr::Paren(paren) => self.compile(paren.expr().unwrap()),
 
             ast::Expr::LegacyLet(_) => todo!("legacy let"),
-            ast::Expr::Lambda(_) => todo!("function definition"),
             ast::Expr::Apply(_) => todo!("function application"),
 
             ast::Expr::Root(_) => unreachable!("there cannot be more than one root"),
@@ -735,6 +735,45 @@ impl Compiler {
         self.compile(node.body().unwrap());
     }
 
+    fn compile_lambda(&mut self, node: ast::Lambda) {
+        // Open new lambda context in compiler, which has its own
+        // scope etc.
+        self.contexts.push(LambdaCtx::new());
+        self.begin_scope();
+
+        // Compile the function itself
+        match node.param().unwrap() {
+            ast::Param::Pattern(_) => todo!("formals function definitions"),
+            ast::Param::IdentParam(param) => {
+                let name = param
+                    .ident()
+                    .unwrap()
+                    .ident_token()
+                    .unwrap()
+                    .text()
+                    .to_string();
+
+                self.declare_local(param.syntax().clone(), name);
+            }
+        }
+
+        self.compile(node.body().unwrap());
+        self.end_scope();
+
+        // TODO: determine and insert enclosing name, if available.
+
+        // Pop the lambda context back off, and emit the finished
+        // lambda as a constant.
+        let compiled = self.contexts.pop().unwrap();
+
+        #[cfg(feature = "disassembler")]
+        {
+            crate::disassembler::disassemble_chunk(&compiled.lambda.chunk);
+        }
+
+        self.emit_constant(Value::Lambda(compiled.lambda));
+    }
+
     /// Emit the literal string value of an identifier. Required for
     /// several operations related to attribute sets, where
     /// identifiers are used as string keys.