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 <grfn@gws.fyi>
This commit is contained in:
parent
2d401a32e5
commit
342b233a0a
4 changed files with 31 additions and 1 deletions
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue