Skip to main content

luaur_compiler/methods/
compiler_unroll_concats.rs

1use luaur_ast::records::ast_expr::AstExpr;
2use luaur_ast::records::ast_expr_binary::{AstExprBinary, AstExprBinary_Op};
3
4use crate::records::compiler::Compiler;
5
6impl Compiler {
7    #[allow(non_snake_case)]
8    pub fn unroll_concats(&mut self, args: &mut Vec<*mut AstExpr>) {
9        loop {
10            if args.is_empty() {
11                break;
12            }
13
14            let back = *args.last().unwrap();
15            if back.is_null() {
16                break;
17            }
18
19            // C++ `args.back()->as<AstExprBinary>()` — a CHECKED RTTI downcast that
20            // returns null when the node is not an AstExprBinary. The model used
21            // `as_expr() as *mut AstExprBinary`, a blind reinterpret that treats any
22            // node (e.g. the trailing string in `a..b..c`) as a Binary and derefs
23            // its garbage `op`/`left`/`right` -> SIGSEGV.
24            let be = unsafe {
25                luaur_ast::rtti::ast_node_as::<AstExprBinary>(
26                    back as *mut luaur_ast::records::ast_node::AstNode,
27                )
28            };
29            if be.is_null() {
30                break;
31            }
32
33            let op = unsafe { (*be).op };
34            if op != AstExprBinary_Op::Concat {
35                break;
36            }
37
38            args.pop();
39            args.push(unsafe { (*be).left });
40            args.push(unsafe { (*be).right });
41        }
42    }
43}