diff --git a/dust-lang/Cargo.toml b/dust-lang/Cargo.toml index da8fe02..c6993bb 100644 --- a/dust-lang/Cargo.toml +++ b/dust-lang/Cargo.toml @@ -38,3 +38,7 @@ harness = false [[bench]] name = "threads" harness = false + +[[test]] +name = "add" +path = "tests/math/add.rs" diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index 8310e6e..775a5ab 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -269,7 +269,7 @@ impl<'src> Compiler<'src> { .iter() .rev() .find_map(|(instruction, r#type, _)| { - if r#type == &Type::Boolean && instruction.yields_value() { + if instruction.b_type() == TypeCode::BOOLEAN && instruction.yields_value() { Some(instruction.a_field() + 1) } else { None @@ -301,7 +301,10 @@ impl<'src> Compiler<'src> { .iter() .rev() .find_map(|(instruction, r#type, _)| { - if r#type == &Type::Character && instruction.yields_value() { + if instruction.b_type() == TypeCode::CHARACTER + && r#type == &Type::Character + && instruction.yields_value() + { Some(instruction.a_field() + 1) } else { None @@ -314,8 +317,8 @@ impl<'src> Compiler<'src> { self.instructions .iter() .rev() - .find_map(|(instruction, r#type, _)| { - if r#type == &Type::Float && instruction.yields_value() { + .find_map(|(instruction, _, _)| { + if instruction.b_type() == TypeCode::FLOAT && instruction.yields_value() { Some(instruction.a_field() + 1) } else { None @@ -329,7 +332,7 @@ impl<'src> Compiler<'src> { .iter() .rev() .find_map(|(instruction, r#type, _)| { - if r#type == &Type::Integer && instruction.yields_value() { + if r#type == &Type::Integer { Some(instruction.a_field() + 1) } else { None @@ -343,7 +346,10 @@ impl<'src> Compiler<'src> { .iter() .rev() .find_map(|(instruction, r#type, _)| { - if r#type == &Type::String && instruction.yields_value() { + if instruction.b_type() == TypeCode::STRING + && r#type == &Type::String + && instruction.yields_value() + { Some(instruction.a_field() + 1) } else { None @@ -358,7 +364,11 @@ impl<'src> Compiler<'src> { .rev() .find_map(|(instruction, r#type, _)| { if let Type::List(_) = r#type { - Some(instruction.a_field() + 1) + if instruction.yields_value() { + Some(instruction.a_field() + 1) + } else { + None + } } else { None } @@ -370,10 +380,8 @@ impl<'src> Compiler<'src> { self.instructions .iter() .rev() - .find_map(|(instruction, r#type, _)| { - if matches!(r#type, Type::Function(_) | Type::SelfFunction) - && instruction.yields_value() - { + .find_map(|(instruction, _, _)| { + if instruction.b_type() == TypeCode::FUNCTION && instruction.yields_value() { Some(instruction.a_field() + 1) } else { None @@ -858,6 +866,10 @@ impl<'src> Compiler<'src> { self.advance()?; self.parse_sub_expression(&rule.precedence)?; + if is_assignment { + self.allow(Token::Semicolon)?; + } + let (right_instruction, right_type, right_position) = self.instructions.pop().unwrap(); let (right, push_back_right) = self.handle_binary_argument(&right_instruction); @@ -1164,25 +1176,7 @@ impl<'src> Compiler<'src> { let (math_instruction, _, _) = self.instructions.last_mut().unwrap(); math_instruction.set_a_field(local_register_index); - } else { - let register = match local_type { - Type::Boolean => self.next_boolean_register(), - Type::Byte => self.next_byte_register(), - Type::Character => self.next_character_register(), - Type::Float => self.next_float_register(), - Type::Integer => self.next_integer_register(), - Type::String => self.next_string_register(), - _ => todo!(), - }; - let point = Instruction::point( - local_register_index, - Operand::Register(register, local_type.type_code()), - ); - - self.emit_instruction(point, local_type, start_position); } - - return Ok(()); } let destination = match local_type { @@ -1262,25 +1256,12 @@ impl<'src> Compiler<'src> { if item_type == Type::None { item_type = self.get_last_instruction_type(); + } else { + // TODO: Check if the item type the same as the previous item type } if start_register.is_none() { - let first_index = match item_type { - Type::Boolean => self.next_boolean_register() - 1, - Type::Byte => self.next_byte_register() - 1, - Type::Character => self.next_character_register() - 1, - Type::Float => self.next_float_register() - 1, - Type::Integer => self.next_integer_register() - 1, - Type::String => self.next_string_register() - 1, - Type::List(_) => self.next_list_register() - 1, - Type::None => { - return Err(CompileError::ExpectedExpression { - found: self.previous_token.to_owned(), - position: self.previous_position, - }); - } - _ => todo!(), - }; + let first_index = self.instructions.last().unwrap().0.a_field(); start_register = Some(first_index); } @@ -1369,12 +1350,12 @@ impl<'src> Compiler<'src> { } } Type::List(_) => { - let used_list_registers = self.next_list_register() - next_list_register - 1; + let used_list_registers = self.next_list_register() - next_list_register; if used_list_registers > 1 { let close = Instruction::close( next_list_register, - next_list_register + used_list_registers - 1, + self.next_list_register() - 2, TypeCode::LIST, ); @@ -1387,13 +1368,13 @@ impl<'src> Compiler<'src> { let end = self.previous_position.1; let end_register = match item_type { - Type::Boolean => self.next_boolean_register() - 1, - Type::Byte => self.next_byte_register() - 1, - Type::Character => self.next_character_register() - 1, - Type::Float => self.next_float_register() - 1, - Type::Integer => self.next_integer_register() - 1, - Type::String => self.next_string_register() - 1, - Type::List(_) => self.next_list_register() - 1, + Type::Boolean => self.next_boolean_register().saturating_sub(1), + Type::Byte => self.next_byte_register().saturating_sub(1), + Type::Character => self.next_character_register().saturating_sub(1), + Type::Float => self.next_float_register().saturating_sub(1), + Type::Integer => self.next_integer_register().saturating_sub(1), + Type::String => self.next_string_register().saturating_sub(1), + Type::List(_) => self.next_list_register().saturating_sub(1), _ => todo!(), }; let destination = self.next_list_register(); @@ -1636,11 +1617,6 @@ impl<'src> Compiler<'src> { Ok(()) } - fn parse_semicolon(&mut self) -> Result<(), CompileError> { - self.advance()?; - self.parse(Precedence::None) - } - fn parse_expression(&mut self) -> Result<(), CompileError> { self.parse(Precedence::None)?; @@ -1732,8 +1708,18 @@ impl<'src> Compiler<'src> { if matches!(self.get_last_operation(), Some(Operation::POINT)) { let Point { to, .. } = Point::from(self.instructions.last().unwrap().0); - let (_, r#type, _) = self.instructions.pop().unwrap(); - let r#return = Instruction::r#return(true, to.index(), to.as_type()); + let (point, r#type, position) = self.instructions.pop().unwrap(); + let (should_return, target_register) = if r#type == Type::None { + (false, 0) + } else { + (true, to.index()) + }; + let r#return = + Instruction::r#return(should_return, target_register, r#type.type_code()); + + if !should_return { + self.instructions.push((point, r#type.clone(), position)); + } self.emit_instruction(r#return, r#type, self.current_position); } else if matches!(self.get_last_operation(), Some(Operation::RETURN)) @@ -1821,6 +1807,7 @@ impl<'src> Compiler<'src> { self.expect(Token::Equal)?; self.parse_expression()?; + self.allow(Token::Semicolon)?; let register_index = match self.get_last_instruction_type() { Type::Boolean => self.next_boolean_register() - 1, diff --git a/dust-lang/src/compiler/parse_rule.rs b/dust-lang/src/compiler/parse_rule.rs index 90261c5..1317b42 100644 --- a/dust-lang/src/compiler/parse_rule.rs +++ b/dust-lang/src/compiler/parse_rule.rs @@ -237,7 +237,7 @@ impl From<&Token<'_>> for ParseRule<'_> { precedence: Precedence::None, }, Token::Semicolon => ParseRule { - prefix: Some(Compiler::parse_semicolon), + prefix: None, infix: None, precedence: Precedence::None, }, diff --git a/dust-lang/src/instruction/point.rs b/dust-lang/src/instruction/point.rs index 93bd206..68cd9af 100644 --- a/dust-lang/src/instruction/point.rs +++ b/dust-lang/src/instruction/point.rs @@ -42,12 +42,12 @@ impl Display for Point { let Point { destination, to } = self; match to.as_type() { - TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} -> R_BOOL_{to}"), - TypeCode::BYTE => write!(f, "R_BYTE_{destination} -> R_BYTE_{to}"), - TypeCode::CHARACTER => write!(f, "R_CHAR_{destination} -> R_CHAR_{to}"), - TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} -> R_FLOAT_{to}"), - TypeCode::INTEGER => write!(f, "R_INT_{destination} -> R_INT_{to}"), - TypeCode::STRING => write!(f, "R_STR_{destination} -> R_STR_{to}"), + TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} -> {to}"), + TypeCode::BYTE => write!(f, "R_BYTE_{destination} -> {to}"), + TypeCode::CHARACTER => write!(f, "R_CHAR_{destination} -> {to}"), + TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} -> {to}"), + TypeCode::INTEGER => write!(f, "R_INT_{destination} -> {to}"), + TypeCode::STRING => write!(f, "R_STR_{destination} -> {to}"), unsupported => write!( f, "Unsupported type code: {unsupported} for Point instruction" diff --git a/dust-lang/src/instruction/return.rs b/dust-lang/src/instruction/return.rs index 7e3a926..3a95459 100644 --- a/dust-lang/src/instruction/return.rs +++ b/dust-lang/src/instruction/return.rs @@ -62,7 +62,7 @@ impl Display for Return { TypeCode::STRING => write!(f, "R_STR_{return_register}"), TypeCode::LIST => write!(f, "R_LIST_{return_register}"), TypeCode::FUNCTION => write!(f, "R_FN_{return_register}"), - unsupported => unreachable!("Unsupported return type: {:?}", unsupported), + unsupported => unreachable!("Unsupported return type: {}", unsupported), } } else { write!(f, "RETURN") diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action.rs index 27d37a4..e390c9a 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action.rs @@ -68,7 +68,112 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [ r#return, ]; -pub fn point(_: InstructionFields, thread: &mut Thread) {} +pub fn point(instruction: InstructionFields, thread: &mut Thread) { + let destination = instruction.a_field as usize; + let to = instruction.b_field as usize; + let to_is_constant = instruction.b_is_constant; + let r#type = instruction.b_type; + + match r#type { + TypeCode::BOOLEAN => { + let boolean = if to_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(to).as_boolean().unwrap() + } else { + unsafe { thread.get_constant(to).as_boolean().unwrap_unchecked() } + } + } else { + thread.get_boolean_register(to) + }; + let register = Register::Value(*boolean); + + thread.set_boolean_register(destination, register); + } + TypeCode::BYTE => { + let byte = if to_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(to).as_byte().unwrap() + } else { + unsafe { thread.get_constant(to).as_byte().unwrap_unchecked() } + } + } else { + thread.get_byte_register(to) + }; + let register = Register::Value(*byte); + + thread.set_byte_register(destination, register); + } + TypeCode::CHARACTER => { + let character = if to_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(to).as_character().unwrap() + } else { + unsafe { thread.get_constant(to).as_character().unwrap_unchecked() } + } + } else { + thread.get_character_register(to) + }; + let register = Register::Value(*character); + + thread.set_character_register(destination, register); + } + TypeCode::FLOAT => { + let float = if to_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(to).as_float().unwrap() + } else { + unsafe { thread.get_constant(to).as_float().unwrap_unchecked() } + } + } else { + thread.get_float_register(to) + }; + let register = Register::Value(*float); + + thread.set_float_register(destination, register); + } + TypeCode::INTEGER => { + let integer = if to_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(to).as_integer().unwrap() + } else { + unsafe { thread.get_constant(to).as_integer().unwrap_unchecked() } + } + } else { + thread.get_integer_register(to) + }; + let register = Register::Value(*integer); + + thread.set_integer_register(destination, register); + } + TypeCode::STRING => { + let string = if to_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(to).as_string().unwrap().clone() + } else { + unsafe { + thread + .get_constant(to) + .as_string() + .unwrap_unchecked() + .clone() + } + } + } else { + thread.get_string_register(to).clone() + }; + let register = Register::Value(string); + + thread.set_string_register(destination, register); + } + TypeCode::LIST => { + let list = thread.get_list_register(to).clone(); + let register = Register::Value(list); + + thread.set_list_register(destination, register); + } + _ => unimplemented!(), + } +} pub fn close(instruction: InstructionFields, thread: &mut Thread) { let from = instruction.b_field as usize; @@ -599,7 +704,9 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) { let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len()); for pointer in &abstract_list.item_pointers { - concrete_list.push(thread.get_value_from_pointer(pointer)); + let value = thread.get_value_from_pointer(pointer); + + concrete_list.push(value); } thread.return_value = diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index bc81301..cf22f54 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -122,7 +122,9 @@ impl Thread { let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len()); for pointer in &abstract_list.item_pointers { - concrete_list.push(self.get_value_from_pointer(pointer)); + let value = self.get_value_from_pointer(pointer); + + concrete_list.push(value); } ConcreteValue::List(concrete_list) diff --git a/dust-lang/tests/add.rs b/dust-lang/tests/math/add.rs similarity index 100% rename from dust-lang/tests/add.rs rename to dust-lang/tests/math/add.rs