From 653dedcba93698ed471769f784808b473de474d0 Mon Sep 17 00:00:00 2001 From: Patric Bucher Date: Fri, 12 Jul 2024 12:26:36 +0100 Subject: [PATCH] Adding support for strings --- src/compiler/parser/mod.rs | 13 ++++++++++++- src/compiler/parser/rules.rs | 2 +- src/vm/block/block.rs | 12 ++++++++++++ src/vm/mod.rs | 1 + src/vm/opcodes.rs | 1 + src/vm/virtual_machine.rs | 17 ++++++++++++++++- 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/compiler/parser/mod.rs b/src/compiler/parser/mod.rs index e98b938..dd8185a 100644 --- a/src/compiler/parser/mod.rs +++ b/src/compiler/parser/mod.rs @@ -6,7 +6,7 @@ use crate::vm::{Block, Value}; use rules::{ParseRule, Precedence}; use std::str::FromStr; -use crate::number; +use crate::{number, string}; #[cfg(feature = "disassemble")] use tracing_attributes::instrument; @@ -68,6 +68,12 @@ impl Parser { self.emit_constant(number!(value)); } + #[cfg_attr(feature = "disassemble", instrument(skip(self)))] + fn string(&mut self) { + let value = &*self.previous_token.token; + self.emit_string(string!(value.to_string())); + } + #[cfg_attr(feature = "disassemble", instrument(skip(self)))] fn grouping(&mut self) { self.expression(); @@ -184,6 +190,11 @@ impl Parser { self.current_block().write_constant(value, line) } + fn emit_string(&mut self, value: Value) { + let line = self.previous_token.line; + self.current_block().write_string(value, line) + } + fn emit_op_code(&mut self, op_code: OpCode) { let line = self.previous_token.line; self.current_block().write_op_code(op_code, line); diff --git a/src/compiler/parser/rules.rs b/src/compiler/parser/rules.rs index 809cdf8..136bff3 100644 --- a/src/compiler/parser/rules.rs +++ b/src/compiler/parser/rules.rs @@ -67,7 +67,7 @@ lazy_static! { (TokenType::Less, ParseRule::new(None, Some(Parser::binary), Precedence::Comparison)), (TokenType::LessEqual, ParseRule::new(None, Some(Parser::binary), Precedence::Comparison)), (TokenType::Identifier, ParseRule::new(None, None, Precedence::None)), - (TokenType::String, ParseRule::new(None, None, Precedence::None)), + (TokenType::String, ParseRule::new(Some(Parser::string), None, Precedence::None)), (TokenType::InterpolatedString, ParseRule::new(None, None, Precedence::None)), (TokenType::Number, ParseRule::new(Some(Parser::number), None, Precedence::None)), (TokenType::And, ParseRule::new(None, None, Precedence::None)), diff --git a/src/vm/block/block.rs b/src/vm/block/block.rs index 2639a3d..8eb2e56 100644 --- a/src/vm/block/block.rs +++ b/src/vm/block/block.rs @@ -6,6 +6,7 @@ impl Block { Block { name: String::from(name), constants: Constants::new(), + strings: Constants::new(), instructions: Vec::new(), lines: Vec::new(), } @@ -32,6 +33,12 @@ impl Block { } } + pub(crate) fn write_string(&mut self, value: Value, line: u32) { + let string_index = self.strings.write_value(value) as u8; + self.write_op_code(OpCode::String, line); + self.write_u8(string_index) + } + pub(crate) fn write_u8(&mut self, value: u8) { self.instructions.push(value) } @@ -51,6 +58,11 @@ impl Block { self.constants.read_value(index) } + #[inline(always)] + pub(in crate::vm) fn read_string(&self, index: usize) -> Value { + self.strings.read_value(index) + } + #[inline(always)] pub(in crate::vm) fn read_u8(&self, offset: usize) -> u8 { self.instructions[offset] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index beaf7d2..76f97e7 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -34,6 +34,7 @@ pub struct VirtualMachine { pub(crate) struct Block { name: String, constants: Constants, + strings: Constants, instructions: Vec, lines: Vec, } diff --git a/src/vm/opcodes.rs b/src/vm/opcodes.rs index 8ff622c..b4b15d4 100644 --- a/src/vm/opcodes.rs +++ b/src/vm/opcodes.rs @@ -19,6 +19,7 @@ pub(crate) enum OpCode { Greater = 0x0D, Less = 0x0E, Not = 0x0F, + String = 0x10, } impl OpCode { diff --git a/src/vm/virtual_machine.rs b/src/vm/virtual_machine.rs index f2b8d18..80408fd 100644 --- a/src/vm/virtual_machine.rs +++ b/src/vm/virtual_machine.rs @@ -77,7 +77,16 @@ impl VirtualMachine { OpCode::Add => { let b = self.pop(); let a = self.pop(); - self.push(Value::Number(as_number!(a) + as_number!(b))); + match (a, b) { + (Value::Number(a), Value::Number(b)) => self.push(Value::Number(a + b)), + (Value::String(a), Value::String(b)) => { + self.push(Value::String(format!("{a}{b}"))) + } + _ => { + self.runtime_error("Operands must be two numbers or two strings"); + return Result::RuntimeError; + } + } } OpCode::Subtract => { let b = self.pop(); @@ -122,6 +131,12 @@ impl VirtualMachine { let value = self.pop(); self.push(boolean!(is_falsey!(value))); } + OpCode::String => { + let string_index = block.read_u8(self.ip + 1) as usize; + let string = block.read_string(string_index); + self.push(string); + self.ip += 1; + } } self.ip += 1; }