about summary refs log tree commit diff
path: root/tvix/eval
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-08T00·07+0300
committertazjin <tazjin@tvl.su>2022-08-12T14·09+0000
commit9c5a249b3059fa7951948b27ba5365d4570843ff (patch)
tree26c101688aeece3ff75ddbeab38adb7668bd6508 /tvix/eval
parentd431f43f5fbb0c8eaa23fd082ddb8839cdc0f642 (diff)
feat(tvix/compiler): incompletely handle true/false/null literals r/4416
These are a bit tricky to implement because Nix technically treats
them as identifiers, and only if the identifier is not explicitly
overridden within the scope does it yield the expected literal values.

Note that weirdness even occurs with scopedImport.

Change-Id: Ie55723405ccfcc25da37c5a08fa3332f37cf9ae5
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6080
Tested-by: BuildkiteCI
Autosubmit: tazjin <tazjin@tvl.su>
Reviewed-by: grfn <grfn@gws.fyi>
Diffstat (limited to 'tvix/eval')
-rw-r--r--tvix/eval/src/compiler.rs29
-rw-r--r--tvix/eval/src/vm.rs6
2 files changed, 31 insertions, 4 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs
index 297d23d3d84f..4526bf16d6b7 100644
--- a/tvix/eval/src/compiler.rs
+++ b/tvix/eval/src/compiler.rs
@@ -6,7 +6,7 @@ use crate::errors::EvalResult;
 use crate::opcode::OpCode;
 use crate::value::Value;
 use rnix;
-use rnix::types::{TypedNode, Wrapper};
+use rnix::types::{TokenWrapper, TypedNode, Wrapper};
 
 struct Compiler {
     chunk: Chunk,
@@ -41,6 +41,11 @@ impl Compiler {
                 self.compile(node.inner().unwrap())
             }
 
+            rnix::SyntaxKind::NODE_IDENT => {
+                let node = rnix::types::Ident::cast(node).unwrap();
+                self.compile_ident(node)
+            }
+
             kind => {
                 println!("visiting unsupported node: {:?}", kind);
                 Ok(())
@@ -98,6 +103,28 @@ impl Compiler {
         self.chunk.add_op(opcode);
         Ok(())
     }
+
+    fn compile_ident(&mut self, node: rnix::types::Ident) -> EvalResult<()> {
+        match node.as_str() {
+            // TODO(tazjin): Nix technically allows code like
+            //
+            //   let null = 1; in null
+            //   => 1
+            //
+            // which we do *not* want to check at runtime. Once
+            // scoping is introduced, the compiler should carry some
+            // optimised information about any "weird" stuff that's
+            // happened to the scope (such as overrides of these
+            // literals, or builtins).
+            "true" => self.chunk.add_op(OpCode::OpTrue),
+            "false" => self.chunk.add_op(OpCode::OpFalse),
+            "null" => self.chunk.add_op(OpCode::OpNull),
+
+            _ => todo!("identifier access"),
+        };
+
+        Ok(())
+    }
 }
 
 pub fn compile(ast: rnix::AST) -> EvalResult<Chunk> {
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index 7b02c68dc193..7b7834c650c6 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -111,9 +111,9 @@ impl VM {
                     self.push(Value::Bool(eq))
                 }
 
-                OpCode::OpNull => todo!("null"),
-                OpCode::OpTrue => todo!("true"),
-                OpCode::OpFalse => todo!("false"),
+                OpCode::OpNull => self.push(Value::Null),
+                OpCode::OpTrue => self.push(Value::Bool(true)),
+                OpCode::OpFalse => self.push(Value::Bool(false)),
             }
 
             if self.ip == self.chunk.code.len() {