Add jump incrementing when emitting return instructions
This commit is contained in:
parent
86bdf0bc37
commit
10c66b3f95
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,4 @@ fn fib (n: int) -> int {
|
||||
fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
|
||||
write_line(fib(1))
|
||||
write_line(fib(0))
|
||||
|
Loading…
Reference in New Issue
Block a user