luaur_analysis/functions/
create_function.rs1use crate::functions::alloc_type_user_data::alloc_type_user_data;
2use crate::functions::allocate_type_function_type_pack::allocate_type_function_type_pack;
3use crate::functions::get_generics::get_generics;
4use crate::functions::get_type_function_runtime_alt_o::get_type_function_type_id;
5use crate::functions::get_type_user_data::get_type_user_data;
6use crate::functions::optional_type_user_data::optional_type_user_data;
7use crate::records::type_function_function_type::TypeFunctionFunctionType;
8use crate::records::type_function_generic_type::TypeFunctionGenericType;
9use crate::records::type_function_generic_type_pack::TypeFunctionGenericTypePack;
10use crate::records::type_function_type_pack::TypeFunctionTypePack;
11use crate::records::type_function_variadic_type_pack::TypeFunctionVariadicTypePack;
12use crate::type_aliases::lua_state::lua_State;
13use crate::type_aliases::type_function_type_pack_id::TypeFunctionTypePackId;
14use crate::type_aliases::type_function_type_pack_variant::TypeFunctionTypePackVariant;
15use crate::type_aliases::type_function_type_variant::TypeFunctionTypeVariant;
16use alloc::vec::Vec;
17use luaur_vm::functions::lua_getfield::lua_getfield;
18use luaur_vm::functions::lua_gettable::lua_gettable;
19use luaur_vm::functions::lua_gettop::lua_gettop;
20use luaur_vm::functions::lua_l_error_l::lua_l_error_l;
21use luaur_vm::functions::lua_l_typeerror_l::lua_l_typeerror_l;
22use luaur_vm::functions::lua_objlen::lua_objlen;
23use luaur_vm::functions::lua_pushinteger::lua_pushinteger;
24use luaur_vm::functions::lua_pushvalue::lua_pushvalue;
25use luaur_vm::macros::lua_isnil::lua_isnil;
26use luaur_vm::macros::lua_isnoneornil::lua_isnoneornil;
27use luaur_vm::macros::lua_istable::lua_istable;
28use luaur_vm::macros::lua_pop::lua_pop;
29
30pub unsafe fn create_function(l: *mut lua_State) -> core::ffi::c_int {
31 let vm_l = l as *mut luaur_vm::records::lua_state::lua_State;
32 let argument_count = lua_gettop(vm_l);
33 if argument_count > 3 {
34 lua_l_error_l(
35 vm_l,
36 c"%s".as_ptr(),
37 core::format_args!(
38 "types.newfunction: expected 0-3 arguments, but got {}",
39 argument_count
40 ),
41 );
42 }
43
44 let arg_types: TypeFunctionTypePackId;
45
46 if lua_istable!(vm_l, 1) {
47 lua_getfield(vm_l, 1, c"head".as_ptr());
48 lua_getfield(vm_l, 1, c"tail".as_ptr());
49
50 arg_types = get_type_pack_runtime(l, -2, -1);
51
52 lua_pop(vm_l, 2);
53 } else if !lua_isnoneornil!(vm_l, 1) {
54 lua_l_typeerror_l(vm_l, 1, "table");
55 } else {
56 arg_types = allocate_type_function_type_pack(
57 l,
58 TypeFunctionTypePackVariant::V0(TypeFunctionTypePack {
59 head: Vec::new(),
60 tail: None,
61 }),
62 );
63 }
64
65 let ret_types: TypeFunctionTypePackId;
66
67 if lua_istable!(vm_l, 2) {
68 lua_getfield(vm_l, 2, c"head".as_ptr());
69 lua_getfield(vm_l, 2, c"tail".as_ptr());
70
71 ret_types = get_type_pack_runtime(l, -2, -1);
72
73 lua_pop(vm_l, 2);
74 } else if !lua_isnoneornil!(vm_l, 2) {
75 lua_l_typeerror_l(vm_l, 2, "table");
76 } else {
77 ret_types = allocate_type_function_type_pack(
78 l,
79 TypeFunctionTypePackVariant::V0(TypeFunctionTypePack {
80 head: Vec::new(),
81 tail: None,
82 }),
83 );
84 }
85
86 let (generic_types, generic_packs) = get_generics(l, 3, "types.newfunction");
87
88 alloc_type_user_data(
89 l,
90 TypeFunctionTypeVariant::Function(TypeFunctionFunctionType {
91 generics: generic_types,
92 generic_packs,
93 arg_types,
94 ret_types,
95 arg_names: Vec::new(),
96 }),
97 false,
98 );
99
100 1
101}
102
103pub(crate) unsafe fn get_type_pack_runtime(
104 l: *mut lua_State,
105 head_idx: core::ffi::c_int,
106 tail_idx: core::ffi::c_int,
107) -> TypeFunctionTypePackId {
108 let vm_l = l as *mut luaur_vm::records::lua_state::lua_State;
109 let mut head = Vec::new();
110
111 if lua_istable!(vm_l, head_idx) {
112 lua_pushvalue(vm_l, head_idx);
113
114 for i in 1..=lua_objlen(vm_l, -1) {
115 lua_pushinteger(vm_l, i);
116 lua_gettable(vm_l, -2);
117
118 if lua_isnil!(vm_l, -1) {
119 lua_pop(vm_l, 1);
120 break;
121 }
122
123 head.push(get_type_user_data(l, -1));
124 lua_pop(vm_l, 1);
125 }
126
127 lua_pop(vm_l, 1);
128 }
129
130 let mut tail: Option<TypeFunctionTypePackId> = None;
131
132 if let Some(type_id) = optional_type_user_data(l, tail_idx) {
133 let gty = get_type_function_type_id::<TypeFunctionGenericType>(type_id);
134 if !gty.is_null() && (*gty).is_pack {
135 tail = Some(allocate_type_function_type_pack(
136 l,
137 TypeFunctionTypePackVariant::V2(TypeFunctionGenericTypePack {
138 is_named: (*gty).is_named,
139 name: (*gty).name.clone(),
140 }),
141 ));
142 } else {
143 tail = Some(allocate_type_function_type_pack(
144 l,
145 TypeFunctionTypePackVariant::V1(TypeFunctionVariadicTypePack { type_id }),
146 ));
147 }
148 }
149
150 if head.is_empty() && tail.is_some() {
151 tail.unwrap()
152 } else {
153 allocate_type_function_type_pack(
154 l,
155 TypeFunctionTypePackVariant::V0(TypeFunctionTypePack { head, tail }),
156 )
157 }
158}