Skip to content
This repository was archived by the owner on Dec 29, 2024. It is now read-only.

Commit ac5beb3

Browse files
authored
Registry indexing, global manipulation, recursion (#156)
1 parent 8d08147 commit ac5beb3

File tree

8 files changed

+162
-11
lines changed

8 files changed

+162
-11
lines changed

doc_classes/LuaAPI.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<return type="bool" />
4646
<param index="0" name="LuaFunctionName" type="String" />
4747
<description>
48-
Returns [code]true[/code] only if [code]LuaFunctionName[/code] is defined in current Lua's state as a function.
48+
Returns [code]true[/code] only if [code]LuaFunctionName[/code] is defined in the global environment table as a function.
4949
</description>
5050
</method>
5151
<method name="call_function">
@@ -80,6 +80,21 @@
8080
Will push a copy of a Variant to lua as a global. Returns a error if the type is not supported.
8181
</description>
8282
</method>
83+
<method name="get_registry_value">
84+
<return type="Variant" />
85+
<param index="0" name="Name" type="String" />
86+
<description>
87+
Will pull a copy of a Variant from lua's registry table.
88+
</description>
89+
</method>
90+
<method name="set_registry_value">
91+
<return type="LuaError" />
92+
<param index="0" name="Name" type="String" />
93+
<param index="1" name="var" type="Variant" />
94+
<description>
95+
Will push a copy of a Variant to lua's registry table. Returns a error if the type is not supported.
96+
</description>
97+
</method>
8398
<method name="set_hook">
8499
<return type="void" />
85100
<param index="0" name="hook" type="Callable" />

doc_classes/LuaCoroutine.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@
8787
Will push a copy of a Variant to lua as a global. Returns a error if the type is not supported.
8888
</description>
8989
</method>
90+
<method name="get_registry_value">
91+
<return type="Variant" />
92+
<param index="0" name="Name" type="String" />
93+
<description>
94+
Will pull a copy of a Variant from lua's registry table.
95+
</description>
96+
</method>
97+
<method name="set_registry_value">
98+
<return type="LuaError" />
99+
<param index="0" name="Name" type="String" />
100+
<param index="1" name="var" type="Variant" />
101+
<description>
102+
Will push a copy of a Variant to lua's registry table. Returns a error if the type is not supported.
103+
</description>
104+
</method>
90105
<method name="set_hook">
91106
<return type="void" />
92107
<param index="0" name="hook" type="Callable" />

src/classes/luaAPI.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ void LuaAPI::_bind_methods() {
3434
ClassDB::bind_method(D_METHOD("get_memory_usage"), &LuaAPI::getMemoryUsage);
3535
ClassDB::bind_method(D_METHOD("push_variant", "Name", "var"), &LuaAPI::pushGlobalVariant);
3636
ClassDB::bind_method(D_METHOD("pull_variant", "Name"), &LuaAPI::pullVariant);
37+
ClassDB::bind_method(D_METHOD("get_registry_value", "Name"), &LuaAPI::getRegistryValue);
38+
ClassDB::bind_method(D_METHOD("set_registry_value", "Name", "var"), &LuaAPI::setRegistryValue);
3739
ClassDB::bind_method(D_METHOD("call_function", "LuaFunctionName", "Args"), &LuaAPI::callFunction);
3840
ClassDB::bind_method(D_METHOD("call_function_ref", "Args", "LuaFunctionRef"), &LuaAPI::callFunctionRef);
3941
ClassDB::bind_method(D_METHOD("function_exists", "LuaFunctionName"), &LuaAPI::luaFunctionExists);
@@ -94,6 +96,14 @@ uint64_t LuaAPI::getMemoryLimit() const {
9496
return luaAllocData.memoryLimit;
9597
}
9698

99+
Variant LuaAPI::getRegistryValue(String name) {
100+
return state.getRegistryValue(name);
101+
}
102+
103+
Ref<LuaError> LuaAPI::setRegistryValue(String name, Variant var) {
104+
return state.setRegistryValue(name, var);
105+
}
106+
97107
uint64_t LuaAPI::getMemoryUsage() const {
98108
return luaAllocData.memoryUsed;
99109
}
@@ -259,4 +269,4 @@ void *LuaAPI::luaAlloc(void *ud, void *ptr, size_t osize, size_t nsize) {
259269
data->memoryUsed -= (uint64_t)osize;
260270
data->memoryUsed += (uint64_t)nsize;
261271
return memrealloc(ptr, nsize);
262-
}
272+
}

src/classes/luaAPI.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ class LuaAPI : public RefCounted {
4848
Variant callFunction(String functionName, Array args);
4949
Variant callFunctionRef(Array args, int funcRef);
5050

51+
Variant getRegistryValue(String name);
52+
Ref<LuaError> setRegistryValue(String name, Variant var);
53+
5154
Ref<LuaError> doFile(String fileName);
5255
Ref<LuaError> doString(String code);
5356
Ref<LuaError> pushGlobalVariant(String name, Variant var);

src/classes/luaCoroutine.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ void LuaCoroutine::_bind_methods() {
2323
ClassDB::bind_method(D_METHOD("function_exists", "LuaFunctionName"), &LuaCoroutine::luaFunctionExists);
2424
ClassDB::bind_method(D_METHOD("push_variant", "Name", "var"), &LuaCoroutine::pushGlobalVariant);
2525
ClassDB::bind_method(D_METHOD("pull_variant", "Name"), &LuaCoroutine::pullVariant);
26+
ClassDB::bind_method(D_METHOD("get_registry_value", "Name"), &LuaCoroutine::getRegistryValue);
27+
ClassDB::bind_method(D_METHOD("set_registry_value", "Name", "var"), &LuaCoroutine::setRegistryValue);
2628

2729
// This signal is only meant to be used by await when yield_await is called.
2830
ADD_SIGNAL(MethodInfo("coroutine_resume"));
@@ -85,6 +87,16 @@ Variant LuaCoroutine::callFunction(String functionName, Array args) {
8587
return state.callFunction(functionName, args);
8688
}
8789

90+
// Calls LuaState::getRegistryValue()
91+
Variant LuaCoroutine::getRegistryValue(String name) {
92+
return state.getRegistryValue(name);
93+
}
94+
95+
// Calls LuaState::setRegistryValue()
96+
Ref<LuaError> LuaCoroutine::setRegistryValue(String name, Variant var) {
97+
return state.setRegistryValue(name, var);
98+
}
99+
88100
// loads a string into the threads state
89101
Ref<LuaError> LuaCoroutine::loadString(String code) {
90102
done = false;

src/classes/luaCoroutine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class LuaCoroutine : public RefCounted {
3434

3535
bool luaFunctionExists(String functionName);
3636

37+
Variant getRegistryValue(String name);
38+
Ref<LuaError> setRegistryValue(String name, Variant var);
39+
3740
Ref<LuaError> loadString(String code);
3841
Ref<LuaError> loadFile(String fileName);
3942
Ref<LuaError> pushGlobalVariant(String name, Variant var);

src/luaState.cpp

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ lua_State *LuaState::getState() const {
4343

4444
#ifndef LAPI_LUAJIT
4545

46-
// Binds lua librares with the lua state
46+
// Binds lua libraries with the lua state
4747
void LuaState::bindLibraries(Array libs) {
4848
for (int i = 0; i < libs.size(); i++) {
4949
String lib = ((String)libs[i]).to_lower();
@@ -85,7 +85,7 @@ void LuaState::bindLibraries(Array libs) {
8585

8686
#else
8787

88-
// Binds lua librares with the lua state
88+
// Binds lua libraries with the lua state
8989
void LuaState::bindLibraries(Array libs) {
9090
for (int i = 0; i < libs.size(); i++) {
9191
String lib = ((String)libs[i]).to_lower();
@@ -141,10 +141,52 @@ void LuaState::setHook(Callable hook, int mask, int count) {
141141
lua_sethook(L, luaHook, mask, count);
142142
}
143143

144+
void LuaState::indexForReading(String name) {
145+
#ifndef LAPI_GDEXTENSION
146+
Vector<String> strs = name.split(".");
147+
#else
148+
PackedStringArray strs = name.split(".");
149+
#endif
150+
for (String str : strs) {
151+
if (lua_type(L, -1) != LUA_TTABLE) {
152+
lua_pop(L, 1);
153+
lua_pushnil(L);
154+
break;
155+
}
156+
lua_getfield(L, -1, str.ascii().get_data());
157+
lua_remove(L, -2);
158+
}
159+
}
160+
161+
String LuaState::indexForWriting(String name) {
162+
#ifndef LAPI_GDEXTENSION
163+
Vector<String> strs = name.split(".");
164+
#else
165+
PackedStringArray strs = name.split(".");
166+
#endif
167+
String last = strs[strs.size() - 1];
168+
strs.remove_at(strs.size() - 1);
169+
for (String str : strs) {
170+
if (lua_type(L, -1) != LUA_TTABLE) {
171+
lua_pop(L, 1);
172+
lua_pushnil(L);
173+
break;
174+
}
175+
lua_getfield(L, -1, str.ascii().get_data());
176+
lua_remove(L, -2);
177+
}
178+
return last;
179+
}
180+
144181
// Returns true if a lua function exists with the given name
145182
bool LuaState::luaFunctionExists(String functionName) {
183+
#ifndef LAPI_LUAJIT
184+
lua_pushglobaltable(L);
185+
#else
186+
lua_pushvalue(L, LUA_GLOBALSINDEX);
187+
#endif
188+
indexForReading(functionName);
146189
// LuaJIT does not return a type here
147-
lua_getglobal(L, functionName.ascii().get_data());
148190
int type = lua_type(L, -1);
149191
lua_pop(L, 1);
150192
return type == LUA_TFUNCTION;
@@ -157,20 +199,52 @@ Variant LuaState::getVar(int index) const {
157199

158200
// Pull a global variant from Lua to GDScript
159201
Variant LuaState::pullVariant(String name) {
160-
lua_getglobal(L, name.ascii().get_data());
202+
#ifndef LAPI_LUAJIT
203+
lua_pushglobaltable(L);
204+
#else
205+
lua_pushvalue(L, LUA_GLOBALSINDEX);
206+
#endif
207+
indexForReading(name);
208+
Variant val = getVar(-1);
209+
lua_pop(L, 1);
210+
return val;
211+
}
212+
Variant LuaState::getRegistryValue(String name) {
213+
lua_pushvalue(L, LUA_REGISTRYINDEX);
214+
indexForReading(name);
161215
Variant val = getVar(-1);
162216
lua_pop(L, 1);
163217
return val;
164218
}
165219

220+
Ref<LuaError> LuaState::setRegistryValue(String name, Variant var) {
221+
lua_pushvalue(L, LUA_REGISTRYINDEX);
222+
String field = indexForWriting(name);
223+
if (lua_isnil(L, -1)) {
224+
lua_pop(L, 1);
225+
return LuaError::newError("cannot index nil with string", LuaError::ERR_RUNTIME); // Make it look natural.
226+
}
227+
Ref<LuaError> err = pushVariant(var);
228+
if (err.is_null()) {
229+
lua_setfield(L, -2, field.ascii().get_data());
230+
lua_pop(L, 1);
231+
return nullptr;
232+
}
233+
lua_pop(L, 1);
234+
return err;
235+
}
236+
166237
// call a Lua function from GDScript
167238
Variant LuaState::callFunction(String functionName, Array args) {
168239
// push the error handler on to the stack
169240
lua_pushcfunction(L, luaErrorHandler);
170241

171-
// put global function name on stack
172-
lua_getglobal(L, functionName.ascii().get_data());
173-
242+
#ifndef LAPI_LUAJIT
243+
lua_pushglobaltable(L);
244+
#else
245+
lua_pushvalue(L, LUA_GLOBALSINDEX);
246+
#endif
247+
indexForReading(functionName);
174248
// push args
175249
for (int i = 0; i < args.size(); ++i) {
176250
pushVariant(args[i]);
@@ -193,11 +267,23 @@ Ref<LuaError> LuaState::pushVariant(Variant var) const {
193267

194268
// Call pushVariant() and set it to a global name
195269
Ref<LuaError> LuaState::pushGlobalVariant(String name, Variant var) {
270+
#ifndef LAPI_LUAJIT
271+
lua_pushglobaltable(L);
272+
#else
273+
lua_pushvalue(L, LUA_GLOBALSINDEX);
274+
#endif
275+
String field = indexForWriting(name);
276+
if (lua_isnil(L, -1)) {
277+
lua_pop(L, 1);
278+
return LuaError::newError("cannot index nil with string", LuaError::ERR_RUNTIME); // Make it look natural.
279+
}
196280
Ref<LuaError> err = pushVariant(var);
197281
if (err.is_null()) {
198-
lua_setglobal(L, name.ascii().get_data());
282+
lua_setfield(L, -2, field.ascii().get_data());
283+
lua_pop(L, 1);
199284
return nullptr;
200285
}
286+
lua_pop(L, 1);
201287
return err;
202288
}
203289

@@ -332,7 +418,7 @@ Ref<LuaError> LuaState::pushVariant(lua_State *state, Variant var) {
332418
break;
333419
}
334420

335-
// If the type being pushed is a lua error, Raise a error
421+
// If the type being pushed is a lua error, Raise an error
336422
#ifndef LAPI_GDEXTENSION
337423
if (Ref<LuaError> err = Object::cast_to<LuaError>(var.operator Object *()); !err.is_null()) {
338424
#else

src/luaState.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ class LuaState {
2929
Variant pullVariant(String name);
3030
Variant callFunction(String functionName, Array args);
3131

32+
Variant getRegistryValue(String name);
33+
Ref<LuaError> setRegistryValue(String name, Variant var);
34+
3235
Ref<LuaError> pushVariant(Variant var) const;
3336
Ref<LuaError> pushGlobalVariant(String name, Variant var);
3437
Ref<LuaError> handleError(int lua_error) const;
@@ -55,6 +58,10 @@ class LuaState {
5558
private:
5659
lua_State *L = nullptr;
5760

61+
// Helper functions for recursive indexing
62+
void indexForReading(String name); // Puts the object on the stack
63+
String indexForWriting(String name); // Puts the table on the stack and gives the last name. (Please make sure the table is not nil.)
64+
5865
void exposeConstructors();
5966
void createVector2Metatable();
6067
void createVector3Metatable();

0 commit comments

Comments
 (0)