From 49c4cc6c56048dbf35dbe5d87837d47b80d90f82 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Sun, 17 Jan 2021 20:33:39 +0300 Subject: feat(tazjin/rlox): Initial bytecode representation This is significantly simplified from the version in the book, since I'm using Rust's Vec and not implementing dynamic arrays manually. We'll see if I run into issues with that ... Change-Id: Ie3446ac3884b850f3ba73a4b1a6ca14e68054188 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2413 Reviewed-by: tazjin Tested-by: BuildkiteCI --- users/tazjin/rlox/src/bytecode/chunk.rs | 57 ++++++++++++++++++++++++++++++++ users/tazjin/rlox/src/bytecode/mod.rs | 15 ++++++++- users/tazjin/rlox/src/bytecode/opcode.rs | 8 +++++ users/tazjin/rlox/src/bytecode/value.rs | 1 + 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 users/tazjin/rlox/src/bytecode/chunk.rs create mode 100644 users/tazjin/rlox/src/bytecode/opcode.rs create mode 100644 users/tazjin/rlox/src/bytecode/value.rs (limited to 'users/tazjin') diff --git a/users/tazjin/rlox/src/bytecode/chunk.rs b/users/tazjin/rlox/src/bytecode/chunk.rs new file mode 100644 index 000000000000..f5c0a2bb85d0 --- /dev/null +++ b/users/tazjin/rlox/src/bytecode/chunk.rs @@ -0,0 +1,57 @@ +use std::ops::Index; + +use super::opcode::OpCode; +use super::value; + +// In the book, this type is a hand-rolled dynamic array +// implementation in C. The main benefit of following that approach +// would be avoiding issues with OpCode variants not having equal +// sizes, but for the purpose of this I'm going to ignore that +// problem. +#[derive(Debug, Default)] +pub struct Chunk { + code: Vec, + constants: Vec, +} + +impl Chunk { + pub fn add_op(&mut self, data: OpCode) -> usize { + let idx = self.code.len(); + self.code.push(data); + idx + } + + pub fn add_constant(&mut self, data: value::Value) -> usize { + let idx = self.constants.len(); + self.constants.push(data); + idx + } +} + +impl Index 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) { + print!("{:04} ", offset); + + match &chunk[offset] { + OpCode::OpConstant(idx) => println!("OpConstant idx '{:?}'", chunk.constants[*idx]), + op => println!("{:?}", op), + } +} diff --git a/users/tazjin/rlox/src/bytecode/mod.rs b/users/tazjin/rlox/src/bytecode/mod.rs index 412e73106ead..a58f610417fd 100644 --- a/users/tazjin/rlox/src/bytecode/mod.rs +++ b/users/tazjin/rlox/src/bytecode/mod.rs @@ -2,6 +2,19 @@ //! //! https://craftinginterpreters.com/chunks-of-bytecode.html +mod chunk; +mod opcode; +mod value; + +use chunk::Chunk; +use opcode::OpCode; + pub fn main() { - unimplemented!() + let mut chunk: Chunk = Default::default(); + + let constant = chunk.add_constant(1.2); + chunk.add_op(OpCode::OpConstant(constant)); + chunk.add_op(OpCode::OpReturn); + + chunk::disassemble(&chunk, "test chunk"); } diff --git a/users/tazjin/rlox/src/bytecode/opcode.rs b/users/tazjin/rlox/src/bytecode/opcode.rs new file mode 100644 index 000000000000..f2b6a9f1baf3 --- /dev/null +++ b/users/tazjin/rlox/src/bytecode/opcode.rs @@ -0,0 +1,8 @@ +#[derive(Debug)] +pub enum OpCode { + /// Access a constant for use. + OpConstant(usize), + + /// Return from the current function. + OpReturn, +} diff --git a/users/tazjin/rlox/src/bytecode/value.rs b/users/tazjin/rlox/src/bytecode/value.rs new file mode 100644 index 000000000000..343d142ac830 --- /dev/null +++ b/users/tazjin/rlox/src/bytecode/value.rs @@ -0,0 +1 @@ +pub type Value = f64; -- cgit 1.4.1