gbf_core/decompiler/handlers/
builtins.rs

1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6    decompiler::{
7        ProcessedInstruction, ProcessedInstructionBuilder,
8        ast::{
9            array_kind::ArrayKind, expr::ExprKind, new_array, new_assignment, new_fn_call,
10            new_fn_call_normal, new_id, new_id_with_version, new_member_access, new_phi_array,
11        },
12        function_decompiler::FunctionDecompilerError,
13        function_decompiler_context::FunctionDecompilerContext,
14    },
15    instruction::Instruction,
16    opcode::Opcode,
17};
18
19use super::OpcodeHandler;
20
21/// Handles other instructions.
22pub struct BuiltinsHandler;
23
24impl OpcodeHandler for BuiltinsHandler {
25    fn handle_instruction(
26        &self,
27        context: &mut FunctionDecompilerContext,
28        instruction: &Instruction,
29    ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
30        let (fn_id, args): (ExprKind, Vec<_>) = match instruction.opcode {
31            Opcode::Char => {
32                let args: Vec<_> = vec![context.pop_expression()?];
33                (new_id("char").into(), args)
34            }
35            Opcode::Int => {
36                let args: Vec<_> = vec![context.pop_expression()?];
37                (new_id("int").into(), args)
38            }
39            Opcode::Random => {
40                let param2 = context.pop_expression()?;
41                let param1 = context.pop_expression()?;
42                let args: Vec<_> = [param1, param2].to_vec();
43                (new_id("random").into(), args)
44            }
45            Opcode::Abs => {
46                let args: Vec<_> = vec![context.pop_expression()?];
47                (new_id("abs").into(), args)
48            }
49            Opcode::Sin => {
50                let args: Vec<_> = vec![context.pop_expression()?];
51                (new_id("sin").into(), args)
52            }
53            Opcode::Cos => {
54                let args: Vec<_> = vec![context.pop_expression()?];
55                (new_id("cos").into(), args)
56            }
57            Opcode::VecX => {
58                let args: Vec<_> = vec![context.pop_expression()?];
59                (new_id("vecx").into(), args)
60            }
61            Opcode::VecY => {
62                let args: Vec<_> = vec![context.pop_expression()?];
63                (new_id("vecy").into(), args)
64            }
65            Opcode::Sleep => {
66                let args: Vec<_> = vec![context.pop_expression()?];
67                (new_id("sleep").into(), args)
68            }
69            Opcode::ArcTan => {
70                let args: Vec<_> = vec![context.pop_expression()?];
71                (new_id("arctan").into(), args)
72            }
73            Opcode::MakeVar => {
74                let args: Vec<_> = vec![context.pop_expression()?];
75                (new_id("makevar").into(), args)
76            }
77            Opcode::GetTranslation => {
78                let args: Vec<_> = vec![context.pop_expression()?];
79                (new_id("_").into(), args)
80            }
81            Opcode::Min => {
82                let param2 = context.pop_expression()?;
83                let param1 = context.pop_expression()?;
84                let args: Vec<_> = [param1, param2].to_vec();
85                (new_id("min").into(), args)
86            }
87            Opcode::Max => {
88                let param2 = context.pop_expression()?;
89                let param1 = context.pop_expression()?;
90                let args: Vec<_> = [param1, param2].to_vec();
91                (new_id("max").into(), args)
92            }
93            Opcode::WaitFor => {
94                let param3 = context.pop_expression()?;
95                let param2 = context.pop_expression()?;
96                let param1 = context.pop_expression()?;
97                let args: Vec<_> = [param1, param2, param3].to_vec();
98                (new_id("waitfor").into(), args)
99            }
100            Opcode::GetAngle => {
101                let param2 = context.pop_expression()?;
102                let param1 = context.pop_expression()?;
103                let args: Vec<_> = [param1, param2].to_vec();
104                (new_id("getangle").into(), args)
105            }
106            Opcode::GetDir => {
107                let param2 = context.pop_expression()?;
108                let param1 = context.pop_expression()?;
109                let args: Vec<_> = [param1, param2].to_vec();
110                (new_id("getdir").into(), args)
111            }
112            Opcode::ObjSubstring => {
113                let param2 = context.pop_expression()?;
114                let param1 = context.pop_expression()?;
115                let args: Vec<_> = [param1, param2].to_vec();
116                (
117                    new_member_access(context.pop_expression()?, new_id("substring"))
118                        .map_err(|e| FunctionDecompilerError::AstNodeError {
119                            source: e,
120                            context: context.get_error_context(),
121                            backtrace: Backtrace::capture(),
122                        })?
123                        .into(),
124                    args,
125                )
126            }
127            Opcode::ObjTokenize => {
128                let args: Vec<_> = vec![context.pop_expression()?];
129                (
130                    new_member_access(context.pop_expression()?, new_id("tokenize"))
131                        .map_err(|e| FunctionDecompilerError::AstNodeError {
132                            source: e,
133                            context: context.get_error_context(),
134                            backtrace: Backtrace::capture(),
135                        })?
136                        .into(),
137                    args,
138                )
139            }
140            Opcode::ObjStarts => {
141                let args: Vec<_> = vec![context.pop_expression()?];
142                (
143                    new_member_access(context.pop_expression()?, new_id("starts"))
144                        .map_err(|e| FunctionDecompilerError::AstNodeError {
145                            source: e,
146                            context: context.get_error_context(),
147                            backtrace: Backtrace::capture(),
148                        })?
149                        .into(),
150                    args,
151                )
152            }
153            Opcode::ObjEnds => {
154                let args: Vec<_> = vec![context.pop_expression()?];
155                (
156                    new_member_access(context.pop_expression()?, new_id("ends"))
157                        .map_err(|e| FunctionDecompilerError::AstNodeError {
158                            source: e,
159                            context: context.get_error_context(),
160                            backtrace: Backtrace::capture(),
161                        })?
162                        .into(),
163                    args,
164                )
165            }
166            Opcode::ObjPos => {
167                let args: Vec<_> = [context.pop_expression()?].to_vec();
168                (
169                    new_member_access(context.pop_expression()?, new_id("pos"))
170                        .map_err(|e| FunctionDecompilerError::AstNodeError {
171                            source: e,
172                            context: context.get_error_context(),
173                            backtrace: Backtrace::capture(),
174                        })?
175                        .into(),
176                    args,
177                )
178            }
179            Opcode::ObjCharAt => {
180                let args: Vec<_> = [context.pop_expression()?].to_vec();
181                (
182                    new_member_access(context.pop_expression()?, new_id("charat"))
183                        .map_err(|e| FunctionDecompilerError::AstNodeError {
184                            source: e,
185                            context: context.get_error_context(),
186                            backtrace: Backtrace::capture(),
187                        })?
188                        .into(),
189                    args,
190                )
191            }
192            Opcode::ObjLength => {
193                let args = vec![];
194                (
195                    new_member_access(context.pop_expression()?, new_id("length"))
196                        .map_err(|e| FunctionDecompilerError::AstNodeError {
197                            source: e,
198                            context: context.get_error_context(),
199                            backtrace: Backtrace::capture(),
200                        })?
201                        .into(),
202                    args,
203                )
204            }
205            Opcode::ObjLink => {
206                let args: Vec<_> = vec![];
207                (
208                    new_member_access(context.pop_expression()?, new_id("link"))
209                        .map_err(|e| FunctionDecompilerError::AstNodeError {
210                            source: e,
211                            context: context.get_error_context(),
212                            backtrace: Backtrace::capture(),
213                        })?
214                        .into(),
215                    args,
216                )
217            }
218            Opcode::ObjTrim => {
219                let args: Vec<_> = vec![];
220                (
221                    new_member_access(context.pop_expression()?, new_id("trim"))
222                        .map_err(|e| FunctionDecompilerError::AstNodeError {
223                            source: e,
224                            context: context.get_error_context(),
225                            backtrace: Backtrace::capture(),
226                        })?
227                        .into(),
228                    args,
229                )
230            }
231            Opcode::ObjSize => {
232                let args: Vec<_> = vec![];
233                (
234                    new_member_access(context.pop_expression()?, new_id("size"))
235                        .map_err(|e| FunctionDecompilerError::AstNodeError {
236                            source: e,
237                            context: context.get_error_context(),
238                            backtrace: Backtrace::capture(),
239                        })?
240                        .into(),
241                    args,
242                )
243            }
244            // TODO: This has no return value
245            Opcode::ObjClear => {
246                let args: Vec<_> = vec![];
247                (
248                    new_member_access(context.pop_expression()?, new_id("clear"))
249                        .map_err(|e| FunctionDecompilerError::AstNodeError {
250                            source: e,
251                            context: context.get_error_context(),
252                            backtrace: Backtrace::capture(),
253                        })?
254                        .into(),
255                    args,
256                )
257            }
258            Opcode::ObjIndex => {
259                let args: Vec<_> = vec![context.pop_expression()?];
260                (
261                    new_member_access(context.pop_expression()?, new_id("index"))
262                        .map_err(|e| FunctionDecompilerError::AstNodeError {
263                            source: e,
264                            context: context.get_error_context(),
265                            backtrace: Backtrace::capture(),
266                        })?
267                        .into(),
268                    args,
269                )
270            }
271            Opcode::ObjPositions => {
272                let args: Vec<_> = vec![context.pop_expression()?];
273                (
274                    new_member_access(context.pop_expression()?, new_id("positions"))
275                        .map_err(|e| FunctionDecompilerError::AstNodeError {
276                            source: e,
277                            context: context.get_error_context(),
278                            backtrace: Backtrace::capture(),
279                        })?
280                        .into(),
281                    args,
282                )
283            }
284            // TODO: This has no return value
285            Opcode::ObjAddString => {
286                let args: Vec<_> = vec![context.pop_expression()?];
287                (
288                    new_member_access(context.pop_expression()?, new_id("add"))
289                        .map_err(|e| FunctionDecompilerError::AstNodeError {
290                            source: e,
291                            context: context.get_error_context(),
292                            backtrace: Backtrace::capture(),
293                        })?
294                        .into(),
295                    args,
296                )
297            }
298            // TODO: This has no return value
299            Opcode::ObjRemoveString => {
300                let args: Vec<_> = vec![context.pop_expression()?];
301                (
302                    new_member_access(context.pop_expression()?, new_id("remove"))
303                        .map_err(|e| FunctionDecompilerError::AstNodeError {
304                            source: e,
305                            context: context.get_error_context(),
306                            backtrace: Backtrace::capture(),
307                        })?
308                        .into(),
309                    args,
310                )
311            }
312            // TODO: This has no return value
313            Opcode::ObjDeleteString => {
314                let args: Vec<_> = vec![context.pop_expression()?];
315                (
316                    new_member_access(context.pop_expression()?, new_id("delete"))
317                        .map_err(|e| FunctionDecompilerError::AstNodeError {
318                            source: e,
319                            context: context.get_error_context(),
320                            backtrace: Backtrace::capture(),
321                        })?
322                        .into(),
323                    args,
324                )
325            }
326            // TODO: This has no return value
327            Opcode::ObjInsertString => {
328                let args: Vec<_> = vec![context.pop_expression()?, context.pop_expression()?];
329                (
330                    new_member_access(context.pop_expression()?, new_id("insert"))
331                        .map_err(|e| FunctionDecompilerError::AstNodeError {
332                            source: e,
333                            context: context.get_error_context(),
334                            backtrace: Backtrace::capture(),
335                        })?
336                        .into(),
337                    args,
338                )
339            }
340            // TODO: This has no return value
341            Opcode::ObjReplaceString => {
342                let args: Vec<_> = vec![context.pop_expression()?, context.pop_expression()?];
343                (
344                    new_member_access(context.pop_expression()?, new_id("replace"))
345                        .map_err(|e| FunctionDecompilerError::AstNodeError {
346                            source: e,
347                            context: context.get_error_context(),
348                            backtrace: Backtrace::capture(),
349                        })?
350                        .into(),
351                    args,
352                )
353            }
354            Opcode::ObjSubArray => {
355                let args: Vec<_> = vec![context.pop_expression()?, context.pop_expression()?];
356                (
357                    new_member_access(context.pop_expression()?, new_id("subarray"))
358                        .map_err(|e| FunctionDecompilerError::AstNodeError {
359                            source: e,
360                            context: context.get_error_context(),
361                            backtrace: Backtrace::capture(),
362                        })?
363                        .into(),
364                    args,
365                )
366            }
367            Opcode::ObjType => {
368                let args: Vec<_> = vec![];
369                (
370                    new_member_access(context.pop_expression()?, new_id("type"))
371                        .map_err(|e| FunctionDecompilerError::AstNodeError {
372                            source: e,
373                            context: context.get_error_context(),
374                            backtrace: Backtrace::capture(),
375                        })?
376                        .into(),
377                    args,
378                )
379            }
380            Opcode::Format => {
381                let arr = context.pop_building_array()?;
382
383                let new_array_kind = match arr {
384                    ArrayKind::MergedArray(elems) => {
385                        // return args with the first element new_id("format")
386                        let mut format = vec![new_id("format").into()];
387                        let args = elems.elements.clone();
388                        format.extend(args);
389                        new_array(format).into()
390                    }
391                    ArrayKind::PhiArray(elems) => {
392                        // return args with the first element new_id("format")
393                        let mut format = vec![new_id("format").into()];
394                        let args = elems.elements.clone();
395                        format.extend(args);
396                        new_phi_array(elems.phi.clone(), format).into()
397                    }
398                };
399
400                let fn_call = new_fn_call(new_array_kind);
401
402                let var = context.ssa_context.new_ssa_version_for("builtin_fn_call");
403                let ssa_id = new_id_with_version("builtin_fn_call", var);
404                let stmt = new_assignment(ssa_id.clone(), fn_call);
405
406                return Ok(ProcessedInstructionBuilder::new()
407                    .ssa_id(ssa_id.into())
408                    .push_to_region(stmt.into())
409                    .build());
410            }
411            _ => {
412                return Err(FunctionDecompilerError::UnimplementedOpcode {
413                    opcode: instruction.opcode,
414                    context: context.get_error_context(),
415                    backtrace: Backtrace::capture(),
416                });
417            }
418        };
419
420        let fn_call = new_fn_call_normal(fn_id, args);
421
422        let var = context.ssa_context.new_ssa_version_for("builtin_fn_call");
423        let ssa_id = new_id_with_version("builtin_fn_call", var);
424        let stmt = new_assignment(ssa_id.clone(), fn_call);
425
426        Ok(ProcessedInstructionBuilder::new()
427            .ssa_id(ssa_id.into())
428            .push_to_region(stmt.into())
429            .build())
430    }
431}