Continue value overhaul
This commit is contained in:
parent
151cfe7095
commit
ae79c2bac1
@ -118,10 +118,6 @@ pub struct Compiler<'src> {
|
|||||||
/// [`Compiler::finish`] is called.
|
/// [`Compiler::finish`] is called.
|
||||||
stack_size: usize,
|
stack_size: usize,
|
||||||
|
|
||||||
/// Register usage tracker. This is used to determine the next available register of each
|
|
||||||
/// type.
|
|
||||||
register_usage: RegisterUsage,
|
|
||||||
|
|
||||||
/// 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.
|
||||||
block_index: u8,
|
block_index: u8,
|
||||||
@ -169,7 +165,6 @@ impl<'src> Compiler<'src> {
|
|||||||
argument_lists: Vec::new(),
|
argument_lists: Vec::new(),
|
||||||
stack_size: 0,
|
stack_size: 0,
|
||||||
lexer,
|
lexer,
|
||||||
register_usage: RegisterUsage::default(),
|
|
||||||
block_index: 0,
|
block_index: 0,
|
||||||
current_scope: Scope::default(),
|
current_scope: Scope::default(),
|
||||||
prototype_index: 0,
|
prototype_index: 0,
|
||||||
@ -321,7 +316,7 @@ impl<'src> Compiler<'src> {
|
|||||||
if let Some(index) = self
|
if let Some(index) = self
|
||||||
.constant_strings
|
.constant_strings
|
||||||
.iter()
|
.iter()
|
||||||
.position(|constant| constant == &string)
|
.position(|constant| constant == string)
|
||||||
{
|
{
|
||||||
index as u16
|
index as u16
|
||||||
} else {
|
} else {
|
||||||
@ -418,64 +413,116 @@ impl<'src> Compiler<'src> {
|
|||||||
self.instructions.push((instruction, r#type, position));
|
self.instructions.push((instruction, r#type, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_constant_character(
|
fn next_boolean_register(&self) -> u16 {
|
||||||
&mut self,
|
self.instructions
|
||||||
character: char,
|
.iter()
|
||||||
position: Span,
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
) -> Result<(), CompileError> {
|
if r#type == &Type::Boolean {
|
||||||
let constant_index = self.constant_characters.len() as u16;
|
Some(instruction.a_field())
|
||||||
|
} else {
|
||||||
self.constant_characters.push(character);
|
None
|
||||||
|
}
|
||||||
let destination = self.register_usage.next_character_register();
|
})
|
||||||
let load_constant = Instruction::load_constant(destination, constant_index, false);
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
self.emit_instruction(load_constant, Type::Character, position);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_constant_float(&mut self, float: f64, position: Span) -> Result<(), CompileError> {
|
fn next_byte_register(&self) -> u16 {
|
||||||
let constant_index = self.constant_floats.len() as u16;
|
self.instructions
|
||||||
|
.iter()
|
||||||
self.constant_floats.push(float);
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
|
if r#type == &Type::Byte {
|
||||||
let destination = self.register_usage.next_float_register();
|
Some(instruction.a_field())
|
||||||
let load_constant = Instruction::load_constant(destination, constant_index, false);
|
} else {
|
||||||
|
None
|
||||||
self.emit_instruction(load_constant, Type::Float, position);
|
}
|
||||||
|
})
|
||||||
Ok(())
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_constant_integer(&mut self, integer: i64, position: Span) -> Result<(), CompileError> {
|
fn next_character_register(&self) -> u16 {
|
||||||
let constant_index = self.constant_integers.len() as u16;
|
self.instructions
|
||||||
|
.iter()
|
||||||
self.constant_integers.push(integer);
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
|
if r#type == &Type::Character {
|
||||||
let destination = self.register_usage.next_integer_register();
|
Some(instruction.a_field())
|
||||||
let load_constant = Instruction::load_constant(destination, constant_index, false);
|
} else {
|
||||||
|
None
|
||||||
self.emit_instruction(load_constant, Type::Integer, position);
|
}
|
||||||
|
})
|
||||||
Ok(())
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_constant_string(
|
fn next_float_register(&self) -> u16 {
|
||||||
&mut self,
|
self.instructions
|
||||||
string: DustString,
|
.iter()
|
||||||
position: Span,
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
) -> Result<(), CompileError> {
|
if r#type == &Type::Float {
|
||||||
let constant_index = self.constant_strings.len() as u16;
|
Some(instruction.a_field())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
|
}
|
||||||
|
|
||||||
self.constant_strings.push(string);
|
fn next_integer_register(&self) -> u16 {
|
||||||
|
self.instructions
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
|
if r#type == &Type::Integer {
|
||||||
|
Some(instruction.a_field())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
|
}
|
||||||
|
|
||||||
let destination = self.register_usage.next_string_register();
|
fn next_string_register(&self) -> u16 {
|
||||||
let load_constant = Instruction::load_constant(destination, constant_index, false);
|
self.instructions
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
|
if r#type == &Type::String {
|
||||||
|
Some(instruction.a_field())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
|
}
|
||||||
|
|
||||||
self.emit_instruction(load_constant, Type::String, position);
|
fn next_list_register(&self) -> u16 {
|
||||||
|
self.instructions
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
|
if matches!(r#type, Type::List(_)) {
|
||||||
|
Some(instruction.a_field())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
fn next_function_register(&self) -> u16 {
|
||||||
|
self.instructions
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(instruction, r#type, _)| {
|
||||||
|
if matches!(r#type, Type::Function(_)) {
|
||||||
|
Some(instruction.a_field())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.map_or(0, |register| register + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_boolean(&mut self) -> Result<(), CompileError> {
|
fn parse_boolean(&mut self) -> Result<(), CompileError> {
|
||||||
@ -486,7 +533,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
let boolean = text.parse::<bool>().unwrap();
|
let boolean = text.parse::<bool>().unwrap();
|
||||||
let boolean_encoded = boolean as u16;
|
let boolean_encoded = boolean as u16;
|
||||||
let destination = self.register_usage.next_boolean_register();
|
let destination = self.next_boolean_register();
|
||||||
let load_encoded =
|
let load_encoded =
|
||||||
Instruction::load_encoded(destination, boolean_encoded, TypeCode::BOOLEAN, false);
|
Instruction::load_encoded(destination, boolean_encoded, TypeCode::BOOLEAN, false);
|
||||||
|
|
||||||
@ -510,7 +557,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
let byte = u8::from_str_radix(&text[2..], 16)
|
let byte = u8::from_str_radix(&text[2..], 16)
|
||||||
.map_err(|error| CompileError::ParseIntError { error, position })?;
|
.map_err(|error| CompileError::ParseIntError { error, position })?;
|
||||||
let destination = self.register_usage.next_byte_register();
|
let destination = self.next_byte_register();
|
||||||
let load_encoded =
|
let load_encoded =
|
||||||
Instruction::load_encoded(destination, byte as u16, TypeCode::BYTE, true);
|
Instruction::load_encoded(destination, byte as u16, TypeCode::BYTE, true);
|
||||||
|
|
||||||
@ -536,7 +583,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.constant_characters.push(character);
|
self.constant_characters.push(character);
|
||||||
|
|
||||||
let destination = self.register_usage.next_character_register();
|
let destination = self.next_character_register();
|
||||||
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, Type::Character, position);
|
self.emit_instruction(load_constant, Type::Character, position);
|
||||||
@ -567,7 +614,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.constant_floats.push(float);
|
self.constant_floats.push(float);
|
||||||
|
|
||||||
let destination = self.register_usage.next_float_register();
|
let destination = self.next_float_register();
|
||||||
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, Type::Float, position);
|
self.emit_instruction(load_constant, Type::Float, position);
|
||||||
@ -604,7 +651,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.constant_integers.push(integer);
|
self.constant_integers.push(integer);
|
||||||
|
|
||||||
let destination = self.register_usage.next_integer_register();
|
let destination = self.next_integer_register();
|
||||||
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, Type::Integer, position);
|
self.emit_instruction(load_constant, Type::Integer, position);
|
||||||
@ -629,7 +676,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.constant_strings.push(DustString::from(text));
|
self.constant_strings.push(DustString::from(text));
|
||||||
|
|
||||||
let destination = self.register_usage.next_string_register();
|
let destination = self.next_string_register();
|
||||||
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, Type::String, position);
|
self.emit_instruction(load_constant, Type::String, position);
|
||||||
@ -661,7 +708,8 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
let (previous_instruction, previous_type, previous_position) =
|
let (previous_instruction, previous_type, previous_position) =
|
||||||
self.instructions.pop().unwrap();
|
self.instructions.pop().unwrap();
|
||||||
let (argument, push_back) = self.handle_binary_argument(&previous_instruction)?;
|
let (argument, push_back) =
|
||||||
|
self.handle_binary_argument(&previous_instruction, &previous_type)?;
|
||||||
|
|
||||||
if push_back {
|
if push_back {
|
||||||
self.instructions.push((
|
self.instructions.push((
|
||||||
@ -672,21 +720,12 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (destination, type_code) = match previous_type {
|
let (destination, type_code) = match previous_type {
|
||||||
Type::Boolean => (
|
Type::Boolean => (self.next_boolean_register(), TypeCode::BOOLEAN),
|
||||||
self.register_usage.next_boolean_register(),
|
Type::Byte => (self.next_byte_register(), TypeCode::BYTE),
|
||||||
TypeCode::BOOLEAN,
|
Type::Character => (self.next_character_register(), TypeCode::CHARACTER),
|
||||||
),
|
Type::Float => (self.next_float_register(), TypeCode::FLOAT),
|
||||||
Type::Byte => (self.register_usage.next_byte_register(), TypeCode::BYTE),
|
Type::Integer => (self.next_integer_register(), TypeCode::INTEGER),
|
||||||
Type::Character => (
|
Type::String => (self.next_string_register(), TypeCode::STRING),
|
||||||
self.register_usage.next_character_register(),
|
|
||||||
TypeCode::CHARACTER,
|
|
||||||
),
|
|
||||||
Type::Float => (self.register_usage.next_float_register(), TypeCode::FLOAT),
|
|
||||||
Type::Integer => (
|
|
||||||
self.register_usage.next_integer_register(),
|
|
||||||
TypeCode::INTEGER,
|
|
||||||
),
|
|
||||||
Type::String => (self.register_usage.next_string_register(), TypeCode::STRING),
|
|
||||||
_ => match operator {
|
_ => match operator {
|
||||||
Token::Minus => {
|
Token::Minus => {
|
||||||
return Err(CompileError::CannotNegateType {
|
return Err(CompileError::CannotNegateType {
|
||||||
@ -723,29 +762,54 @@ impl<'src> Compiler<'src> {
|
|||||||
fn handle_binary_argument(
|
fn handle_binary_argument(
|
||||||
&mut self,
|
&mut self,
|
||||||
instruction: &Instruction,
|
instruction: &Instruction,
|
||||||
|
instruction_type: &Type,
|
||||||
) -> Result<(Operand, bool), CompileError> {
|
) -> Result<(Operand, bool), CompileError> {
|
||||||
let (argument, push_back) = match instruction.operation() {
|
let (argument, push_back) = match instruction.operation() {
|
||||||
Operation::LOAD_CONSTANT => (Operand::Constant(instruction.b_field()), false),
|
Operation::LOAD_CONSTANT => match instruction_type {
|
||||||
|
Type::Character => (Operand::ConstantCharacter(instruction.b_field()), false),
|
||||||
|
Type::Float => (Operand::ConstantFloat(instruction.b_field()), false),
|
||||||
|
Type::Integer => (Operand::ConstantInteger(instruction.b_field()), false),
|
||||||
|
Type::String => (Operand::ConstantString(instruction.b_field()), false),
|
||||||
|
unsupported => panic!("Unsupported type: {unsupported}"),
|
||||||
|
},
|
||||||
Operation::POINT
|
Operation::POINT
|
||||||
| Operation::LOAD_ENCODED
|
| Operation::LOAD_ENCODED
|
||||||
| Operation::LOAD_LIST
|
| Operation::LOAD_LIST
|
||||||
| Operation::LOAD_SELF
|
|
||||||
| Operation::ADD
|
| Operation::ADD
|
||||||
| Operation::SUBTRACT
|
| Operation::SUBTRACT
|
||||||
| Operation::MULTIPLY
|
| Operation::MULTIPLY
|
||||||
| Operation::DIVIDE
|
| Operation::DIVIDE
|
||||||
| Operation::MODULO
|
| Operation::MODULO
|
||||||
|
| Operation::LOAD_SELF
|
||||||
| Operation::EQUAL
|
| Operation::EQUAL
|
||||||
| Operation::LESS
|
| Operation::LESS
|
||||||
| Operation::LESS_EQUAL
|
| Operation::LESS_EQUAL
|
||||||
| Operation::NEGATE
|
| Operation::NEGATE
|
||||||
| Operation::NOT
|
| Operation::NOT
|
||||||
| Operation::CALL => (Operand::Register(instruction.a_field()), true),
|
| Operation::CALL => match instruction_type {
|
||||||
|
Type::Boolean => (Operand::RegisterBoolean(instruction.a_field()), true),
|
||||||
|
Type::Byte => (Operand::RegisterByte(instruction.a_field()), true),
|
||||||
|
Type::Character => (Operand::RegisterCharacter(instruction.a_field()), true),
|
||||||
|
Type::Float => (Operand::RegisterFloat(instruction.a_field()), true),
|
||||||
|
Type::Integer => (Operand::RegisterInteger(instruction.a_field()), true),
|
||||||
|
Type::String => (Operand::RegisterString(instruction.a_field()), true),
|
||||||
|
unsupported => panic!("{unsupported} type is not supported here"),
|
||||||
|
},
|
||||||
Operation::CALL_NATIVE => {
|
Operation::CALL_NATIVE => {
|
||||||
let function = NativeFunction::from(instruction.b_field());
|
let function = NativeFunction::from(instruction.b_field());
|
||||||
|
|
||||||
if function.returns_value() {
|
if function.returns_value() {
|
||||||
(Operand::Register(instruction.a_field()), true)
|
match instruction_type {
|
||||||
|
Type::Boolean => (Operand::RegisterBoolean(instruction.a_field()), true),
|
||||||
|
Type::Byte => (Operand::RegisterByte(instruction.a_field()), true),
|
||||||
|
Type::Character => {
|
||||||
|
(Operand::RegisterCharacter(instruction.a_field()), true)
|
||||||
|
}
|
||||||
|
Type::Float => (Operand::RegisterFloat(instruction.a_field()), true),
|
||||||
|
Type::Integer => (Operand::RegisterInteger(instruction.a_field()), true),
|
||||||
|
Type::String => (Operand::RegisterString(instruction.a_field()), true),
|
||||||
|
unsupported => panic!("{unsupported} type is not supported here"),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(CompileError::ExpectedExpression {
|
return Err(CompileError::ExpectedExpression {
|
||||||
found: self.previous_token.to_owned(),
|
found: self.previous_token.to_owned(),
|
||||||
@ -772,11 +836,17 @@ impl<'src> Compiler<'src> {
|
|||||||
found: self.previous_token.to_owned(),
|
found: self.previous_token.to_owned(),
|
||||||
position: self.previous_position,
|
position: self.previous_position,
|
||||||
})?;
|
})?;
|
||||||
let (left, push_back_left) = self.handle_binary_argument(&left_instruction)?;
|
let (left, push_back_left) = self.handle_binary_argument(&left_instruction, &left_type)?;
|
||||||
let left_is_mutable_local = self.locals.iter().any(|local| {
|
let left_is_mutable_local = self.locals.iter().any(|local| {
|
||||||
matches!(
|
matches!(
|
||||||
left,
|
left,
|
||||||
Operand::Register(register) if register == local.register_index
|
Operand::RegisterBoolean(register)
|
||||||
|
| Operand::RegisterByte(register)
|
||||||
|
| Operand::RegisterCharacter(register)
|
||||||
|
| Operand::RegisterFloat(register)
|
||||||
|
| Operand::RegisterInteger(register)
|
||||||
|
| Operand::RegisterString(register)
|
||||||
|
if register == local.register_index
|
||||||
) && local.is_mutable
|
) && local.is_mutable
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -820,7 +890,8 @@ impl<'src> Compiler<'src> {
|
|||||||
self.parse_sub_expression(&rule.precedence)?;
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
|
|
||||||
let (right_instruction, right_type, right_position) = self.instructions.pop().unwrap();
|
let (right_instruction, right_type, right_position) = self.instructions.pop().unwrap();
|
||||||
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
|
let (right, push_back_right) =
|
||||||
|
self.handle_binary_argument(&right_instruction, &right_type)?;
|
||||||
|
|
||||||
check_math_type(&right_type, operator, &right_position)?;
|
check_math_type(&right_type, operator, &right_position)?;
|
||||||
check_math_types(
|
check_math_types(
|
||||||
@ -855,25 +926,33 @@ impl<'src> Compiler<'src> {
|
|||||||
};
|
};
|
||||||
let destination = if is_assignment {
|
let destination = if is_assignment {
|
||||||
match left {
|
match left {
|
||||||
Operand::Register(register) => register,
|
Operand::RegisterBoolean(register)
|
||||||
Operand::Constant(_) => match left_type {
|
| Operand::RegisterByte(register)
|
||||||
Type::Boolean => self.register_usage.next_boolean_register(),
|
| Operand::RegisterCharacter(register)
|
||||||
Type::Byte => self.register_usage.next_byte_register(),
|
| Operand::RegisterFloat(register)
|
||||||
Type::Character => self.register_usage.next_character_register(),
|
| Operand::RegisterInteger(register)
|
||||||
Type::Float => self.register_usage.next_float_register(),
|
| Operand::RegisterString(register) => register,
|
||||||
Type::Integer => self.register_usage.next_integer_register(),
|
Operand::ConstantCharacter(_)
|
||||||
Type::String => self.register_usage.next_string_register(),
|
| Operand::ConstantFloat(_)
|
||||||
|
| Operand::ConstantInteger(_)
|
||||||
|
| Operand::ConstantString(_) => match left_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(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match left_type {
|
match left_type {
|
||||||
Type::Boolean => self.register_usage.next_boolean_register(),
|
Type::Boolean => self.next_boolean_register(),
|
||||||
Type::Byte => self.register_usage.next_byte_register(),
|
Type::Byte => self.next_byte_register(),
|
||||||
Type::Character => self.register_usage.next_character_register(),
|
Type::Character => self.next_character_register(),
|
||||||
Type::Float => self.register_usage.next_float_register(),
|
Type::Float => self.next_float_register(),
|
||||||
Type::Integer => self.register_usage.next_integer_register(),
|
Type::Integer => self.next_integer_register(),
|
||||||
Type::String => self.register_usage.next_string_register(),
|
Type::String => self.next_string_register(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -939,7 +1018,7 @@ impl<'src> Compiler<'src> {
|
|||||||
found: self.previous_token.to_owned(),
|
found: self.previous_token.to_owned(),
|
||||||
position: self.previous_position,
|
position: self.previous_position,
|
||||||
})?;
|
})?;
|
||||||
let (left, push_back_left) = self.handle_binary_argument(&left_instruction)?;
|
let (left, push_back_left) = self.handle_binary_argument(&left_instruction, &left_type)?;
|
||||||
let operator = self.current_token;
|
let operator = self.current_token;
|
||||||
let operator_position = self.current_position;
|
let operator_position = self.current_position;
|
||||||
let rule = ParseRule::from(&operator);
|
let rule = ParseRule::from(&operator);
|
||||||
@ -971,7 +1050,8 @@ impl<'src> Compiler<'src> {
|
|||||||
found: self.previous_token.to_owned(),
|
found: self.previous_token.to_owned(),
|
||||||
position: self.previous_position,
|
position: self.previous_position,
|
||||||
})?;
|
})?;
|
||||||
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
|
let (right, push_back_right) =
|
||||||
|
self.handle_binary_argument(&right_instruction, &right_type)?;
|
||||||
|
|
||||||
// TODO: Check if the right type is a valid type for comparison
|
// TODO: Check if the right type is a valid type for comparison
|
||||||
// TODO: Check if the left and right types are compatible
|
// TODO: Check if the left and right types are compatible
|
||||||
@ -991,7 +1071,7 @@ impl<'src> Compiler<'src> {
|
|||||||
.push((right_instruction, right_type, right_position));
|
.push((right_instruction, right_type, right_position));
|
||||||
}
|
}
|
||||||
|
|
||||||
let destination = self.register_usage.next_boolean_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)
|
||||||
@ -1039,18 +1119,18 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_logical_binary(&mut self) -> Result<(), CompileError> {
|
fn parse_logical_binary(&mut self) -> Result<(), CompileError> {
|
||||||
let (last_instruction, last_type, last_position) =
|
let (left_instruction, left_type, left_position) =
|
||||||
self.instructions
|
self.instructions
|
||||||
.pop()
|
.pop()
|
||||||
.ok_or_else(|| CompileError::ExpectedExpression {
|
.ok_or_else(|| CompileError::ExpectedExpression {
|
||||||
found: self.previous_token.to_owned(),
|
found: self.previous_token.to_owned(),
|
||||||
position: self.previous_position,
|
position: self.previous_position,
|
||||||
})?;
|
})?;
|
||||||
let operand_register = if last_instruction.yields_value() {
|
let operand_register = if left_instruction.yields_value() {
|
||||||
let register = last_instruction.a_field();
|
let register = left_instruction.a_field();
|
||||||
|
|
||||||
self.instructions
|
self.instructions
|
||||||
.push((last_instruction, last_type, last_position));
|
.push((left_instruction, left_type, left_position));
|
||||||
|
|
||||||
register
|
register
|
||||||
} else {
|
} else {
|
||||||
@ -1081,6 +1161,21 @@ impl<'src> Compiler<'src> {
|
|||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse_sub_expression(&rule.precedence)?;
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
|
|
||||||
|
let (mut right_instruction, right_type, right_position) = self
|
||||||
|
.instructions
|
||||||
|
.pop()
|
||||||
|
.ok_or_else(|| CompileError::ExpectedExpression {
|
||||||
|
found: self.previous_token.to_owned(),
|
||||||
|
position: self.previous_position,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// TODO: Check if the right type is a boolean
|
||||||
|
|
||||||
|
right_instruction.set_a_field(left_instruction.a_field());
|
||||||
|
|
||||||
|
self.instructions
|
||||||
|
.push((right_instruction, right_type, right_position));
|
||||||
|
|
||||||
let instructions_length = self.instructions.len();
|
let instructions_length = self.instructions.len();
|
||||||
|
|
||||||
for (group_index, instructions) in self.instructions.rchunks_mut(3).enumerate().rev() {
|
for (group_index, instructions) in self.instructions.rchunks_mut(3).enumerate().rev() {
|
||||||
@ -1124,7 +1219,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.register_usage.next_function_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);
|
||||||
@ -1176,12 +1271,12 @@ impl<'src> Compiler<'src> {
|
|||||||
math_instruction.set_a_field(local.register_index);
|
math_instruction.set_a_field(local.register_index);
|
||||||
} else {
|
} else {
|
||||||
let (register, r#type) = match local.r#type {
|
let (register, r#type) = match local.r#type {
|
||||||
Type::Boolean => (self.register_usage.boolean, TypeCode::BOOLEAN),
|
Type::Boolean => (self.next_boolean_register() - 1, TypeCode::BOOLEAN),
|
||||||
Type::Byte => (self.register_usage.byte, TypeCode::BYTE),
|
Type::Byte => (self.next_byte_register() - 1, TypeCode::BYTE),
|
||||||
Type::Character => (self.register_usage.character, TypeCode::CHARACTER),
|
Type::Character => (self.next_character_register() - 1, TypeCode::CHARACTER),
|
||||||
Type::Float => (self.register_usage.float, TypeCode::FLOAT),
|
Type::Float => (self.next_float_register() - 1, TypeCode::FLOAT),
|
||||||
Type::Integer => (self.register_usage.integer, TypeCode::INTEGER),
|
Type::Integer => (self.next_integer_register() - 1, TypeCode::INTEGER),
|
||||||
Type::String => (self.register_usage.string, TypeCode::STRING),
|
Type::String => (self.next_string_register() - 1, TypeCode::STRING),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let point = Instruction::point(local.register_index, register, r#type);
|
let point = Instruction::point(local.register_index, register, r#type);
|
||||||
@ -1193,21 +1288,12 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (destination, r#type) = match local.r#type {
|
let (destination, r#type) = match local.r#type {
|
||||||
Type::Boolean => (
|
Type::Boolean => (self.next_boolean_register(), TypeCode::BOOLEAN),
|
||||||
self.register_usage.next_boolean_register(),
|
Type::Byte => (self.next_byte_register(), TypeCode::BYTE),
|
||||||
TypeCode::BOOLEAN,
|
Type::Character => (self.next_character_register(), TypeCode::CHARACTER),
|
||||||
),
|
Type::Float => (self.next_float_register(), TypeCode::FLOAT),
|
||||||
Type::Byte => (self.register_usage.next_byte_register(), TypeCode::BYTE),
|
Type::Integer => (self.next_integer_register(), TypeCode::INTEGER),
|
||||||
Type::Character => (
|
Type::String => (self.next_string_register(), TypeCode::STRING),
|
||||||
self.register_usage.next_character_register(),
|
|
||||||
TypeCode::CHARACTER,
|
|
||||||
),
|
|
||||||
Type::Float => (self.register_usage.next_float_register(), TypeCode::FLOAT),
|
|
||||||
Type::Integer => (
|
|
||||||
self.register_usage.next_integer_register(),
|
|
||||||
TypeCode::INTEGER,
|
|
||||||
),
|
|
||||||
Type::String => (self.register_usage.next_string_register(), TypeCode::STRING),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let point = Instruction::point(destination, local.register_index, r#type);
|
let point = Instruction::point(destination, local.register_index, r#type);
|
||||||
@ -1277,12 +1363,12 @@ impl<'src> Compiler<'src> {
|
|||||||
self.instructions.pop();
|
self.instructions.pop();
|
||||||
} else {
|
} else {
|
||||||
let operand_register = match r#type {
|
let operand_register = match r#type {
|
||||||
Type::Boolean => self.register_usage.next_boolean_register() - 1,
|
Type::Boolean => self.next_boolean_register() - 1,
|
||||||
Type::Byte => self.register_usage.next_byte_register() - 1,
|
Type::Byte => self.next_byte_register() - 1,
|
||||||
Type::Character => self.register_usage.next_character_register() - 1,
|
Type::Character => self.next_character_register() - 1,
|
||||||
Type::Float => self.register_usage.next_float_register() - 1,
|
Type::Float => self.next_float_register() - 1,
|
||||||
Type::Integer => self.register_usage.next_integer_register() - 1,
|
Type::Integer => self.next_integer_register() - 1,
|
||||||
Type::String => self.register_usage.next_string_register() - 1,
|
Type::String => self.next_string_register() - 1,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let test = Instruction::test(operand_register, true);
|
let test = Instruction::test(operand_register, true);
|
||||||
@ -1400,12 +1486,12 @@ impl<'src> Compiler<'src> {
|
|||||||
self.instructions.pop();
|
self.instructions.pop();
|
||||||
} else {
|
} else {
|
||||||
let operand_register = match r#type {
|
let operand_register = match r#type {
|
||||||
Type::Boolean => self.register_usage.next_boolean_register() - 1,
|
Type::Boolean => self.next_boolean_register() - 1,
|
||||||
Type::Byte => self.register_usage.next_byte_register() - 1,
|
Type::Byte => self.next_byte_register() - 1,
|
||||||
Type::Character => self.register_usage.next_character_register() - 1,
|
Type::Character => self.next_character_register() - 1,
|
||||||
Type::Float => self.register_usage.next_float_register() - 1,
|
Type::Float => self.next_float_register() - 1,
|
||||||
Type::Integer => self.register_usage.next_integer_register() - 1,
|
Type::Integer => self.next_integer_register() - 1,
|
||||||
Type::String => self.register_usage.next_string_register() - 1,
|
Type::String => self.next_string_register() - 1,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let test = Instruction::test(operand_register, true);
|
let test = Instruction::test(operand_register, true);
|
||||||
@ -1460,12 +1546,12 @@ impl<'src> Compiler<'src> {
|
|||||||
// TODO: Check if the argument type matches the expected type
|
// TODO: Check if the argument type matches the expected type
|
||||||
|
|
||||||
let argument_register = match argument_type {
|
let argument_register = match argument_type {
|
||||||
Type::Boolean => self.register_usage.boolean,
|
Type::Boolean => self.next_boolean_register() - 1,
|
||||||
Type::Byte => self.register_usage.byte,
|
Type::Byte => self.next_byte_register() - 1,
|
||||||
Type::Character => self.register_usage.character,
|
Type::Character => self.next_character_register() - 1,
|
||||||
Type::Float => self.register_usage.float,
|
Type::Float => self.next_float_register() - 1,
|
||||||
Type::Integer => self.register_usage.integer,
|
Type::Integer => self.next_integer_register() - 1,
|
||||||
Type::String => self.register_usage.string,
|
Type::String => self.next_string_register() - 1,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1479,12 +1565,12 @@ impl<'src> Compiler<'src> {
|
|||||||
let end = self.previous_position.1;
|
let end = self.previous_position.1;
|
||||||
let return_type = function.r#type().return_type;
|
let return_type = function.r#type().return_type;
|
||||||
let destination = match return_type {
|
let destination = match return_type {
|
||||||
Type::Boolean => self.register_usage.next_boolean_register(),
|
Type::Boolean => self.next_boolean_register(),
|
||||||
Type::Byte => self.register_usage.next_byte_register(),
|
Type::Byte => self.next_byte_register(),
|
||||||
Type::Character => self.register_usage.next_character_register(),
|
Type::Character => self.next_character_register(),
|
||||||
Type::Float => self.register_usage.next_float_register(),
|
Type::Float => self.next_float_register(),
|
||||||
Type::Integer => self.register_usage.next_integer_register(),
|
Type::Integer => self.next_integer_register(),
|
||||||
Type::String => self.register_usage.next_string_register(),
|
Type::String => self.next_string_register(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let argument_list_index = self.argument_lists.len() as u16;
|
let argument_list_index = self.argument_lists.len() as u16;
|
||||||
@ -1558,18 +1644,25 @@ impl<'src> Compiler<'src> {
|
|||||||
};
|
};
|
||||||
let end = self.current_position.1;
|
let end = self.current_position.1;
|
||||||
let return_register = match self.r#type.return_type {
|
let return_register = match self.r#type.return_type {
|
||||||
Type::Boolean => self.register_usage.boolean,
|
Type::Boolean => self.next_boolean_register() - 1,
|
||||||
Type::Byte => self.register_usage.byte,
|
Type::Byte => self.next_byte_register() - 1,
|
||||||
Type::Character => self.register_usage.character,
|
Type::Character => self.next_character_register() - 1,
|
||||||
Type::Float => self.register_usage.float,
|
Type::Float => self.next_float_register() - 1,
|
||||||
Type::Integer => self.register_usage.integer,
|
Type::Integer => self.next_integer_register() - 1,
|
||||||
Type::String => self.register_usage.string,
|
Type::String => self.next_string_register() - 1,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let r#return = Instruction::from(Return {
|
let return_type_code = match self.r#type.return_type {
|
||||||
should_return_value,
|
Type::Boolean => TypeCode::BOOLEAN,
|
||||||
return_register,
|
Type::Byte => TypeCode::BYTE,
|
||||||
});
|
Type::Character => TypeCode::CHARACTER,
|
||||||
|
Type::Float => TypeCode::FLOAT,
|
||||||
|
Type::Integer => TypeCode::INTEGER,
|
||||||
|
Type::String => TypeCode::STRING,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let r#return =
|
||||||
|
Instruction::r#return(should_return_value, return_type_code, return_register);
|
||||||
|
|
||||||
self.emit_instruction(r#return, Type::None, Span(start, end));
|
self.emit_instruction(r#return, Type::None, Span(start, end));
|
||||||
|
|
||||||
@ -1601,7 +1694,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, TypeCode::NONE, 0);
|
||||||
|
|
||||||
self.emit_instruction(r#return, Type::None, self.current_position);
|
self.emit_instruction(r#return, Type::None, self.current_position);
|
||||||
} else {
|
} else {
|
||||||
@ -1621,7 +1714,18 @@ 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 return_type_code = match previous_expression_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,
|
||||||
|
Type::None => TypeCode::NONE,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let r#return =
|
||||||
|
Instruction::r#return(should_return_value, return_type_code, previous_register);
|
||||||
|
|
||||||
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);
|
||||||
@ -1680,12 +1784,12 @@ impl<'src> Compiler<'src> {
|
|||||||
// TODO: Check if the actual type matches the explicit type
|
// TODO: Check if the actual type matches the explicit type
|
||||||
|
|
||||||
let register_index = match actual_type {
|
let register_index = match actual_type {
|
||||||
Type::Boolean => self.register_usage.boolean,
|
Type::Boolean => self.next_boolean_register() - 1,
|
||||||
Type::Byte => self.register_usage.byte,
|
Type::Byte => self.next_byte_register() - 1,
|
||||||
Type::Character => self.register_usage.character,
|
Type::Character => self.next_character_register() - 1,
|
||||||
Type::Float => self.register_usage.float,
|
Type::Float => self.next_float_register() - 1,
|
||||||
Type::Integer => self.register_usage.integer,
|
Type::Integer => self.next_integer_register() - 1,
|
||||||
Type::String => self.register_usage.string,
|
Type::String => self.next_string_register() - 1,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1753,12 +1857,12 @@ impl<'src> Compiler<'src> {
|
|||||||
function_compiler.advance()?;
|
function_compiler.advance()?;
|
||||||
|
|
||||||
let local_register_index = match r#type {
|
let local_register_index = match r#type {
|
||||||
Type::Boolean => function_compiler.register_usage.next_boolean_register(),
|
Type::Boolean => function_compiler.next_boolean_register(),
|
||||||
Type::Byte => function_compiler.register_usage.next_byte_register(),
|
Type::Byte => function_compiler.next_byte_register(),
|
||||||
Type::Character => function_compiler.register_usage.next_character_register(),
|
Type::Character => function_compiler.next_character_register(),
|
||||||
Type::Float => function_compiler.register_usage.next_float_register(),
|
Type::Float => function_compiler.next_float_register(),
|
||||||
Type::Integer => function_compiler.register_usage.next_integer_register(),
|
Type::Integer => function_compiler.next_integer_register(),
|
||||||
Type::String => function_compiler.register_usage.next_string_register(),
|
Type::String => function_compiler.next_string_register(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let (_, identifier_index) = function_compiler.declare_local(
|
let (_, identifier_index) = function_compiler.declare_local(
|
||||||
@ -1807,7 +1911,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.register_usage.next_function_register();
|
let destination = self.next_function_register();
|
||||||
|
|
||||||
self.prototypes.push(Arc::new(chunk));
|
self.prototypes.push(Arc::new(chunk));
|
||||||
|
|
||||||
@ -1868,6 +1972,15 @@ impl<'src> Compiler<'src> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let return_type_code = match function_return_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,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
let is_recursive = last_instruction_type == &Type::SelfFunction;
|
let is_recursive = last_instruction_type == &Type::SelfFunction;
|
||||||
|
|
||||||
let mut argument_list = Vec::new();
|
let mut argument_list = Vec::new();
|
||||||
@ -1878,12 +1991,12 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
let argument_type = self.get_last_instruction_type();
|
let argument_type = self.get_last_instruction_type();
|
||||||
let argument_register = match argument_type {
|
let argument_register = match argument_type {
|
||||||
Type::Boolean => self.register_usage.next_boolean_register(),
|
Type::Boolean => self.next_boolean_register(),
|
||||||
Type::Byte => self.register_usage.next_byte_register(),
|
Type::Byte => self.next_byte_register(),
|
||||||
Type::Character => self.register_usage.next_character_register(),
|
Type::Character => self.next_character_register(),
|
||||||
Type::Float => self.register_usage.next_float_register(),
|
Type::Float => self.next_float_register(),
|
||||||
Type::Integer => self.register_usage.next_integer_register(),
|
Type::Integer => self.next_integer_register(),
|
||||||
Type::String => self.register_usage.next_string_register(),
|
Type::String => self.next_string_register(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1897,8 +2010,14 @@ impl<'src> Compiler<'src> {
|
|||||||
self.argument_lists.push(argument_list);
|
self.argument_lists.push(argument_list);
|
||||||
|
|
||||||
let end = self.current_position.1;
|
let end = self.current_position.1;
|
||||||
let destination = self.register_usage.next_function_register();
|
let destination = self.next_function_register();
|
||||||
let call = Instruction::call(destination, function_register, argument_count, is_recursive);
|
let call = Instruction::call(
|
||||||
|
destination,
|
||||||
|
function_register,
|
||||||
|
argument_count,
|
||||||
|
return_type_code,
|
||||||
|
is_recursive,
|
||||||
|
);
|
||||||
|
|
||||||
self.emit_instruction(call, function_return_type, Span(start, end));
|
self.emit_instruction(call, function_return_type, Span(start, end));
|
||||||
|
|
||||||
@ -1949,90 +2068,3 @@ impl<'src> Compiler<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct RegisterUsage {
|
|
||||||
boolean: u16,
|
|
||||||
byte: u16,
|
|
||||||
character: u16,
|
|
||||||
float: u16,
|
|
||||||
integer: u16,
|
|
||||||
string: u16,
|
|
||||||
list: u16,
|
|
||||||
function: u16,
|
|
||||||
argument: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegisterUsage {
|
|
||||||
fn next_boolean_register(&mut self) -> u16 {
|
|
||||||
let register = self.boolean;
|
|
||||||
|
|
||||||
self.boolean += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_byte_register(&mut self) -> u16 {
|
|
||||||
let register = self.byte;
|
|
||||||
|
|
||||||
self.byte += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_character_register(&mut self) -> u16 {
|
|
||||||
let register = self.character;
|
|
||||||
|
|
||||||
self.character += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_float_register(&mut self) -> u16 {
|
|
||||||
let register = self.float;
|
|
||||||
|
|
||||||
self.float += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_integer_register(&mut self) -> u16 {
|
|
||||||
let register = self.integer;
|
|
||||||
|
|
||||||
self.integer += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_string_register(&mut self) -> u16 {
|
|
||||||
let register = self.string;
|
|
||||||
|
|
||||||
self.string += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_list_register(&mut self) -> u16 {
|
|
||||||
let register = self.list;
|
|
||||||
|
|
||||||
self.list += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_function_register(&mut self) -> u16 {
|
|
||||||
let register = self.function;
|
|
||||||
|
|
||||||
self.function += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_argument_register(&mut self) -> u16 {
|
|
||||||
let register = self.argument;
|
|
||||||
|
|
||||||
self.argument += 1;
|
|
||||||
|
|
||||||
register
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -58,12 +58,17 @@ impl Display for Add {
|
|||||||
left,
|
left,
|
||||||
left_type,
|
left_type,
|
||||||
right,
|
right,
|
||||||
right_type,
|
right_type: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
write!(
|
match *left_type {
|
||||||
f,
|
TypeCode::CHARACTER => write!(f, "R_STR_{destination}")?,
|
||||||
"R{destination} = {left}({left_type}) + {right}({right_type})",
|
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?,
|
||||||
)
|
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
|
||||||
|
TypeCode::STRING => write!(f, "R_STR_{destination}")?,
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, " = {left} + {right}",)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,13 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::{InstructionBuilder, TypeCode};
|
||||||
|
|
||||||
pub struct Call {
|
pub struct Call {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
pub function_register: u16,
|
pub function_register: u16,
|
||||||
pub argument_count: u16,
|
pub argument_count: u16,
|
||||||
|
pub return_type: TypeCode,
|
||||||
pub is_recursive: bool,
|
pub is_recursive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,12 +17,14 @@ impl From<Instruction> for Call {
|
|||||||
let destination = instruction.a_field();
|
let destination = instruction.a_field();
|
||||||
let function_register = instruction.b_field();
|
let function_register = instruction.b_field();
|
||||||
let argument_count = instruction.c_field();
|
let argument_count = instruction.c_field();
|
||||||
|
let return_type = instruction.b_type();
|
||||||
let is_recursive = instruction.d_field();
|
let is_recursive = instruction.d_field();
|
||||||
|
|
||||||
Call {
|
Call {
|
||||||
destination,
|
destination,
|
||||||
function_register,
|
function_register,
|
||||||
argument_count,
|
argument_count,
|
||||||
|
return_type,
|
||||||
is_recursive,
|
is_recursive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,6 +34,7 @@ impl From<Call> for Instruction {
|
|||||||
fn from(call: Call) -> Self {
|
fn from(call: Call) -> Self {
|
||||||
let a_field = call.destination;
|
let a_field = call.destination;
|
||||||
let b_field = call.function_register;
|
let b_field = call.function_register;
|
||||||
|
let b_type = call.return_type;
|
||||||
let c_field = call.argument_count;
|
let c_field = call.argument_count;
|
||||||
let d_field = call.is_recursive;
|
let d_field = call.is_recursive;
|
||||||
|
|
||||||
@ -38,6 +42,7 @@ impl From<Call> for Instruction {
|
|||||||
operation: Operation::CALL,
|
operation: Operation::CALL,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
b_type,
|
||||||
c_field,
|
c_field,
|
||||||
d_field,
|
d_field,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -56,15 +56,12 @@ impl Display for Less {
|
|||||||
let Less {
|
let Less {
|
||||||
comparator,
|
comparator,
|
||||||
left,
|
left,
|
||||||
left_type,
|
left_type: _,
|
||||||
right,
|
right,
|
||||||
right_type,
|
right_type: _,
|
||||||
} = self;
|
} = self;
|
||||||
let operator = if *comparator { "<" } else { "≥" };
|
let operator = if *comparator { "<" } else { "≥" };
|
||||||
|
|
||||||
write!(
|
write!(f, "if {left} {operator} {right} {{ JUMP +1 }}")
|
||||||
f,
|
|
||||||
"if {left_type}({left}) {operator} {right_type}({right}) {{ JUMP +1 }}"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,15 +56,12 @@ impl Display for LessEqual {
|
|||||||
let LessEqual {
|
let LessEqual {
|
||||||
comparator,
|
comparator,
|
||||||
left,
|
left,
|
||||||
left_type,
|
left_type: _,
|
||||||
right,
|
right,
|
||||||
right_type,
|
right_type: _,
|
||||||
} = self;
|
} = self;
|
||||||
let operator = if *comparator { "≤" } else { ">" };
|
let operator = if *comparator { "≤" } else { ">" };
|
||||||
|
|
||||||
write!(
|
write!(f, "if {left} {operator} {right} {{ JUMP +1 }}")
|
||||||
f,
|
|
||||||
"if {left_type}({left}) {operator} {right_type}({right}) {{ JUMP +1 }}"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,9 +52,9 @@ impl Display for LoadEncoded {
|
|||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
match *r#type {
|
match *r#type {
|
||||||
TypeCode::BOOLEAN => write!(f, "R{destination} = {}", *value != 0)?,
|
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} = {}", *value != 0)?,
|
||||||
TypeCode::BYTE => write!(f, "R{destination} = {value}")?,
|
TypeCode::BYTE => write!(f, "R_BYTE_{destination} = {value}")?,
|
||||||
unsupported => unsupported.panic_from_unsupported_code(),
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
if *jump_next {
|
if *jump_next {
|
||||||
|
@ -148,7 +148,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
pub use type_code::TypeCode;
|
pub use type_code::TypeCode;
|
||||||
|
|
||||||
use crate::NativeFunction;
|
use crate::{NativeFunction, Type};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct InstructionBuilder {
|
pub struct InstructionBuilder {
|
||||||
@ -261,15 +261,21 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_a_field(&mut self, bits: u16) {
|
pub fn set_a_field(&mut self, bits: u16) {
|
||||||
self.0 = (bits as u64) << 31;
|
let mut builder = InstructionBuilder::from(&*self);
|
||||||
|
builder.a_field = bits;
|
||||||
|
*self = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_b_field(&mut self, bits: u16) {
|
pub fn set_b_field(&mut self, bits: u16) {
|
||||||
self.0 = (bits as u64) << 47;
|
let mut builder = InstructionBuilder::from(&*self);
|
||||||
|
builder.b_field = bits;
|
||||||
|
*self = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_c_field(&mut self, bits: u16) {
|
pub fn set_c_field(&mut self, bits: u16) {
|
||||||
self.0 = (bits as u64) << 63;
|
let mut builder = InstructionBuilder::from(&*self);
|
||||||
|
builder.c_field = bits;
|
||||||
|
*self = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point(destination: u16, to: u16, r#type: TypeCode) -> Instruction {
|
pub fn point(destination: u16, to: u16, r#type: TypeCode) -> Instruction {
|
||||||
@ -498,12 +504,14 @@ impl Instruction {
|
|||||||
destination: u16,
|
destination: u16,
|
||||||
function_register: u16,
|
function_register: u16,
|
||||||
argument_count: u16,
|
argument_count: u16,
|
||||||
|
return_type: TypeCode,
|
||||||
is_recursive: bool,
|
is_recursive: bool,
|
||||||
) -> Instruction {
|
) -> Instruction {
|
||||||
Instruction::from(Call {
|
Instruction::from(Call {
|
||||||
destination,
|
destination,
|
||||||
function_register,
|
function_register,
|
||||||
argument_count,
|
argument_count,
|
||||||
|
return_type,
|
||||||
is_recursive,
|
is_recursive,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -520,9 +528,14 @@ impl Instruction {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#return(should_return_value: bool, return_register: u16) -> Instruction {
|
pub fn r#return(
|
||||||
|
should_return_value: bool,
|
||||||
|
return_type: TypeCode,
|
||||||
|
return_register: u16,
|
||||||
|
) -> Instruction {
|
||||||
Instruction::from(Return {
|
Instruction::from(Return {
|
||||||
should_return_value,
|
should_return_value,
|
||||||
|
return_type,
|
||||||
return_register,
|
return_register,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -537,7 +550,13 @@ impl Instruction {
|
|||||||
|
|
||||||
pub fn as_argument(&self) -> Option<Operand> {
|
pub fn as_argument(&self) -> Option<Operand> {
|
||||||
match self.operation() {
|
match self.operation() {
|
||||||
Operation::LOAD_CONSTANT => Some(Operand::Constant(self.b_field())),
|
Operation::LOAD_CONSTANT => match self.b_type() {
|
||||||
|
TypeCode::CHARACTER => Some(Operand::ConstantCharacter(self.b_field())),
|
||||||
|
TypeCode::FLOAT => Some(Operand::ConstantFloat(self.b_field())),
|
||||||
|
TypeCode::INTEGER => Some(Operand::ConstantInteger(self.b_field())),
|
||||||
|
TypeCode::STRING => Some(Operand::ConstantString(self.b_field())),
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
},
|
||||||
Operation::LOAD_ENCODED
|
Operation::LOAD_ENCODED
|
||||||
| Operation::LOAD_LIST
|
| Operation::LOAD_LIST
|
||||||
| Operation::LOAD_SELF
|
| Operation::LOAD_SELF
|
||||||
@ -551,12 +570,28 @@ impl Instruction {
|
|||||||
| Operation::LESS_EQUAL
|
| Operation::LESS_EQUAL
|
||||||
| Operation::NEGATE
|
| Operation::NEGATE
|
||||||
| Operation::NOT
|
| Operation::NOT
|
||||||
| Operation::CALL => Some(Operand::Register(self.a_field())),
|
| Operation::CALL => match self.b_type() {
|
||||||
|
TypeCode::BOOLEAN => Some(Operand::RegisterBoolean(self.b_field())),
|
||||||
|
TypeCode::BYTE => Some(Operand::RegisterByte(self.b_field())),
|
||||||
|
TypeCode::CHARACTER => Some(Operand::RegisterCharacter(self.b_field())),
|
||||||
|
TypeCode::FLOAT => Some(Operand::RegisterFloat(self.b_field())),
|
||||||
|
TypeCode::INTEGER => Some(Operand::RegisterInteger(self.b_field())),
|
||||||
|
TypeCode::STRING => Some(Operand::RegisterString(self.b_field())),
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
},
|
||||||
Operation::CALL_NATIVE => {
|
Operation::CALL_NATIVE => {
|
||||||
let function = NativeFunction::from(self.b_field());
|
let function = NativeFunction::from(self.b_field());
|
||||||
|
|
||||||
if function.returns_value() {
|
if function.returns_value() {
|
||||||
Some(Operand::Register(self.a_field()))
|
match function.r#type().return_type {
|
||||||
|
Type::Boolean => Some(Operand::RegisterBoolean(self.b_field())),
|
||||||
|
Type::Byte => Some(Operand::RegisterByte(self.b_field())),
|
||||||
|
Type::Character => Some(Operand::RegisterCharacter(self.b_field())),
|
||||||
|
Type::Float => Some(Operand::RegisterFloat(self.b_field())),
|
||||||
|
Type::Integer => Some(Operand::RegisterInteger(self.b_field())),
|
||||||
|
Type::String => Some(Operand::RegisterString(self.b_field())),
|
||||||
|
unsupported => panic!("{unsupported} type is not supported here"),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -567,22 +602,46 @@ impl Instruction {
|
|||||||
|
|
||||||
pub fn b_as_argument(&self) -> Operand {
|
pub fn b_as_argument(&self) -> Operand {
|
||||||
if self.b_is_constant() {
|
if self.b_is_constant() {
|
||||||
Operand::Constant(self.b_field())
|
match self.b_type() {
|
||||||
|
TypeCode::CHARACTER => Operand::ConstantCharacter(self.b_field()),
|
||||||
|
TypeCode::FLOAT => Operand::ConstantFloat(self.b_field()),
|
||||||
|
TypeCode::INTEGER => Operand::ConstantInteger(self.b_field()),
|
||||||
|
TypeCode::STRING => Operand::ConstantString(self.b_field()),
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Operand::Register(self.b_field())
|
match self.b_type() {
|
||||||
|
TypeCode::BOOLEAN => Operand::RegisterBoolean(self.b_field()),
|
||||||
|
TypeCode::BYTE => Operand::RegisterByte(self.b_field()),
|
||||||
|
TypeCode::CHARACTER => Operand::RegisterCharacter(self.b_field()),
|
||||||
|
TypeCode::FLOAT => Operand::RegisterFloat(self.b_field()),
|
||||||
|
TypeCode::INTEGER => Operand::RegisterInteger(self.b_field()),
|
||||||
|
TypeCode::STRING => Operand::RegisterString(self.b_field()),
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn b_and_c_as_operands(&self) -> (Operand, Operand) {
|
pub fn b_and_c_as_operands(&self) -> (Operand, Operand) {
|
||||||
let left = if self.b_is_constant() {
|
let left = self.b_as_argument();
|
||||||
Operand::Constant(self.b_field())
|
|
||||||
} else {
|
|
||||||
Operand::Register(self.b_field())
|
|
||||||
};
|
|
||||||
let right = if self.c_is_constant() {
|
let right = if self.c_is_constant() {
|
||||||
Operand::Constant(self.c_field())
|
match self.c_type() {
|
||||||
|
TypeCode::CHARACTER => Operand::ConstantCharacter(self.c_field()),
|
||||||
|
TypeCode::FLOAT => Operand::ConstantFloat(self.c_field()),
|
||||||
|
TypeCode::INTEGER => Operand::ConstantInteger(self.c_field()),
|
||||||
|
TypeCode::STRING => Operand::ConstantString(self.c_field()),
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Operand::Register(self.c_field())
|
match self.c_type() {
|
||||||
|
TypeCode::BOOLEAN => Operand::RegisterBoolean(self.c_field()),
|
||||||
|
TypeCode::BYTE => Operand::RegisterByte(self.c_field()),
|
||||||
|
TypeCode::CHARACTER => Operand::RegisterCharacter(self.c_field()),
|
||||||
|
TypeCode::FLOAT => Operand::RegisterFloat(self.c_field()),
|
||||||
|
TypeCode::INTEGER => Operand::RegisterInteger(self.c_field()),
|
||||||
|
TypeCode::STRING => Operand::RegisterString(self.c_field()),
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(left, right)
|
(left, right)
|
||||||
@ -668,30 +727,68 @@ impl Display for Instruction {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Operand {
|
pub enum Operand {
|
||||||
Constant(u16),
|
ConstantCharacter(u16),
|
||||||
Register(u16),
|
ConstantFloat(u16),
|
||||||
|
ConstantInteger(u16),
|
||||||
|
ConstantString(u16),
|
||||||
|
RegisterBoolean(u16),
|
||||||
|
RegisterByte(u16),
|
||||||
|
RegisterCharacter(u16),
|
||||||
|
RegisterFloat(u16),
|
||||||
|
RegisterInteger(u16),
|
||||||
|
RegisterString(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operand {
|
impl Operand {
|
||||||
pub fn index(&self) -> u16 {
|
pub fn index(&self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
Operand::Constant(index) => *index,
|
Operand::ConstantCharacter(index) => *index,
|
||||||
Operand::Register(index) => *index,
|
Operand::ConstantFloat(index) => *index,
|
||||||
|
Operand::ConstantInteger(index) => *index,
|
||||||
|
Operand::ConstantString(index) => *index,
|
||||||
|
Operand::RegisterBoolean(index) => *index,
|
||||||
|
Operand::RegisterByte(index) => *index,
|
||||||
|
Operand::RegisterCharacter(index) => *index,
|
||||||
|
Operand::RegisterFloat(index) => *index,
|
||||||
|
Operand::RegisterInteger(index) => *index,
|
||||||
|
Operand::RegisterString(index) => *index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_constant(&self) -> bool {
|
pub fn is_constant(&self) -> bool {
|
||||||
matches!(self, Operand::Constant(_))
|
matches!(
|
||||||
|
self,
|
||||||
|
Operand::ConstantCharacter(_)
|
||||||
|
| Operand::ConstantFloat(_)
|
||||||
|
| Operand::ConstantInteger(_)
|
||||||
|
| Operand::ConstantString(_)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_register(&self) -> bool {
|
pub fn is_register(&self) -> bool {
|
||||||
matches!(self, Operand::Register(_))
|
matches!(
|
||||||
|
self,
|
||||||
|
Operand::RegisterBoolean(_)
|
||||||
|
| Operand::RegisterByte(_)
|
||||||
|
| Operand::RegisterCharacter(_)
|
||||||
|
| Operand::RegisterFloat(_)
|
||||||
|
| Operand::RegisterInteger(_)
|
||||||
|
| Operand::RegisterString(_)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_index_and_constant_flag(&self) -> (u16, bool) {
|
pub fn as_index_and_constant_flag(&self) -> (u16, bool) {
|
||||||
match self {
|
match self {
|
||||||
Operand::Constant(index) => (*index, true),
|
Operand::ConstantCharacter(index) => (*index, true),
|
||||||
Operand::Register(index) => (*index, false),
|
Operand::ConstantFloat(index) => (*index, true),
|
||||||
|
Operand::ConstantInteger(index) => (*index, true),
|
||||||
|
Operand::ConstantString(index) => (*index, true),
|
||||||
|
Operand::RegisterBoolean(index) => (*index, false),
|
||||||
|
Operand::RegisterByte(index) => (*index, false),
|
||||||
|
Operand::RegisterCharacter(index) => (*index, false),
|
||||||
|
Operand::RegisterFloat(index) => (*index, false),
|
||||||
|
Operand::RegisterInteger(index) => (*index, false),
|
||||||
|
Operand::RegisterString(index) => (*index, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -699,8 +796,16 @@ impl Operand {
|
|||||||
impl Display for Operand {
|
impl Display for Operand {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Operand::Constant(index) => write!(f, "C{index}"),
|
Operand::ConstantCharacter(index) => write!(f, "C_CHAR_{index}"),
|
||||||
Operand::Register(index) => write!(f, "R{index}"),
|
Operand::ConstantFloat(index) => write!(f, "C_FLOAT_{index}"),
|
||||||
|
Operand::ConstantInteger(index) => write!(f, "C_INT_{index}"),
|
||||||
|
Operand::ConstantString(index) => write!(f, "C_STR_{index}"),
|
||||||
|
Operand::RegisterBoolean(index) => write!(f, "R_BOOL_{index}"),
|
||||||
|
Operand::RegisterByte(index) => write!(f, "R_BYTE_{index}"),
|
||||||
|
Operand::RegisterCharacter(index) => write!(f, "R_CHAR_{index}"),
|
||||||
|
Operand::RegisterFloat(index) => write!(f, "R_FLOAT_{index}"),
|
||||||
|
Operand::RegisterInteger(index) => write!(f, "R_INT_{index}"),
|
||||||
|
Operand::RegisterString(index) => write!(f, "R_STR_{index}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -713,9 +818,9 @@ mod tests {
|
|||||||
fn decode_operation() {
|
fn decode_operation() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(40),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -726,9 +831,9 @@ mod tests {
|
|||||||
fn decode_a_field() {
|
fn decode_a_field() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -739,9 +844,9 @@ mod tests {
|
|||||||
fn decode_b_field() {
|
fn decode_b_field() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -752,9 +857,9 @@ mod tests {
|
|||||||
fn decode_c_field() {
|
fn decode_c_field() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -765,22 +870,22 @@ mod tests {
|
|||||||
fn decode_d_field() {
|
fn decode_d_field() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(instruction.d_field());
|
assert!(!instruction.d_field());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_b_is_constant() {
|
fn decode_b_is_constant() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -791,9 +896,9 @@ mod tests {
|
|||||||
fn decode_c_is_constant() {
|
fn decode_c_is_constant() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -804,9 +909,9 @@ mod tests {
|
|||||||
fn decode_b_type() {
|
fn decode_b_type() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -817,9 +922,9 @@ mod tests {
|
|||||||
fn decode_c_type() {
|
fn decode_c_type() {
|
||||||
let instruction = Instruction::add(
|
let instruction = Instruction::add(
|
||||||
42,
|
42,
|
||||||
Operand::Constant(4),
|
Operand::ConstantInteger(4),
|
||||||
TypeCode::STRING,
|
TypeCode::STRING,
|
||||||
Operand::Register(2),
|
Operand::RegisterInteger(2),
|
||||||
TypeCode::CHARACTER,
|
TypeCode::CHARACTER,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ impl Display for Point {
|
|||||||
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} = R_FLOAT_{to}"),
|
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} = R_FLOAT_{to}"),
|
||||||
TypeCode::INTEGER => write!(f, "R_INT_{destination} = R_INT_{to}"),
|
TypeCode::INTEGER => write!(f, "R_INT_{destination} = R_INT_{to}"),
|
||||||
TypeCode::STRING => write!(f, "R_STR_{destination} = R_STR_{to}"),
|
TypeCode::STRING => write!(f, "R_STR_{destination} = R_STR_{to}"),
|
||||||
unsupported => unsupported.panic_from_unsupported_code(),
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,23 @@ 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_type: TypeCode,
|
||||||
pub return_register: u16,
|
pub return_register: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
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_type = instruction.b_type();
|
||||||
let return_register = instruction.c_field();
|
let return_register = instruction.c_field();
|
||||||
|
|
||||||
Return {
|
Return {
|
||||||
should_return_value,
|
should_return_value,
|
||||||
|
return_type,
|
||||||
return_register,
|
return_register,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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.return_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()
|
||||||
}
|
}
|
||||||
@ -41,11 +46,20 @@ impl Display for Return {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
let Return {
|
let Return {
|
||||||
should_return_value,
|
should_return_value,
|
||||||
|
return_type,
|
||||||
return_register,
|
return_register,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
if *should_return_value {
|
if *should_return_value {
|
||||||
write!(f, "RETURN R{return_register}")
|
match *return_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_STR_{return_register}"),
|
||||||
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
write!(f, "RETURN")
|
write!(f, "RETURN")
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,6 @@ impl Display for Test {
|
|||||||
} = self;
|
} = self;
|
||||||
let bang = if *test_value { "" } else { "!" };
|
let bang = if *test_value { "" } else { "!" };
|
||||||
|
|
||||||
write!(f, "if {bang}R{operand_register} {{ JUMP +1 }}")
|
write!(f, "if {bang}R_BOOL_{operand_register} {{ JUMP +1 }}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,6 @@ impl TypeCode {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panic_from_unsupported_code(self) -> ! {
|
|
||||||
panic!("Type code {} is not supported in the context", self.0,);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for TypeCode {
|
impl Display for TypeCode {
|
||||||
|
@ -91,7 +91,7 @@ pub fn point(instruction: InstructionBuilder, thread: &mut Thread) {
|
|||||||
TypeCode::STRING => {
|
TypeCode::STRING => {
|
||||||
thread.set_string_register(destination, Register::Pointer(Pointer::Register(to)));
|
thread.set_string_register(destination, Register::Pointer(Pointer::Register(to)));
|
||||||
}
|
}
|
||||||
unsupported => unsupported.panic_from_unsupported_code(),
|
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user