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
21pub 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 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 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 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 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 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 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 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 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}