Skip to content

Commit

Permalink
Adding the VirtualMachine
Browse files Browse the repository at this point in the history
Plus plenty of module changes
  • Loading branch information
patbuc committed Nov 10, 2023
1 parent ba518ae commit 9286324
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 97 deletions.
8 changes: 5 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use colored::Colorize;

use crate::vm::block::{Block, OpCode};

#[cfg(feature = "disassemble")]
use crate::vm::block::Disassembler;
use crate::vm::vm::VirtualMachine;

fn main() {
println!(
Expand All @@ -23,5 +22,8 @@ fn main() {
block.write_op_code(OpCode::Return, 6);

#[cfg(feature = "disassemble")]
block.disassemble_block();
block.disassemble();

let mut vm = VirtualMachine::new(block);
vm.interpret();
}
76 changes: 76 additions & 0 deletions src/vm/block/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#[cfg(feature = "disassemble")]
use crate::vm::block::disassembler::Disassembler;
use crate::vm::block::opcodes::OpCode;
use crate::vm::block::{Block, Constants};

impl Block {
pub fn new(name: &str) -> Self {
Block {
name: String::from(name),
constants: Constants::new(),
instructions: Vec::new(),
lines: Vec::new(),
}
}

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 write_constant(&mut self, value: f64, line: usize) {
let constant_index = self.constants.write_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(super) fn write_u8(&mut self, value: u8) {
self.instructions.push(value)
}
pub(super) fn write_u16(&mut self, value: u16) {
self.instructions.push((value) as u8);
self.instructions.push((value >> 8) as u8);
}
pub(super) 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);
}

pub fn read_constant(&mut self, index: usize) -> f64 {
self.constants.read_value(index)
}

pub fn read_u8(&self, offset: usize) -> u8 {
self.instructions[offset]
}

pub fn read_u16(&self, offset: usize) -> u16 {
let byte1 = self.instructions[offset] as u16;
let byte2 = self.instructions[offset + 1] as u16;
(byte2 << 8) | byte1
}

pub fn read_u32(&self, offset: usize) -> u32 {
let byte1 = self.instructions[offset] as u32;
let byte2 = self.instructions[offset + 1] as u32;
let byte3 = self.instructions[offset + 2] as u32;
let byte4 = self.instructions[offset + 3] as u32;
(byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1
}

#[cfg(feature = "disassemble")]
pub fn disassemble(&self) {
self.disassemble_block();
}
}
10 changes: 3 additions & 7 deletions src/vm/block/constants.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
type Value = f64;

pub(super) struct Constants {
values: Vec<Value>,
}
use crate::vm::block::{Constants, Value};

impl Constants {
pub fn new() -> Self {
Expand All @@ -20,8 +16,8 @@ impl Constants {
(self.values.len() - 1) as u32
}

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

Expand Down
16 changes: 8 additions & 8 deletions src/vm/block/disassemble.rs → src/vm/block/disassembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,18 @@ impl Disassembler for Block {
}

fn constant_instruction(&self, op_code: OpCode, offset: usize) -> usize {
fn get_constant_index(block: &Block, op_code: &OpCode, offset: usize) -> usize {
fn get_constant_index(block: &Block, op_code: &OpCode, offset: usize) -> (usize, usize) {
match op_code {
OpCode::Constant => block.read_u8(offset) as usize,
OpCode::Constant2 => block.read_u16(offset) as usize,
OpCode::Constant4 => block.read_u32(offset) as usize,
OpCode::Constant => (block.read_u8(offset) as usize, 1),
OpCode::Constant2 => (block.read_u16(offset) as usize, 2),
OpCode::Constant4 => (block.read_u32(offset) as usize, 4),
_ => panic!("Invalid OpCode"),
}
}

let constant_index = get_constant_index(self, &op_code, offset);
let constant = self.constants.read_value(constant_index as u32);
println!("{:?} {:02} '{}'", op_code, constant_index, constant);
offset + 2
let (index, offset_shift) = get_constant_index(self, &op_code, offset + 1);
let constant = self.constants.read_value(index);
println!("{:?} {:02} '{}'", op_code, index, constant);
offset + 1 + offset_shift
}
}
82 changes: 7 additions & 75 deletions src/vm/block/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
pub(self) mod block;
mod constants;
mod opcodes;

#[cfg(feature = "disassemble")]
mod disassemble;
#[cfg(feature = "disassemble")]
pub(crate) use crate::vm::block::disassemble::Disassembler;

use crate::vm::block::constants::Constants;
use enum_primitive_derive::Primitive;
mod disassembler;

#[repr(u8)]
#[derive(Debug, PartialEq, Primitive)]
pub enum OpCode {
Return = 0x00,
Constant = 0x01,
Constant2 = 0x02,
Constant4 = 0x03,
}
pub(crate) use crate::vm::block::opcodes::OpCode;

#[allow(dead_code)]
pub struct Block {
Expand All @@ -25,67 +15,9 @@ pub struct Block {
lines: Vec<usize>,
}

impl Block {
pub fn new(name: &str) -> Self {
Block {
name: String::from(name),
constants: Constants::new(),
instructions: Vec::new(),
lines: Vec::new(),
}
}

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 write_constant(&mut self, value: f64, line: usize) {
let constant_index = self.constants.write_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)
}
}

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);
}

pub fn read_u8(&self, offset: usize) -> u8 {
self.instructions[offset]
}

pub fn read_u16(&self, offset: usize) -> u16 {
let byte1 = self.instructions[offset] as u16;
let byte2 = self.instructions[offset + 1] as u16;
(byte2 << 8) | byte1
}

pub fn read_u32(&self, offset: usize) -> u32 {
let byte1 = self.instructions[offset] as u32;
let byte2 = self.instructions[offset + 1] as u32;
let byte3 = self.instructions[offset + 2] as u32;
let byte4 = self.instructions[offset + 3] as u32;
(byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1
}
type Value = f64;
pub struct Constants {
values: Vec<Value>,
}

#[cfg(test)]
Expand Down
10 changes: 10 additions & 0 deletions src/vm/block/opcodes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use enum_primitive_derive::Primitive;

#[repr(u8)]
#[derive(Debug, PartialEq, Primitive)]
pub enum OpCode {
Return = 0x00,
Constant = 0x01,
Constant2 = 0x02,
Constant4 = 0x03,
}
7 changes: 4 additions & 3 deletions src/vm/block/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::vm::block::{Block, OpCode};
use crate::vm::block::opcodes::OpCode;
use crate::vm::block::Block;
use num_traits::FromPrimitive;

#[test]
Expand Down Expand Up @@ -38,9 +39,9 @@ fn can_write_more_then_256_constants() {
OpCode::Constant2,
OpCode::from_u8(block.instructions[2 * 256 + 3]).unwrap()
);
let constant_index = block.read_u16(2 * 256 + 4);
let constant_index = block.read_u16(2 * 256 + 4) as usize;
assert_eq!(257, constant_index);
assert_eq!(257f64, block.constants.read_value(constant_index as u32));
assert_eq!(257f64, block.constants.read_value(constant_index));
}

#[test]
Expand Down
3 changes: 2 additions & 1 deletion src/vm/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub(super) mod block;
pub mod block;
pub mod vm;
50 changes: 50 additions & 0 deletions src/vm/vm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::vm::block::{Block, OpCode};
use num_traits::FromPrimitive;

pub struct VirtualMachine {
block: Block,
ip: usize,
}

pub enum Result {
Ok,
// CompileError,
// RuntimeError,
}

impl VirtualMachine {
pub fn new(block: Block) -> Self {
VirtualMachine { block, ip: 0 }
}
pub fn interpret(&mut self) -> Result {
return self.run();
}

#[inline(always)]
fn run(&mut self) -> Result {
loop {
match OpCode::from_u8(self.block.read_u8(self.ip)).unwrap() {
OpCode::Return => return Result::Ok,
OpCode::Constant => {
let constant_index = self.block.read_u8(self.ip + 1) as usize;
let constant = self.block.read_constant(constant_index);
println!("{}", constant);
self.ip += 1;
}
OpCode::Constant2 => {
let constant_index = self.block.read_u16(self.ip + 1) as usize;
let constant = self.block.read_constant(constant_index);
println!("{}", constant);
self.ip += 2;
}
OpCode::Constant4 => {
let constant_index = self.block.read_u32(self.ip + 1) as usize;
let constant = self.block.read_constant(constant_index);
println!("{}", constant);
self.ip += 4;
}
}
self.ip += 1;
}
}
}

0 comments on commit 9286324

Please sign in to comment.