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
|
self.instructions
|
||||||
.push((last_instruction, last_type, last_position));
|
.push((last_instruction, last_type, last_position));
|
||||||
|
|
||||||
self.next_register() - 1
|
self.next_register().saturating_sub(1)
|
||||||
};
|
};
|
||||||
let operator = self.current_token;
|
let operator = self.current_token;
|
||||||
let operator_position = self.current_position;
|
let operator_position = self.current_position;
|
||||||
@ -962,11 +962,17 @@ impl<'src> Compiler<'src> {
|
|||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse_sub_expression(&rule.precedence)?;
|
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() {
|
for (group_index, instructions) in self.instructions.rchunks_mut(3).enumerate().rev() {
|
||||||
if instructions[0].0.operation() != Operation::TEST
|
if instructions.len() < 3 {
|
||||||
|| instructions[1].0.operation() != Operation::JUMP
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matches!(
|
||||||
|
instructions[0].0.operation(),
|
||||||
|
Operation::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL
|
||||||
|
) || !matches!(instructions[1].0.operation(), Operation::JUMP)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1152,10 +1158,29 @@ impl<'src> Compiler<'src> {
|
|||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
let operand_register = self.next_register() - 1;
|
let emit_test_and_jump = if matches!(
|
||||||
let test = Instruction::test(operand_register, true);
|
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 = self.instructions.len();
|
||||||
let if_block_start_position = self.current_position;
|
let if_block_start_position = self.current_position;
|
||||||
@ -1173,7 +1198,7 @@ impl<'src> Compiler<'src> {
|
|||||||
let if_block_end = self.instructions.len();
|
let if_block_end = self.instructions.len();
|
||||||
let mut if_block_distance = (if_block_end - if_block_start) as u8;
|
let mut if_block_distance = (if_block_end - if_block_start) as u8;
|
||||||
let if_block_type = self.get_last_instruction_type();
|
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 {
|
if let Token::Else = self.current_token {
|
||||||
self.advance()?;
|
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
|
self.instructions
|
||||||
.insert(if_block_start, (jump, Type::None, if_block_start_position));
|
.insert(if_block_start, (jump, Type::None, if_block_start_position));
|
||||||
|
}
|
||||||
|
|
||||||
control_flow_register_consolidation(self);
|
control_flow_register_consolidation(self);
|
||||||
|
|
||||||
let else_last_register = self.next_register().saturating_sub(1);
|
// let else_last_register = self.next_register().saturating_sub(1);
|
||||||
let point = Instruction::point(else_last_register, if_last_register);
|
// let point = Instruction::point(else_last_register, if_last_register);
|
||||||
|
|
||||||
if if_last_register < else_last_register {
|
// if if_last_register < else_last_register {
|
||||||
self.emit_instruction(point, else_block_type, self.current_position);
|
// self.emit_instruction(point, else_block_type, self.current_position);
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1406,6 +1433,22 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.emit_instruction(r#return, Type::None, Span(start, end));
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1432,6 +1475,22 @@ impl<'src> Compiler<'src> {
|
|||||||
self.emit_instruction(r#return, Type::None, self.current_position);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,15 +41,16 @@ pub fn write(
|
|||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
|
|
||||||
for register_index in argument_range {
|
for register_index in argument_range {
|
||||||
let value = record.open_register(register_index);
|
if let Some(value) = record.open_register_allow_empty(register_index) {
|
||||||
let string = value.display(record);
|
let string = value.display(record);
|
||||||
|
|
||||||
stdout
|
stdout
|
||||||
.write(string.as_bytes())
|
.write(string.as_bytes())
|
||||||
.map_err(|io_error| NativeFunctionError::Io {
|
.map_err(|io_error| NativeFunctionError::Io {
|
||||||
error: io_error.kind(),
|
error: io_error.kind(),
|
||||||
position: record.current_position(),
|
position: record.current_position(),
|
||||||
})?;
|
})?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.flush().map_err(|io_error| NativeFunctionError::Io {
|
stdout.flush().map_err(|io_error| NativeFunctionError::Io {
|
||||||
@ -68,21 +69,22 @@ pub fn write_line(
|
|||||||
let mut stdout = stdout().lock();
|
let mut stdout = stdout().lock();
|
||||||
|
|
||||||
for register_index in argument_range {
|
for register_index in argument_range {
|
||||||
let value = record.open_register(register_index);
|
if let Some(value) = record.open_register_allow_empty(register_index) {
|
||||||
let string = value.display(record);
|
let string = value.display(record);
|
||||||
|
|
||||||
stdout
|
stdout
|
||||||
.write(string.as_bytes())
|
.write(string.as_bytes())
|
||||||
.map_err(|io_error| NativeFunctionError::Io {
|
.map_err(|io_error| NativeFunctionError::Io {
|
||||||
error: io_error.kind(),
|
error: io_error.kind(),
|
||||||
position: record.current_position(),
|
position: record.current_position(),
|
||||||
})?;
|
})?;
|
||||||
stdout
|
stdout
|
||||||
.write(b"\n")
|
.write(b"\n")
|
||||||
.map_err(|io_error| NativeFunctionError::Io {
|
.map_err(|io_error| NativeFunctionError::Io {
|
||||||
error: io_error.kind(),
|
error: io_error.kind(),
|
||||||
position: record.current_position(),
|
position: record.current_position(),
|
||||||
})?;
|
})?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.flush().map_err(|io_error| NativeFunctionError::Io {
|
stdout.flush().map_err(|io_error| NativeFunctionError::Io {
|
||||||
|
@ -38,6 +38,10 @@ impl CallStack {
|
|||||||
self.calls.last()
|
self.calls.last()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn last_mut(&mut self) -> Option<&mut FunctionCall> {
|
||||||
|
self.calls.last_mut()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pop_or_panic(&mut self) -> FunctionCall {
|
pub fn pop_or_panic(&mut self) -> FunctionCall {
|
||||||
assert!(!self.is_empty(), "{}", VmError::CallStackUnderflow);
|
assert!(!self.is_empty(), "{}", VmError::CallStackUnderflow);
|
||||||
|
|
||||||
|
@ -82,7 +82,10 @@ impl Thread {
|
|||||||
if record_index == active.index() as usize {
|
if record_index == active.index() as usize {
|
||||||
trace!("Recursion detected");
|
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;
|
active.ip = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,10 +136,8 @@ impl Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let outer_call = self.call_stack.last_or_panic();
|
let outer_call = self.call_stack.last();
|
||||||
let record_index = outer_call.record_index as usize;
|
let record_index = outer_call.map_or(0, |call| call.record_index as usize);
|
||||||
|
|
||||||
trace!("Return from {returning_call} to {outer_call}");
|
|
||||||
|
|
||||||
if should_return_value {
|
if should_return_value {
|
||||||
let return_register = active
|
let return_register = active
|
||||||
@ -153,7 +154,7 @@ impl Thread {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
active = &mut self.records[record_index];
|
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)
|
fib(n - 1) + fib(n - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
write_line(fib(1))
|
write_line(fib(0))
|
||||||
|
Loading…
Reference in New Issue
Block a user