about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-17T20·03+0300
committertazjin <mail@tazj.in>2021-01-17T21·17+0000
commit7fb93fb49008491184a7d55ccd43db846452dce0 (patch)
treee07383f72d95ee2cfc150811a99af7caef87bb55
parentb1d0e22b1f5fe907ba3d48931e5a38b9a75b0dcf (diff)
feat(tazjin/rlox): Bootstrap VM for Lox bytecode r/2127
Change-Id: I479e20bf2087e5c4aa20e31b364c57ed0d961bcf
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2416
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
-rw-r--r--users/tazjin/rlox/Cargo.toml7
-rw-r--r--users/tazjin/rlox/src/bytecode/chunk.rs27
-rw-r--r--users/tazjin/rlox/src/bytecode/errors.rs13
-rw-r--r--users/tazjin/rlox/src/bytecode/mod.rs4
-rw-r--r--users/tazjin/rlox/src/bytecode/vm.rs59
-rw-r--r--users/tazjin/rlox/src/treewalk/interpreter/builtins.rs2
-rw-r--r--users/tazjin/rlox/src/treewalk/mod.rs2
7 files changed, 89 insertions, 25 deletions
diff --git a/users/tazjin/rlox/Cargo.toml b/users/tazjin/rlox/Cargo.toml
index 1562e7ecc2..b66af6ba85 100644
--- a/users/tazjin/rlox/Cargo.toml
+++ b/users/tazjin/rlox/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.1.0"
 authors = ["Vincent Ambo <mail@tazj.in>"]
 edition = "2018"
 
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
+[features]
+# Enables debugging/disassembling in the bytecode interpreter. Off by
+# default as it is quite spammy.
+disassemble = []
diff --git a/users/tazjin/rlox/src/bytecode/chunk.rs b/users/tazjin/rlox/src/bytecode/chunk.rs
index fa3909f038..4a671c8383 100644
--- a/users/tazjin/rlox/src/bytecode/chunk.rs
+++ b/users/tazjin/rlox/src/bytecode/chunk.rs
@@ -10,7 +10,7 @@ use super::value;
 // problem.
 #[derive(Debug, Default)]
 pub struct Chunk {
-    code: Vec<OpCode>,
+    pub code: Vec<OpCode>,
     lines: Vec<Span>,
     constants: Vec<value::Value>,
 }
@@ -38,6 +38,10 @@ impl Chunk {
         idx
     }
 
