Implement typed registers with untyped constants
This commit is contained in:
parent
03103e4fa1
commit
4775d425a0
@ -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));
|
||||
|
@ -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}",)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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');
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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!()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user