Skip to main content

luaur_analysis/functions/
create_table.rs

1use crate::functions::alloc_type_user_data::alloc_type_user_data;
2use crate::functions::get_tag::get_tag;
3use crate::functions::get_type_function_runtime_alt_o::get_type_function_type_id;
4use crate::functions::get_type_user_data::get_type_user_data;
5use crate::functions::optional_type_user_data::optional_type_user_data;
6use crate::records::type_function_property::TypeFunctionProperty;
7use crate::records::type_function_singleton_type::TypeFunctionSingletonType;
8use crate::records::type_function_string_singleton::TypeFunctionStringSingleton;
9use crate::records::type_function_table_indexer::TypeFunctionTableIndexer;
10use crate::records::type_function_table_type::TypeFunctionTableType;
11use crate::type_aliases::lua_state::lua_State;
12use crate::type_aliases::type_function_type_id::TypeFunctionTypeId;
13use crate::type_aliases::type_function_type_variant::TypeFunctionTypeVariant;
14use alloc::string::String;
15use core::ffi::c_int;
16use luaur_vm::functions::lua_getfield::lua_getfield;
17use luaur_vm::functions::lua_gettop::lua_gettop;
18use luaur_vm::functions::lua_l_error_l::lua_l_error_l;
19use luaur_vm::functions::lua_l_typeerror_l::lua_l_typeerror_l;
20use luaur_vm::functions::lua_next::lua_next;
21use luaur_vm::functions::lua_pushnil::lua_pushnil;
22use luaur_vm::macros::lua_isnil::lua_isnil;
23use luaur_vm::macros::lua_isnoneornil::lua_isnoneornil;
24use luaur_vm::macros::lua_istable::lua_istable;
25use luaur_vm::macros::lua_pop::lua_pop;
26
27pub unsafe fn create_table(l: *mut lua_State) -> c_int {
28    let vm_l = l as *mut luaur_vm::records::lua_state::lua_State;
29    let argument_count = lua_gettop(vm_l);
30    if argument_count > 3 {
31        lua_l_error_l(
32            vm_l,
33            c"%s".as_ptr(),
34            core::format_args!(
35                "types.newtable: expected 0-3 arguments, but got {}",
36                argument_count
37            ),
38        );
39    }
40
41    let mut props: alloc::collections::BTreeMap<String, TypeFunctionProperty> =
42        alloc::collections::BTreeMap::new();
43
44    if lua_istable!(vm_l, 1) {
45        lua_pushnil(vm_l);
46        while lua_next(vm_l, 1) != 0 {
47            let key = get_type_user_data(l, -2);
48
49            let tfst = get_type_function_type_id::<TypeFunctionSingletonType>(key);
50            if tfst.is_null() {
51                let tag = get_tag(l, key);
52                lua_l_error_l(
53                    vm_l,
54                    c"%s".as_ptr(),
55                    core::format_args!(
56                        "types.newtable: expected to be given a singleton type, but got {} instead",
57                        tag
58                    ),
59                );
60            }
61
62            let tfsst = (*tfst).variant.get_if::<TypeFunctionStringSingleton>();
63            if tfsst.is_none() {
64                let tag = get_tag(l, key);
65                lua_l_error_l(
66                    vm_l,
67                    c"%s".as_ptr(),
68                    core::format_args!(
69                        "types.newtable: expected to be given a string singleton type, but got {} instead",
70                        tag
71                    ),
72                );
73            }
74            let tfsst = tfsst.unwrap();
75
76            if lua_istable!(vm_l, -1) {
77                lua_getfield(vm_l, -1, c"read".as_ptr());
78                let mut read_ty: Option<TypeFunctionTypeId> = None;
79                if !lua_isnil!(vm_l, -1) {
80                    read_ty = Some(get_type_user_data(l, -1));
81                }
82                lua_pop(vm_l, 1);
83
84                lua_getfield(vm_l, -1, c"write".as_ptr());
85                let mut write_ty: Option<TypeFunctionTypeId> = None;
86                if !lua_isnil!(vm_l, -1) {
87                    write_ty = Some(get_type_user_data(l, -1));
88                }
89                lua_pop(vm_l, 1);
90
91                let key_name = &tfsst.value;
92                props.insert(key_name.clone(), TypeFunctionProperty { read_ty, write_ty });
93            } else {
94                let value = get_type_user_data(l, -1);
95                let key_name = &tfsst.value;
96                props.insert(
97                    key_name.clone(),
98                    TypeFunctionProperty {
99                        read_ty: Some(value),
100                        write_ty: Some(value),
101                    },
102                );
103            }
104
105            lua_pop(vm_l, 1);
106        }
107    } else if !lua_isnoneornil!(vm_l, 1) {
108        lua_l_typeerror_l(vm_l, 1, "table");
109    }
110
111    let mut indexer: Option<TypeFunctionTableIndexer> = None;
112    if lua_istable!(vm_l, 2) {
113        lua_getfield(vm_l, 2, c"index".as_ptr());
114        let key_type = get_type_user_data(l, -1);
115        lua_pop(vm_l, 1);
116
117        lua_getfield(vm_l, 2, c"readresult".as_ptr());
118        let value_type = get_type_user_data(l, -1);
119        lua_pop(vm_l, 1);
120
121        indexer = Some(TypeFunctionTableIndexer::new(key_type, value_type));
122    } else if !lua_isnoneornil!(vm_l, 2) {
123        lua_l_typeerror_l(vm_l, 2, "table");
124    }
125
126    let metatable = optional_type_user_data(l, 3);
127    if let Some(mt) = metatable {
128        let mt_table = get_type_function_type_id::<TypeFunctionTableType>(mt);
129        if mt_table.is_null() {
130            let tag = get_tag(l, mt);
131            lua_l_error_l(
132                vm_l,
133                c"%s".as_ptr(),
134                core::format_args!(
135                    "types.newtable: expected to be given a table type as a metatable, but got {} instead",
136                    tag
137                ),
138            );
139        }
140    }
141
142    alloc_type_user_data(
143        l,
144        TypeFunctionTypeVariant::Table(TypeFunctionTableType {
145            props,
146            indexer,
147            metatable,
148        }),
149        false,
150    );
151    1
152}