diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index fc3569a..b2ff1b2 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -938,7 +938,7 @@ impl<'src> Compiler<'src> { self.instructions .push((last_instruction, last_type, last_position)); - self.next_register() - 1 + self.next_register().saturating_sub(1) }; let operator = self.current_token; let operator_position = self.current_position; @@ -962,11 +962,17 @@ impl<'src> Compiler<'src> { self.advance()?; self.parse_sub_expression(&rule.precedence)?; - let instructions_length = self.instructions.len() - 1; + let instructions_length = self.instructions.len(); for (group_index, instructions) in self.instructions.rchunks_mut(3).enumerate().rev() { - if instructions[0].0.operation() != Operation::TEST - || instructions[1].0.operation() != Operation::JUMP + if instructions.len() < 3 { + continue; + } + + if !matches!( + instructions[0].0.operation(), + Operation::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL + ) || !matches!(instructions[1].0.operation(), Operation::JUMP) { continue; } @@ -1152,10 +1158,29 @@ impl<'src> Compiler<'src> { self.advance()?; self.parse_expression()?; - let operand_register = self.next_register() - 1; - let test = Instruction::test(operand_register, true); + let emit_test_and_jump = if matches!( + self.get_last_operations(), + Some([ + Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, + Operation::JUMP, + Operation::LOAD_BOOLEAN, + Operation::LOAD_BOOLEAN + ]), + ) { + self.instructions.pop(); + self.instructions.pop(); - self.emit_instruction(test, Type::None, self.current_position); + false + } else { + true + }; + + if emit_test_and_jump { + let operand_register = self.next_register() - 1; + let test = Instruction::test(operand_register, true); + + self.emit_instruction(test, Type::None, self.current_position); + } let if_block_start = self.instructions.len(); let if_block_start_position = self.current_position; @@ -1173,7 +1198,7 @@ impl<'src> Compiler<'src> { let if_block_end = self.instructions.len(); let mut if_block_distance = (if_block_end - if_block_start) as u8; let if_block_type = self.get_last_instruction_type(); - let if_last_register = self.next_register().saturating_sub(1); + // let if_last_register = self.next_register().saturating_sub(1); if let Token::Else = self.current_token { self.advance()?; @@ -1236,19 +1261,21 @@ impl<'src> Compiler<'src> { } } - let jump = Instruction::jump(if_block_distance, true); + if emit_test_and_jump { + let jump = Instruction::jump(if_block_distance, true); - self.instructions - .insert(if_block_start, (jump, Type::None, if_block_start_position)); + self.instructions + .insert(if_block_start, (jump, Type::None, if_block_start_position)); + } control_flow_register_consolidation(self); - let else_last_register = self.next_register().saturating_sub(1); - let point = Instruction::point(else_last_register, if_last_register); + // let else_last_register = self.next_register().saturating_sub(1); + // let point = Instruction::point(else_last_register, if_last_register); - if if_last_register < else_last_register { - self.emit_instruction(point, else_block_type, self.current_position); - } + // if if_last_register < else_last_register { + // self.emit_instruction(point, else_block_type, self.current_position); + // } Ok(()) } @@ -1406,6 +1433,22 @@ impl<'src> Compiler<'src> { self.emit_instruction(r#return, Type::None, Span(start, end)); + let instruction_length = self.instructions.len(); + + for (index, (instruction, _, _)) in self.instructions.iter_mut().enumerate() { + if instruction.operation() == Operation::JUMP { + let Jump { + offset, + is_positive, + } = Jump::from(&*instruction); + let offset = offset as usize; + + if is_positive && offset + index == instruction_length - 2 { + *instruction = Instruction::jump((offset + 1) as u8, true); + } + } + } + Ok(()) } @@ -1432,6 +1475,22 @@ impl<'src> Compiler<'src> { self.emit_instruction(r#return, Type::None, self.current_position); } + let instruction_length = self.instructions.len(); + + for (index, (instruction, _, _)) in self.instructions.iter_mut().enumerate() { + if instruction.operation() == Operation::JUMP { + let Jump { + offset, + is_positive, + } = Jump::from(&*instruction); + let offset = offset as usize; + + if is_positive && offset + index == instruction_length - 2 { + *instruction = Instruction::jump((offset + 1) as u8, true); + } + } + } + Ok(()) } diff --git a/dust-lang/src/native_function/io.rs b/dust-lang/src/native_function/io.rs index 3b74b28..382e0e5 100644 --- a/dust-lang/src/native_function/io.rs +++ b/dust-lang/src/native_function/io.rs @@ -41,15 +41,16 @@ pub fn write( let mut stdout = stdout(); for register_index in argument_range { - let value = record.open_register(register_index); - let string = value.display(record); + if let Some(value) = record.open_register_allow_empty(register_index) { + let string = value.display(record); - stdout - .write(string.as_bytes()) - .map_err(|io_error| NativeFunctionError::Io { - error: io_error.kind(), - position: record.current_position(), - })?; + stdout + .write(string.as_bytes()) + .map_err(|io_error| NativeFunctionError::Io { + error: io_error.kind(), + position: record.current_position(), + })?; + } } stdout.flush().map_err(|io_error| NativeFunctionError::Io { @@ -68,21 +69,22 @@ pub fn write_line( let mut stdout = stdout().lock(); for register_index in argument_range { - let value = record.open_register(register_index); - let string = value.display(record); + if let Some(value) = record.open_register_allow_empty(register_index) { + let string = value.display(record); - stdout - .write(string.as_bytes()) - .map_err(|io_error| NativeFunctionError::Io { - error: io_error.kind(), - position: record.current_position(), - })?; - stdout - .write(b"\n") - .map_err(|io_error| NativeFunctionError::Io { - error: io_error.kind(), - position: record.current_position(), - })?; + stdout + .write(string.as_bytes()) + .map_err(|io_error| NativeFunctionError::Io { + error: io_error.kind(), + position: record.current_position(), + })?; + stdout + .write(b"\n") + .map_err(|io_error| NativeFunctionError::Io { + error: io_error.kind(), + position: record.current_position(), + })?; + } } stdout.flush().map_err(|io_error| NativeFunctionError::Io { diff --git a/dust-lang/src/vm/call_stack.rs b/dust-lang/src/vm/call_stack.rs index e727124..345ee1b 100644 --- a/dust-lang/src/vm/call_stack.rs +++ b/dust-lang/src/vm/call_stack.rs @@ -38,6 +38,10 @@ impl CallStack { self.calls.last() } + pub fn last_mut(&mut self) -> Option<&mut FunctionCall> { + self.calls.last_mut() + } + pub fn pop_or_panic(&mut self) -> FunctionCall { assert!(!self.is_empty(), "{}", VmError::CallStackUnderflow); diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index 1dcf1b9..71aadea 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -82,7 +82,10 @@ impl Thread { if record_index == active.index() as usize { trace!("Recursion detected"); - self.call_stack.last_mut_or_panic().ip = active.ip; + if let Some(record) = self.call_stack.last_mut() { + record.ip = active.ip; + } + active.ip = 0; } @@ -133,10 +136,8 @@ impl Thread { } } }; - let outer_call = self.call_stack.last_or_panic(); - let record_index = outer_call.record_index as usize; - - trace!("Return from {returning_call} to {outer_call}"); + let outer_call = self.call_stack.last(); + let record_index = outer_call.map_or(0, |call| call.record_index as usize); if should_return_value { let return_register = active @@ -153,7 +154,7 @@ impl Thread { ); } else { active = &mut self.records[record_index]; - active.ip = outer_call.ip; + active.ip = record_index; } } } diff --git a/examples/fibonacci.ds b/examples/fibonacci.ds index a0f4e09..6a59bba 100644 --- a/examples/fibonacci.ds +++ b/examples/fibonacci.ds @@ -5,4 +5,4 @@ fn fib (n: int) -> int { fib(n - 1) + fib(n - 2) } -write_line(fib(1)) +write_line(fib(0))