diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index ce90131..4995ab2 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -437,7 +437,13 @@ impl<'a> ChunkDisassembler<'a> { }; let jump_offset = if let Some(jump_offset) = jump_offset { let index = index as isize; - let jump_index = index + jump_offset + 1; + let jump_index = { + if jump_offset > 0 { + index + (jump_offset + 1) + } else { + index + jump_offset + } + }; format!("{index} -> {jump_index}") } else { diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 90f4f9c..b6db338 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -345,11 +345,13 @@ impl<'src> Parser<'src> { fn handle_binary_argument( &mut self, instruction: &Instruction, - ) -> Result<(bool, bool, u8), ParseError> { + ) -> Result<(bool, bool, bool, u8), ParseError> { let mut push_back = false; let mut is_constant = false; + let mut is_local = false; let argument = match instruction.operation() { Operation::GetLocal => { + is_local = true; let local_index = instruction.b(); let local = self.chunk.get_local(local_index, self.current_position)?; @@ -378,13 +380,13 @@ impl<'src> Parser<'src> { } }; - Ok((push_back, is_constant, argument)) + Ok((push_back, is_constant, is_local, argument)) } fn parse_math_binary(&mut self) -> Result<(), ParseError> { let (left_instruction, left_position) = self.chunk.pop_instruction(self.current_position)?; - let (push_back_left, left_is_constant, left) = + let (push_back_left, left_is_constant, left_is_local, left) = self.handle_binary_argument(&left_instruction)?; let operator = self.current_token; @@ -394,12 +396,21 @@ impl<'src> Parser<'src> { self.advance()?; self.parse(rule.precedence.increment())?; + let register = if left_is_local { + left + } else { + let current = self.current_register; + + self.increment_register()?; + + current + }; let mut new_instruction = match operator.kind() { - TokenKind::Plus => Instruction::add(self.current_register, left, 0), - TokenKind::Minus => Instruction::subtract(self.current_register, left, 0), - TokenKind::Star => Instruction::multiply(self.current_register, left, 0), - TokenKind::Slash => Instruction::divide(self.current_register, left, 0), - TokenKind::Percent => Instruction::modulo(self.current_register, left, 0), + TokenKind::Plus => Instruction::add(register, left, 0), + TokenKind::Minus => Instruction::subtract(register, left, 0), + TokenKind::Star => Instruction::multiply(register, left, 0), + TokenKind::Slash => Instruction::divide(register, left, 0), + TokenKind::Percent => Instruction::modulo(register, left, 0), _ => { return Err(ParseError::ExpectedTokenMultiple { expected: &[ @@ -415,11 +426,9 @@ impl<'src> Parser<'src> { } }; - self.increment_register()?; - let (right_instruction, right_position) = self.chunk.pop_instruction(self.current_position)?; - let (push_back_right, right_is_constant, right) = + let (push_back_right, right_is_constant, right_is_local, right) = self.handle_binary_argument(&right_instruction)?; new_instruction.set_c(right); @@ -476,7 +485,7 @@ impl<'src> Parser<'src> { fn parse_comparison_binary(&mut self) -> Result<(), ParseError> { let (left_instruction, left_position) = self.chunk.pop_instruction(self.current_position)?; - let (push_back_left, left_is_constant, left) = + let (push_back_left, left_is_constant, _, left) = self.handle_binary_argument(&left_instruction)?; let operator = self.current_token; @@ -510,7 +519,7 @@ impl<'src> Parser<'src> { let (right_instruction, right_position) = self.chunk.pop_instruction(self.current_position)?; - let (push_back_right, right_is_constant, right) = + let (push_back_right, right_is_constant, _, right) = self.handle_binary_argument(&right_instruction)?; instruction.set_c(right); @@ -771,14 +780,14 @@ impl<'src> Parser<'src> { self.parse_block(allow_assignment, allow_return)?; let jump_end = self.chunk.len(); - let jump_distance = jump_end.saturating_sub(jump_start) as u8; + let jump_distance = jump_end.abs_diff(jump_start) as u8; let jump_back = Instruction::jump(jump_distance, false); let jump_over_index = self.chunk.find_last_instruction(Operation::Jump); if let Some(index) = jump_over_index { - let (mut jump_over, jump_over_position) = self.chunk.remove_instruction(index); + let (_, jump_over_position) = self.chunk.remove_instruction(index); + let jump_over = Instruction::jump(jump_distance - 1, true); - jump_over.set_b(jump_distance); self.chunk .insert_instruction(index, jump_over, jump_over_position); } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index fcd3c05..75a86bc 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -356,7 +356,7 @@ impl Vm { let new_ip = if is_positive { self.ip + offset as usize } else { - self.ip - offset as usize + self.ip - (offset + 1) as usize }; self.ip = new_ip; diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index 0a3ba3e..b738329 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -332,7 +332,33 @@ fn if_else_expression() { } #[test] -fn if_expression() { +fn if_expression_false() { + let source = "if 1 == 2 { 2 }"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::equal(true, 0, 1) + .set_b_is_constant() + .set_c_is_constant(), + Span(5, 7) + ), + (Instruction::jump(1, true), Span(5, 7)), + (Instruction::load_constant(0, 2, false), Span(12, 13)), + (Instruction::r#return(), Span(15, 15)), + ], + vec![Value::integer(1), Value::integer(2), Value::integer(2)], + vec![] + )), + ); + + assert_eq!(run(source), Ok(None)); +} + +#[test] +fn if_expression_true() { let source = "if 1 == 1 { 2 }"; assert_eq!( @@ -730,12 +756,15 @@ fn subtract() { assert_eq!( parse(source), Ok(Chunk::with_data( - vec![( - *Instruction::subtract(0, 0, 1) - .set_b_is_constant() - .set_c_is_constant(), - Span(2, 3) - ),], + vec![ + ( + *Instruction::subtract(0, 0, 1) + .set_b_is_constant() + .set_c_is_constant(), + Span(2, 3) + ), + (Instruction::r#return(), Span(5, 5)), + ], vec![Value::integer(1), Value::integer(2)], vec![] )) @@ -759,6 +788,7 @@ fn variable_and() { (Instruction::test(2, false), Span(31, 33)), (Instruction::jump(1, true), Span(31, 33)), (Instruction::get_local(3, 1), Span(34, 35)), + (Instruction::r#return(), Span(35, 35)), ], vec![], vec![ @@ -779,23 +809,20 @@ fn r#while() { parse(source), Ok(Chunk::with_data( vec![ - (Instruction::load_constant(0, 0, false), Span(0, 1)), - (Instruction::define_local(0, 0, true), Span(0, 0)), + (Instruction::load_constant(0, 0, false), Span(12, 13)), + (Instruction::define_local(0, 0, true), Span(8, 9)), ( - *Instruction::less(false, 0, 1) - .set_b_is_constant() - .set_c_is_constant(), - Span(0, 1) + *Instruction::less(true, 0, 1).set_c_is_constant(), + Span(23, 24) ), - (Instruction::jump(1, true), Span(0, 1)), - (Instruction::load_boolean(1, true, true), Span(0, 1)), - (Instruction::load_boolean(1, false, false), Span(0, 1)), - (Instruction::add(0, 0, 2), Span(0, 1)), - (Instruction::jump(0, false), Span(0, 1)), - (Instruction::get_local(3, 0), Span(0, 1)), + (Instruction::jump(2, true), Span(23, 24)), + (*Instruction::add(0, 0, 2).set_c_is_constant(), Span(39, 40)), + (Instruction::jump(3, false), Span(41, 42)), + (Instruction::get_local(1, 0), Span(41, 42)), + (Instruction::r#return(), Span(42, 42)), ], - vec![], - vec![] + vec![Value::integer(0), Value::integer(5), Value::integer(1),], + vec![Local::new(Identifier::new("x"), true, 0, Some(0)),] )), );