about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/compiler.rs21
-rw-r--r--tvix/eval/src/errors.rs3
-rw-r--r--tvix/eval/src/opcode.rs3
-rw-r--r--tvix/eval/src/vm.rs5
4 files changed, 31 insertions, 1 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs
index c0e895b7be5b..ac630360d403 100644
--- a/tvix/eval/src/compiler.rs
+++ b/tvix/eval/src/compiler.rs
@@ -331,7 +331,14 @@ impl Compiler {
             "false" => self.chunk.push_op(OpCode::OpFalse),
             "null" => self.chunk.push_op(OpCode::OpNull),
 
-            _ => todo!("identifier access"),
+            name => {
+                // Note: `with` and some other special scoping
+                // features are not yet implemented.
+                match self.resolve_local(name) {
+                    Some(idx) => self.chunk.push_op(OpCode::OpGetLocal(idx)),
+                    None => return Err(Error::UnknownStaticVariable(node)),
+                }
+            }
         };
 
         Ok(())
@@ -727,6 +734,18 @@ impl Compiler {
             self.chunk.push_op(OpCode::OpCloseScope(pops));
         }
     }
+
+    fn resolve_local(&mut self, name: &str) -> Option<usize> {
+        let scope = &self.locals;
+
+        for (idx, local) in scope.locals.iter().enumerate().rev() {
+            if local.name == name {
+                return Some(idx);
+            }
+        }
+
+        None
+    }
 }
 
 /// Convert a single identifier path fragment to a string if possible,
diff --git a/tvix/eval/src/errors.rs b/tvix/eval/src/errors.rs
index a0e380822517..4b4610f1e9b2 100644
--- a/tvix/eval/src/errors.rs
+++ b/tvix/eval/src/errors.rs
@@ -29,6 +29,9 @@ pub enum Error {
 
     // Dynamic keys are not allowed in let.
     DynamicKeyInLet(rnix::SyntaxNode),
+
+    // Unknown variable in statically known scope.
+    UnknownStaticVariable(rnix::types::Ident),
 }
 
 impl Display for Error {
diff --git a/tvix/eval/src/opcode.rs b/tvix/eval/src/opcode.rs
index ebd91dd43924..ce17dab63124 100644
--- a/tvix/eval/src/opcode.rs
+++ b/tvix/eval/src/opcode.rs
@@ -62,6 +62,9 @@ pub enum OpCode {
     // Type assertion operators
     OpAssertBool,
 
+    // Access local identifiers with statically known positions.
+    OpGetLocal(usize),
+
     // Close scopes while leaving their expression value around.
     OpCloseScope(usize), // number of locals to pop
 }
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index eb860eae007e..8ee17258602e 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -254,6 +254,11 @@ impl VM {
                         self.pop();
                     }
                 }
+
+                OpCode::OpGetLocal(local_idx) => {
+                    let value = self.stack[local_idx].clone();
+                    self.push(value)
+                }
             }
 
             if self.ip == self.chunk.code.len() {