Skip to main content

luaur_analysis/functions/
get_fallthrough.rs

1use luaur_ast::records::ast_expr_call::AstExprCall;
2use luaur_ast::records::ast_expr_constant_bool::AstExprConstantBool;
3use luaur_ast::records::ast_stat::AstStat;
4use luaur_ast::records::ast_stat_block::AstStatBlock;
5use luaur_ast::records::ast_stat_expr::AstStatExpr;
6use luaur_ast::records::ast_stat_if::AstStatIf;
7use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
8use luaur_ast::records::ast_stat_return::AstStatReturn;
9use luaur_ast::records::ast_stat_while::AstStatWhile;
10use luaur_ast::rtti::ast_node_as;
11use luaur_ast::rtti::ast_node_is;
12
13use crate::functions::does_call_error::does_call_error;
14use crate::functions::has_break::has_break;
15
16pub fn get_fallthrough(node: *const AstStat) -> *const AstStat {
17    if node.is_null() {
18        return core::ptr::null();
19    }
20
21    unsafe {
22        if !ast_node_as::<AstStatBlock>(
23            node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
24        )
25        .is_null()
26        {
27            let stat = ast_node_as::<AstStatBlock>(
28                node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
29            );
30            if stat.is_null() {
31                return core::ptr::null();
32            }
33
34            if (*stat).body.size == 0 {
35                return stat as *const AstStat;
36            }
37
38            let size = (*stat).body.size;
39            for i in 0..(size.saturating_sub(1)) {
40                let s = *(*stat).body.data.add(i);
41                if get_fallthrough(s).is_null() {
42                    return core::ptr::null();
43                }
44            }
45
46            let last = *(*stat).body.data.add(size - 1);
47            return get_fallthrough(last);
48        }
49
50        if !ast_node_as::<AstStatIf>(node as *const _ as *mut luaur_ast::records::ast_node::AstNode)
51            .is_null()
52        {
53            let stat = ast_node_as::<AstStatIf>(
54                node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
55            );
56            if stat.is_null() {
57                return core::ptr::null();
58            }
59
60            let thenf = get_fallthrough((*stat).thenbody as *const AstStat);
61            if !thenf.is_null() {
62                return thenf;
63            }
64
65            if !(*stat).elsebody.is_null() {
66                let elsef = get_fallthrough((*stat).elsebody);
67                if !elsef.is_null() {
68                    return elsef;
69                }
70                return core::ptr::null();
71            } else {
72                return node;
73            }
74        }
75
76        if ast_node_is::<AstStatReturn>(unsafe {
77            &*(node as *const luaur_ast::records::ast_node::AstNode)
78        }) {
79            return core::ptr::null();
80        }
81
82        if !ast_node_as::<AstStatExpr>(
83            node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
84        )
85        .is_null()
86        {
87            let stat = ast_node_as::<AstStatExpr>(
88                node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
89            );
90            if stat.is_null() {
91                return core::ptr::null();
92            }
93
94            if !(*stat).expr.is_null() {
95                let call = ast_node_as::<AstExprCall>(
96                    (*stat).expr as *mut luaur_ast::records::ast_node::AstNode,
97                );
98                if !call.is_null() {
99                    if does_call_error(&*call) {
100                        return core::ptr::null();
101                    }
102                }
103            }
104
105            return node;
106        }
107
108        if !ast_node_as::<AstStatWhile>(
109            node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
110        )
111        .is_null()
112        {
113            let stat = ast_node_as::<AstStatWhile>(
114                node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
115            );
116            if stat.is_null() {
117                return core::ptr::null();
118            }
119
120            if !(*stat).condition.is_null() {
121                let expr = ast_node_as::<AstExprConstantBool>(
122                    (*stat).condition as *mut luaur_ast::records::ast_node::AstNode,
123                );
124                if !expr.is_null() {
125                    if (*expr).value && !has_break((*stat).body as *mut AstStat) {
126                        return core::ptr::null();
127                    }
128                }
129            }
130
131            return node;
132        }
133
134        if !ast_node_as::<AstStatRepeat>(
135            node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
136        )
137        .is_null()
138        {
139            let stat = ast_node_as::<AstStatRepeat>(
140                node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
141            );
142            if stat.is_null() {
143                return core::ptr::null();
144            }
145
146            if !(*stat).condition.is_null() {
147                let expr = ast_node_as::<AstExprConstantBool>(
148                    (*stat).condition as *mut luaur_ast::records::ast_node::AstNode,
149                );
150                if !expr.is_null() {
151                    if !(*expr).value && !has_break((*stat).body as *mut AstStat) {
152                        return core::ptr::null();
153                    }
154                }
155            }
156
157            if get_fallthrough((*stat).body as *const AstStat).is_null() {
158                return core::ptr::null();
159            }
160
161            return node;
162        }
163
164        node
165    }
166}