gbf_core/decompiler/handlers/
variable_operand.rs#![deny(missing_docs)]
use crate::{
decompiler::{
ast::{
assignable::AssignableKind, expr::ExprKind, new_fn_call, new_id_with_version, statement,
},
execution_frame::ExecutionFrame,
function_decompiler::FunctionDecompilerError,
function_decompiler_context::FunctionDecompilerContext,
ProcessedInstruction, ProcessedInstructionBuilder,
},
instruction::Instruction,
opcode::Opcode,
};
use super::OpcodeHandler;
pub struct VariableOperandHandler;
impl OpcodeHandler for VariableOperandHandler {
fn handle_instruction(
&self,
context: &mut FunctionDecompilerContext,
instruction: &Instruction,
) -> Result<ProcessedInstruction, FunctionDecompilerError> {
let current_block_id = context.current_block_id.expect("Block ID should be set");
match instruction.opcode {
Opcode::Call => {
let last_frame = context
.block_ast_node_stack
.get_mut(¤t_block_id)
.ok_or(FunctionDecompilerError::CannotPopNode(current_block_id))?
.pop()
.ok_or(FunctionDecompilerError::ExecutionStackEmpty)?;
if let ExecutionFrame::BuildingArray(mut args) = last_frame {
if args.is_empty() {
return Err(FunctionDecompilerError::InvalidNodeType(
current_block_id,
"Identifier".to_string(),
"Empty argument list for Call".to_string(),
));
}
let function_name = args.pop().unwrap();
let function_name = match function_name {
ExprKind::Assignable(AssignableKind::Identifier(ident)) => Ok(ident),
_ => Err(FunctionDecompilerError::InvalidNodeType(
current_block_id,
"Identifier".to_string(),
format!("{:?}", function_name),
)),
}?;
let args = args.into_iter().rev().collect::<Vec<_>>();
let function_call_node = new_fn_call(function_name, args);
let var = context.ssa_context.new_ssa_version_for("fn_call");
let ssa_id = new_id_with_version("fn_call", var);
let stmt = statement(ssa_id.clone(), function_call_node);
return Ok(ProcessedInstructionBuilder::new()
.ssa_id(ssa_id.into())
.push_to_region(stmt.into())
.build());
}
Err(FunctionDecompilerError::UnexpectedExecutionState(
ExecutionFrame::BuildingArray(Vec::new()),
last_frame,
))
}
Opcode::EndParams => {
let last_frame = context
.block_ast_node_stack
.get_mut(¤t_block_id)
.ok_or(FunctionDecompilerError::CannotPopNode(current_block_id))?
.pop()
.ok_or(FunctionDecompilerError::ExecutionStackEmpty)?;
if let ExecutionFrame::BuildingArray(args) = last_frame {
let args = args.into_iter().rev().collect::<Vec<_>>();
return Ok(ProcessedInstructionBuilder::new()
.function_parameters(args.into())
.build());
}
Err(FunctionDecompilerError::UnexpectedExecutionState(
ExecutionFrame::BuildingArray(Vec::new()),
last_frame,
))
}
_ => Err(FunctionDecompilerError::UnimplementedOpcode(
instruction.opcode,
current_block_id,
)),
}
}
}