Skip to main content

luaur_vm/functions/
lua_getlocal.rs

1use crate::functions::currentpc::currentpc;
2use crate::functions::getluaproto::get_lua_proto;
3use crate::functions::lua_a_pushvalue::luaA_pushvalue;
4use crate::functions::lua_f_getlocal::luaF_getlocal;
5use crate::macros::getstr::getstr;
6use crate::macros::lua_c_threadbarrier::luaC_threadbarrier;
7use crate::macros::lua_callinfo_native::LUA_CALLINFO_NATIVE;
8use crate::records::call_info::CallInfo;
9use crate::records::loc_var::LocVar;
10use crate::records::lua_state::lua_State;
11use crate::type_aliases::proto::Proto;
12
13#[no_mangle]
14pub unsafe fn lua_getlocal(
15    L: *mut lua_State,
16    level: core::ffi::c_int,
17    n: core::ffi::c_int,
18) -> *const core::ffi::c_char {
19    if (level as u32) >= ((*L).ci.offset_from((*L).base_ci) as u32) {
20        return core::ptr::null();
21    }
22
23    let ci: *mut CallInfo = (*L).ci.offset(-(level as isize));
24
25    // changing tables in native functions externally may invalidate safety contracts wrt table state (metatable/size/readonly)
26    if ((*ci).flags & LUA_CALLINFO_NATIVE as u32) != 0 {
27        return core::ptr::null();
28    }
29
30    let fp: *mut Proto = get_lua_proto(ci);
31    let var: *const LocVar = if !fp.is_null() {
32        luaF_getlocal(fp, n, currentpc(L, ci))
33    } else {
34        core::ptr::null()
35    };
36
37    if !var.is_null() {
38        luaC_threadbarrier!(L);
39        luaA_pushvalue(L, (*ci).base.offset((*var).reg as isize));
40    }
41
42    if !var.is_null() {
43        getstr((*var).varname)
44    } else {
45        core::ptr::null()
46    }
47}