Skip to main content

luaur_analysis/functions/
try_get_l_value.rs

1use crate::records::field::Field;
2use crate::records::symbol::Symbol;
3use crate::type_aliases::l_value::LValue;
4use alloc::sync::Arc;
5use luaur_ast::records::ast_expr::AstExpr;
6use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
7use luaur_ast::records::ast_expr_global::AstExprGlobal;
8use luaur_ast::records::ast_expr_group::AstExprGroup;
9use luaur_ast::records::ast_expr_index_expr::AstExprIndexExpr;
10use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
11use luaur_ast::records::ast_expr_local::AstExprLocal;
12use luaur_ast::rtti::ast_node_as;
13
14pub fn try_get_l_value(node: &AstExpr) -> Option<LValue> {
15    let mut expr = node as *const AstExpr;
16
17    unsafe {
18        loop {
19            let group =
20                ast_node_as::<AstExprGroup>(expr as *mut luaur_ast::records::ast_node::AstNode);
21            if !group.is_null() {
22                expr = (*group).expr;
23                continue;
24            }
25            break;
26        }
27
28        let local = ast_node_as::<AstExprLocal>(expr as *mut luaur_ast::records::ast_node::AstNode);
29        if !local.is_null() {
30            return Some(LValue::Symbol(Symbol::symbol_ast_local((*local).local)));
31        }
32
33        let global =
34            ast_node_as::<AstExprGlobal>(expr as *mut luaur_ast::records::ast_node::AstNode);
35        if !global.is_null() {
36            return Some(LValue::Symbol(Symbol::symbol_ast_name((*global).name)));
37        }
38
39        let indexname =
40            ast_node_as::<AstExprIndexName>(expr as *mut luaur_ast::records::ast_node::AstNode);
41        if !indexname.is_null() {
42            if let Some(lvalue) = try_get_l_value(&*(*indexname).expr) {
43                let key = if (*indexname).index.value.is_null() {
44                    alloc::string::String::new()
45                } else {
46                    core::ffi::CStr::from_ptr((*indexname).index.value)
47                        .to_string_lossy()
48                        .into_owned()
49                };
50                return Some(LValue::Field(Field {
51                    parent: Some(Arc::new(lvalue)),
52                    key,
53                }));
54            }
55        }
56
57        let indexexpr =
58            ast_node_as::<AstExprIndexExpr>(expr as *mut luaur_ast::records::ast_node::AstNode);
59        if !indexexpr.is_null() {
60            if let Some(lvalue) = try_get_l_value(&*(*indexexpr).expr) {
61                let string_node = ast_node_as::<AstExprConstantString>(
62                    (*indexexpr).index as *mut luaur_ast::records::ast_node::AstNode,
63                );
64                if !string_node.is_null() {
65                    let data = (*string_node).value.data;
66                    let size = (*string_node).value.size;
67                    let key = if data.is_null() {
68                        alloc::string::String::new()
69                    } else {
70                        let slice = core::slice::from_raw_parts(data as *const u8, size as usize);
71                        alloc::string::String::from_utf8_lossy(slice).into_owned()
72                    };
73                    return Some(LValue::Field(Field {
74                        parent: Some(Arc::new(lvalue)),
75                        key,
76                    }));
77                }
78            }
79        }
80    }
81
82    None
83}