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. /// [`Compiler::finish`] is called.
stack_size: usize, stack_size: usize,
/// The first register index that the compiler should use. This is used to avoid reusing the /// The first boolean register index that the compiler should use. This is used to avoid reusing
/// registers that are used for the function's arguments. /// the registers that are used for the function's arguments.
minimum_register: u16, 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 /// Index of the current block. This is used to determine the scope of locals and is incremented
/// when a new block is entered. /// when a new block is entered.
@ -149,7 +177,14 @@ impl<'src> Compiler<'src> {
prototypes: Vec::new(), prototypes: Vec::new(),
stack_size: 0, stack_size: 0,
lexer, 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, block_index: 0,
current_scope: Scope::default(), current_scope: Scope::default(),
prototype_index: 0, prototype_index: 0,
@ -215,7 +250,7 @@ impl<'src> Compiler<'src> {
r#type: self.r#type, r#type: self.r#type,
instructions, instructions,
positions, positions,
constants: self.constants.to_vec(), constants: self.constants,
locals, locals,
prototypes: self.prototypes, prototypes: self.prototypes,
register_count: self.stack_size, register_count: self.stack_size,
@ -227,18 +262,118 @@ impl<'src> Compiler<'src> {
matches!(self.current_token, Token::Eof) matches!(self.current_token, Token::Eof)
} }
fn next_register(&self) -> u16 { fn next_boolean_register(&self) -> u16 {
self.instructions self.instructions
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, _, _)| { .find_map(|(instruction, r#type, _)| {
if instruction.yields_value() { if r#type == &Type::Boolean && instruction.yields_value() {
Some(instruction.a_field() + 1) Some(instruction.a_field() + 1)
} else { } else {
None 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> { fn advance(&mut self) -> Result<(), CompileError> {
@ -473,7 +608,13 @@ impl<'src> Compiler<'src> {
) -> Result<(), CompileError> { ) -> Result<(), CompileError> {
let r#type = constant.r#type(); let r#type = constant.r#type();
let constant_index = self.push_or_get_constant(Value::Concrete(constant)); 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); let load_constant = Instruction::load_constant(destination, constant_index, false);
self.emit_instruction(load_constant, r#type, position); self.emit_instruction(load_constant, r#type, position);
@ -488,7 +629,7 @@ impl<'src> Compiler<'src> {
self.advance()?; self.advance()?;
let boolean = text.parse::<bool>().unwrap(); 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); let load_boolean = Instruction::load_boolean(destination, boolean, false);
self.emit_instruction(load_boolean, Type::Boolean, position); self.emit_instruction(load_boolean, Type::Boolean, position);
@ -650,14 +791,10 @@ impl<'src> Compiler<'src> {
)) ))
} }
let destination = self.next_register(); let (type_code, destination) = match previous_type {
let type_code = match previous_type { Type::Boolean => (TypeCode::BOOLEAN, self.next_boolean_register()),
Type::Boolean => TypeCode::BOOLEAN, Type::Float => (TypeCode::FLOAT, self.next_float_register()),
Type::Byte => TypeCode::BYTE, Type::Integer => (TypeCode::INTEGER, self.next_integer_register()),
Type::Character => TypeCode::CHARACTER,
Type::Float => TypeCode::FLOAT,
Type::Integer => TypeCode::INTEGER,
Type::String => TypeCode::STRING,
_ => match operator { _ => match operator {
Token::Minus => { Token::Minus => {
return Err(CompileError::CannotNegateType { return Err(CompileError::CannotNegateType {
@ -774,13 +911,13 @@ impl<'src> Compiler<'src> {
check_math_type(&left_type, operator, &left_position)?; check_math_type(&left_type, operator, &left_position)?;
let left_type_code = match left_type { let (left_type_code, destination) = match left_type {
Type::Boolean => TypeCode::BOOLEAN, Type::Boolean => (TypeCode::BOOLEAN, self.next_boolean_register()),
Type::Byte => TypeCode::BYTE, Type::Byte => (TypeCode::BYTE, self.next_byte_register()),
Type::Character => TypeCode::CHARACTER, Type::Character => (TypeCode::CHARACTER, self.next_character_register()),
Type::Float => TypeCode::FLOAT, Type::Float => (TypeCode::FLOAT, self.next_float_register()),
Type::Integer => TypeCode::INTEGER, Type::Integer => (TypeCode::INTEGER, self.next_integer_register()),
Type::String => TypeCode::STRING, Type::String => (TypeCode::STRING, self.next_string_register()),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -828,14 +965,6 @@ impl<'src> Compiler<'src> {
} else { } else {
left_type.clone() 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 { let instruction = match operator {
Token::Plus | Token::PlusEqual => { Token::Plus | Token::PlusEqual => {
Instruction::add(destination, left, left_type_code, right, right_type_code) 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)); .push((right_instruction, right_type, right_position));
} }
let destination = self.next_register(); let destination = self.next_boolean_register();
let comparison = match operator { let comparison = match operator {
Token::DoubleEqual => { Token::DoubleEqual => {
Instruction::equal(true, left, left_type_code, right, right_type_code) Instruction::equal(true, left, left_type_code, right, right_type_code)
@ -1016,10 +1145,20 @@ impl<'src> Compiler<'src> {
register register
} else { } 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 self.instructions
.push((last_instruction, last_type, last_position)); .push((last_instruction, last_type, last_position));
self.next_register().saturating_sub(1) register
}; };
let operator = self.current_token; let operator = self.current_token;
let operator_position = self.current_position; let operator_position = self.current_position;
@ -1086,7 +1225,7 @@ impl<'src> Compiler<'src> {
} else if let Some(native_function) = NativeFunction::from_str(identifier) { } else if let Some(native_function) = NativeFunction::from_str(identifier) {
return self.parse_call_native(native_function); return self.parse_call_native(native_function);
} else if self.function_name.as_deref() == Some(identifier) && !self.is_main { } 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); let load_self = Instruction::load_self(destination, false);
self.emit_instruction(load_self, Type::SelfFunction, start_position); 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); math_instruction.set_a_field(local_register_index);
} else { } 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)); let point = Instruction::point(local_register_index, Operand::Register(register));
self.emit_instruction(point, r#type, start_position); self.emit_instruction(point, r#type, start_position);
@ -1142,7 +1289,15 @@ impl<'src> Compiler<'src> {
return Ok(()); 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)); let point = Instruction::point(destination, Operand::Register(local_register_index));
self.emit_instruction(point, r#type, self.previous_position); self.emit_instruction(point, r#type, self.previous_position);
@ -1191,33 +1346,27 @@ impl<'src> Compiler<'src> {
self.advance()?; self.advance()?;
let start_register = self.next_register(); let mut item_type = Type::None;
let mut item_type = Type::Any; let mut start_register = 0;
while !self.allow(Token::RightBracket)? && !self.is_eof() { while !self.allow(Token::RightBracket)? && !self.is_eof() {
let expected_register = self.next_register();
self.parse_expression()?; self.parse_expression()?;
let actual_register = self.next_register() - 1;
if item_type == Type::Any {
item_type = self.get_last_instruction_type(); item_type = self.get_last_instruction_type();
} start_register = match item_type {
Type::Boolean => self.next_boolean_register() - 1,
if expected_register < actual_register { Type::Byte => self.next_byte_register() - 1,
let close = Instruction::from(Close { Type::Character => self.next_character_register() - 1,
from: expected_register, Type::Float => self.next_float_register() - 1,
to: actual_register, Type::Integer => self.next_integer_register() - 1,
}); Type::String => self.next_string_register() - 1,
_ => todo!(),
self.emit_instruction(close, Type::None, self.current_position); };
}
self.allow(Token::Comma)?; self.allow(Token::Comma)?;
} }
let destination = self.next_register(); let destination = self.next_list_register();
let end = self.previous_position.1; let end = self.previous_position.1;
let load_list = Instruction::load_list(destination, start_register, false); let load_list = Instruction::load_list(destination, start_register, false);
@ -1243,7 +1392,15 @@ impl<'src> Compiler<'src> {
self.instructions.pop(); self.instructions.pop();
self.instructions.pop(); self.instructions.pop();
} else { } 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); let test = Instruction::test(operand_register, true);
self.emit_instruction(test, Type::None, self.current_position); self.emit_instruction(test, Type::None, self.current_position);
@ -1356,7 +1513,15 @@ impl<'src> Compiler<'src> {
self.instructions.pop(); self.instructions.pop();
self.instructions.pop(); self.instructions.pop();
} else { } 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); let test = Instruction::test(operand_register, true);
self.emit_instruction(test, Type::None, self.current_position); 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> { fn parse_call_native(&mut self, function: NativeFunction) -> Result<(), CompileError> {
let start = self.previous_position.0; let start = self.previous_position.0;
let start_register = self.next_register(); let mut argument_count = 0;
self.expect(Token::LeftParenthesis)?; self.expect(Token::LeftParenthesis)?;
while !self.allow(Token::RightParenthesis)? { while !self.allow(Token::RightParenthesis)? {
let expected_register = self.next_register();
self.parse_expression()?; 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)?; self.allow(Token::Comma)?;
argument_count += 1;
} }
let end = self.previous_position.1; let end = self.previous_position.1;
let destination = self.next_register(); let destination = match function.r#type().return_type {
let argument_count = destination - start_register; 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 return_type = function.r#type().return_type;
let call_native = Instruction::from(CallNative { let call_native = Instruction::from(CallNative {
destination, destination,
@ -1468,25 +1627,35 @@ impl<'src> Compiler<'src> {
self.advance()?; self.advance()?;
let should_return_value = let (should_return_value, type_code, return_register) =
if matches!(self.current_token, Token::Semicolon | Token::RightBrace) { if matches!(self.current_token, Token::Semicolon | Token::RightBrace) {
self.update_return_type(Type::None)?; self.update_return_type(Type::None)?;
false (false, TypeCode::NONE, 0)
} else { } else {
self.parse_expression()?; self.parse_expression()?;
let expression_type = self.get_last_instruction_type(); 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)?; self.update_return_type(expression_type)?;
true (true, type_code, return_register)
}; };
let end = self.current_position.1; let end = self.current_position.1;
let return_register = self.next_register() - 1;
let r#return = Instruction::from(Return { let r#return = Instruction::from(Return {
should_return_value, should_return_value,
return_register, return_register,
r#type: type_code,
}); });
self.emit_instruction(r#return, Type::None, Span(start, end)); 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 // Do nothing if the last instruction is a return or a return followed by a jump
} else if self.allow(Token::Semicolon)? { } 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); self.emit_instruction(r#return, Type::None, self.current_position);
} else { } else {
@ -1539,7 +1708,11 @@ impl<'src> Compiler<'src> {
})?; })?;
let should_return_value = previous_expression_type != Type::None; 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.update_return_type(previous_expression_type.clone())?;
self.emit_instruction(r#return, Type::None, self.current_position); self.emit_instruction(r#return, Type::None, self.current_position);
@ -1593,7 +1766,15 @@ impl<'src> Compiler<'src> {
self.expect(Token::Equal)?; self.expect(Token::Equal)?;
self.parse_expression()?; 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 { let r#type = if let Some(r#type) = explicit_type {
r#type r#type
} else { } else {
@ -1666,7 +1847,15 @@ impl<'src> Compiler<'src> {
function_compiler.advance()?; 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( let (_, identifier_index) = function_compiler.declare_local(
parameter, parameter,
local_register_index, local_register_index,
@ -1675,10 +1864,18 @@ impl<'src> Compiler<'src> {
function_compiler.current_scope, 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)); value_parameters.push((identifier_index, r#type));
function_compiler.allow(Token::Comma)?; function_compiler.allow(Token::Comma)?;
function_compiler.minimum_register += 1;
} }
let return_type = if function_compiler.allow(Token::ArrowThin)? { 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 function_end = function_compiler.previous_position.1;
let prototype_index = function_compiler.prototype_index; let prototype_index = function_compiler.prototype_index;
let chunk = function_compiler.finish(); let chunk = function_compiler.finish();
let destination = self.next_register(); let destination = self.next_function_register();
self.prototypes.push(Arc::new(chunk)); self.prototypes.push(Arc::new(chunk));
@ -1781,29 +1978,22 @@ impl<'src> Compiler<'src> {
let mut argument_count = 0; let mut argument_count = 0;
while !self.allow(Token::RightParenthesis)? { while !self.allow(Token::RightParenthesis)? {
let expected_register = self.next_register();
self.parse_expression()?; 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)?; self.allow(Token::Comma)?;
argument_count += 1;
} }
let end = self.current_position.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); let call = Instruction::call(destination, function_register, argument_count, is_recursive);
self.emit_instruction(call, function_return_type, Span(start, end)); self.emit_instruction(call, function_return_type, Span(start, end));

View File

@ -56,11 +56,21 @@ impl Display for Add {
let Add { let Add {
destination, destination,
left, left,
left_type: _, left_type,
right, right,
right_type: _, right_type: _,
} = self; } = 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 { Instruction::from(Return {
should_return_value, should_return_value,
return_register, return_register,
r#type,
}) })
} }

View File

@ -2,21 +2,24 @@ use std::fmt::{self, Display, Formatter};
use crate::{Instruction, Operation}; use crate::{Instruction, Operation};
use super::InstructionBuilder; use super::{InstructionBuilder, TypeCode};
pub struct Return { pub struct Return {
pub should_return_value: bool, pub should_return_value: bool,
pub return_register: u16, pub return_register: u16,
pub r#type: TypeCode,
} }
impl From<Instruction> for Return { impl From<Instruction> for Return {
fn from(instruction: Instruction) -> Self { fn from(instruction: Instruction) -> Self {
let should_return_value = instruction.b_field() != 0; let should_return_value = instruction.b_field() != 0;
let return_register = instruction.c_field(); let return_register = instruction.c_field();
let r#type = instruction.b_type();
Return { Return {
should_return_value, should_return_value,
return_register, return_register,
r#type,
} }
} }
} }
@ -25,11 +28,13 @@ impl From<Return> for Instruction {
fn from(r#return: Return) -> Self { fn from(r#return: Return) -> Self {
let operation = Operation::RETURN; let operation = Operation::RETURN;
let b_field = r#return.should_return_value as u16; let b_field = r#return.should_return_value as u16;
let b_type = r#return.r#type;
let c_field = r#return.return_register; let c_field = r#return.return_register;
InstructionBuilder { InstructionBuilder {
operation, operation,
b_field, b_field,
b_type,
c_field, c_field,
..Default::default() ..Default::default()
} }
@ -42,10 +47,19 @@ impl Display for Return {
let Return { let Return {
should_return_value, should_return_value,
return_register, return_register,
r#type,
} = self; } = self;
if *should_return_value { 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 { } else {
write!(f, "RETURN") write!(f, "RETURN")
} }

View File

@ -4,12 +4,13 @@ use std::fmt::Display;
pub struct TypeCode(pub u8); pub struct TypeCode(pub u8);
impl TypeCode { impl TypeCode {
pub const BOOLEAN: TypeCode = TypeCode(0); pub const NONE: TypeCode = TypeCode(0);
pub const BYTE: TypeCode = TypeCode(1); pub const BOOLEAN: TypeCode = TypeCode(1);
pub const CHARACTER: TypeCode = TypeCode(2); pub const BYTE: TypeCode = TypeCode(2);
pub const FLOAT: TypeCode = TypeCode(3); pub const CHARACTER: TypeCode = TypeCode(3);
pub const INTEGER: TypeCode = TypeCode(4); pub const FLOAT: TypeCode = TypeCode(4);
pub const STRING: TypeCode = TypeCode(5); pub const INTEGER: TypeCode = TypeCode(5);
pub const STRING: TypeCode = TypeCode(6);
pub fn panic_from_unknown_code(self) -> ! { pub fn panic_from_unknown_code(self) -> ! {
panic!("Unknown type code: {}", self.0); 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::chunk::{Chunk, Disassembler, Local, Scope};
pub use crate::compiler::{CompileError, Compiler, compile}; pub use crate::compiler::{CompileError, Compiler, compile};
pub use crate::dust_error::{AnnotatedError, DustError}; 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::lexer::{LexError, Lexer, lex};
pub use crate::native_function::{NativeFunction, NativeFunctionError}; pub use crate::native_function::{NativeFunction, NativeFunctionError};
pub use crate::token::{Token, TokenKind, TokenOwned}; 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::{ pub use crate::value::{
AbstractList, ConcreteValue, DustString, Function, RangeValue, Value, ValueError, AbstractList, ConcreteValue, DustString, Function, RangeValue, Value, ValueError,
}; };
pub use crate::vm::{Pointer, Vm, run}; pub use crate::vm::{Vm, run};
use std::fmt::Display; 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}!"); let mut message = format!("Dust panic at {position}!");
for register_index in argument_range { for register_index in argument_range {
let value = data.get_register(register_index); let string = data.get_string_register(register_index);
let string = value.display(data);
message.push_str(&string); message.push_str(&string);
message.push('\n'); message.push('\n');

View File

@ -1,10 +1,8 @@
use std::io::{Write, stdin, stdout}; use std::io::{Write, stdin, stdout};
use std::ops::Range; use std::ops::Range;
use crate::{ use crate::DustString;
ConcreteValue, Value, use crate::vm::Thread;
vm::{Register, Thread},
};
pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<usize>) { pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<usize>) {
let mut buffer = String::new(); 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)); buffer.truncate(length.saturating_sub(1));
let new_register = Register::Value(Value::Concrete(ConcreteValue::string(buffer))); let string = DustString::from(buffer);
let old_register = data.get_register_mut(destination);
*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(); let mut stdout = stdout();
for register_index in argument_range { 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()); 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(); let mut stdout = stdout().lock();
for register_index in argument_range { 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()); let _ = stdout.write(value.to_string().as_bytes());
} }

View File

@ -2,10 +2,7 @@ use std::ops::Range;
use rand::Rng; use rand::Rng;
use crate::{ use crate::{Value, vm::Thread};
Value,
vm::{Register, Thread},
};
pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<usize>) { pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<usize>) {
let mut argument_range_iter = argument_range.into_iter(); 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 let register_index = argument_range_iter
.next() .next()
.unwrap_or_else(|| panic!("No argument was passed to \"random_int\"")); .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() { if min.is_none() {
min = Some(integer); min = Some(integer);
} else { } else {
break (min, integer); break (min, integer);
} }
} }
}
}; };
let random_integer = rand::thread_rng().gen_range(min.unwrap()..max); 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 std::ops::Range;
use crate::{ use crate::{ConcreteValue, Value, vm::Thread};
ConcreteValue, Value,
vm::{Register, Thread},
};
pub fn to_string(thread: &mut Thread, destination: usize, argument_range: Range<usize>) { pub fn to_string(thread: &mut Thread, destination: usize, argument_range: Range<usize>) {
let argument_value = thread.get_register(argument_range.start); todo!()
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;
} }

View File

@ -7,6 +7,8 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::instruction::TypeCode;
/// Description of a kind of value. /// Description of a kind of value.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Type { pub enum Type {
@ -47,6 +49,19 @@ impl Type {
Type::List(Box::new(element_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. /// Returns a concrete type, either the type itself or the concrete type of a generic type.
pub fn concrete_type(&self) -> &Type { pub fn concrete_type(&self) -> &Type {
if let Type::Generic { if let Type::Generic {

View File

@ -1,6 +1,9 @@
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use crate::{Pointer, Type, vm::Thread}; use crate::{
Type,
vm::{Pointer, Thread},
};
use super::DustString; use super::DustString;
@ -21,7 +24,15 @@ impl AbstractList {
display.push_str(", "); 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); display.push_str(&item_display);
} }

View File

@ -49,8 +49,9 @@ impl From<&Instruction> for Action {
pub type RunnerLogic = fn(InstructionBuilder, &mut Thread); pub type RunnerLogic = fn(InstructionBuilder, &mut Thread);
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 22] = [ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [
point, point,
close,
load_boolean, load_boolean,
load_constant, load_constant,
load_function, load_function,
@ -74,20 +75,9 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 22] = [
r#return, r#return,
]; ];
pub fn point(instruction: InstructionBuilder, thread: &mut Thread) { 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);
*old_register = new_register; pub fn close(instruction: InstructionBuilder, thread: &mut Thread) {}
}
pub fn load_boolean(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 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) {} 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 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)] #[cfg(test)]
mod tests { mod tests {
@ -138,10 +202,12 @@ mod tests {
use super::*; use super::*;
const ALL_OPERATIONS: [(Operation, RunnerLogic); 21] = [ const ALL_OPERATIONS: [(Operation, RunnerLogic); 23] = [
(Operation::POINT, point), (Operation::POINT, point),
(Operation::CLOSE, close),
(Operation::LOAD_BOOLEAN, load_boolean), (Operation::LOAD_BOOLEAN, load_boolean),
(Operation::LOAD_CONSTANT, load_constant), (Operation::LOAD_CONSTANT, load_constant),
(Operation::LOAD_FUNCTION, load_function),
(Operation::LOAD_LIST, load_list), (Operation::LOAD_LIST, load_list),
(Operation::LOAD_SELF, load_self), (Operation::LOAD_SELF, load_self),
(Operation::ADD, add), (Operation::ADD, add),

View File

@ -7,20 +7,20 @@ use smallvec::{SmallVec, smallvec};
use crate::{Chunk, DustString}; use crate::{Chunk, DustString};
use super::{Register, action::ActionSequence}; use super::action::ActionSequence;
#[derive(Debug)] #[derive(Debug)]
pub struct CallFrame { pub struct CallFrame {
pub chunk: Arc<Chunk>, pub chunk: Arc<Chunk>,
pub ip: usize, pub ip: usize,
pub return_register: u16, pub return_register: u16,
pub registers: SmallVec<[Register; 64]>, pub registers: RegisterTable,
pub action_sequence: ActionSequence, pub action_sequence: ActionSequence,
} }
impl CallFrame { impl CallFrame {
pub fn new(chunk: Arc<Chunk>, return_register: u16) -> Self { 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); let action_sequence = ActionSequence::new(&chunk.instructions);
Self { Self {
@ -37,13 +37,77 @@ impl Display for CallFrame {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!( write!(
f, f,
"FunctionCall: {} | IP: {} | Registers: {}", "FunctionCall: {} | IP: {}",
self.chunk self.chunk
.name .name
.as_ref() .as_ref()
.unwrap_or(&DustString::from("anonymous")), .unwrap_or(&DustString::from("anonymous")),
self.ip, 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 call_frame;
mod thread; mod thread;
use std::{ use std::{sync::Arc, thread::Builder};
fmt::{self, Debug, Display, Formatter},
sync::Arc,
thread::Builder,
};
pub use action::Action; pub use action::Action;
pub use call_frame::CallFrame; pub use call_frame::{CallFrame, Pointer, Register, RegisterTable};
pub use thread::Thread; pub use thread::Thread;
use crossbeam_channel::bounded; use crossbeam_channel::bounded;
@ -60,39 +56,3 @@ impl Vm {
rx.recv().unwrap_or(None) 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 crate::{Chunk, DustString, Span, Value, vm::CallFrame};
use super::{Pointer, Register}; use super::call_frame::{Pointer, Register};
pub struct Thread { pub struct Thread {
chunk: Arc<Chunk>, chunk: Arc<Chunk>,
call_stack: Vec<CallFrame>, call_stack: Vec<CallFrame>,
return_value_index: Option<Option<usize>>, pub return_value: Option<Option<Value>>,
spawned_threads: Vec<JoinHandle<()>>, spawned_threads: Vec<JoinHandle<()>>,
} }
@ -23,7 +23,7 @@ impl Thread {
Thread { Thread {
chunk, chunk,
call_stack, call_stack,
return_value_index: None, return_value: None,
spawned_threads: Vec::new(), spawned_threads: Vec::new(),
} }
} }
@ -58,14 +58,8 @@ impl Thread {
(current_action.logic)(current_action.instruction, &mut self); (current_action.logic)(current_action.instruction, &mut self);
if let Some(return_index_option) = self.return_value_index { if let Some(return_value_option) = self.return_value {
if let Some(return_index) = return_index_option { return return_value_option;
let return_value = self.get_register(return_index).clone();
return Some(return_value);
} else {
return None;
}
} }
} }
} }
@ -92,14 +86,13 @@ impl Thread {
} }
} }
pub fn get_register(&self, register_index: usize) -> &Value { pub fn get_boolean_register(&self, register_index: usize) -> bool {
trace!("Get R{register_index}");
let register = if cfg!(debug_assertions) { let register = if cfg!(debug_assertions) {
self.call_stack self.call_stack
.last() .last()
.unwrap() .unwrap()
.registers .registers
.booleans
.get(register_index) .get(register_index)
.unwrap() .unwrap()
} else { } else {
@ -108,25 +101,52 @@ impl Thread {
.last() .last()
.unwrap_unchecked() .unwrap_unchecked()
.registers .registers
.booleans
.get_unchecked(register_index) .get_unchecked(register_index)
} }
}; };
match register { match register {
Register::Value(value) => value, Register::Value(value) => *value,
Register::Pointer(pointer) => self.get_pointer_value(pointer), Register::Pointer(pointer) => self.get_pointer_to_boolean(pointer),
Register::Empty => panic!("Attempted to get value from empty register"), Register::Empty => panic!("Attempted to get value from empty register"),
} }
} }
pub fn get_register_mut(&mut self, register_index: usize) -> &mut Register { pub fn get_pointer_to_boolean(&self, pointer: &Pointer) -> bool {
trace!("Get R{register_index}"); 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 self.call_stack
.last_mut() .last_mut()
.unwrap() .unwrap()
.registers .registers
.booleans
.get_mut(register_index) .get_mut(register_index)
.unwrap() .unwrap()
} else { } else {
@ -135,9 +155,406 @@ impl Thread {
.last_mut() .last_mut()
.unwrap_unchecked() .unwrap_unchecked()
.registers .registers
.booleans
.get_unchecked_mut(register_index) .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 { pub fn get_constant(&self, constant_index: usize) -> &Value {
@ -147,29 +564,4 @@ impl Thread {
unsafe { self.chunk.constants.get_unchecked(constant_index) } 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"),
}
}
}
}
} }