use crate::instruction::Instruction;
use super::super::super::HighLevelEmitter;
impl HighLevelEmitter {
pub(in super::super::super) fn emit_relative(
&mut self,
instruction: &Instruction,
label: &str,
) {
if self.skip_jumps.remove(&instruction.offset) {
return;
}
if let Some(target) = self.jump_target(instruction) {
self.warn(
instruction,
&format!("{label} -> 0x{target:04X} (control flow not yet lifted)"),
);
} else {
self.warn(
instruction,
&format!("{label} with unsupported operand (skipping)"),
);
}
}
pub(in super::super::super) fn emit_jump(&mut self, instruction: &Instruction) {
if self.skip_jumps.remove(&instruction.offset) {
return;
}
match self.jump_target(instruction) {
Some(target) => self.emit_known_jump_target(instruction, target),
None => self.warn(instruction, "jump with unsupported operand (skipping)"),
}
}
pub(in super::super::super) fn emit_endtry(&mut self, instruction: &Instruction) {
if self.skip_jumps.remove(&instruction.offset) {
return;
}
self.push_comment(instruction);
match self.jump_target(instruction) {
Some(target) => self.emit_known_endtry_target(target),
None => self.warn(instruction, "end-try with unsupported operand (skipping)"),
}
}
fn emit_known_jump_target(&mut self, instruction: &Instruction, target: usize) {
if self.try_emit_loop_jump(instruction, target) {
return;
}
if self.method_labels_by_offset.contains_key(&target) {
self.emit_internal_call(instruction, target);
let result = self.stack.pop().unwrap_or_default();
if result.is_empty() {
self.statements.push("return;".into());
} else {
self.statements.push(format!("return {result};"));
}
return;
}
self.push_comment(instruction);
if self.index_by_offset.contains_key(&target) {
self.transfer_labels.insert(target);
}
self.statements
.push(format!("goto {};", Self::transfer_label_name(target)));
}
fn emit_known_endtry_target(&mut self, target: usize) {
if self
.loop_stack
.iter()
.rev()
.any(|ctx| target == ctx.continue_offset)
{
self.statements.push("continue;".into());
return;
}
if self
.loop_stack
.iter()
.rev()
.any(|ctx| target >= ctx.break_offset)
{
self.statements.push("break;".into());
return;
}
if self.index_by_offset.contains_key(&target) {
self.transfer_labels.insert(target);
}
self.statements
.push(format!("leave {};", Self::transfer_label_name(target)));
}
}