From f793d8ef7ec33d103dd7f3b3f59325719595937b Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Mon, 23 Sep 2024 01:02:58 -0400 Subject: [PATCH] Lua API: Plugin execute functionality now supports named tuples in the closure --- src/scripting/application_lua_kernel.cpp | 22 +++++++++++++++----- src/scripting/lua_common.cpp | 13 ++++++++++++ src/scripting/lua_common.hpp | 6 ++++++ src/scripting/lua_kernel_base.cpp | 26 ++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/scripting/application_lua_kernel.cpp b/src/scripting/application_lua_kernel.cpp index 5e7c6f5c021..9bec6fa171d 100644 --- a/src/scripting/application_lua_kernel.cpp +++ b/src/scripting/application_lua_kernel.cpp @@ -422,14 +422,15 @@ application_lua_kernel::request_list application_lua_kernel::thread::run_script( results.push_back([this, lk = ctxt.execute_kernel_, data = req.data]() { auto result = lk->run_binary_lua_tag(data); int ref = result["ref"]; - auto func = result.mandatory_child("executed"); + if(auto func = result.optional_child("executed")) { + lua_rawgeti(T_, LUA_REGISTRYINDEX, ref); + luaW_copy_upvalues(T_, *func); + luaL_unref(T_, LUA_REGISTRYINDEX, ref); + lua_pop(T_, 1); + } result.remove_children("executed"); result.remove_attribute("ref"); plugins_manager::get()->notify_event(result["name"], result); - lua_rawgeti(T_, LUA_REGISTRYINDEX, ref); - luaW_copy_upvalues(T_, func); - luaL_unref(T_, LUA_REGISTRYINDEX, ref); - lua_pop(T_, 1); return true; }); continue; @@ -462,6 +463,17 @@ bool luaW_copy_upvalues(lua_State* L, const config& cfg) luaW_pushscalar(L, cfg["value"]); lua_rawseti(L, -2, lua_rawlen(L, -2) + 1); } + } else if(child["upvalue_type"] == "named tuple") { + auto children = upvalues->child_range(name); + std::vector names; + for(const auto& cfg : children) { + names.push_back(cfg["name"]); + } + luaW_push_namedtuple(L, names); + for(const auto& cfg : children) { + luaW_pushscalar(L, cfg["value"]); + lua_rawseti(L, -2, lua_rawlen(L, -2) + 1); + } } else if(child["upvalue_type"] == "config") { luaW_pushconfig(L, child); } else if(child["upvalue_type"] == "function") { diff --git a/src/scripting/lua_common.cpp b/src/scripting/lua_common.cpp index 6843b7cbd92..3d23bc88762 100644 --- a/src/scripting/lua_common.cpp +++ b/src/scripting/lua_common.cpp @@ -792,6 +792,19 @@ void luaW_push_namedtuple(lua_State* L, const std::vector& names) lua_setmetatable(L, -2); } +std::vector luaW_to_namedtuple(lua_State* L, int idx) { + std::vector names; + if(luaL_getmetafield(L, idx, "__name")) { + if(lua_check(L, -1) == "named tuple") { + luaL_getmetafield(L, idx, "__names"); + names = lua_check>(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + return names; +} + void luaW_pushlocation(lua_State *L, const map_location& ml) { luaW_push_namedtuple(L, {"x", "y"}); diff --git a/src/scripting/lua_common.hpp b/src/scripting/lua_common.hpp index cb22dfbd526..12837da8c35 100644 --- a/src/scripting/lua_common.hpp +++ b/src/scripting/lua_common.hpp @@ -101,6 +101,12 @@ void luaW_filltable(lua_State *L, const config& cfg); */ void luaW_push_namedtuple(lua_State* L, const std::vector& names); +/** + * Get the keys of a "named tuple" from the stack. + * Returns an empty array if the stack element is not a named tuple. + */ +std::vector luaW_to_namedtuple(lua_State* L, int idx); + /** * Converts a map location object to a Lua table pushed at the top of the stack. */ diff --git a/src/scripting/lua_kernel_base.cpp b/src/scripting/lua_kernel_base.cpp index afb8a2e941c..0a695152183 100644 --- a/src/scripting/lua_kernel_base.cpp +++ b/src/scripting/lua_kernel_base.cpp @@ -1135,9 +1135,29 @@ config luaW_serialize_function(lua_State* L, int func) case LUA_TFUNCTION: upvalues.add_child(name, luaW_serialize_function(L, idx))["upvalue_type"] = "function"; break; + case LUA_TNIL: + upvalues.add_child(name, config{"upvalue_type", "nil"}); + break; case LUA_TTABLE: - if(config cfg; luaW_toconfig(L, idx, cfg)) { - upvalues.add_child(name, cfg)["upvalue_type"] = "config"; + if(std::vector names = luaW_to_namedtuple(L, idx); !names.empty()) { + for(size_t i = 1; i <= lua_rawlen(L, -1); i++, lua_pop(L, 1)) { + lua_rawgeti(L, idx, i); + config& cfg = upvalues.add_child(name); + luaW_toscalar(L, -1, cfg["value"]); + cfg["name"] = names[0]; + cfg["upvalue_type"] = "named tuple"; + names.erase(names.begin()); + } + break; + } else if(config cfg; luaW_toconfig(L, idx, cfg)) { + std::vector names; + int save_top = lua_gettop(L); + if(luaL_getmetafield(L, idx, "__name") && lua_check(L, -1) == "named tuple") { + luaL_getmetafield(L, -2, "__names"); + names = lua_check>(L, -1); + } + lua_settop(L, save_top); + upvalues.add_child(name, cfg)["upvalue_type"] = names.empty() ? "config" : "named tuple"; break; } else { for(size_t i = 1; i <= lua_rawlen(L, -1); i++, lua_pop(L, 1)) { @@ -1199,6 +1219,8 @@ bool lua_kernel_base::load_binary(const config& cfg, error_handler eh) luaW_pushconfig(mState, child); } else if(child["upvalue_type"] == "function") { if(!load_binary(child, eh)) return false; + } else if(child["upvalue_type"] == "nil") { + lua_pushnil(mState); } } else continue; lua_setupvalue(mState, funcindex, i);