Skip to main content

luaur_reduce_cli/methods/
reducer_get_nested_stats.rs

1use alloc::vec::Vec;
2use luaur_ast::records::ast_stat::AstStat;
3use luaur_ast::records::ast_stat_block::AstStatBlock;
4use luaur_ast::records::ast_stat_for::AstStatFor;
5use luaur_ast::records::ast_stat_for_in::AstStatForIn;
6use luaur_ast::records::ast_stat_function::AstStatFunction;
7use luaur_ast::records::ast_stat_if::AstStatIf;
8use luaur_ast::records::ast_stat_local_function::AstStatLocalFunction;
9use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
10use luaur_ast::records::ast_stat_while::AstStatWhile;
11use luaur_ast::rtti::ast_node_as;
12use luaur_common::macros::luau_assert::LUAU_ASSERT;
13
14use crate::records::reducer::Reducer;
15
16impl Reducer {
17    pub fn get_nested_stats(&self, stat: *mut AstStat) -> Vec<*mut AstStat> {
18        let mut result: Vec<*mut AstStat> = Vec::new();
19
20        let mut append = |block: *mut AstStatBlock| {
21            if !block.is_null() {
22                unsafe {
23                    let data = (*block).body.begin();
24                    let end = (*block).body.end();
25                    let size =
26                        (end as usize - data as usize) / core::mem::size_of::<*mut AstStat>();
27                    if !data.is_null() && size > 0 {
28                        let slice = core::slice::from_raw_parts(data, size);
29                        result.extend_from_slice(slice);
30                    }
31                }
32            }
33        };
34
35        unsafe {
36            if stat.is_null() {
37                return result;
38            }
39
40            let node_ptr = stat as *mut luaur_ast::records::ast_node::AstNode;
41
42            let block = ast_node_as::<AstStatBlock>(node_ptr);
43            if !block.is_null() {
44                append(block);
45            } else {
46                let ifs = ast_node_as::<AstStatIf>(node_ptr);
47                if !ifs.is_null() {
48                    append((*ifs).thenbody);
49                    if !(*ifs).elsebody.is_null() {
50                        let else_ptr =
51                            (*ifs).elsebody as *mut luaur_ast::records::ast_node::AstNode;
52                        let else_block = ast_node_as::<AstStatBlock>(else_ptr);
53                        if !else_block.is_null() {
54                            append(else_block);
55                        } else {
56                            let else_if = ast_node_as::<AstStatIf>(else_ptr);
57                            if !else_if.is_null() {
58                                let inner_stats = self.get_nested_stats(else_if as *mut AstStat);
59                                result.extend(inner_stats);
60                            } else {
61                                eprintln!("AstStatIf's else clause can have more statement types than I thought");
62                                LUAU_ASSERT!(false);
63                            }
64                        }
65                    }
66                } else {
67                    let w = ast_node_as::<AstStatWhile>(node_ptr);
68                    if !w.is_null() {
69                        append((*w).body);
70                    } else {
71                        let r = ast_node_as::<AstStatRepeat>(node_ptr);
72                        if !r.is_null() {
73                            append((*r).body);
74                        } else {
75                            let f = ast_node_as::<AstStatFor>(node_ptr);
76                            if !f.is_null() {
77                                append((*f).body);
78                            } else {
79                                let f_in = ast_node_as::<AstStatForIn>(node_ptr);
80                                if !f_in.is_null() {
81                                    append((*f_in).body);
82                                } else {
83                                    let f_func = ast_node_as::<AstStatFunction>(node_ptr);
84                                    if !f_func.is_null() {
85                                        append((*(*f_func).func).body);
86                                    } else {
87                                        let f_local = ast_node_as::<AstStatLocalFunction>(node_ptr);
88                                        if !f_local.is_null() {
89                                            append((*(*f_local).func).body);
90                                        }
91                                    }
92                                }
93                            }
94                        }
95                    }
96                }
97            }
98        }
99
100        result
101    }
102}
103
104pub fn reducer_get_nested_stats(this: &Reducer, stat: *mut AstStat) -> Vec<*mut AstStat> {
105    this.get_nested_stats(stat)
106}