Skip to main content

luaur_analysis/functions/
create_function.rs

1use 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}