Skip to main content

luaur_vm/functions/
lua_v_gettable.rs

1//! Node: `cxx:Function:Luau.VM:VM/src/lvmutils.cpp:102:luaV_gettable`
2//! Source: `VM/src/lvmutils.cpp:102-180` (hand-ported)
3
4use crate::functions::call_t_mres::call_t_mres;
5use crate::functions::lua_g_indexerror::luaG_indexerror;
6use crate::functions::lua_g_missingmembererror::luaG_missingmembererror;
7use crate::functions::lua_h_get::lua_h_get;
8use crate::functions::lua_t_gettmbyobj::lua_t_gettmbyobj;
9use crate::macros::classvalue::classvalue;
10use crate::macros::fasttm::fasttm;
11use crate::macros::gval_2_slot::gval2slot;
12use crate::macros::hvalue::hvalue;
13use crate::macros::lua_g_runerror::lua_g_runerror;
14use crate::macros::lua_o_nilobject::luaO_nilobject;
15use crate::macros::lua_r_lookupmemberatoffset::luaR_lookupmemberatoffset;
16use crate::macros::maxtagloop::MAXTAGLOOP;
17use crate::macros::nvalue::nvalue;
18use crate::macros::objectvalue::objectvalue;
19use crate::macros::setobj_2_s::setobj2s;
20use crate::macros::ttisclass::ttisclass;
21use crate::macros::ttisfunction::ttisfunction;
22use crate::macros::ttisnil::ttisnil;
23use crate::macros::ttisnumber::ttisnumber;
24use crate::macros::ttisobject::ttisobject;
25use crate::macros::ttistable::ttistable;
26use crate::records::luau_class::LuauClass;
27use crate::records::luau_object::LuauObject;
28use crate::type_aliases::lua_state::lua_State;
29use crate::type_aliases::stk_id::StkId;
30use crate::type_aliases::t_value::TValue;
31use crate::type_aliases::tms::TMS;
32use luaur_common::macros::luau_assert::LUAU_ASSERT;
33
34#[allow(non_snake_case)]
35pub unsafe fn lua_v_gettable(
36    L: *mut lua_State,
37    mut t: *const TValue,
38    key: *mut TValue,
39    val: StkId,
40) {
41    let mut loop_ = 0;
42    while loop_ < MAXTAGLOOP {
43        let mut tm: *const TValue;
44        if ttistable!(t) {
45            let h = hvalue!(t);
46
47            let res = lua_h_get(h, key as *const TValue);
48
49            if res != luaO_nilobject {
50                (*L).cachedslot = gval2slot!(h, res);
51            }
52
53            if !ttisnil!(res) {
54                setobj2s!(L, val, res);
55                return;
56            }
57
58            tm = fasttm(L, (*h).metatable, TMS::TM_INDEX as i32);
59            if tm.is_null() {
60                setobj2s!(L, val, res);
61                return;
62            }
63        } else if luaur_common::FFlag::DebugLuauUserDefinedClassesRuntime.get() && ttisobject!(t) {
64            let inst = &mut **objectvalue!(t) as *mut LuauObject;
65            let offsettval = lua_h_get((*(*inst).lclass).memberstooffset, key as *const TValue);
66
67            if ttisnil!(offsettval) {
68                luaG_missingmembererror(L, t, key as *const TValue);
69            }
70
71            LUAU_ASSERT!(ttisnumber!(offsettval));
72            let offset = nvalue!(offsettval) as i32;
73            setobj2s!(L, val, luaR_lookupmemberatoffset!(inst, offset));
74            return;
75        } else if luaur_common::FFlag::DebugLuauUserDefinedClassesRuntime.get() && ttisclass!(t) {
76            let lco = &mut **classvalue!(t) as *mut LuauClass;
77            let res = lua_h_get((*lco).memberstooffset, key as *const TValue);
78
79            if ttisnil!(res) {
80                luaG_missingmembererror(L, t, key as *const TValue);
81            }
82
83            LUAU_ASSERT!(ttisnumber!(res));
84            let offset = nvalue!(res) as i32;
85            LUAU_ASSERT!(offset >= 0 && offset < (*lco).numberofallmembers);
86
87            if offset < (*lco).numberofinstancemembers {
88                luaG_missingmembererror(L, t, key as *const TValue);
89            }
90
91            setobj2s!(
92                L,
93                val,
94                (*lco)
95                    .staticmembers
96                    .add((offset - (*lco).numberofinstancemembers) as usize)
97            );
98            return;
99        } else {
100            tm = lua_t_gettmbyobj(L, t, TMS::TM_INDEX);
101            if ttisnil!(tm) {
102                luaG_indexerror(L, t, key as *const TValue);
103            }
104        }
105
106        if ttisfunction!(tm) {
107            call_t_mres(L, val, tm, t, key as *const TValue);
108            return;
109        }
110        t = tm;
111        loop_ += 1;
112    }
113    lua_g_runerror!(L, "'__index' chain too long; possible loop");
114}
115
116#[export_name = "luaV_gettable"]
117pub unsafe extern "C" fn lua_v_gettable_export(
118    L: *mut lua_State,
119    t: *const TValue,
120    key: *mut TValue,
121    val: StkId,
122) {
123    lua_v_gettable(L, t, key, val);
124}
125
126#[allow(non_snake_case, unused_imports)]
127pub use lua_v_gettable as luaV_gettable;