gbf_core/decompiler/handlers/
jump.rs

1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6    decompiler::{
7        ProcessedInstruction, ProcessedInstructionBuilder,
8        ast::{bin_op::BinOpType, new_bin_op, new_unary_op, unary_op::UnaryOpType},
9        function_decompiler::FunctionDecompilerError,
10        function_decompiler_context::FunctionDecompilerContext,
11    },
12    instruction::Instruction,
13    opcode::Opcode,
14};
15
16use super::OpcodeHandler;
17
18/// Handles jump instructions.
19pub struct JumpHandler;
20
21impl OpcodeHandler for JumpHandler {
22    fn handle_instruction(
23        &self,
24        context: &mut FunctionDecompilerContext,
25        instruction: &Instruction,
26    ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
27        match instruction.opcode {
28            Opcode::Jne => {
29                let condition = context.pop_expression()?;
30
31                Ok(ProcessedInstructionBuilder::new()
32                    .jump_condition(condition)
33                    .build())
34            }
35            Opcode::Jeq => {
36                let condition = context.pop_expression()?;
37                let wrapped = new_unary_op(condition, UnaryOpType::LogicalNot).map_err(|e| {
38                    FunctionDecompilerError::AstNodeError {
39                        source: e,
40                        context: context.get_error_context(),
41                        backtrace: Backtrace::capture(),
42                    }
43                })?;
44
45                Ok(ProcessedInstructionBuilder::new()
46                    .jump_condition(wrapped.into())
47                    .build())
48            }
49            Opcode::With => {
50                let condition = context.pop_expression()?;
51
52                Ok(ProcessedInstructionBuilder::new()
53                    .jump_condition(condition)
54                    .build())
55            }
56            Opcode::ForEach => {
57                // iter_var is the variable that will be assigned to each element in the array
58                let iter_var = context.pop_expression()?;
59                // arr is the array to iterate over
60                let arr = context.pop_expression()?;
61
62                // push arr and iter_var back onto the stack
63                context.push_one_node(arr.clone().into())?;
64                context.push_one_node(iter_var.clone().into())?;
65
66                // construct a new binary operation node with Foreach as the type
67                let bin_op = new_bin_op(iter_var, arr, BinOpType::Foreach).map_err(|e| {
68                    FunctionDecompilerError::AstNodeError {
69                        source: e,
70                        context: context.get_error_context(),
71                        backtrace: Backtrace::capture(),
72                    }
73                })?;
74
75                Ok(ProcessedInstructionBuilder::new()
76                    .jump_condition(bin_op.into())
77                    .build())
78            }
79            _ => Err(FunctionDecompilerError::UnimplementedOpcode {
80                opcode: instruction.opcode,
81                context: context.get_error_context(),
82                backtrace: Backtrace::capture(),
83            }),
84        }
85    }
86}