Skip to main content

luaur_analysis/functions/
get_generics.rs

1//! Faithful port of
2//! `static std::tuple<std::vector<TypeFunctionTypeId>, std::vector<TypeFunctionTypePackId>>
3//!  getGenerics(lua_State* L, int idx, const char* fname)`
4//! (Analysis/src/TypeFunctionRuntime.cpp:1125-1177).
5use crate::functions::allocate_type_function_type_pack::allocate_type_function_type_pack;
6use crate::functions::get_type_function_runtime_alt_o::get_type_function_type_id;
7use crate::functions::get_type_user_data::get_type_user_data;
8use crate::records::type_function_generic_type::TypeFunctionGenericType;
9use crate::records::type_function_generic_type_pack::TypeFunctionGenericTypePack;
10use crate::type_aliases::lua_state::lua_State;
11use crate::type_aliases::type_function_type_id::TypeFunctionTypeId;
12use crate::type_aliases::type_function_type_pack_id::TypeFunctionTypePackId;
13use crate::type_aliases::type_function_type_pack_variant::TypeFunctionTypePackVariant;
14use alloc::vec::Vec;
15use luaur_vm::functions::lua_gettable::lua_gettable;
16use luaur_vm::functions::lua_l_error_l::lua_l_error_l;
17use luaur_vm::functions::lua_l_typeerror_l::lua_l_typeerror_l;
18use luaur_vm::functions::lua_objlen::lua_objlen;
19use luaur_vm::functions::lua_pushinteger::lua_pushinteger;
20use luaur_vm::functions::lua_pushvalue::lua_pushvalue;
21use luaur_vm::macros::lua_isnil::lua_isnil;
22use luaur_vm::macros::lua_isnoneornil::lua_isnoneornil;
23use luaur_vm::macros::lua_istable::lua_istable;
24use luaur_vm::macros::lua_pop::lua_pop;
25
26pub unsafe fn get_generics(
27    l: *mut lua_State,
28    idx: i32,
29    fname: &str,
30) -> (Vec<TypeFunctionTypeId>, Vec<TypeFunctionTypePackId>) {
31    let vm_l = l as *mut luaur_vm::records::lua_state::lua_State;
32
33    let mut types: Vec<TypeFunctionTypeId> = Vec::new();
34    let mut packs: Vec<TypeFunctionTypePackId> = Vec::new();
35
36    if lua_istable!(vm_l, idx) {
37        lua_pushvalue(vm_l, idx);
38
39        let mut i: core::ffi::c_int = 1;
40        while i <= lua_objlen(vm_l, -1) {
41            lua_pushinteger(vm_l, i);
42            lua_gettable(vm_l, -2);
43
44            if lua_isnil!(vm_l, -1) {
45                lua_pop(vm_l, 1);
46                break;
47            }
48
49            // TypeFunctionTypeId ty = getTypeUserData(L, -1);
50            let ty = get_type_user_data(l, -1);
51
52            // if (auto gty = get<TypeFunctionGenericType>(ty))
53            let gty = get_type_function_type_id::<TypeFunctionGenericType>(ty);
54            if !gty.is_null() {
55                if (*gty).is_pack {
56                    packs.push(allocate_type_function_type_pack(
57                        l,
58                        TypeFunctionTypePackVariant::V2(TypeFunctionGenericTypePack {
59                            is_named: (*gty).is_named,
60                            name: (*gty).name.clone(),
61                        }),
62                    ));
63                } else {
64                    if !packs.is_empty() {
65                        lua_l_error_l(
66                            vm_l,
67                            c"%s".as_ptr(),
68                            core::format_args!(
69                                "{}: generic type cannot follow a generic pack",
70                                fname
71                            ),
72                        );
73                    }
74
75                    types.push(ty);
76                }
77            } else {
78                lua_l_error_l(
79                    vm_l,
80                    c"%s".as_ptr(),
81                    core::format_args!("{}: table member was not a generic type", fname),
82                );
83            }
84
85            lua_pop(vm_l, 1);
86            i += 1;
87        }
88
89        lua_pop(vm_l, 1);
90    } else if !lua_isnoneornil!(vm_l, idx) {
91        lua_l_typeerror_l(vm_l, idx, "table");
92    }
93
94    (types, packs)
95}