1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#include "compat.h"
#include "macros_and_utils.h"
// #################################################################################################
// ###################################### Lua 5.1 / 5.2 / 5.3 ######################################
// #################################################################################################
// #################################################################################################
// a small helper to obtain a module's table from the registry instead of relying on the presence of _G["<name>"]
LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_)
{
STACK_CHECK_START_REL(L_, 0);
LuaType _type{ luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil
if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil
STACK_CHECK(L_, 1);
return _type;
}
_type = luaG_getfield(L_, -1, name_); // L_: _R._LOADED {module}|nil
lua_remove(L_, -2); // L_: {module}|nil
STACK_CHECK(L_, 1);
return _type;
}
// #################################################################################################
// #################################################################################################
#if LUA_VERSION_NUM == 501
// #################################################################################################
// #################################################################################################
// Copied from Lua 5.2 loadlib.c
int luaL_getsubtable(lua_State* L_, int idx_, const char* fname_)
{
lua_getfield(L_, idx_, fname_);
if (lua_istable(L_, -1))
return 1; /* table already there */
else {
lua_pop(L_, 1); /* remove previous result */
idx_ = luaG_absindex(L_, idx_);
lua_newtable(L_);
lua_pushvalue(L_, -1); /* copy to be left at top */
lua_setfield(L_, idx_, fname_); /* assign new table to field */
return 0; /* false, because did not find table there */
}
}
// #################################################################################################
void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, int glb_)
{
lua_pushcfunction(L_, openf_);
lua_pushstring(L_, modname_); /* argument to open function */
lua_call(L_, 1, 1); /* open module */
luaL_getsubtable(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_pushvalue(L_, -2); /* make copy of module (call result) */
lua_setfield(L_, -2, modname_); /* _LOADED[modname] = module */
lua_pop(L_, 1); /* remove _LOADED table */
if (glb_) {
lua_pushvalue(L_, -1); /* copy of 'mod' */
lua_setglobal(L_, modname_); /* _G[modname] = module */
}
}
#endif // LUA_VERSION_NUM
// #################################################################################################
// #################################################################################################
#if LUA_VERSION_NUM < 504
// #################################################################################################
// #################################################################################################
void* lua_newuserdatauv(lua_State* L_, size_t sz_, [[maybe_unused]] int nuvalue_)
{
LUA_ASSERT(L_, nuvalue_ <= 1);
return lua_newuserdata(L_, sz_);
}
// #################################################################################################
// push on stack uservalue #n of full userdata at idx
int lua_getiuservalue(lua_State* L_, int idx_, int n_)
{
STACK_CHECK_START_REL(L_, 0);
// full userdata can have only 1 uservalue before 5.4
if (n_ > 1) {
lua_pushnil(L_);
return LUA_TNONE;
}
#if LUA_VERSION_NUM == 501
lua_getfenv(L_, idx_); // L_: ... {}|nil
STACK_CHECK(L_, 1);
// default environment is not a nil (see lua_getfenv)
lua_getglobal(L_, LUA_LOADLIBNAME); // L_: ... {}|nil package
if (lua_rawequal(L_, -2, -1) || lua_rawequal(L_, -2, LUA_GLOBALSINDEX)) {
lua_pop(L_, 2); // L_: ...
lua_pushnil(L_); // L_: ... nil
STACK_CHECK(L_, 1);
return LUA_TNONE;
}
else {
lua_pop(L_, 1); // L_: ... nil
}
#else // LUA_VERSION_NUM > 501
lua_getuservalue(L_, idx_); // L_: {}|nil
#endif// LUA_VERSION_NUM > 501
STACK_CHECK(L_, 1);
int const _uvType{ lua_type(L_, -1) };
// under Lua 5.2, there is a single uservalue that is either nil or a table.
// If nil, don't transfer it, as it can cause issues when copying to a Keeper state because of nil sentinel conversion
return (LUA_VERSION_NUM == 502 && _uvType == LUA_TNIL) ? LUA_TNONE : _uvType;
}
// #################################################################################################
// Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index.
// Returns 0 if the userdata does not have that value.
int lua_setiuservalue(lua_State* L_, int idx_, int n_)
{
if (n_ > 1
#if LUA_VERSION_NUM == 501
|| lua_type(L_, -1) != LUA_TTABLE
#endif
) {
lua_pop(L_, 1);
return 0;
}
#if LUA_VERSION_NUM == 501
lua_setfenv(L_, idx_);
#else // LUA_VERSION_NUM == 501
lua_setuservalue(L_, idx_);
#endif // LUA_VERSION_NUM == 501
return 1; // I guess anything non-0 is ok
}
#endif // LUA_VERSION_NUM
|