diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index e1a3c11..c5c5ca2 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -102,9 +102,37 @@ pub struct Compiler<'src> { /// [`Compiler::finish`] is called. stack_size: usize, - /// The first register index that the compiler should use. This is used to avoid reusing the - /// registers that are used for the function's arguments. - minimum_register: u16, + /// The first boolean register index that the compiler should use. This is used to avoid reusing + /// the registers that are used for the function's arguments. + minimum_boolean_register: u16, + + /// The first byte register index that the compiler should use. This is used to avoid reusing + /// the registers that are used for the function's arguments. + minimum_byte_register: u16, + + /// The first character register index that the compiler should use. This is used to avoid + /// reusing the registers that are used for the function's arguments. + minimum_character_register: u16, + + /// The first float register index that the compiler should use. This is used to avoid reusing + /// the registers that are used for the function's arguments. + minimum_float_register: u16, + + /// The first integer register index that the compiler should use. This is used to avoid reusing + /// the registers that are used for the function's arguments. + minimum_integer_register: u16, + + /// The first string register index that the compiler should use. This is used to avoid reusing + /// the registers that are used for the function's arguments. + minimum_string_register: u16, + + /// The first list register index that the compiler should use. This is used to avoid reusing + /// the registers that are used for the function's arguments. + minimum_list_register: u16, + + /// The first function register index that the compiler should use. This is used to avoid + /// reusing the registers that are used for the function's arguments. + minimum_function_register: u16, /// Index of the current block. This is used to determine the scope of locals and is incremented /// when a new block is entered. @@ -149,7 +177,14 @@ impl<'src> Compiler<'src> { prototypes: Vec::new(), stack_size: 0, lexer, - minimum_register: 0, + minimum_byte_register: 0, + minimum_boolean_register: 0, + minimum_character_register: 0, + minimum_float_register: 0, + minimum_integer_register: 0, + minimum_string_register: 0, + minimum_list_register: 0, + minimum_function_register: 0, block_index: 0, current_scope: Scope::default(), prototype_index: 0, @@ -215,7 +250,7 @@ impl<'src> Compiler<'src> { r#type: self.r#type, instructions, positions, - constants: self.constants.to_vec(), + constants: self.constants, locals, prototypes: self.prototypes, register_count: self.stack_size, @@ -227,18 +262,118 @@ impl<'src> Compiler<'src> { matches!(self.current_token, Token::Eof) } - fn next_register(&self) -> u16 { + fn next_boolean_register(&self) -> u16 { self.instructions .iter() .rev() - .find_map(|(instruction, _, _)| { - if instruction.yields_value() { + .find_map(|(instruction, r#type, _)| { + if r#type == &Type::Boolean && instruction.yields_value() { Some(instruction.a_field() + 1) } else { None } }) - .unwrap_or(self.minimum_register) + .unwrap_or(self.minimum_boolean_register) + } + + fn next_byte_register(&self) -> u16 { + self.instructions + .iter() + .rev() + .find_map(|(instruction, r#type, _)| { + if r#type == &Type::Byte && instruction.yields_value() { + Some(instruction.a_field() + 1) + } else { + None + } + }) + .unwrap_or(self.minimum_byte_register) + } + + fn next_character_register(&self) -> u16 { + self.instructions + .iter() + .rev() + .find_map(|(instruction, r#type, _)| { + if r#type == &Type::Character && instruction.yields_value() { + Some(instruction.a_field() + 1) + } else { + None + } + }) + .unwrap_or(self.minimum_character_register) + } + + fn next_float_register(&self) -> u16 { + self.instructions + .iter() + .rev() + .find_map(|(instruction, r#type, _)| { + if r#type == &Type::Float && instruction.yields_value() { + Some(instruction.a_field() + 1) + } else { + None + } + }) + .unwrap_or(self.minimum_float_register) + } + + fn next_integer_register(&self) -> u16 { + self.instructions + .iter() + .rev() + .find_map(|(instruction, r#type, _)| { + if r#type == &Type::Integer && instruction.yields_value() { + Some(instruction.a_field() + 1) + } else { + None + } + }) + .unwrap_or(self.minimum_integer_register) + } + + fn next_string_register(&self) -> u16 { + self.instructions + .iter() + .rev() + .find_map(|(instruction, r#type, _)| { + if r#type == &Type::String && instruction.yields_value() { + Some(instruction.a_field() + 1) + } else { + None + } + }) + .unwrap_or(self.minimum_string_register) + } + + fn next_list_register(&self) -> u16 { + self.instructions + .iter() + .rev() + .find_map(|(instruction, r#type, _)| { + if let Type::List(_) = r#type { + Some(instruction.a_field() + 1) + } else { + None + } + }) + .unwrap_or(self.minimum_list_register) + } + + fn next_function_register(&self) -> u16 { + self.instructions + .iter() + .rev() + .find_map(|(instruction, r#type, _)| { + if matches!(r#type, Type::Function(_) | Type::SelfFunction) + && instruction.yields_value() + { + Some(instruction.a_field() + 1) + } else { + None + } + }) + .unwrap_or(self.minimum_function_register) } fn advance(&mut self) -> Result<(), CompileError> { @@ -473,7 +608,13 @@ impl<'src> Compiler<'src> { ) -> Result<(), CompileError> { let r#type = constant.r#type(); let constant_index = self.push_or_get_constant(Value::Concrete(constant)); - let destination = self.next_register(); + let destination = match r#type { + Type::Character => self.next_character_register(), + Type::Float => self.next_float_register(), + Type::Integer => self.next_integer_register(), + Type::String => self.next_string_register(), + _ => todo!(), + }; let load_constant = Instruction::load_constant(destination, constant_index, false); self.emit_instruction(load_constant, r#type, position); @@ -488,7 +629,7 @@ impl<'src> Compiler<'src> { self.advance()?; let boolean = text.parse::().unwrap(); - let destination = self.next_register(); + let destination = self.next_boolean_register(); let load_boolean = Instruction::load_boolean(destination, boolean, false); self.emit_instruction(load_boolean, Type::Boolean, position); @@ -650,14 +791,10 @@ impl<'src> Compiler<'src> { )) } - let destination = self.next_register(); - let type_code = match previous_type { - Type::Boolean => TypeCode::BOOLEAN, - Type::Byte => TypeCode::BYTE, - Type::Character => TypeCode::CHARACTER, - Type::Float => TypeCode::FLOAT, - Type::Integer => TypeCode::INTEGER, - Type::String => TypeCode::STRING, + let (type_code, destination) = match previous_type { + Type::Boolean => (TypeCode::BOOLEAN, self.next_boolean_register()), + Type::Float => (TypeCode::FLOAT, self.next_float_register()), + Type::Integer => (TypeCode::INTEGER, self.next_integer_register()), _ => match operator { Token::Minus => { return Err(CompileError::CannotNegateType { @@ -774,13 +911,13 @@ impl<'src> Compiler<'src> { check_math_type(&left_type, operator, &left_position)?; - let left_type_code = match left_type { - Type::Boolean => TypeCode::BOOLEAN, - Type::Byte => TypeCode::BYTE, - Type::Character => TypeCode::CHARACTER, - Type::Float => TypeCode::FLOAT, - Type::Integer => TypeCode::INTEGER, - Type::String => TypeCode::STRING, + let (left_type_code, destination) = match left_type { + Type::Boolean => (TypeCode::BOOLEAN, self.next_boolean_register()), + Type::Byte => (TypeCode::BYTE, self.next_byte_register()), + Type::Character => (TypeCode::CHARACTER, self.next_character_register()), + Type::Float => (TypeCode::FLOAT, self.next_float_register()), + Type::Integer => (TypeCode::INTEGER, self.next_integer_register()), + Type::String => (TypeCode::STRING, self.next_string_register()), _ => unreachable!(), }; @@ -828,14 +965,6 @@ impl<'src> Compiler<'src> { } else { left_type.clone() }; - let destination = if is_assignment { - match left { - Operand::Register(register) => register, - Operand::Constant(_) => self.next_register(), - } - } else { - self.next_register() - }; let instruction = match operator { Token::Plus | Token::PlusEqual => { Instruction::add(destination, left, left_type_code, right, right_type_code) @@ -950,7 +1079,7 @@ impl<'src> Compiler<'src> { .push((right_instruction, right_type, right_position)); } - let destination = self.next_register(); + let destination = self.next_boolean_register(); let comparison = match operator { Token::DoubleEqual => { Instruction::equal(true, left, left_type_code, right, right_type_code) @@ -1016,10 +1145,20 @@ impl<'src> Compiler<'src> { register } else { + let register = match last_type { + Type::Boolean => self.next_boolean_register() - 1, + Type::Byte => self.next_byte_register() - 1, + Type::Character => self.next_character_register() - 1, + Type::Float => self.next_float_register() - 1, + Type::Integer => self.next_integer_register() - 1, + Type::String => self.next_string_register() - 1, + _ => todo!(), + }; + self.instructions .push((last_instruction, last_type, last_position)); - self.next_register().saturating_sub(1) + register }; let operator = self.current_token; let operator_position = self.current_position; @@ -1086,7 +1225,7 @@ impl<'src> Compiler<'src> { } else if let Some(native_function) = NativeFunction::from_str(identifier) { return self.parse_call_native(native_function); } else if self.function_name.as_deref() == Some(identifier) && !self.is_main { - let destination = self.next_register(); + let destination = self.next_function_register(); let load_self = Instruction::load_self(destination, false); self.emit_instruction(load_self, Type::SelfFunction, start_position); @@ -1133,7 +1272,15 @@ impl<'src> Compiler<'src> { math_instruction.set_a_field(local_register_index); } else { - let register = self.next_register() - 1; + let register = match r#type { + Type::Boolean => self.next_boolean_register(), + Type::Byte => self.next_byte_register(), + Type::Character => self.next_character_register(), + Type::Float => self.next_float_register(), + Type::Integer => self.next_integer_register(), + Type::String => self.next_string_register(), + _ => todo!(), + }; let point = Instruction::point(local_register_index, Operand::Register(register)); self.emit_instruction(point, r#type, start_position); @@ -1142,7 +1289,15 @@ impl<'src> Compiler<'src> { return Ok(()); } - let destination = self.next_register(); + let destination = match r#type { + Type::Boolean => self.next_boolean_register(), + Type::Byte => self.next_byte_register(), + Type::Character => self.next_character_register(), + Type::Float => self.next_float_register(), + Type::Integer => self.next_integer_register(), + Type::String => self.next_string_register(), + _ => todo!(), + }; let point = Instruction::point(destination, Operand::Register(local_register_index)); self.emit_instruction(point, r#type, self.previous_position); @@ -1191,33 +1346,27 @@ impl<'src> Compiler<'src> { self.advance()?; - let start_register = self.next_register(); - let mut item_type = Type::Any; + let mut item_type = Type::None; + let mut start_register = 0; while !self.allow(Token::RightBracket)? && !self.is_eof() { - let expected_register = self.next_register(); - self.parse_expression()?; - let actual_register = self.next_register() - 1; - - if item_type == Type::Any { - item_type = self.get_last_instruction_type(); - } - - if expected_register < actual_register { - let close = Instruction::from(Close { - from: expected_register, - to: actual_register, - }); - - self.emit_instruction(close, Type::None, self.current_position); - } + item_type = self.get_last_instruction_type(); + start_register = match item_type { + Type::Boolean => self.next_boolean_register() - 1, + Type::Byte => self.next_byte_register() - 1, + Type::Character => self.next_character_register() - 1, + Type::Float => self.next_float_register() - 1, + Type::Integer => self.next_integer_register() - 1, + Type::String => self.next_string_register() - 1, + _ => todo!(), + }; self.allow(Token::Comma)?; } - let destination = self.next_register(); + let destination = self.next_list_register(); let end = self.previous_position.1; let load_list = Instruction::load_list(destination, start_register, false); @@ -1243,7 +1392,15 @@ impl<'src> Compiler<'src> { self.instructions.pop(); self.instructions.pop(); } else { - let operand_register = self.next_register() - 1; + let operand_register = match self.get_last_instruction_type() { + Type::Boolean => self.next_boolean_register() - 1, + Type::Byte => self.next_byte_register() - 1, + Type::Character => self.next_character_register() - 1, + Type::Float => self.next_float_register() - 1, + Type::Integer => self.next_integer_register() - 1, + Type::String => self.next_string_register() - 1, + _ => todo!(), + }; let test = Instruction::test(operand_register, true); self.emit_instruction(test, Type::None, self.current_position); @@ -1356,7 +1513,15 @@ impl<'src> Compiler<'src> { self.instructions.pop(); self.instructions.pop(); } else { - let operand_register = self.next_register() - 1; + let operand_register = match self.get_last_instruction_type() { + Type::Boolean => self.next_boolean_register() - 1, + Type::Byte => self.next_byte_register() - 1, + Type::Character => self.next_character_register() - 1, + Type::Float => self.next_float_register() - 1, + Type::Integer => self.next_integer_register() - 1, + Type::String => self.next_string_register() - 1, + _ => todo!(), + }; let test = Instruction::test(operand_register, true); self.emit_instruction(test, Type::None, self.current_position); @@ -1389,33 +1554,27 @@ impl<'src> Compiler<'src> { fn parse_call_native(&mut self, function: NativeFunction) -> Result<(), CompileError> { let start = self.previous_position.0; - let start_register = self.next_register(); + let mut argument_count = 0; self.expect(Token::LeftParenthesis)?; while !self.allow(Token::RightParenthesis)? { - let expected_register = self.next_register(); - self.parse_expression()?; - - let actual_register = self.next_register() - 1; - let registers_to_close = actual_register - expected_register; - - if registers_to_close > 0 { - let close = Instruction::from(Close { - from: expected_register, - to: actual_register, - }); - - self.emit_instruction(close, Type::None, self.current_position); - } - self.allow(Token::Comma)?; + + argument_count += 1; } let end = self.previous_position.1; - let destination = self.next_register(); - let argument_count = destination - start_register; + let destination = match function.r#type().return_type { + Type::Boolean => self.next_boolean_register(), + Type::Byte => self.next_byte_register(), + Type::Character => self.next_character_register(), + Type::Float => self.next_float_register(), + Type::Integer => self.next_integer_register(), + Type::String => self.next_string_register(), + _ => todo!(), + }; let return_type = function.r#type().return_type; let call_native = Instruction::from(CallNative { destination, @@ -1468,25 +1627,35 @@ impl<'src> Compiler<'src> { self.advance()?; - let should_return_value = + let (should_return_value, type_code, return_register) = if matches!(self.current_token, Token::Semicolon | Token::RightBrace) { self.update_return_type(Type::None)?; - false + (false, TypeCode::NONE, 0) } else { self.parse_expression()?; let expression_type = self.get_last_instruction_type(); + let type_code = expression_type.type_code(); + let return_register = match expression_type { + Type::Boolean => self.next_boolean_register() - 1, + Type::Byte => self.next_byte_register() - 1, + Type::Character => self.next_character_register() - 1, + Type::Float => self.next_float_register() - 1, + Type::Integer => self.next_integer_register() - 1, + Type::String => self.next_string_register() - 1, + _ => todo!(), + }; self.update_return_type(expression_type)?; - true + (true, type_code, return_register) }; let end = self.current_position.1; - let return_register = self.next_register() - 1; let r#return = Instruction::from(Return { should_return_value, return_register, + r#type: type_code, }); self.emit_instruction(r#return, Type::None, Span(start, end)); @@ -1519,7 +1688,7 @@ impl<'src> Compiler<'src> { { // Do nothing if the last instruction is a return or a return followed by a jump } else if self.allow(Token::Semicolon)? { - let r#return = Instruction::r#return(false, 0); + let r#return = Instruction::r#return(false, 0, TypeCode::NONE); self.emit_instruction(r#return, Type::None, self.current_position); } else { @@ -1539,7 +1708,11 @@ impl<'src> Compiler<'src> { })?; let should_return_value = previous_expression_type != Type::None; - let r#return = Instruction::r#return(should_return_value, previous_register); + let r#return = Instruction::r#return( + should_return_value, + previous_register, + previous_expression_type.type_code(), + ); self.update_return_type(previous_expression_type.clone())?; self.emit_instruction(r#return, Type::None, self.current_position); @@ -1593,7 +1766,15 @@ impl<'src> Compiler<'src> { self.expect(Token::Equal)?; self.parse_expression()?; - let register_index = self.next_register() - 1; + let register_index = match self.get_last_instruction_type() { + Type::Boolean => self.next_boolean_register() - 1, + Type::Byte => self.next_byte_register() - 1, + Type::Character => self.next_character_register() - 1, + Type::Float => self.next_float_register() - 1, + Type::Integer => self.next_integer_register() - 1, + Type::String => self.next_string_register() - 1, + _ => todo!(), + }; let r#type = if let Some(r#type) = explicit_type { r#type } else { @@ -1666,7 +1847,15 @@ impl<'src> Compiler<'src> { function_compiler.advance()?; - let local_register_index = function_compiler.next_register(); + let local_register_index = match r#type { + Type::Boolean => function_compiler.next_boolean_register(), + Type::Byte => function_compiler.next_byte_register(), + Type::Character => function_compiler.next_character_register(), + Type::Float => function_compiler.next_float_register(), + Type::Integer => function_compiler.next_integer_register(), + Type::String => function_compiler.next_string_register(), + _ => todo!(), + }; let (_, identifier_index) = function_compiler.declare_local( parameter, local_register_index, @@ -1675,10 +1864,18 @@ impl<'src> Compiler<'src> { function_compiler.current_scope, ); + match r#type { + Type::Boolean => function_compiler.minimum_boolean_register += 1, + Type::Byte => function_compiler.minimum_byte_register += 1, + Type::Character => function_compiler.minimum_character_register += 1, + Type::Float => function_compiler.minimum_float_register += 1, + Type::Integer => function_compiler.minimum_integer_register += 1, + Type::String => function_compiler.minimum_string_register += 1, + _ => {} + } + value_parameters.push((identifier_index, r#type)); function_compiler.allow(Token::Comma)?; - - function_compiler.minimum_register += 1; } let return_type = if function_compiler.allow(Token::ArrowThin)? { @@ -1715,7 +1912,7 @@ impl<'src> Compiler<'src> { let function_end = function_compiler.previous_position.1; let prototype_index = function_compiler.prototype_index; let chunk = function_compiler.finish(); - let destination = self.next_register(); + let destination = self.next_function_register(); self.prototypes.push(Arc::new(chunk)); @@ -1781,29 +1978,22 @@ impl<'src> Compiler<'src> { let mut argument_count = 0; while !self.allow(Token::RightParenthesis)? { - let expected_register = self.next_register(); - self.parse_expression()?; - - let actual_register = self.next_register() - 1; - let registers_to_close = (actual_register - expected_register).saturating_sub(1); - - if registers_to_close > 0 { - let close = Instruction::from(Close { - from: expected_register, - to: actual_register, - }); - - self.emit_instruction(close, Type::None, self.current_position); - } - - argument_count += registers_to_close + 1; - self.allow(Token::Comma)?; + + argument_count += 1; } let end = self.current_position.1; - let destination = self.next_register(); + let destination = match function_return_type { + Type::Boolean => self.next_boolean_register(), + Type::Byte => self.next_byte_register(), + Type::Character => self.next_character_register(), + Type::Float => self.next_float_register(), + Type::Integer => self.next_integer_register(), + Type::String => self.next_string_register(), + _ => todo!(), + }; let call = Instruction::call(destination, function_register, argument_count, is_recursive); self.emit_instruction(call, function_return_type, Span(start, end)); diff --git a/dust-lang/src/instruction/add.rs b/dust-lang/src/instruction/add.rs index c00f643..956a732 100644 --- a/dust-lang/src/instruction/add.rs +++ b/dust-lang/src/instruction/add.rs @@ -56,11 +56,21 @@ impl Display for Add { let Add { destination, left, - left_type: _, + left_type, right, right_type: _, } = self; - write!(f, "R{destination} = {left} + {right}",) + match *left_type { + TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?, + TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?, + TypeCode::CHARACTER => write!(f, "R_CHAR_{destination}")?, + TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?, + TypeCode::INTEGER => write!(f, "R_INT_{destination}")?, + TypeCode::STRING => write!(f, "R_STR_{destination}")?, + _ => todo!(), + } + + write!(f, " = {left} + {right}",) } } diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index 8fbfe46..e708cab 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -510,10 +510,15 @@ impl Instruction { }) } - pub fn r#return(should_return_value: bool, return_register: u16) -> Instruction { + pub fn r#return( + should_return_value: bool, + return_register: u16, + r#type: TypeCode, + ) -> Instruction { Instruction::from(Return { should_return_value, return_register, + r#type, }) } diff --git a/dust-lang/src/instruction/return.rs b/dust-lang/src/instruction/return.rs index b1c6e76..ada31bf 100644 --- a/dust-lang/src/instruction/return.rs +++ b/dust-lang/src/instruction/return.rs @@ -2,21 +2,24 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::{InstructionBuilder, TypeCode}; pub struct Return { pub should_return_value: bool, pub return_register: u16, + pub r#type: TypeCode, } impl From for Return { fn from(instruction: Instruction) -> Self { let should_return_value = instruction.b_field() != 0; let return_register = instruction.c_field(); + let r#type = instruction.b_type(); Return { should_return_value, return_register, + r#type, } } } @@ -25,11 +28,13 @@ impl From for Instruction { fn from(r#return: Return) -> Self { let operation = Operation::RETURN; let b_field = r#return.should_return_value as u16; + let b_type = r#return.r#type; let c_field = r#return.return_register; InstructionBuilder { operation, b_field, + b_type, c_field, ..Default::default() } @@ -42,10 +47,19 @@ impl Display for Return { let Return { should_return_value, return_register, + r#type, } = self; if *should_return_value { - write!(f, "RETURN R{return_register}") + match *r#type { + TypeCode::BOOLEAN => write!(f, "RETURN R_BOOL_{return_register}"), + TypeCode::BYTE => write!(f, "RETURN R_BYTE_{return_register}"), + TypeCode::CHARACTER => write!(f, "RETURN R_CHAR_{return_register}"), + TypeCode::FLOAT => write!(f, "RETURN R_FLOAT_{return_register}"), + TypeCode::INTEGER => write!(f, "RETURN R_INT_{return_register}"), + TypeCode::STRING => write!(f, "RETURN R_STRING_{return_register}"), + unsupported => unreachable!("Unsupported return type: {:?}", unsupported), + } } else { write!(f, "RETURN") } diff --git a/dust-lang/src/instruction/type_code.rs b/dust-lang/src/instruction/type_code.rs index daf6e82..228d699 100644 --- a/dust-lang/src/instruction/type_code.rs +++ b/dust-lang/src/instruction/type_code.rs @@ -4,12 +4,13 @@ use std::fmt::Display; pub struct TypeCode(pub u8); impl TypeCode { - pub const BOOLEAN: TypeCode = TypeCode(0); - pub const BYTE: TypeCode = TypeCode(1); - pub const CHARACTER: TypeCode = TypeCode(2); - pub const FLOAT: TypeCode = TypeCode(3); - pub const INTEGER: TypeCode = TypeCode(4); - pub const STRING: TypeCode = TypeCode(5); + pub const NONE: TypeCode = TypeCode(0); + pub const BOOLEAN: TypeCode = TypeCode(1); + pub const BYTE: TypeCode = TypeCode(2); + pub const CHARACTER: TypeCode = TypeCode(3); + pub const FLOAT: TypeCode = TypeCode(4); + pub const INTEGER: TypeCode = TypeCode(5); + pub const STRING: TypeCode = TypeCode(6); pub fn panic_from_unknown_code(self) -> ! { panic!("Unknown type code: {}", self.0); diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index bc6cb03..d8e4aa6 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -42,7 +42,7 @@ pub mod vm; pub use crate::chunk::{Chunk, Disassembler, Local, Scope}; pub use crate::compiler::{CompileError, Compiler, compile}; pub use crate::dust_error::{AnnotatedError, DustError}; -pub use crate::instruction::{Operand, Instruction, Operation}; +pub use crate::instruction::{Instruction, Operand, Operation}; pub use crate::lexer::{LexError, Lexer, lex}; pub use crate::native_function::{NativeFunction, NativeFunctionError}; pub use crate::token::{Token, TokenKind, TokenOwned}; @@ -50,7 +50,7 @@ pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict}; pub use crate::value::{ AbstractList, ConcreteValue, DustString, Function, RangeValue, Value, ValueError, }; -pub use crate::vm::{Pointer, Vm, run}; +pub use crate::vm::{Vm, run}; use std::fmt::Display; diff --git a/dust-lang/src/native_function/assert.rs b/dust-lang/src/native_function/assert.rs index a006f27..bb8610b 100644 --- a/dust-lang/src/native_function/assert.rs +++ b/dust-lang/src/native_function/assert.rs @@ -7,8 +7,7 @@ pub fn panic(data: &mut Thread, _: usize, argument_range: Range) { let mut message = format!("Dust panic at {position}!"); for register_index in argument_range { - let value = data.get_register(register_index); - let string = value.display(data); + let string = data.get_string_register(register_index); message.push_str(&string); message.push('\n'); diff --git a/dust-lang/src/native_function/io.rs b/dust-lang/src/native_function/io.rs index 402ebfc..5ef1840 100644 --- a/dust-lang/src/native_function/io.rs +++ b/dust-lang/src/native_function/io.rs @@ -1,10 +1,8 @@ use std::io::{Write, stdin, stdout}; use std::ops::Range; -use crate::{ - ConcreteValue, Value, - vm::{Register, Thread}, -}; +use crate::DustString; +use crate::vm::Thread; pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range) { let mut buffer = String::new(); @@ -14,10 +12,9 @@ pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range) { let mut stdout = stdout(); for register_index in argument_range { - let value = data.get_register(register_index); + let value = data.get_string_register(register_index); let _ = stdout.write(value.to_string().as_bytes()); } @@ -36,7 +33,7 @@ pub fn write_line(data: &mut Thread, _: usize, argument_range: Range) { let mut stdout = stdout().lock(); for register_index in argument_range { - let value = data.get_register(register_index); + let value = data.get_string_register(register_index); let _ = stdout.write(value.to_string().as_bytes()); } diff --git a/dust-lang/src/native_function/random.rs b/dust-lang/src/native_function/random.rs index 71d112c..a146281 100644 --- a/dust-lang/src/native_function/random.rs +++ b/dust-lang/src/native_function/random.rs @@ -2,10 +2,7 @@ use std::ops::Range; use rand::Rng; -use crate::{ - Value, - vm::{Register, Thread}, -}; +use crate::{Value, vm::Thread}; pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range) { let mut argument_range_iter = argument_range.into_iter(); @@ -16,21 +13,17 @@ pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range) { - let argument_value = thread.get_register(argument_range.start); - let argument_string = argument_value.display(thread); - let new_register = Register::Value(Value::Concrete(ConcreteValue::string(argument_string))); - let old_register = thread.get_register_mut(destination); - - *old_register = new_register; + todo!() } diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index 1258526..a36e31d 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -7,6 +7,8 @@ use std::{ use serde::{Deserialize, Serialize}; +use crate::instruction::TypeCode; + /// Description of a kind of value. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum Type { @@ -47,6 +49,19 @@ impl Type { Type::List(Box::new(element_type)) } + pub fn type_code(&self) -> TypeCode { + match self { + Type::Boolean => TypeCode::BOOLEAN, + Type::Byte => TypeCode::BYTE, + Type::Character => TypeCode::CHARACTER, + Type::Float => TypeCode::FLOAT, + Type::Integer => TypeCode::INTEGER, + Type::None => TypeCode::NONE, + Type::String => TypeCode::STRING, + _ => todo!(), + } + } + /// Returns a concrete type, either the type itself or the concrete type of a generic type. pub fn concrete_type(&self) -> &Type { if let Type::Generic { diff --git a/dust-lang/src/value/abstract_list.rs b/dust-lang/src/value/abstract_list.rs index 7b7ded6..391f043 100644 --- a/dust-lang/src/value/abstract_list.rs +++ b/dust-lang/src/value/abstract_list.rs @@ -1,6 +1,9 @@ use std::fmt::{self, Display, Formatter}; -use crate::{Pointer, Type, vm::Thread}; +use crate::{ + Type, + vm::{Pointer, Thread}, +}; use super::DustString; @@ -21,7 +24,15 @@ impl AbstractList { display.push_str(", "); } - let item_display = thread.get_pointer_value(pointer).to_string(); + let item_display = match self.item_type { + Type::Boolean => thread.get_pointer_to_boolean(pointer).to_string(), + Type::Byte => thread.get_pointer_to_byte(pointer).to_string(), + Type::Character => thread.get_pointer_to_character(pointer).to_string(), + Type::Float => thread.get_pointer_to_float(pointer).to_string(), + Type::Integer => thread.get_pointer_to_integer(pointer).to_string(), + Type::String => thread.get_pointer_to_string(pointer).to_string(), + _ => todo!(), + }; display.push_str(&item_display); } diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action.rs index 52d4307..a4fc683 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action.rs @@ -49,8 +49,9 @@ impl From<&Instruction> for Action { pub type RunnerLogic = fn(InstructionBuilder, &mut Thread); -pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 22] = [ +pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [ point, + close, load_boolean, load_constant, load_function, @@ -74,20 +75,9 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 22] = [ r#return, ]; -pub fn point(instruction: InstructionBuilder, thread: &mut Thread) { - let destination = instruction.a_field as usize; - let to = instruction.b_field as usize; - let to_is_constant = instruction.b_is_constant; - let pointer = if to_is_constant { - Pointer::Constant(to) - } else { - Pointer::Register(to) - }; - let new_register = Register::Pointer(pointer); - let old_register = thread.get_register_mut(destination); +pub fn point(instruction: InstructionBuilder, thread: &mut Thread) {} - *old_register = new_register; -} +pub fn close(instruction: InstructionBuilder, thread: &mut Thread) {} pub fn load_boolean(instruction: InstructionBuilder, thread: &mut Thread) {} @@ -99,7 +89,45 @@ pub fn load_function(instruction: InstructionBuilder, thread: &mut Thread) {} pub fn load_self(instruction: InstructionBuilder, thread: &mut Thread) {} -pub fn add(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn add(instruction: InstructionBuilder, thread: &mut Thread) { + let destination = instruction.a_field as usize; + let left = instruction.b_field as usize; + let left_is_constant = instruction.b_is_constant; + let left_type = instruction.b_type; + let right = instruction.c_field as usize; + let right_is_constant = instruction.c_is_constant; + let right_type = instruction.c_type; + + match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_integer().unwrap() + } else { + unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() } + } + } else { + thread.get_integer_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_integer().unwrap() + } else { + unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() } + } + } else { + thread.get_integer_register(right) + }; + let result = left_value + right_value; + + println!("{left} + {right} = {destination}"); + println!("{left_value} + {right_value} = {result}"); + + thread.set_integer_register(destination, result); + } + _ => unimplemented!(), + } +} pub fn subtract(instruction: InstructionBuilder, thread: &mut Thread) {} @@ -129,7 +157,43 @@ pub fn call(instruction: InstructionBuilder, thread: &mut Thread) {} pub fn call_native(instruction: InstructionBuilder, thread: &mut Thread) {} -pub fn r#return(instruction: InstructionBuilder, thread: &mut Thread) {} +pub fn r#return(instruction: InstructionBuilder, thread: &mut Thread) { + let should_return_value = instruction.b_field != 0; + let return_register = instruction.c_field as usize; + let return_type = instruction.b_type; + + if should_return_value { + match return_type { + TypeCode::BOOLEAN => { + let return_value = thread.get_boolean_register(return_register); + thread.return_value = Some(Some(Value::boolean(return_value))); + } + TypeCode::BYTE => { + let return_value = thread.get_byte_register(return_register); + thread.return_value = Some(Some(Value::byte(return_value))); + } + TypeCode::CHARACTER => { + let return_value = thread.get_character_register(return_register); + thread.return_value = Some(Some(Value::character(return_value))); + } + TypeCode::FLOAT => { + let return_value = thread.get_float_register(return_register); + thread.return_value = Some(Some(Value::float(return_value))); + } + TypeCode::INTEGER => { + let return_value = thread.get_integer_register(return_register); + thread.return_value = Some(Some(Value::integer(return_value))); + } + TypeCode::STRING => { + let return_value = thread.get_string_register(return_register).clone(); + thread.return_value = Some(Some(Value::string(return_value))); + } + _ => unimplemented!(), + } + } else { + thread.return_value = Some(None); + } +} #[cfg(test)] mod tests { @@ -138,10 +202,12 @@ mod tests { use super::*; - const ALL_OPERATIONS: [(Operation, RunnerLogic); 21] = [ + const ALL_OPERATIONS: [(Operation, RunnerLogic); 23] = [ (Operation::POINT, point), + (Operation::CLOSE, close), (Operation::LOAD_BOOLEAN, load_boolean), (Operation::LOAD_CONSTANT, load_constant), + (Operation::LOAD_FUNCTION, load_function), (Operation::LOAD_LIST, load_list), (Operation::LOAD_SELF, load_self), (Operation::ADD, add), diff --git a/dust-lang/src/vm/call_frame.rs b/dust-lang/src/vm/call_frame.rs index 13cf626..bd6462c 100644 --- a/dust-lang/src/vm/call_frame.rs +++ b/dust-lang/src/vm/call_frame.rs @@ -7,20 +7,20 @@ use smallvec::{SmallVec, smallvec}; use crate::{Chunk, DustString}; -use super::{Register, action::ActionSequence}; +use super::action::ActionSequence; #[derive(Debug)] pub struct CallFrame { pub chunk: Arc, pub ip: usize, pub return_register: u16, - pub registers: SmallVec<[Register; 64]>, + pub registers: RegisterTable, pub action_sequence: ActionSequence, } impl CallFrame { pub fn new(chunk: Arc, return_register: u16) -> Self { - let registers = smallvec![Register::Empty; chunk.register_count]; + let registers = RegisterTable::new(); let action_sequence = ActionSequence::new(&chunk.instructions); Self { @@ -37,13 +37,77 @@ impl Display for CallFrame { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!( f, - "FunctionCall: {} | IP: {} | Registers: {}", + "FunctionCall: {} | IP: {}", self.chunk .name .as_ref() .unwrap_or(&DustString::from("anonymous")), self.ip, - self.registers.len() ) } } + +#[derive(Debug)] +pub struct RegisterTable { + pub booleans: SmallVec<[Register; 64]>, + pub bytes: SmallVec<[Register; 64]>, + pub characters: SmallVec<[Register; 64]>, + pub floats: SmallVec<[Register; 64]>, + pub integers: SmallVec<[Register; 64]>, + pub strings: SmallVec<[Register; 64]>, +} + +impl RegisterTable { + pub fn new() -> Self { + Self { + booleans: smallvec![Register::Empty; 64], + bytes: smallvec![Register::Empty; 64], + characters: smallvec![Register::Empty; 64], + floats: smallvec![Register::Empty; 64], + integers: smallvec![Register::Empty; 64], + strings: smallvec![Register::Empty; 64], + } + } +} + +impl Default for RegisterTable { + fn default() -> Self { + Self::new() + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Register { + Empty, + Value(T), + Pointer(Pointer), +} + +impl Display for Register { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::Empty => write!(f, "empty"), + Self::Value(value) => write!(f, "{value}"), + Self::Pointer(pointer) => write!(f, "{pointer}"), + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum Pointer { + Register(usize), + Constant(usize), + Stack(usize, usize), +} + +impl Display for Pointer { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::Register(index) => write!(f, "PR{}", index), + Self::Constant(index) => write!(f, "PC{}", index), + Self::Stack(call_index, register_index) => { + write!(f, "PS{}R{}", call_index, register_index) + } + } + } +} diff --git a/dust-lang/src/vm/mod.rs b/dust-lang/src/vm/mod.rs index 8631d27..a88f3b6 100644 --- a/dust-lang/src/vm/mod.rs +++ b/dust-lang/src/vm/mod.rs @@ -3,14 +3,10 @@ mod action; mod call_frame; mod thread; -use std::{ - fmt::{self, Debug, Display, Formatter}, - sync::Arc, - thread::Builder, -}; +use std::{sync::Arc, thread::Builder}; pub use action::Action; -pub use call_frame::CallFrame; +pub use call_frame::{CallFrame, Pointer, Register, RegisterTable}; pub use thread::Thread; use crossbeam_channel::bounded; @@ -60,39 +56,3 @@ impl Vm { rx.recv().unwrap_or(None) } } - -#[derive(Clone, Debug, PartialEq)] -pub enum Register { - Empty, - Value(Value), - Pointer(Pointer), -} - -impl Display for Register { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Empty => write!(f, "empty"), - Self::Value(value) => write!(f, "{value}"), - Self::Pointer(pointer) => write!(f, "{pointer}"), - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum Pointer { - Register(usize), - Constant(usize), - Stack(usize, usize), -} - -impl Display for Pointer { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Register(index) => write!(f, "PR{}", index), - Self::Constant(index) => write!(f, "PC{}", index), - Self::Stack(call_index, register_index) => { - write!(f, "PS{}R{}", call_index, register_index) - } - } - } -} diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index fe2b493..4bb455f 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -4,12 +4,12 @@ use tracing::{info, trace}; use crate::{Chunk, DustString, Span, Value, vm::CallFrame}; -use super::{Pointer, Register}; +use super::call_frame::{Pointer, Register}; pub struct Thread { chunk: Arc, call_stack: Vec, - return_value_index: Option>, + pub return_value: Option>, spawned_threads: Vec>, } @@ -23,7 +23,7 @@ impl Thread { Thread { chunk, call_stack, - return_value_index: None, + return_value: None, spawned_threads: Vec::new(), } } @@ -58,14 +58,8 @@ impl Thread { (current_action.logic)(current_action.instruction, &mut self); - if let Some(return_index_option) = self.return_value_index { - if let Some(return_index) = return_index_option { - let return_value = self.get_register(return_index).clone(); - - return Some(return_value); - } else { - return None; - } + if let Some(return_value_option) = self.return_value { + return return_value_option; } } } @@ -92,14 +86,13 @@ impl Thread { } } - pub fn get_register(&self, register_index: usize) -> &Value { - trace!("Get R{register_index}"); - + pub fn get_boolean_register(&self, register_index: usize) -> bool { let register = if cfg!(debug_assertions) { self.call_stack .last() .unwrap() .registers + .booleans .get(register_index) .unwrap() } else { @@ -108,25 +101,52 @@ impl Thread { .last() .unwrap_unchecked() .registers + .booleans .get_unchecked(register_index) } }; match register { - Register::Value(value) => value, - Register::Pointer(pointer) => self.get_pointer_value(pointer), + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_boolean(pointer), Register::Empty => panic!("Attempted to get value from empty register"), } } - pub fn get_register_mut(&mut self, register_index: usize) -> &mut Register { - trace!("Get R{register_index}"); + pub fn get_pointer_to_boolean(&self, pointer: &Pointer) -> bool { + match pointer { + Pointer::Register(register_index) => self.get_boolean_register(*register_index), + Pointer::Constant(constant_index) => { + self.get_constant(*constant_index).as_boolean().unwrap() + } + Pointer::Stack(call_index, register_index) => { + let call_frame = if cfg!(debug_assertions) { + self.call_stack.get(*call_index).unwrap() + } else { + unsafe { self.call_stack.get_unchecked(*call_index) } + }; + let register = if cfg!(debug_assertions) { + call_frame.registers.booleans.get(*register_index).unwrap() + } else { + unsafe { call_frame.registers.booleans.get_unchecked(*register_index) } + }; - if cfg!(debug_assertions) { + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_boolean(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + } + } + + pub fn set_boolean_register(&mut self, register_index: usize, value: bool) { + let register = if cfg!(debug_assertions) { self.call_stack .last_mut() .unwrap() .registers + .booleans .get_mut(register_index) .unwrap() } else { @@ -135,11 +155,408 @@ impl Thread { .last_mut() .unwrap_unchecked() .registers + .booleans .get_unchecked_mut(register_index) } + }; + + *register = Register::Value(value); + } + + pub fn get_byte_register(&self, register_index: usize) -> u8 { + let register = if cfg!(debug_assertions) { + self.call_stack + .last() + .unwrap() + .registers + .bytes + .get(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last() + .unwrap_unchecked() + .registers + .bytes + .get_unchecked(register_index) + } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_byte(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), } } + pub fn get_pointer_to_byte(&self, pointer: &Pointer) -> u8 { + match pointer { + Pointer::Register(register_index) => self.get_byte_register(*register_index), + Pointer::Constant(constant_index) => { + self.get_constant(*constant_index).as_byte().unwrap() + } + Pointer::Stack(call_index, register_index) => { + let call_frame = if cfg!(debug_assertions) { + self.call_stack.get(*call_index).unwrap() + } else { + unsafe { self.call_stack.get_unchecked(*call_index) } + }; + let register = if cfg!(debug_assertions) { + call_frame.registers.bytes.get(*register_index).unwrap() + } else { + unsafe { call_frame.registers.bytes.get_unchecked(*register_index) } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_byte(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + } + } + + pub fn set_byte_register(&mut self, register_index: usize, value: u8) { + let register = if cfg!(debug_assertions) { + self.call_stack + .last_mut() + .unwrap() + .registers + .bytes + .get_mut(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last_mut() + .unwrap_unchecked() + .registers + .bytes + .get_unchecked_mut(register_index) + } + }; + + *register = Register::Value(value); + } + + pub fn get_character_register(&self, register_index: usize) -> char { + let register = if cfg!(debug_assertions) { + self.call_stack + .last() + .unwrap() + .registers + .characters + .get(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last() + .unwrap_unchecked() + .registers + .characters + .get_unchecked(register_index) + } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_character(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + + pub fn get_pointer_to_character(&self, pointer: &Pointer) -> char { + match pointer { + Pointer::Register(register_index) => self.get_character_register(*register_index), + Pointer::Constant(constant_index) => { + self.get_constant(*constant_index).as_character().unwrap() + } + Pointer::Stack(call_index, register_index) => { + let call_frame = if cfg!(debug_assertions) { + self.call_stack.get(*call_index).unwrap() + } else { + unsafe { self.call_stack.get_unchecked(*call_index) } + }; + let register = if cfg!(debug_assertions) { + call_frame + .registers + .characters + .get(*register_index) + .unwrap() + } else { + unsafe { + call_frame + .registers + .characters + .get_unchecked(*register_index) + } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_character(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + } + } + + pub fn set_character_register(&mut self, register_index: usize, value: char) { + let register = if cfg!(debug_assertions) { + self.call_stack + .last_mut() + .unwrap() + .registers + .characters + .get_mut(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last_mut() + .unwrap_unchecked() + .registers + .characters + .get_unchecked_mut(register_index) + } + }; + + *register = Register::Value(value); + } + + pub fn get_float_register(&self, register_index: usize) -> f64 { + let register = if cfg!(debug_assertions) { + self.call_stack + .last() + .unwrap() + .registers + .floats + .get(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last() + .unwrap_unchecked() + .registers + .floats + .get_unchecked(register_index) + } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_float(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + + pub fn get_pointer_to_float(&self, pointer: &Pointer) -> f64 { + match pointer { + Pointer::Register(register_index) => self.get_float_register(*register_index), + Pointer::Constant(constant_index) => { + self.get_constant(*constant_index).as_float().unwrap() + } + Pointer::Stack(call_index, register_index) => { + let call_frame = if cfg!(debug_assertions) { + self.call_stack.get(*call_index).unwrap() + } else { + unsafe { self.call_stack.get_unchecked(*call_index) } + }; + let register = if cfg!(debug_assertions) { + call_frame.registers.floats.get(*register_index).unwrap() + } else { + unsafe { call_frame.registers.floats.get_unchecked(*register_index) } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_float(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + } + } + + pub fn set_float_register(&mut self, register_index: usize, value: f64) { + let register = if cfg!(debug_assertions) { + self.call_stack + .last_mut() + .unwrap() + .registers + .floats + .get_mut(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last_mut() + .unwrap_unchecked() + .registers + .floats + .get_unchecked_mut(register_index) + } + }; + + *register = Register::Value(value); + } + + pub fn get_integer_register(&self, register_index: usize) -> i64 { + let register = if cfg!(debug_assertions) { + self.call_stack + .last() + .unwrap() + .registers + .integers + .get(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last() + .unwrap_unchecked() + .registers + .integers + .get_unchecked(register_index) + } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_integer(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + + pub fn get_pointer_to_integer(&self, pointer: &Pointer) -> i64 { + match pointer { + Pointer::Register(register_index) => self.get_integer_register(*register_index), + Pointer::Constant(constant_index) => { + self.get_constant(*constant_index).as_integer().unwrap() + } + Pointer::Stack(call_index, register_index) => { + let call_frame = if cfg!(debug_assertions) { + self.call_stack.get(*call_index).unwrap() + } else { + unsafe { self.call_stack.get_unchecked(*call_index) } + }; + let register = if cfg!(debug_assertions) { + call_frame.registers.integers.get(*register_index).unwrap() + } else { + unsafe { call_frame.registers.integers.get_unchecked(*register_index) } + }; + + match register { + Register::Value(value) => *value, + Register::Pointer(pointer) => self.get_pointer_to_integer(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + } + } + + pub fn set_integer_register(&mut self, register_index: usize, value: i64) { + let register = if cfg!(debug_assertions) { + self.call_stack + .last_mut() + .unwrap() + .registers + .integers + .get_mut(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last_mut() + .unwrap_unchecked() + .registers + .integers + .get_unchecked_mut(register_index) + } + }; + + *register = Register::Value(value); + } + + pub fn get_string_register(&self, register_index: usize) -> &DustString { + let register = if cfg!(debug_assertions) { + self.call_stack + .last() + .unwrap() + .registers + .strings + .get(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last() + .unwrap_unchecked() + .registers + .strings + .get_unchecked(register_index) + } + }; + + match register { + Register::Value(value) => value, + Register::Pointer(pointer) => self.get_pointer_to_string(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + + pub fn get_pointer_to_string(&self, pointer: &Pointer) -> &DustString { + match pointer { + Pointer::Register(register_index) => self.get_string_register(*register_index), + Pointer::Constant(constant_index) => { + self.get_constant(*constant_index).as_string().unwrap() + } + Pointer::Stack(call_index, register_index) => { + let call_frame = if cfg!(debug_assertions) { + self.call_stack.get(*call_index).unwrap() + } else { + unsafe { self.call_stack.get_unchecked(*call_index) } + }; + let register = if cfg!(debug_assertions) { + call_frame.registers.strings.get(*register_index).unwrap() + } else { + unsafe { call_frame.registers.strings.get_unchecked(*register_index) } + }; + + match register { + Register::Value(value) => value, + Register::Pointer(pointer) => self.get_pointer_to_string(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + } + } + + pub fn set_string_register(&mut self, register_index: usize, value: DustString) { + let register = if cfg!(debug_assertions) { + self.call_stack + .last_mut() + .unwrap() + .registers + .strings + .get_mut(register_index) + .unwrap() + } else { + unsafe { + self.call_stack + .last_mut() + .unwrap_unchecked() + .registers + .strings + .get_unchecked_mut(register_index) + } + }; + + *register = Register::Value(value); + } + pub fn get_constant(&self, constant_index: usize) -> &Value { if cfg!(debug_assertions) { self.chunk.constants.get(constant_index).unwrap() @@ -147,29 +564,4 @@ impl Thread { unsafe { self.chunk.constants.get_unchecked(constant_index) } } } - - pub fn get_pointer_value(&self, pointer: &Pointer) -> &Value { - match pointer { - Pointer::Register(register_index) => self.get_register(*register_index), - Pointer::Constant(constant_index) => self.get_constant(*constant_index), - Pointer::Stack(call_index, register_index) => { - let call_frame = if cfg!(debug_assertions) { - self.call_stack.get(*call_index).unwrap() - } else { - unsafe { self.call_stack.get_unchecked(*call_index) } - }; - let register = if cfg!(debug_assertions) { - call_frame.registers.get(*register_index).unwrap() - } else { - unsafe { call_frame.registers.get_unchecked(*register_index) } - }; - - match register { - Register::Value(value) => value, - Register::Pointer(pointer) => self.get_pointer_value(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), - } - } - } - } }