gbf_core/decompiler/handlers/
special_three_operand.rs

1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6    decompiler::{
7        ProcessedInstruction, ProcessedInstructionBuilder,
8        ast::{bin_op::BinOpType, new_array_access, new_assignment, new_bin_op, new_range},
9        function_decompiler::FunctionDecompilerError,
10        function_decompiler_context::FunctionDecompilerContext,
11    },
12    instruction::Instruction,
13    opcode::Opcode,
14};
15
16use super::OpcodeHandler;
17
18/// Handles other instructions.
19pub struct SpecialThreeOperandHandler;
20
21impl OpcodeHandler for SpecialThreeOperandHandler {
22    fn handle_instruction(
23        &self,
24        context: &mut FunctionDecompilerContext,
25        instruction: &Instruction,
26    ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
27        match instruction.opcode {
28            Opcode::AssignArray => {
29                let rhs = context.pop_expression()?;
30                let lhs_ind = context.pop_expression()?;
31                let lhs_arr = context.pop_expression()?;
32
33                let arr_access = new_array_access(lhs_arr, lhs_ind);
34                let stmt = new_assignment(arr_access, rhs);
35
36                Ok(ProcessedInstructionBuilder::new()
37                    .push_to_region(stmt.into())
38                    .build())
39            }
40            Opcode::InRange => {
41                let last = context.pop_expression()?;
42                let first = context.pop_expression()?;
43                let lhs = context.pop_expression()?;
44
45                let range = new_range(first, last);
46                let bin_op = new_bin_op(lhs, range, BinOpType::In).map_err(|e| {
47                    FunctionDecompilerError::AstNodeError {
48                        source: e,
49                        context: context.get_error_context(),
50                        backtrace: Backtrace::capture(),
51                    }
52                })?;
53
54                context.push_one_node(bin_op.into())?;
55                Ok(ProcessedInstructionBuilder::new().build())
56            }
57            Opcode::AssignMultiDimensionalArrayIndex => {
58                let ind_2 = context.pop_expression()?;
59                let ind_1 = context.pop_expression()?;
60                let arr = context.pop_expression()?;
61
62                let arr_access = new_array_access(new_array_access(arr, ind_1), ind_2);
63
64                context.push_one_node(arr_access.into())?;
65                Ok(ProcessedInstructionBuilder::new().build())
66            }
67            Opcode::AssignMultiDimensionalArray => {
68                let assign_var = context.pop_expression()?;
69                let ind_2 = context.pop_expression()?;
70                let ind_1 = context.pop_expression()?;
71                let arr = context.pop_expression()?;
72
73                let arr_access = new_array_access(new_array_access(arr, ind_1), ind_2);
74
75                let stmt = new_assignment(arr_access, assign_var);
76                Ok(ProcessedInstructionBuilder::new()
77                    .push_to_region(stmt.into())
78                    .build())
79            }
80            _ => Err(FunctionDecompilerError::UnimplementedOpcode {
81                opcode: instruction.opcode,
82                context: context.get_error_context(),
83                backtrace: Backtrace::capture(),
84            }),
85        }
86    }
87}