From 342b233a0a626aaad4ea32b1e5bf4f873afe7206 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Sat, 13 Aug 2022 20:17:25 +0300 Subject: feat(tvix/eval): add local identifier access This makes basic `let ... in ...` statements work correctly. It does not yet account for the call frames pushed into the VM during function application. Change-Id: I67155171daf1a43011b96716dd9d1ab04b27db33 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6190 Tested-by: BuildkiteCI Reviewed-by: grfn --- tvix/eval/src/compiler.rs | 21 ++++++++++++++++++++- tvix/eval/src/errors.rs | 3 +++ tvix/eval/src/opcode.rs | 3 +++ tvix/eval/src/vm.rs | 5 +++++ 4 files changed, 31 insertions(+), 1 deletion(-) (limited to 'tvix/eval') diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs index c0e895b7be..ac630360d4 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 { + 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 a0e3808225..4b4610f1e9 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 ebd91dd439..ce17dab631 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 eb860eae00..8ee1725860 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() { -- cgit 1.4.1