Fix compiling of comparison expressions; Implement LoadEncoded in the VM
This commit is contained in:
parent
1155b5fff8
commit
72421bf510
@ -282,9 +282,13 @@ impl<'src> Compiler<'src> {
|
|||||||
self.instructions
|
self.instructions
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|(instruction, r#type, _)| {
|
.find_map(|(instruction, _, _)| {
|
||||||
if r#type == &Type::Byte && instruction.yields_value() {
|
if instruction.operation() == Operation::LOAD_ENCODED {
|
||||||
Some(instruction.a_field() + 1)
|
if instruction.b_type() == TypeCode::BYTE {
|
||||||
|
Some(instruction.a_field() + 1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -530,46 +534,6 @@ impl<'src> Compiler<'src> {
|
|||||||
.unwrap_or(Type::None)
|
.unwrap_or(Type::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_register_type(&self, register_index: u16) -> Result<Type, CompileError> {
|
|
||||||
if let Some(r#type) = self.locals.iter().find_map(|local| {
|
|
||||||
if local.register_index == register_index {
|
|
||||||
Some(local.r#type.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
return Ok(r#type);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (instruction, r#type, _) in &self.instructions {
|
|
||||||
if !instruction.yields_value() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let operation = instruction.operation();
|
|
||||||
|
|
||||||
if let Operation::LOAD_LIST = operation {
|
|
||||||
let LoadList { start_register, .. } = LoadList::from(*instruction);
|
|
||||||
let item_type = self.get_register_type(start_register)?;
|
|
||||||
|
|
||||||
return Ok(Type::List(Box::new(item_type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Operation::LOAD_SELF = operation {
|
|
||||||
return Ok(Type::SelfFunction);
|
|
||||||
}
|
|
||||||
|
|
||||||
if instruction.yields_value() {
|
|
||||||
return Ok(r#type.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(CompileError::CannotResolveRegisterType {
|
|
||||||
register_index: register_index as usize,
|
|
||||||
position: self.current_position,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates [`Self::type`] with the given [Type] as `return_type`.
|
/// Updates [`Self::type`] with the given [Type] as `return_type`.
|
||||||
///
|
///
|
||||||
/// If [`Self::type`] is already set, it will check if the given [Type] is compatible.
|
/// If [`Self::type`] is already set, it will check if the given [Type] is compatible.
|
||||||
@ -831,9 +795,13 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_binary_argument(&mut self, instruction: &Instruction) -> (Operand, bool) {
|
fn handle_binary_argument(&mut self, instruction: &Instruction) -> (Operand, bool) {
|
||||||
let (argument, push_back) = (instruction.as_operand(), !instruction.yields_value());
|
let operand = instruction.as_operand();
|
||||||
|
let push_back = match instruction.operation() {
|
||||||
|
Operation::LOAD_ENCODED | Operation::LOAD_SELF => true,
|
||||||
|
_ => !instruction.yields_value(),
|
||||||
|
};
|
||||||
|
|
||||||
(argument, push_back)
|
(operand, push_back)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_math_binary(&mut self) -> Result<(), CompileError> {
|
fn parse_math_binary(&mut self) -> Result<(), CompileError> {
|
||||||
@ -875,14 +843,18 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
check_math_type(&left_type, operator, &left_position)?;
|
check_math_type(&left_type, operator, &left_position)?;
|
||||||
|
|
||||||
let destination = match left_type {
|
let destination = if is_assignment {
|
||||||
Type::Boolean => self.next_boolean_register(),
|
left.index()
|
||||||
Type::Byte => self.next_byte_register(),
|
} else {
|
||||||
Type::Character => self.next_character_register(),
|
match left_type {
|
||||||
Type::Float => self.next_float_register(),
|
Type::Boolean => self.next_boolean_register(),
|
||||||
Type::Integer => self.next_integer_register(),
|
Type::Byte => self.next_byte_register(),
|
||||||
Type::String => self.next_string_register(),
|
Type::Character => self.next_character_register(),
|
||||||
_ => unreachable!(),
|
Type::Float => self.next_float_register(),
|
||||||
|
Type::Integer => self.next_integer_register(),
|
||||||
|
Type::String => self.next_string_register(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_assignment && !left_is_mutable_local {
|
if is_assignment && !left_is_mutable_local {
|
||||||
@ -964,28 +936,15 @@ impl<'src> Compiler<'src> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let (left_instruction, left_type, left_position) =
|
|
||||||
self.instructions
|
|
||||||
.pop()
|
|
||||||
.ok_or_else(|| CompileError::ExpectedExpression {
|
|
||||||
found: self.previous_token.to_owned(),
|
|
||||||
position: self.previous_position,
|
|
||||||
})?;
|
|
||||||
let (left, push_back_left) = self.handle_binary_argument(&left_instruction);
|
|
||||||
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);
|
||||||
|
|
||||||
// TODO: Check if the left type is a valid type for comparison
|
|
||||||
|
|
||||||
if push_back_left {
|
|
||||||
self.instructions
|
|
||||||
.push((left_instruction, left_type, left_position));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse_sub_expression(&rule.precedence)?;
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
|
|
||||||
|
println!("{:?}", self.instructions);
|
||||||
|
|
||||||
let (right_instruction, right_type, right_position) =
|
let (right_instruction, right_type, right_position) =
|
||||||
self.instructions
|
self.instructions
|
||||||
.pop()
|
.pop()
|
||||||
@ -993,17 +952,32 @@ 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_instruction, left_type, left_position) =
|
||||||
|
self.instructions
|
||||||
|
.pop()
|
||||||
|
.ok_or_else(|| CompileError::ExpectedExpression {
|
||||||
|
found: self.previous_token.to_owned(),
|
||||||
|
position: self.previous_position,
|
||||||
|
})?;
|
||||||
|
let (left, push_back_left) = self.handle_binary_argument(&left_instruction);
|
||||||
let (right, push_back_right) = self.handle_binary_argument(&right_instruction);
|
let (right, push_back_right) = self.handle_binary_argument(&right_instruction);
|
||||||
|
|
||||||
|
println!("{left_instruction} {right_instruction}");
|
||||||
|
|
||||||
|
// TODO: Check if the left type is a valid type for comparison
|
||||||
// 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
|
||||||
|
|
||||||
|
if push_back_left {
|
||||||
|
self.instructions
|
||||||
|
.push((left_instruction, left_type, left_position));
|
||||||
|
}
|
||||||
|
|
||||||
if push_back_right {
|
if push_back_right {
|
||||||
self.instructions
|
self.instructions
|
||||||
.push((right_instruction, right_type, right_position));
|
.push((right_instruction, right_type, right_position));
|
||||||
}
|
}
|
||||||
|
|
||||||
let destination = self.next_boolean_register();
|
|
||||||
let comparison = match operator {
|
let comparison = match operator {
|
||||||
Token::DoubleEqual => Instruction::equal(true, left, right),
|
Token::DoubleEqual => Instruction::equal(true, left, right),
|
||||||
Token::BangEqual => Instruction::equal(false, left, right),
|
Token::BangEqual => Instruction::equal(false, left, right),
|
||||||
@ -1027,6 +1001,7 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let jump = Instruction::jump(1, true);
|
let jump = Instruction::jump(1, true);
|
||||||
|
let destination = self.next_boolean_register();
|
||||||
let load_true =
|
let load_true =
|
||||||
Instruction::load_encoded(destination, true as u16, TypeCode::BOOLEAN, true);
|
Instruction::load_encoded(destination, true as u16, TypeCode::BOOLEAN, true);
|
||||||
let load_false =
|
let load_false =
|
||||||
@ -1471,7 +1446,7 @@ impl<'src> Compiler<'src> {
|
|||||||
self.instructions
|
self.instructions
|
||||||
.insert(block_start, (jump, Type::None, self.current_position));
|
.insert(block_start, (jump, Type::None, self.current_position));
|
||||||
|
|
||||||
let jump_back_distance = (block_end - expression_start + 1) as u16;
|
let jump_back_distance = (block_end - expression_start) as u16;
|
||||||
let jump_back = Instruction::from(Jump {
|
let jump_back = Instruction::from(Jump {
|
||||||
offset: jump_back_distance,
|
offset: jump_back_distance,
|
||||||
is_positive: false,
|
is_positive: false,
|
||||||
@ -1611,10 +1586,10 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
fn parse_implicit_return(&mut self) -> Result<(), CompileError> {
|
fn parse_implicit_return(&mut self) -> Result<(), CompileError> {
|
||||||
if matches!(self.get_last_operation(), Some(Operation::POINT)) {
|
if matches!(self.get_last_operation(), Some(Operation::POINT)) {
|
||||||
let Point { destination, to } = Point::from(self.instructions.last().unwrap().0);
|
let Point { to, .. } = Point::from(self.instructions.last().unwrap().0);
|
||||||
|
|
||||||
let (_, r#type, _) = self.instructions.pop().unwrap();
|
let (_, r#type, _) = self.instructions.pop().unwrap();
|
||||||
let r#return = Instruction::r#return(true, destination, to.as_type());
|
let r#return = Instruction::r#return(true, to.index(), to.as_type());
|
||||||
|
|
||||||
self.emit_instruction(r#return, r#type, self.current_position);
|
self.emit_instruction(r#return, r#type, self.current_position);
|
||||||
} else if matches!(self.get_last_operation(), Some(Operation::RETURN))
|
} else if matches!(self.get_last_operation(), Some(Operation::RETURN))
|
||||||
@ -1715,7 +1690,7 @@ impl<'src> Compiler<'src> {
|
|||||||
let r#type = if let Some(r#type) = explicit_type {
|
let r#type = if let Some(r#type) = explicit_type {
|
||||||
r#type
|
r#type
|
||||||
} else {
|
} else {
|
||||||
self.get_register_type(register_index)?
|
self.get_last_instruction_type()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.declare_local(
|
self.declare_local(
|
||||||
|
@ -281,9 +281,9 @@ impl Instruction {
|
|||||||
pub fn as_operand(&self) -> Operand {
|
pub fn as_operand(&self) -> Operand {
|
||||||
match self.operation() {
|
match self.operation() {
|
||||||
Operation::POINT => {
|
Operation::POINT => {
|
||||||
let Point { destination, to } = Point::from(*self);
|
let Point { to, .. } = Point::from(*self);
|
||||||
|
|
||||||
Operand::Register(destination, to.as_type())
|
Operand::Register(to.index(), to.as_type())
|
||||||
}
|
}
|
||||||
Operation::LOAD_ENCODED => {
|
Operation::LOAD_ENCODED => {
|
||||||
let LoadEncoded {
|
let LoadEncoded {
|
||||||
@ -664,24 +664,24 @@ 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, r#type) => match *r#type {
|
Operand::Constant(index, r#type) => match *r#type {
|
||||||
TypeCode::BOOLEAN => write!(f, "C_{}", index),
|
|
||||||
TypeCode::CHARACTER => write!(f, "C_{}", index),
|
TypeCode::CHARACTER => write!(f, "C_{}", index),
|
||||||
TypeCode::INTEGER => write!(f, "C_{}", index),
|
TypeCode::INTEGER => write!(f, "C_{}", index),
|
||||||
TypeCode::FLOAT => write!(f, "C_{}", index),
|
TypeCode::FLOAT => write!(f, "C_{}", index),
|
||||||
TypeCode::STRING => write!(f, "C_{}", index),
|
TypeCode::STRING => write!(f, "C_{}", index),
|
||||||
TypeCode::LIST => write!(f, "C_{}", index),
|
TypeCode::LIST => write!(f, "C_{}", index),
|
||||||
TypeCode::FUNCTION => write!(f, "C_{}", index),
|
TypeCode::FUNCTION => write!(f, "C_{}", index),
|
||||||
_ => panic!("Unknown type code: {}", r#type.0),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
Operand::Register(index, r#type) => match *r#type {
|
Operand::Register(index, r#type) => match *r#type {
|
||||||
TypeCode::BOOLEAN => write!(f, "R_BOOL_{}", index),
|
TypeCode::BOOLEAN => write!(f, "R_BOOL_{}", index),
|
||||||
|
TypeCode::BYTE => write!(f, "R_BYTE_{}", index),
|
||||||
TypeCode::CHARACTER => write!(f, "R_CHAR_{}", index),
|
TypeCode::CHARACTER => write!(f, "R_CHAR_{}", index),
|
||||||
TypeCode::INTEGER => write!(f, "R_INT_{}", index),
|
TypeCode::INTEGER => write!(f, "R_INT_{}", index),
|
||||||
TypeCode::FLOAT => write!(f, "R_FLOAT_{}", index),
|
TypeCode::FLOAT => write!(f, "R_FLOAT_{}", index),
|
||||||
TypeCode::STRING => write!(f, "R_STR_{}", index),
|
TypeCode::STRING => write!(f, "R_STR_{}", index),
|
||||||
TypeCode::LIST => write!(f, "R_LIST_{}", index),
|
TypeCode::LIST => write!(f, "R_LIST_{}", index),
|
||||||
TypeCode::FUNCTION => write!(f, "R_FN_{}", index),
|
TypeCode::FUNCTION => write!(f, "R_FN_{}", index),
|
||||||
_ => panic!("Unknown type code: {}", r#type.0),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ pub type RunnerLogic = fn(InstructionFields, &mut Thread);
|
|||||||
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [
|
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [
|
||||||
point,
|
point,
|
||||||
close,
|
close,
|
||||||
load_boolean,
|
load_encoded,
|
||||||
load_constant,
|
load_constant,
|
||||||
load_function,
|
load_function,
|
||||||
load_list,
|
load_list,
|
||||||
@ -72,7 +72,30 @@ pub fn point(_: InstructionFields, thread: &mut Thread) {}
|
|||||||
|
|
||||||
pub fn close(_: InstructionFields, thread: &mut Thread) {}
|
pub fn close(_: InstructionFields, thread: &mut Thread) {}
|
||||||
|
|
||||||
pub fn load_boolean(_: InstructionFields, _: &mut Thread) {}
|
pub fn load_encoded(instruction: InstructionFields, thread: &mut Thread) {
|
||||||
|
let destination = instruction.a_field;
|
||||||
|
let value = instruction.b_field;
|
||||||
|
let value_type = instruction.b_type;
|
||||||
|
let jump_next = instruction.c_field != 0;
|
||||||
|
|
||||||
|
match value_type {
|
||||||
|
TypeCode::BOOLEAN => {
|
||||||
|
let register = Register::Value(value != 0);
|
||||||
|
|
||||||
|
thread.set_boolean_register(destination as usize, register);
|
||||||
|
}
|
||||||
|
TypeCode::BYTE => {
|
||||||
|
let register = Register::Value(value as u8);
|
||||||
|
|
||||||
|
thread.set_byte_register(destination as usize, register);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if jump_next {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) {
|
pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) {
|
||||||
let destination = instruction.a_field as usize;
|
let destination = instruction.a_field as usize;
|
||||||
@ -152,6 +175,30 @@ pub fn add(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
|
|
||||||
thread.set_integer_register(destination, register);
|
thread.set_integer_register(destination, register);
|
||||||
}
|
}
|
||||||
|
(TypeCode::BYTE, TypeCode::BYTE) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_byte().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_byte_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_byte().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_byte_register(right)
|
||||||
|
};
|
||||||
|
let sum = left_value + right_value;
|
||||||
|
let register = Register::Value(sum);
|
||||||
|
|
||||||
|
thread.set_byte_register(destination, register);
|
||||||
|
}
|
||||||
(TypeCode::STRING, TypeCode::STRING) => {
|
(TypeCode::STRING, TypeCode::STRING) => {
|
||||||
let left_value = if left_is_constant {
|
let left_value = if left_is_constant {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
@ -241,6 +288,31 @@ pub fn less(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
thread.current_frame_mut().ip += 1;
|
thread.current_frame_mut().ip += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(TypeCode::BYTE, TypeCode::BYTE) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_byte().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_byte_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_byte().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_byte_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value < right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +386,7 @@ mod tests {
|
|||||||
const ALL_OPERATIONS: [(Operation, RunnerLogic); 23] = [
|
const ALL_OPERATIONS: [(Operation, RunnerLogic); 23] = [
|
||||||
(Operation::POINT, point),
|
(Operation::POINT, point),
|
||||||
(Operation::CLOSE, close),
|
(Operation::CLOSE, close),
|
||||||
(Operation::LOAD_ENCODED, load_boolean),
|
(Operation::LOAD_ENCODED, load_encoded),
|
||||||
(Operation::LOAD_CONSTANT, load_constant),
|
(Operation::LOAD_CONSTANT, load_constant),
|
||||||
(Operation::LOAD_FUNCTION, load_function),
|
(Operation::LOAD_FUNCTION, load_function),
|
||||||
(Operation::LOAD_LIST, load_list),
|
(Operation::LOAD_LIST, load_list),
|
||||||
|
@ -53,10 +53,7 @@ impl Thread {
|
|||||||
unsafe { current_frame.action_sequence.actions.get_unchecked_mut(ip) }
|
unsafe { current_frame.action_sequence.actions.get_unchecked_mut(ip) }
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!(
|
trace!("Instruction: {}", current_action.instruction.operation);
|
||||||
"Instruction operation: {}",
|
|
||||||
current_action.instruction.operation
|
|
||||||
);
|
|
||||||
|
|
||||||
(current_action.logic)(current_action.instruction, &mut self);
|
(current_action.logic)(current_action.instruction, &mut self);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user