Skip to content

Commit

Permalink
Registry indexing, global manipulation, recursion (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
RadiantUwU authored Sep 13, 2023
1 parent 8d08147 commit ac5beb3
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 11 deletions.
17 changes: 16 additions & 1 deletion doc_classes/LuaAPI.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
<return type="bool" />
<param index="0" name="LuaFunctionName" type="String" />
<description>
Returns [code]true[/code] only if [code]LuaFunctionName[/code] is defined in current Lua's state as a function.
Returns [code]true[/code] only if [code]LuaFunctionName[/code] is defined in the global environment table as a function.
</description>
</method>
<method name="call_function">
Expand Down Expand Up @@ -80,6 +80,21 @@
Will push a copy of a Variant to lua as a global. Returns a error if the type is not supported.
</description>
</method>
<method name="get_registry_value">
<return type="Variant" />
<param index="0" name="Name" type="String" />
<description>
Will pull a copy of a Variant from lua's registry table.
</description>
</method>
<method name="set_registry_value">
<return type="LuaError" />
<param index="0" name="Name" type="String" />
<param index="1" name="var" type="Variant" />
<description>
Will push a copy of a Variant to lua's registry table. Returns a error if the type is not supported.
</description>
</method>
<method name="set_hook">
<return type="void" />
<param index="0" name="hook" type="Callable" />
Expand Down
15 changes: 15 additions & 0 deletions doc_classes/LuaCoroutine.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@
Will push a copy of a Variant to lua as a global. Returns a error if the type is not supported.
</description>
</method>
<method name="get_registry_value">
<return type="Variant" />
<param index="0" name="Name" type="String" />
<description>
Will pull a copy of a Variant from lua's registry table.
</description>
</method>
<method name="set_registry_value">
<return type="LuaError" />
<param index="0" name="Name" type="String" />
<param index="1" name="var" type="Variant" />
<description>
Will push a copy of a Variant to lua's registry table. Returns a error if the type is not supported.
</description>
</method>
<method name="set_hook">
<return type="void" />
<param index="0" name="hook" type="Callable" />
Expand Down
12 changes: 11 additions & 1 deletion src/classes/luaAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ void LuaAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_memory_usage"), &LuaAPI::getMemoryUsage);
ClassDB::bind_method(D_METHOD("push_variant", "Name", "var"), &LuaAPI::pushGlobalVariant);
ClassDB::bind_method(D_METHOD("pull_variant", "Name"), &LuaAPI::pullVariant);
ClassDB::bind_method(D_METHOD("get_registry_value", "Name"), &LuaAPI::getRegistryValue);
ClassDB::bind_method(D_METHOD("set_registry_value", "Name", "var"), &LuaAPI::setRegistryValue);
ClassDB::bind_method(D_METHOD("call_function", "LuaFunctionName", "Args"), &LuaAPI::callFunction);
ClassDB::bind_method(D_METHOD("call_function_ref", "Args", "LuaFunctionRef"), &LuaAPI::callFunctionRef);
ClassDB::bind_method(D_METHOD("function_exists", "LuaFunctionName"), &LuaAPI::luaFunctionExists);
Expand Down Expand Up @@ -94,6 +96,14 @@ uint64_t LuaAPI::getMemoryLimit() const {
return luaAllocData.memoryLimit;
}

Variant LuaAPI::getRegistryValue(String name) {
return state.getRegistryValue(name);
}

Ref<LuaError> LuaAPI::setRegistryValue(String name, Variant var) {
return state.setRegistryValue(name, var);
}

uint64_t LuaAPI::getMemoryUsage() const {
return luaAllocData.memoryUsed;
}
Expand Down Expand Up @@ -259,4 +269,4 @@ void *LuaAPI::luaAlloc(void *ud, void *ptr, size_t osize, size_t nsize) {
data->memoryUsed -= (uint64_t)osize;
data->memoryUsed += (uint64_t)nsize;
return memrealloc(ptr, nsize);
}
}
3 changes: 3 additions & 0 deletions src/classes/luaAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class LuaAPI : public RefCounted {
Variant callFunction(String functionName, Array args);
Variant callFunctionRef(Array args, int funcRef);

Variant getRegistryValue(String name);
Ref<LuaError> setRegistryValue(String name, Variant var);

Ref<LuaError> doFile(String fileName);
Ref<LuaError> doString(String code);
Ref<LuaError> pushGlobalVariant(String name, Variant var);
Expand Down
12 changes: 12 additions & 0 deletions src/classes/luaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ void LuaCoroutine::_bind_methods() {
ClassDB::bind_method(D_METHOD("function_exists", "LuaFunctionName"), &LuaCoroutine::luaFunctionExists);
ClassDB::bind_method(D_METHOD("push_variant", "Name", "var"), &LuaCoroutine::pushGlobalVariant);
ClassDB::bind_method(D_METHOD("pull_variant", "Name"), &LuaCoroutine::pullVariant);
ClassDB::bind_method(D_METHOD("get_registry_value", "Name"), &LuaCoroutine::getRegistryValue);
ClassDB::bind_method(D_METHOD("set_registry_value", "Name", "var"), &LuaCoroutine::setRegistryValue);

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

// Calls LuaState::getRegistryValue()
Variant LuaCoroutine::getRegistryValue(String name) {
return state.getRegistryValue(name);
}

// Calls LuaState::setRegistryValue()
Ref<LuaError> LuaCoroutine::setRegistryValue(String name, Variant var) {
return state.setRegistryValue(name, var);
}

// loads a string into the threads state
Ref<LuaError> LuaCoroutine::loadString(String code) {
done = false;
Expand Down
3 changes: 3 additions & 0 deletions src/classes/luaCoroutine.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class LuaCoroutine : public RefCounted {

bool luaFunctionExists(String functionName);

Variant getRegistryValue(String name);
Ref<LuaError> setRegistryValue(String name, Variant var);

Ref<LuaError> loadString(String code);
Ref<LuaError> loadFile(String fileName);
Ref<LuaError> pushGlobalVariant(String name, Variant var);
Expand Down
104 changes: 95 additions & 9 deletions src/luaState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ lua_State *LuaState::getState() const {

#ifndef LAPI_LUAJIT

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

#else

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

void LuaState::indexForReading(String name) {
#ifndef LAPI_GDEXTENSION
Vector<String> strs = name.split(".");
#else
PackedStringArray strs = name.split(".");
#endif
for (String str : strs) {
if (lua_type(L, -1) != LUA_TTABLE) {
lua_pop(L, 1);
lua_pushnil(L);
break;
}
lua_getfield(L, -1, str.ascii().get_data());
lua_remove(L, -2);
}
}

String LuaState::indexForWriting(String name) {
#ifndef LAPI_GDEXTENSION
Vector<String> strs = name.split(".");
#else
PackedStringArray strs = name.split(".");
#endif
String last = strs[strs.size() - 1];
strs.remove_at(strs.size() - 1);
for (String str : strs) {
if (lua_type(L, -1) != LUA_TTABLE) {
lua_pop(L, 1);
lua_pushnil(L);
break;
}
lua_getfield(L, -1, str.ascii().get_data());
lua_remove(L, -2);
}
return last;
}

// Returns true if a lua function exists with the given name
bool LuaState::luaFunctionExists(String functionName) {
#ifndef LAPI_LUAJIT
lua_pushglobaltable(L);
#else
lua_pushvalue(L, LUA_GLOBALSINDEX);
#endif
indexForReading(functionName);
// LuaJIT does not return a type here
lua_getglobal(L, functionName.ascii().get_data());
int type = lua_type(L, -1);
lua_pop(L, 1);
return type == LUA_TFUNCTION;
Expand All @@ -157,20 +199,52 @@ Variant LuaState::getVar(int index) const {

// Pull a global variant from Lua to GDScript
Variant LuaState::pullVariant(String name) {
lua_getglobal(L, name.ascii().get_data());
#ifndef LAPI_LUAJIT
lua_pushglobaltable(L);
#else
lua_pushvalue(L, LUA_GLOBALSINDEX);
#endif
indexForReading(name);
Variant val = getVar(-1);
lua_pop(L, 1);
return val;
}
Variant LuaState::getRegistryValue(String name) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
indexForReading(name);
Variant val = getVar(-1);
lua_pop(L, 1);
return val;
}

Ref<LuaError> LuaState::setRegistryValue(String name, Variant var) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
String field = indexForWriting(name);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
return LuaError::newError("cannot index nil with string", LuaError::ERR_RUNTIME); // Make it look natural.
}
Ref<LuaError> err = pushVariant(var);
if (err.is_null()) {
lua_setfield(L, -2, field.ascii().get_data());
lua_pop(L, 1);
return nullptr;
}
lua_pop(L, 1);
return err;
}

// call a Lua function from GDScript
Variant LuaState::callFunction(String functionName, Array args) {
// push the error handler on to the stack
lua_pushcfunction(L, luaErrorHandler);

// put global function name on stack
lua_getglobal(L, functionName.ascii().get_data());

#ifndef LAPI_LUAJIT
lua_pushglobaltable(L);
#else
lua_pushvalue(L, LUA_GLOBALSINDEX);
#endif
indexForReading(functionName);
// push args
for (int i = 0; i < args.size(); ++i) {
pushVariant(args[i]);
Expand All @@ -193,11 +267,23 @@ Ref<LuaError> LuaState::pushVariant(Variant var) const {

// Call pushVariant() and set it to a global name
Ref<LuaError> LuaState::pushGlobalVariant(String name, Variant var) {
#ifndef LAPI_LUAJIT
lua_pushglobaltable(L);
#else
lua_pushvalue(L, LUA_GLOBALSINDEX);
#endif
String field = indexForWriting(name);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
return LuaError::newError("cannot index nil with string", LuaError::ERR_RUNTIME); // Make it look natural.
}
Ref<LuaError> err = pushVariant(var);
if (err.is_null()) {
lua_setglobal(L, name.ascii().get_data());
lua_setfield(L, -2, field.ascii().get_data());
lua_pop(L, 1);
return nullptr;
}
lua_pop(L, 1);
return err;
}

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

// If the type being pushed is a lua error, Raise a error
// If the type being pushed is a lua error, Raise an error
#ifndef LAPI_GDEXTENSION
if (Ref<LuaError> err = Object::cast_to<LuaError>(var.operator Object *()); !err.is_null()) {
#else
Expand Down
7 changes: 7 additions & 0 deletions src/luaState.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class LuaState {
Variant pullVariant(String name);
Variant callFunction(String functionName, Array args);

Variant getRegistryValue(String name);
Ref<LuaError> setRegistryValue(String name, Variant var);

Ref<LuaError> pushVariant(Variant var) const;
Ref<LuaError> pushGlobalVariant(String name, Variant var);
Ref<LuaError> handleError(int lua_error) const;
Expand All @@ -55,6 +58,10 @@ class LuaState {
private:
lua_State *L = nullptr;

// Helper functions for recursive indexing
void indexForReading(String name); // Puts the object on the stack
String indexForWriting(String name); // Puts the table on the stack and gives the last name. (Please make sure the table is not nil.)

void exposeConstructors();
void createVector2Metatable();
void createVector3Metatable();
Expand Down

0 comments on commit ac5beb3

Please sign in to comment.