gbf_core/decompiler/handlers/
identifier.rs

1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6    decompiler::{
7        ProcessedInstruction, ProcessedInstructionBuilder, ast::new_id_with_version,
8        function_decompiler::FunctionDecompilerError,
9        function_decompiler_context::FunctionDecompilerContext,
10    },
11    instruction::Instruction,
12    opcode::Opcode,
13};
14
15use super::OpcodeHandler;
16
17/// Handles identifier instructions.
18pub struct IdentifierHandler;
19
20impl OpcodeHandler for IdentifierHandler {
21    fn handle_instruction(
22        &self,
23        context: &mut FunctionDecompilerContext,
24        instruction: &Instruction,
25    ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
26        let opcode = instruction.opcode;
27        // If we have a variable, we need to use the operand as the identifier name.
28        let str_operand = if opcode == Opcode::PushVariable {
29            let operand = instruction.operand.as_ref().ok_or(
30                FunctionDecompilerError::InstructionMustHaveOperand {
31                    opcode: instruction.opcode,
32                    context: context.get_error_context(),
33                    backtrace: Backtrace::capture(),
34                },
35            )?;
36            operand.to_string()
37        } else {
38            // Otherwise, we can just use the opcode name (e.g. "player", "level", "this", etc.).
39            opcode.to_string().to_lowercase()
40        };
41
42        let id = new_id_with_version(
43            str_operand.as_str(),
44            context.ssa_context.current_version_of_or_new(&str_operand),
45        );
46        Ok(ProcessedInstructionBuilder::new().ssa_id(id.into()).build())
47    }
48}