Skip to content

Commit

Permalink
Added support for up to 2^32 constants
Browse files Browse the repository at this point in the history
Also simplified writing constants to a block
  • Loading branch information
patbuc committed Nov 5, 2023
1 parent df7b906 commit 945721f
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 21 deletions.
11 changes: 3 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@ fn main() {

let mut block = Block::new("ZeBlock");

let constant_index = block.push_constant(1234.56, 2);
block.push_op_code(OpCode::Constant, 2);
block.write_byte(constant_index);
block.write_constant(1234.56, 2);
block.write_constant(789.10, 4);

let constant_index = block.push_constant(789.10, 4);
block.push_op_code(OpCode::Constant, 4);
block.write_byte(constant_index);

block.push_op_code(OpCode::Return, 4);
block.write_op_code(OpCode::Return, 4);

#[cfg(feature = "disassemble")]
block.disassemble_block();
Expand Down
76 changes: 65 additions & 11 deletions src/vm/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ use enum_primitive_derive::Primitive;
use num_traits::FromPrimitive;

#[repr(u8)]
#[derive(Debug, Primitive)]
#[derive(Debug, PartialEq, Primitive)]
pub enum OpCode {
Constant = 0x00,
Return = 0x01,
Return = 0x00,
Constant = 0x01,
Constant2 = 0x02,
Constant4 = 0x03,
}

#[allow(dead_code)]
Expand All @@ -28,18 +30,38 @@ impl Block {
}
}

pub fn push_op_code(&mut self, op_code: OpCode, line: usize) {
pub fn write_op_code(&mut self, op_code: OpCode, line: usize) {
self.lines.push(line);
self.instructions.push(op_code as u8)
}

pub fn push_constant(&mut self, value: f64, line: usize) -> i8 {
self.lines.push(line);
self.constants.push_value(value)
pub fn write_constant(&mut self, value: f64, line: usize) {
let constant_index = self.constants.push_value(value);

if constant_index <= 0xFF {
self.write_op_code(OpCode::Constant, line);
self.write_u8(constant_index as u8)
} else if constant_index <= 0xFFFF {
self.write_op_code(OpCode::Constant2, line);
self.write_u16(constant_index as u16)
} else {
self.write_op_code(OpCode::Constant4, line);
self.write_u32(constant_index)
}
}

pub(crate) fn write_byte(&mut self, byte: i8) {
self.instructions.push(byte as u8)
fn write_u8(&mut self, value: u8) {
self.instructions.push(value)
}
fn write_u16(&mut self, value: u16) {
self.instructions.push((value) as u8);
self.instructions.push((value >> 8) as u8);
}
fn write_u32(&mut self, value: u32) {
self.instructions.push((value) as u8);
self.instructions.push((value >> 8) as u8);
self.instructions.push((value >> 16) as u8);
self.instructions.push((value >> 24) as u8);
}
}

Expand Down Expand Up @@ -76,8 +98,10 @@ impl BlockDbg for Block {

let instruction = OpCode::from_u8(self.instructions[offset]).unwrap();
return match instruction {
OpCode::Constant => self.constant_instruction(OpCode::Constant, offset),
OpCode::Return => self.simple_instruction(OpCode::Return, offset),
OpCode::Constant => self.constant_instruction(instruction, offset),
OpCode::Constant2 => self.constant_instruction(instruction, offset),
OpCode::Constant4 => self.constant_instruction(instruction, offset),
};
}

Expand Down Expand Up @@ -110,9 +134,39 @@ mod tests {
#[test]
fn op_code_can_be_pushed_to_an_block() {
let mut block = Block::new("jenny");
block.push_op_code(OpCode::Return, 123);
block.write_op_code(OpCode::Return, 123);

assert_eq!(1, block.instructions.len());
assert_eq!(OpCode::Return as u8, block.instructions[0]);
}

#[test]
fn can_write_more_then_256_constants() {
let mut block = Block::new("maggie");
for i in 0..258 {
block.write_constant(i as f64, i);
}

assert_eq!(2 * 256 + 6, block.instructions.len());
assert_eq!(
OpCode::Constant2,
OpCode::from_u8(block.instructions[2 * 256]).unwrap()
);

let byte1 = block.instructions[2 * 256 + 1] as u16;
let byte2 = block.instructions[2 * 256 + 2] as u16;
let constant_index: u16 = (byte2 << 8) | byte1;
assert_eq!(256, constant_index);

assert_eq!(
OpCode::Constant2,
OpCode::from_u8(block.instructions[2 * 256 + 3]).unwrap()
);
let byte1 = block.instructions[2 * 256 + 4] as u16;
let byte2 = block.instructions[2 * 256 + 5] as u16;
let constant_index: u16 = (byte2 << 8) | byte1;
assert_eq!(257, constant_index);

assert_eq!(257f64, block.constants.get_value(constant_index as u32));
}
}
8 changes: 6 additions & 2 deletions src/vm/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ impl Constants {
Constants { values: Vec::new() }
}

pub fn push_value(&mut self, value: Value) -> i8 {
pub fn push_value(&mut self, value: Value) -> u32 {
self.values.push(value);
self.values.len() as i8 - 1
(self.values.len() - 1) as u32
}

pub fn get_value(&self, index: u32) -> Value {
self.values[index as usize]
}
}

Expand Down

0 comments on commit 945721f

Please sign in to comment.