From 72421bf510974403a9eb1b1d64baa9f95b874488 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 7 Feb 2025 13:29:14 -0500 Subject: [PATCH] Fix compiling of comparison expressions; Implement LoadEncoded in the VM --- dust-lang/src/compiler/mod.rs | 121 ++++++++++++------------------- dust-lang/src/instruction/mod.rs | 10 +-- dust-lang/src/vm/action.rs | 78 +++++++++++++++++++- dust-lang/src/vm/thread.rs | 5 +- 4 files changed, 129 insertions(+), 85 deletions(-) diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index 53f3491..d00ab41 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -282,9 +282,13 @@ impl<'src> Compiler<'src> { self.instructions .iter() .rev() - .find_map(|(instruction, r#type, _)| { - if r#type == &Type::Byte && instruction.yields_value() { - Some(instruction.a_field() + 1) + .find_map(|(instruction, _, _)| { + if instruction.operation() == Operation::LOAD_ENCODED { + if instruction.b_type() == TypeCode::BYTE { + Some(instruction.a_field() + 1) + } else { + None + } } else { None } @@ -530,46 +534,6 @@ impl<'src> Compiler<'src> { .unwrap_or(Type::None) } - fn get_register_type(&self, register_index: u16) -> Result { - 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`. /// /// 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) { - 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> { @@ -875,14 +843,18 @@ impl<'src> Compiler<'src> { check_math_type(&left_type, operator, &left_position)?; - let destination = 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!(), + let destination = if is_assignment { + left.index() + } else { + 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!(), + } }; 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_position = self.current_position; 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.parse_sub_expression(&rule.precedence)?; + println!("{:?}", self.instructions); + let (right_instruction, right_type, right_position) = self.instructions .pop() @@ -993,17 +952,32 @@ impl<'src> Compiler<'src> { found: self.previous_token.to_owned(), 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); + 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 left and right types are compatible + if push_back_left { + self.instructions + .push((left_instruction, left_type, left_position)); + } + if push_back_right { self.instructions .push((right_instruction, right_type, right_position)); } - let destination = self.next_boolean_register(); let comparison = match operator { Token::DoubleEqual => Instruction::equal(true, left, right), Token::BangEqual => Instruction::equal(false, left, right), @@ -1027,6 +1001,7 @@ impl<'src> Compiler<'src> { } }; let jump = Instruction::jump(1, true); + let destination = self.next_boolean_register(); let load_true = Instruction::load_encoded(destination, true as u16, TypeCode::BOOLEAN, true); let load_false = @@ -1471,7 +1446,7 @@ impl<'src> Compiler<'src> { self.instructions .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 { offset: jump_back_distance, is_positive: false, @@ -1611,10 +1586,10 @@ impl<'src> Compiler<'src> { fn parse_implicit_return(&mut self) -> Result<(), CompileError> { 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#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); } 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 { r#type } else { - self.get_register_type(register_index)? + self.get_last_instruction_type() }; self.declare_local( diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index 3ac87e8..2d08305 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -281,9 +281,9 @@ impl Instruction { pub fn as_operand(&self) -> Operand { match self.operation() { 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 => { let LoadEncoded { @@ -664,24 +664,24 @@ impl Display for Operand { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Operand::Constant(index, r#type) => match *r#type { - TypeCode::BOOLEAN => write!(f, "C_{}", index), TypeCode::CHARACTER => write!(f, "C_{}", index), TypeCode::INTEGER => write!(f, "C_{}", index), TypeCode::FLOAT => write!(f, "C_{}", index), TypeCode::STRING => write!(f, "C_{}", index), TypeCode::LIST => 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 { TypeCode::BOOLEAN => write!(f, "R_BOOL_{}", index), + TypeCode::BYTE => write!(f, "R_BYTE_{}", index), TypeCode::CHARACTER => write!(f, "R_CHAR_{}", index), TypeCode::INTEGER => write!(f, "R_INT_{}", index), TypeCode::FLOAT => write!(f, "R_FLOAT_{}", index), TypeCode::STRING => write!(f, "R_STR_{}", index), TypeCode::LIST => write!(f, "R_LIST_{}", index), TypeCode::FUNCTION => write!(f, "R_FN_{}", index), - _ => panic!("Unknown type code: {}", r#type.0), + _ => unreachable!(), }, } } diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action.rs index 80a08dc..42c01ad 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action.rs @@ -45,7 +45,7 @@ pub type RunnerLogic = fn(InstructionFields, &mut Thread); pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [ point, close, - load_boolean, + load_encoded, load_constant, load_function, load_list, @@ -72,7 +72,30 @@ pub fn point(_: 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) { 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); } + (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) => { let left_value = if left_is_constant { if cfg!(debug_assertions) { @@ -241,6 +288,31 @@ pub fn less(instruction: InstructionFields, thread: &mut Thread) { 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!(), } } @@ -314,7 +386,7 @@ mod tests { const ALL_OPERATIONS: [(Operation, RunnerLogic); 23] = [ (Operation::POINT, point), (Operation::CLOSE, close), - (Operation::LOAD_ENCODED, load_boolean), + (Operation::LOAD_ENCODED, load_encoded), (Operation::LOAD_CONSTANT, load_constant), (Operation::LOAD_FUNCTION, load_function), (Operation::LOAD_LIST, load_list), diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index dcbb4ba..2db34bb 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -53,10 +53,7 @@ impl Thread { unsafe { current_frame.action_sequence.actions.get_unchecked_mut(ip) } }; - trace!( - "Instruction operation: {}", - current_action.instruction.operation - ); + trace!("Instruction: {}", current_action.instruction.operation); (current_action.logic)(current_action.instruction, &mut self);