Skip to content

Commit

Permalink
Added value support for booleans and nil
Browse files Browse the repository at this point in the history
  • Loading branch information
patbuc committed Nov 27, 2023
1 parent 5e85cf7 commit 0f58a3c
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 56 deletions.
37 changes: 22 additions & 15 deletions src/compiler/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::compiler::{Parser, Scanner, Token};
use crate::vm::opcodes::OpCode;
use crate::vm::{Block, Value};
use rules::{ParseRule, Precedence};
use std::str::FromStr;
use tracing_attributes::instrument;

mod rules;
Expand Down Expand Up @@ -60,8 +61,8 @@ impl Parser {

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
fn number(&mut self) {
let value = self.previous_token.token.parse::<f64>().unwrap();
self.emit_constant(value);
let value = f64::from_str(&*self.previous_token.token).unwrap();
self.emit_constant(Value::from_number(value));
}

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
Expand All @@ -77,10 +78,19 @@ impl Parser {
self.parse_precedence(Precedence::from_u8(rule.precedence as u8 + 1));

match operator_type {
token_type if token_type == TokenType::Plus => self.emit_byte(OpCode::Add as u8),
token_type if token_type == TokenType::Minus => self.emit_byte(OpCode::Subtract as u8),
token_type if token_type == TokenType::Star => self.emit_byte(OpCode::Multiply as u8),
token_type if token_type == TokenType::Slash => self.emit_byte(OpCode::Divide as u8),
token_type if token_type == TokenType::Plus => self.emit_op_code(OpCode::Add),
token_type if token_type == TokenType::Minus => self.emit_op_code(OpCode::Subtract),
token_type if token_type == TokenType::Star => self.emit_op_code(OpCode::Multiply),
token_type if token_type == TokenType::Slash => self.emit_op_code(OpCode::Divide),
_ => return, // Unreachable.
}
}

fn literal(&mut self) {
match self.previous_token.token_type {
TokenType::False => self.emit_op_code(OpCode::False),
TokenType::Nil => self.emit_op_code(OpCode::Nil),
TokenType::True => self.emit_op_code(OpCode::True),
_ => return, // Unreachable.
}
}
Expand All @@ -94,7 +104,7 @@ impl Parser {

// Emit the operator instruction.
match operator_type {
TokenType::Minus => self.emit_byte(OpCode::Negate as u8),
TokenType::Minus => self.emit_op_code(OpCode::Negate),
_ => return, // Unreachable.
}
}
Expand All @@ -120,6 +130,7 @@ impl Parser {
if self.panic_mode {
return;
}

self.had_error = true;
self.panic_mode = true;

Expand Down Expand Up @@ -149,19 +160,15 @@ impl Parser {
}

fn emit_return(&mut self) {
self.emit_byte(OpCode::Return as u8);
self.emit_op_code(OpCode::Return);
}

fn emit_constant(&mut self, value: Value) {
self.current_block().write_constant(value, 0)
}

fn emit_byte(&mut self, byte: u8) {
self.current_block().write_u8(byte);
}

fn emit_bytes(&mut self, byte1: u8, byte2: u8) {
self.current_block().write_u8(byte1);
self.current_block().write_u8(byte2);
fn emit_op_code(&mut self, op_code: OpCode) {
let line = self.previous_token.line;
self.current_block().write_op_code(op_code, line);
}
}
6 changes: 3 additions & 3 deletions src/compiler/parser/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,17 @@ lazy_static! {
(TokenType::And, ParseRule::new(None, None, Precedence::None)),
(TokenType::Class, ParseRule::new(None, None, Precedence::None)),
(TokenType::Else, ParseRule::new(None, None, Precedence::None)),
(TokenType::False, ParseRule::new(None, None, Precedence::None)),
(TokenType::False, ParseRule::new(Some(Parser::literal), None, Precedence::None)),
(TokenType::For, ParseRule::new(None, None, Precedence::None)),
(TokenType::Fun, ParseRule::new(None, None, Precedence::None)),
(TokenType::If, ParseRule::new(None, None, Precedence::None)),
(TokenType::Nil, ParseRule::new(None, None, Precedence::None)),
(TokenType::Nil, ParseRule::new(Some(Parser::literal), None, Precedence::None)),
(TokenType::Or, ParseRule::new(None, None, Precedence::None)),
(TokenType::Print, ParseRule::new(None, None, Precedence::None)),
(TokenType::Return, ParseRule::new(None, None, Precedence::None)),
(TokenType::Super, ParseRule::new(None, None, Precedence::None)),
(TokenType::This, ParseRule::new(None, None, Precedence::None)),
(TokenType::True, ParseRule::new(None, None, Precedence::None)),
(TokenType::True, ParseRule::new(Some(Parser::literal), None, Precedence::None)),
(TokenType::Var, ParseRule::new(None, None, Precedence::None)),
(TokenType::While, ParseRule::new(None, None, Precedence::None)),
(TokenType::Error, ParseRule::new(None, None, Precedence::None)),
Expand Down
38 changes: 21 additions & 17 deletions src/vm/block/block.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::vm::opcodes::OpCode;
use crate::vm::{Block, Constants, Line};
use crate::vm::{Block, Constants, Line, Value};

impl Block {
pub(crate) fn new(name: &str) -> Self {
Expand All @@ -13,21 +13,20 @@ impl Block {

pub(crate) fn new_no_opt() -> Self {
let mut block = Block::new("NO OPT BLOCK");
block.write_constant(0.0, 0);
block.write_constant(Value::from_number(0.0), 0);
block.write_op_code(OpCode::Return, 0);
block
}
}

impl Block {
pub(crate) fn write_op_code(&mut self, op_code: OpCode, line: usize) {
pub(crate) fn write_op_code(&mut self, op_code: OpCode, line: u32) {
self.add_line(self.instructions.len(), line);
self.instructions.push(op_code as u8)
}

pub(crate) fn write_constant(&mut self, value: f64, line: usize) {
pub(crate) fn write_constant(&mut self, value: Value, line: u32) {
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)
Expand Down Expand Up @@ -55,7 +54,7 @@ impl Block {
}

#[inline(always)]
pub(in crate::vm) fn read_constant(&mut self, index: usize) -> f64 {
pub(in crate::vm) fn read_constant(&mut self, index: usize) -> Value {
self.constants.read_value(index)
}

Expand All @@ -82,11 +81,11 @@ impl Block {
}

impl Block {
fn add_line(&mut self, offset: usize, line: usize) {
fn add_line(&mut self, offset: usize, line: u32) {
self.lines.push(Line { offset, line });
}

pub(in crate::vm) fn get_line(&self, offset: usize) -> Option<usize> {
pub(in crate::vm) fn get_line(&self, offset: usize) -> Option<u32> {
let mut result = 0;
let mut low = 0;
let mut high = self.lines.len() - 1;
Expand All @@ -112,7 +111,7 @@ impl Block {
#[cfg(test)]
mod tests {
use crate::vm::opcodes::OpCode;
use crate::vm::Block;
use crate::vm::{Block, Value};

#[test]
fn new_block_is_empty() {
Expand All @@ -136,7 +135,7 @@ mod tests {
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);
block.write_constant(Value::from_number(i as f64), i);
}

assert_eq!(2 * 256 + 6, block.instructions.len());
Expand All @@ -152,7 +151,12 @@ mod tests {
);
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));
unsafe {
assert_eq!(
257f64,
block.constants.read_value(constant_index).value.number
);
}
}

#[test]
Expand Down Expand Up @@ -180,11 +184,11 @@ mod tests {
fn can_write_block() {
let mut block = Block::new("ZeBlock");

block.write_constant(1234.56, 2);
block.write_constant(Value::from_number(1234.56), 2);
block.write_op_code(OpCode::Negate, 3);
block.write_constant(345.67, 4);
block.write_constant(Value::from_number(345.67), 4);
block.write_op_code(OpCode::Add, 4);
block.write_constant(1.2, 5);
block.write_constant(Value::from_number(1.2), 5);
block.write_op_code(OpCode::Multiply, 6);
block.write_op_code(OpCode::Return, 8);
}
Expand All @@ -193,11 +197,11 @@ mod tests {
fn can_read_line_information() {
let mut block = Block::new("ZeBlock");

block.write_constant(1234.56, 2);
block.write_constant(Value::from_number(1234.56), 2);
block.write_op_code(OpCode::Negate, 3);
block.write_constant(345.67, 4);
block.write_constant(Value::from_number(345.67), 4);
block.write_op_code(OpCode::Add, 4);
block.write_constant(1.2, 5);
block.write_constant(Value::from_number(1.2), 5);
block.write_op_code(OpCode::Multiply, 6);
block.write_op_code(OpCode::Return, 8);

Expand Down
12 changes: 8 additions & 4 deletions src/vm/block/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,22 @@ mod tests {
#[test]
fn value_can_be_written_to_constants() {
let mut constants = Constants::new();
constants.write_value(123.45);
constants.write_value(Value::from_number(123.45));

assert_eq!(1, constants.len());
assert_eq!(123.45, constants.read_value(0));
unsafe {
assert_eq!(123.45, constants.read_value(0).value.number);
}
}

#[test]
fn value_can_be_read_to_constants() {
let mut constants = Constants::new();
constants.write_value(123.45);
constants.write_value(Value::from_number(123.45));

assert_eq!(1, constants.len());
assert_eq!(123.45, constants.read_value(0));
unsafe {
assert_eq!(123.45, constants.read_value(0).value.number);
}
}
}
7 changes: 6 additions & 1 deletion src/vm/block/disassembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ impl Block {
OpCode::Subtract => self.simple_instruction(OpCode::Subtract, offset),
OpCode::Multiply => self.simple_instruction(OpCode::Multiply, offset),
OpCode::Divide => self.simple_instruction(OpCode::Divide, offset),
OpCode::Nil => self.simple_instruction(OpCode::Nil, offset),
OpCode::True => self.simple_instruction(OpCode::True, offset),
OpCode::False => self.simple_instruction(OpCode::False, offset),
};
}

Expand All @@ -57,7 +60,9 @@ impl Block {

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);
unsafe {
println!("{:?} {:02} '{}'", op_code, index, constant.value.number);
}
offset + 1 + offset_shift
}
}
35 changes: 33 additions & 2 deletions src/vm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
use std::fmt::{Debug, Formatter};

mod block;
pub(crate) mod opcodes;
mod value;
mod virtual_machine;

pub type Value = f64;
// pub type Value = f64;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ValueType {
Number,
Bool,
String,
Nil,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub union ValueUnion {
number: f64,
boolean: bool,
string: *const String,
}

impl Debug for ValueUnion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "ValueUnion")
}
}

#[derive(Debug, Copy, Clone)]
pub struct Value {
pub value_type: ValueType,
pub value: ValueUnion,
}

#[derive(Debug, PartialEq)]
pub enum Result {
Expand Down Expand Up @@ -31,6 +62,6 @@ struct Constants {

#[derive(Debug)]
struct Line {
pub line: usize,
pub offset: usize,
pub line: u32,
}
3 changes: 3 additions & 0 deletions src/vm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub(crate) enum OpCode {
Subtract = 0x06,
Multiply = 0x07,
Divide = 0x08,
Nil = 0x09,
True = 0x0A,
False = 0x0B,
}

impl OpCode {
Expand Down
31 changes: 31 additions & 0 deletions src/vm/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::vm::{Value, ValueType, ValueUnion};

impl Value {
pub fn from_number(value: f64) -> Self {
Value {
value_type: ValueType::Number,
value: ValueUnion { number: value },
}
}

pub fn from_bool(value: bool) -> Self {
Value {
value_type: ValueType::Bool,
value: ValueUnion { boolean: value },
}
}

pub fn from_string(value: *const String) -> Self {
Value {
value_type: ValueType::Bool,
value: ValueUnion { string: value },
}
}

pub fn nil() -> Value {
Value {
value_type: ValueType::Nil,
value: ValueUnion { number: 0.0 },
}
}
}
Loading

0 comments on commit 0f58a3c

Please sign in to comment.