gbf_core/decompiler/handlers/
special_two_operand.rs1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6 decompiler::{
7 ProcessedInstruction, ProcessedInstructionBuilder,
8 ast::{
9 expr::ExprKind, new_array_access, new_assignment, new_id_with_version,
10 new_member_access, new_new,
11 },
12 function_decompiler::FunctionDecompilerError,
13 function_decompiler_context::FunctionDecompilerContext,
14 },
15 instruction::Instruction,
16 opcode::Opcode,
17};
18
19use super::OpcodeHandler;
20
21pub struct SpecialTwoOperandHandler;
23
24impl OpcodeHandler for SpecialTwoOperandHandler {
25 fn handle_instruction(
26 &self,
27 context: &mut FunctionDecompilerContext,
28 instruction: &Instruction,
29 ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
30 match instruction.opcode {
31 Opcode::AccessMember => {
32 let mut rhs = context.pop_expression()?;
33 let mut lhs = context.pop_expression()?;
34
35 if let ExprKind::Identifier(mut id) = lhs {
37 id.ssa_version = None;
38 lhs = id.into();
39 }
40 if let ExprKind::Identifier(mut id) = rhs {
41 id.ssa_version = None;
42 rhs = id.into();
43 }
44
45 let ma: ExprKind = new_member_access(lhs, rhs)
46 .map_err(|e| FunctionDecompilerError::AstNodeError {
47 source: e,
48 context: context.get_error_context(),
49 backtrace: Backtrace::capture(),
50 })?
51 .into();
52 context.push_one_node(ma.into())?;
53 Ok(ProcessedInstructionBuilder::new().build())
54 }
55 Opcode::Assign => {
56 let rhs = context.pop_expression()?;
57 let mut lhs = context.pop_expression()?;
58
59 if let ExprKind::Identifier(mut id) = lhs {
61 let ver = context.ssa_context.new_ssa_version_for(id.id());
62 id.ssa_version = Some(ver);
63 lhs = id.into();
64 }
65 let stmt = new_assignment(lhs, rhs);
66
67 Ok(ProcessedInstructionBuilder::new()
68 .push_to_region(stmt.into())
69 .build())
70 }
71 Opcode::ArrayAccess => {
72 let index = context.pop_expression()?;
73 let arr = context.pop_expression()?;
74
75 let array_access = new_array_access(arr, index);
76
77 context.push_one_node(array_access.into())?;
78 Ok(ProcessedInstructionBuilder::new().build())
79 }
80 Opcode::NewObject => {
81 let new_type = context.pop_expression()?;
82 let arg = context.pop_expression()?;
83
84 let new_node =
85 new_new(new_type, arg).map_err(|e| FunctionDecompilerError::AstNodeError {
86 source: e,
87 context: context.get_error_context(),
88 backtrace: Backtrace::capture(),
89 })?;
90
91 let var = context.ssa_context.new_ssa_version_for("new_node");
93 let ssa_id = new_id_with_version("new_node", var);
94 let stmt = new_assignment(ssa_id.clone(), new_node);
95
96 Ok(ProcessedInstructionBuilder::new()
97 .ssa_id(ssa_id.into())
98 .push_to_region(stmt.into())
99 .build())
100 }
101 _ => Err(FunctionDecompilerError::UnimplementedOpcode {
102 opcode: instruction.opcode,
103 context: context.get_error_context(),
104 backtrace: Backtrace::capture(),
105 }),
106 }
107 }
108}