about summary refs log tree commit diff
path: root/users/tazjin/rlox
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-02-28T13·15+0200
committertazjin <mail@tazj.in>2021-02-28T14·36+0000
commit47ffa8071152bcafb4b6ff87a3142bf12dbce12b (patch)
treea97b223762525febc0a2cfefa5be413a7b80e901 /users/tazjin/rlox
parent127ef984865500d70176347861b2e8bad29a39be (diff)
feat(tazjin/rlox): Support trivial literals in bytecode compiler r/2252
Adds support for true, false & nil. These each come with a new
separate opcode and are pushed directly on the stack.

Change-Id: I405b5b09496dcf99d514d3411c083e0834377167
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2571
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox')
-rw-r--r--users/tazjin/rlox/src/bytecode/compiler.rs30
-rw-r--r--users/tazjin/rlox/src/bytecode/mod.rs1
-rw-r--r--users/tazjin/rlox/src/bytecode/opcode.rs7
-rw-r--r--users/tazjin/rlox/src/bytecode/tests.rs16
-rw-r--r--users/tazjin/rlox/src/bytecode/vm.rs4
5 files changed, 52 insertions, 6 deletions
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs
index 63f34fad3e..95b111dba8 100644
--- a/users/tazjin/rlox/src/bytecode/compiler.rs
+++ b/users/tazjin/rlox/src/bytecode/compiler.rs
@@ -1,9 +1,12 @@
-use super::chunk::{self, Chunk};
+use super::chunk::Chunk;
 use super::errors::{Error, ErrorKind, LoxResult};
 use super::opcode::OpCode;
 use super::value::Value;
 use crate::scanner::{self, Token, TokenKind};
 
+#[cfg(feature = "disassemble")]
+use super::chunk;
+
 struct Compiler<T: Iterator<Item = Token>> {
     tokens: T,
     chunk: Chunk,
@@ -101,6 +104,18 @@ fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> {
             ParseRule::new(Some(Compiler::number), None, Precedence::None)
         }
 
+        TokenKind::True => {
+            ParseRule::new(Some(Compiler::literal), None, Precedence::None)
+        }
+
+        TokenKind::False => {
+            ParseRule::new(Some(Compiler::literal), None, Precedence::None)
+        }
+
+        TokenKind::Nil => {
+            ParseRule::new(Some(Compiler::literal), None, Precedence::None)
+        }
+
         _ => ParseRule::new(None, None, Precedence::None),
     }
 }
@@ -180,6 +195,17 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
         Ok(())
     }
 
+    fn literal(&mut self) -> LoxResult<()> {
+        match self.previous().kind {
+            TokenKind::Nil => self.emit_op(OpCode::OpNil),
+            TokenKind::True => self.emit_op(OpCode::OpTrue),
+            TokenKind::False => self.emit_op(OpCode::OpFalse),
+            _ => unreachable!("only called for literal value tokens"),
+        }
+
+        Ok(())
+    }
+
     fn parse_precedence(&mut self, precedence: Precedence) -> LoxResult<()> {
         self.advance();
         let rule: ParseRule<T> = rule_for(&self.previous().kind);
@@ -206,7 +232,7 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
     }
 
     fn consume(&mut self, expected: &TokenKind, err: ErrorKind) {
-        if (self.current().kind == *expected) {
+        if self.current().kind == *expected {
             self.advance();
             return;
         }
diff --git a/users/tazjin/rlox/src/bytecode/mod.rs b/users/tazjin/rlox/src/bytecode/mod.rs
index 3c7dad97be..27fa7c0f67 100644
--- a/users/tazjin/rlox/src/bytecode/mod.rs
+++ b/users/tazjin/rlox/src/bytecode/mod.rs
@@ -12,7 +12,6 @@ mod vm;
 #[cfg(test)]
 mod tests;
 
-use chunk::Chunk;
 pub struct Interpreter {}
 
 impl crate::Lox for Interpreter {
diff --git a/users/tazjin/rlox/src/bytecode/opcode.rs b/users/tazjin/rlox/src/bytecode/opcode.rs
index 0f070ce9ff..057fa76977 100644
--- a/users/tazjin/rlox/src/bytecode/opcode.rs
+++ b/users/tazjin/rlox/src/bytecode/opcode.rs
@@ -1,8 +1,13 @@
 #[derive(Debug)]
 pub enum OpCode {
-    /// Access a constant for use.
+    /// Push a constant onto the stack.
     OpConstant(usize),
 
+    // Literal pushes
+    OpNil,
+    OpTrue,
+    OpFalse,
+
     /// Return from the current function.
     OpReturn,
 
diff --git a/users/tazjin/rlox/src/bytecode/tests.rs b/users/tazjin/rlox/src/bytecode/tests.rs
index 5a0901be6d..d9a752b387 100644
--- a/users/tazjin/rlox/src/bytecode/tests.rs
+++ b/users/tazjin/rlox/src/bytecode/tests.rs
@@ -1,12 +1,17 @@
+use super::value::Value;
 use super::*;
 
 use crate::Lox;
 
-fn expect_num(code: &str, value: f64) {
+fn expect(code: &str, value: Value) {
     let result = Interpreter::create()
         .interpret(code.into())
         .expect("evaluation failed");
-    assert_eq!(result, value::Value::Number(value));
+    assert_eq!(result, value);
+}
+
+fn expect_num(code: &str, value: f64) {
+    expect(code, Value::Number(value))
 }
 
 #[test]
@@ -46,3 +51,10 @@ fn arithmetic() {
     expect_num("-4 * -4 + (14 - 5)", 25.0);
     expect_num("(702 + 408) - ((239 - 734) / -5) + -4", 1007.0);
 }
+
+#[test]
+fn trivial_literals() {
+    expect("true", Value::Bool(true));
+    expect("false", Value::Bool(false));
+    expect("nil", Value::Nil);
+}
diff --git a/users/tazjin/rlox/src/bytecode/vm.rs b/users/tazjin/rlox/src/bytecode/vm.rs
index ee3abbd6cc..74c3e338fc 100644
--- a/users/tazjin/rlox/src/bytecode/vm.rs
+++ b/users/tazjin/rlox/src/bytecode/vm.rs
@@ -72,6 +72,10 @@ impl VM {
                     self.push(c);
                 }
 
+                OpCode::OpNil => self.push(Value::Nil),
+                OpCode::OpTrue => self.push(Value::Bool(true)),
+                OpCode::OpFalse => self.push(Value::Bool(false)),
+
                 OpCode::OpNegate => {
                     let v = self.pop();
                     with_type!(