luaur_analysis/functions/
create_table.rs1use 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}