1
0

Implement typed registers with untyped constants

This commit is contained in:
Jeff 2025-02-05 19:12:26 -05:00
parent 03103e4fa1
commit 4775d425a0
16 changed files with 974 additions and 265 deletions

View File

@ -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::<bool>().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));

View File

@ -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}",)
}
}

View File

@ -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,
})
}

View File

@ -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<Instruction> 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<Return> 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")
}

View File

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

View File

@ -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;

View File

@ -7,8 +7,7 @@ pub fn panic(data: &mut Thread, _: usize, argument_range: Range<usize>) {
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');

View File

@ -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<usize>) {
let mut buffer = String::new();
@ -14,10 +12,9 @@ pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<u
buffer.truncate(length.saturating_sub(1));
let new_register = Register::Value(Value::Concrete(ConcreteValue::string(buffer)));
let old_register = data.get_register_mut(destination);
let string = DustString::from(buffer);
*old_register = new_register;
data.set_string_register(destination, string);
}
}
@ -25,7 +22,7 @@ pub fn write(data: &mut Thread, _: usize, argument_range: Range<usize>) {
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<usize>) {
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());
}

View File

@ -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<usize>) {
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<u
let register_index = argument_range_iter
.next()
.unwrap_or_else(|| panic!("No argument was passed to \"random_int\""));
let argument = data.get_register(register_index);
let integer = data.get_integer_register(register_index);
if let Some(integer) = argument.as_integer() {
if min.is_none() {
min = Some(integer);
} else {
break (min, integer);
}
if min.is_none() {
min = Some(integer);
} else {
break (min, integer);
}
}
};
let random_integer = rand::thread_rng().gen_range(min.unwrap()..max);
let new_register = Register::Value(Value::integer(random_integer));
let old_register = data.get_register_mut(destination);
*old_register = new_register;
data.set_integer_register(destination, random_integer);
}

View File

@ -1,15 +1,7 @@
use std::ops::Range;
use crate::{
ConcreteValue, Value,
vm::{Register, Thread},
};
use crate::{ConcreteValue, Value, vm::Thread};
pub fn to_string(thread: &mut Thread, destination: usize, argument_range: Range<usize>) {
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!()
}

View File

@ -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 {

View File

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

View File

@ -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),

View File

@ -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<Chunk>,
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<Chunk>, 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<bool>; 64]>,
pub bytes: SmallVec<[Register<u8>; 64]>,
pub characters: SmallVec<[Register<char>; 64]>,
pub floats: SmallVec<[Register<f64>; 64]>,
pub integers: SmallVec<[Register<i64>; 64]>,
pub strings: SmallVec<[Register<DustString>; 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<T> {
Empty,
Value(T),
Pointer(Pointer),
}
impl<T: Display> Display for Register<T> {
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)
}
}
}
}

View File

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

View File

@ -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<Chunk>,
call_stack: Vec<CallFrame>,
return_value_index: Option<Option<usize>>,
pub return_value: Option<Option<Value>>,
spawned_threads: Vec<JoinHandle<()>>,
}
@ -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"),
}
}
}
}
}