gbf_core/decompiler/handlers/
literal.rs

1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6    decompiler::{
7        ProcessedInstruction, ProcessedInstructionBuilder,
8        ast::{
9            new_assignment, new_bool, new_float, new_id_with_version, new_null, new_num, new_str,
10        },
11        function_decompiler::FunctionDecompilerError,
12        function_decompiler_context::FunctionDecompilerContext,
13    },
14    instruction::Instruction,
15    opcode::Opcode,
16    operand::Operand,
17};
18
19use super::OpcodeHandler;
20
21/// Handles identifier instructions.
22pub struct LiteralHandler;
23
24impl OpcodeHandler for LiteralHandler {
25    fn handle_instruction(
26        &self,
27        context: &mut FunctionDecompilerContext,
28        instruction: &Instruction,
29    ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
30        // For PushTrue, PushFalse, we do not pop an operand
31        let literal = if instruction.opcode == Opcode::PushTrue
32            || instruction.opcode == Opcode::PushFalse
33        {
34            new_bool(instruction.opcode == Opcode::PushTrue)
35        } else if instruction.opcode == Opcode::PushNull {
36            new_null()
37        } else {
38            // For literals, the opcode must contain the literal value as an operand.
39            let operand = instruction.operand.as_ref().ok_or(
40                FunctionDecompilerError::InstructionMustHaveOperand {
41                    opcode: instruction.opcode,
42                    context: context.get_error_context(),
43                    backtrace: Backtrace::capture(),
44                },
45            )?;
46
47            match instruction.opcode {
48                Opcode::PushString => new_str(operand.get_string_value().map_err(|e| {
49                    FunctionDecompilerError::OperandError {
50                        source: e,
51                        context: context.get_error_context(),
52                        backtrace: Backtrace::capture(),
53                    }
54                })?),
55                Opcode::PushNumber => match operand {
56                    Operand::Float(_) => new_float(operand.get_string_value().map_err(|e| {
57                        FunctionDecompilerError::OperandError {
58                            source: e,
59                            context: context.get_error_context(),
60                            backtrace: Backtrace::capture(),
61                        }
62                    })?),
63                    Operand::Number(_) => new_num(operand.get_number_value().map_err(|e| {
64                        FunctionDecompilerError::OperandError {
65                            source: e,
66                            context: context.get_error_context(),
67                            backtrace: Backtrace::capture(),
68                        }
69                    })?),
70                    _ => {
71                        return Err(FunctionDecompilerError::Other {
72                            message: format!("Invalid operand type for PushNumber: {:?}", operand),
73                            context: context.get_error_context(),
74                            backtrace: Backtrace::capture(),
75                        });
76                    }
77                },
78                _ => {
79                    return Err(FunctionDecompilerError::UnimplementedOpcode {
80                        opcode: instruction.opcode,
81                        context: context.get_error_context(),
82                        backtrace: Backtrace::capture(),
83                    });
84                }
85            }
86        };
87
88        let ver = context.ssa_context.new_ssa_version_for("lit");
89        let ssa_id = new_id_with_version("lit", ver);
90        let stmt = new_assignment(ssa_id.clone(), literal);
91
92        Ok(ProcessedInstructionBuilder::new()
93            .push_to_region(stmt.into())
94            .ssa_id(ssa_id.into())
95            .build())
96        // context.push_one_node(literal.into())?;
97        // Ok(ProcessedInstructionBuilder::new().build())
98    }
99}