+    pub fn constant(&self, idx: usize) -> &value::Value {
+        self.constants.index(idx)
+    }
+
     fn add_line(&mut self, line: usize) {
         match self.lines.last_mut() {
             Some(span) if span.line == line => span.count += 1,
@@ -58,26 +62,11 @@ impl Chunk {
     }
 }
 
-impl Index<usize> for Chunk {
-    type Output = OpCode;
-
-    fn index(&self, offset: usize) -> &Self::Output {
-        self.code.index(offset)
-    }
-}
-
 // Disassembler
-pub fn disassemble(chunk: &Chunk, name: &str) {
-    println!("== {} ==", name);
-
-    for (idx, _) in chunk.code.iter().enumerate() {
-        disassemble_instruction(chunk, idx);
-    }
-}
 
 /// Print a single disassembled instruction at the specified offset.
 /// Some instructions are printed "raw", others have special handling.
-fn disassemble_instruction(chunk: &Chunk, offset: usize) {
+pub fn disassemble_instruction(chunk: &Chunk, offset: usize) {
     print!("{:04} ", offset);
 
     let line = chunk.get_line(offset);
@@ -87,8 +76,8 @@ fn disassemble_instruction(chunk: &Chunk, offset: usize) {
         print!("{:4} ", line);
     }
 
-    match &chunk[offset] {
-        OpCode::OpConstant(idx) => println!("OpConstant idx '{:?}'", chunk.constants[*idx]),
+    match chunk.code.index(offset) {
+        OpCode::OpConstant(idx) => println!("OpConstant({}) '{:?}'", *idx, chunk.constant(*idx)),
         op => println!("{:?}", op),
     }
 }
diff --git a/users/tazjin/rlox/src/bytecode/errors.rs b/users/tazjin/rlox/src/bytecode/errors.rs
new file mode 100644
index 0000000000..89ab1867a4
--- /dev/null
+++ b/users/tazjin/rlox/src/bytecode/errors.rs
@@ -0,0 +1,13 @@
+#[derive(Debug)]
+pub enum ErrorKind {
+    // CompileError,
+    // RuntimeError,
+    InternalError(&'static str),
+}
+
+#[derive(Debug)]
+pub struct Error {
+    pub kind: ErrorKind,
+}
+
+pub type LoxResult<T> = Result<T, Error>;
diff --git a/users/tazjin/rlox/src/bytecode/mod.rs b/users/tazjin/rlox/src/bytecode/mod.rs
index 922b3bef44..de04d7b06f 100644
--- a/users/tazjin/rlox/src/bytecode/mod.rs
+++ b/users/tazjin/rlox/src/bytecode/mod.rs
@@ -3,8 +3,10 @@
 //! https://craftinginterpreters.com/chunks-of-bytecode.html
 
 mod chunk;
+mod errors;
 mod opcode;
 mod value;
+mod vm;
 
 use chunk::Chunk;
 use opcode::OpCode;
@@ -16,5 +18,5 @@ pub fn main() {
     chunk.add_op(OpCode::OpConstant(constant), 1);
     chunk.add_op(OpCode::OpReturn, 1);
 
-    chunk::disassemble(&chunk, "test chunk");
+    vm::interpret(chunk).expect("it should work");
 }
diff --git a/users/tazjin/rlox/src/bytecode/vm.rs b/users/tazjin/rlox/src/bytecode/vm.rs
new file mode 100644
index 0000000000..1b9c4a2359
--- /dev/null
+++ b/users/tazjin/rlox/src/bytecode/vm.rs
@@ -0,0 +1,59 @@
+use super::chunk;
+use super::errors::*;
+use super::opcode::OpCode;
+use super::value::Value;
+
+pub struct VM {
+    chunk: chunk::Chunk,
+
+    // TODO(tazjin): Accessing array elements constantly is not ideal,
+    // lets see if something clever can be done with iterators.
+    ip: usize,
+
+    stack: Vec<Value>,
+}
+
+impl VM {
+    fn push(&mut self, value: Value) {
+        self.stack.push(value)
+    }
+
+    fn pop(&mut self) -> Value {
+        self.stack.pop().expect("fatal error: stack empty!")
+    }
+}
+
+impl VM {
+    fn run(&mut self) -> LoxResult<()> {
+        loop {
+            let op = &self.chunk.code[self.ip];
+
+            #[cfg(feature = "disassemble")]
+            chunk::disassemble_instruction(&self.chunk, self.ip);
+
+            self.ip += 1;
+
+            match op {
+                OpCode::OpReturn => {
+                    println!("{:?}", self.pop());
+                    return Ok(());
+                }
+
+                OpCode::OpConstant(idx) => {
+                    let c = *self.chunk.constant(*idx);
+                    self.push(c);
+                }
+            }
+        }
+    }
+}
+
+pub fn interpret(chunk: chunk::Chunk) -> LoxResult<()> {
+    let mut vm = VM {
+        chunk,
+        ip: 0,
+        stack: vec![],
+    };
+
+    vm.run()
+}
diff --git a/users/tazjin/rlox/src/treewalk/interpreter/builtins.rs b/users/tazjin/rlox/src/treewalk/interpreter/builtins.rs
index 709e53c7c0..c502d2a171 100644
--- a/users/tazjin/rlox/src/treewalk/interpreter/builtins.rs
+++ b/users/tazjin/rlox/src/treewalk/interpreter/builtins.rs
@@ -2,8 +2,8 @@ use std::fmt;
 use std::time::{SystemTime, UNIX_EPOCH};
 
 use crate::treewalk::errors::Error;
-use crate::treewalk::parser::Literal;
 use crate::treewalk::interpreter::Value;
+use crate::treewalk::parser::Literal;
 
 pub trait Builtin: fmt::Debug {
     fn arity(&self) -> usize;
diff --git a/users/tazjin/rlox/src/treewalk/mod.rs b/users/tazjin/rlox/src/treewalk/mod.rs
index ae1049a12e..b5db454ccc 100644
--- a/users/tazjin/rlox/src/treewalk/mod.rs
+++ b/users/tazjin/rlox/src/treewalk/mod.rs
@@ -1,10 +1,10 @@
 use crate::*;
 
 mod errors;
+pub mod interpreter;
 mod parser;
 mod resolver;
 mod scanner;
-pub mod interpreter;
 
 pub fn main() {
     let mut args = env::args();