From f1d6a8faf987984ebd0ce83116b1e6d31d2341ba Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Tue, 17 Aug 2021 10:07:42 +0200 Subject: [PATCH] SCRIPT: Register functions and jobs when registering a module. Only local functions and jobs are registered, the other will be registered with their parent script. --- rsc/lua/module.lua | 3 + src/Lib/Script/CRTPLuaScriptObject.hh | 14 ++++ .../FunctionDeclaration.cc | 28 ++++++- .../CRTPLuaScriptObject/JobDeclaration.cc | 28 ++++++- .../CRTPLuaScriptObject/ModuleDeclaration.cc | 9 ++- src/Lib/Script/LuaContext.cc | 77 +++++++++++++++++-- src/Lib/Script/LuaContext.hh | 39 ++++++++-- 7 files changed, 181 insertions(+), 17 deletions(-) diff --git a/rsc/lua/module.lua b/rsc/lua/module.lua index 52c28751..8975ff8e 100644 --- a/rsc/lua/module.lua +++ b/rsc/lua/module.lua @@ -113,6 +113,9 @@ function DeclareModule(tbl) if tbl.functions then module:setFunctions(tbl.functions) end ___tryImportOptions(module, tbl) + -- Register jobs and functions in runtime now that they are added to the module! + for _, job in ipairs(tbl.jobs) do job:pushToRuntime() end + for _, fun in ipairs(tbl.functions) do fun:pushToRuntime() end -- Register the module! module:pushToRuntime() diff --git a/src/Lib/Script/CRTPLuaScriptObject.hh b/src/Lib/Script/CRTPLuaScriptObject.hh index c0a145f4..989f0140 100644 --- a/src/Lib/Script/CRTPLuaScriptObject.hh +++ b/src/Lib/Script/CRTPLuaScriptObject.hh @@ -183,6 +183,8 @@ script_class (JobDeclaration) { static int setOptions(lua_State *) noexcept; static int setImportFromScript(lua_State *) noexcept; + static int pushToRuntime(lua_State *const) noexcept; + static int TOSTRING(lua_State *const) noexcept; method_list metaMethods = { luaRegDefaultGC, @@ -190,12 +192,17 @@ script_class (JobDeclaration) { method_list methods = { LUA_DECL_METHOD(JobDeclaration, setName), LUA_DECL_METHOD(JobDeclaration, setOptions), LUA_DECL_METHOD(JobDeclaration, setImportFromScript), + LUA_DECL_METHOD(JobDeclaration, pushToRuntime), LUA_DECL_CREATE(JobDeclaration) }; + bool isImported{ false }; + public: std::string name{}; std::string parentScript{}; std::vector<OptionDeclaration *> options{}; + + bool isLocalToModule() const noexcept; }; // Function declaration @@ -205,17 +212,24 @@ script_class (FunctionDeclaration) { static int setName(lua_State *) noexcept; static int setImportFromScript(lua_State *) noexcept; + static int pushToRuntime(lua_State *const) noexcept; + static int TOSTRING(lua_State *const) noexcept; method_list metaMethods = { luaRegDefaultGC, LUA_DECL_META_METHOD(FunctionDeclaration, "__tostring", TOSTRING) }; method_list methods = { LUA_DECL_METHOD(FunctionDeclaration, setName), LUA_DECL_METHOD(FunctionDeclaration, setImportFromScript), + LUA_DECL_METHOD(FunctionDeclaration, pushToRuntime), LUA_DECL_CREATE(FunctionDeclaration) }; + bool isImported{ false }; + public: std::string name{}; std::string parentScript{}; + + bool isLocalToModule() const noexcept; }; // Module declaration diff --git a/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc index 4612f031..70f2dac4 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc @@ -27,6 +27,32 @@ FunctionDeclaration::setName(lua_State *L) noexcept int FunctionDeclaration::setImportFromScript(lua_State *L) noexcept { - FunctionDeclaration::CHECK(L, 1)->parentScript = CHECK_STRING_VIEW(L, 2); + auto *const fun = FunctionDeclaration::CHECK(L, 1); + fun->parentScript = CHECK_STRING_VIEW(L, 2); + fun->isImported = true; LUA_RETURN_NOTHING(L); } + +int +FunctionDeclaration::pushToRuntime(lua_State *const L) noexcept +{ + FunctionDeclaration *const self = CHECK(L, 1); + auto *const context = LuaContext::getContext(L); + + lua_settop(L, 1); + + if (self->isImported) + err(context) << "The function \"" << self->parentScript << "::" << self->name + << "\" is an imported function\n"; + + else if (context->registerDeclaration(self) == LuaContext::Code::Error) + context->setFailed("Failed to register function " + self->name); + + LUA_RETURN_NOTHING(L); +} + +bool +FunctionDeclaration::isLocalToModule() const noexcept +{ + return parentScript.size() == 0; +} diff --git a/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc index 52e0d9be..5c16cfe0 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc @@ -58,6 +58,32 @@ JobDeclaration::setOptions(lua_State *L) noexcept int JobDeclaration::setImportFromScript(lua_State *L) noexcept { - JobDeclaration::CHECK(L, 1)->parentScript = CHECK_STRING_VIEW(L, 2); + auto *const job = JobDeclaration::CHECK(L, 1); + job->parentScript = CHECK_STRING_VIEW(L, 2); + job->isImported = true; LUA_RETURN_NOTHING(L); } + +int +JobDeclaration::pushToRuntime(lua_State *const L) noexcept +{ + JobDeclaration *const self = CHECK(L, 1); + auto *const context = LuaContext::getContext(L); + + lua_settop(L, 1); + + if (self->isImported) + err(context) << "The job \"" << self->parentScript << "::" << self->name + << "\" is an imported job\n"; + + else if (context->registerDeclaration(self) == LuaContext::Code::Error) + context->setFailed("Failed to register job " + self->name); + + LUA_RETURN_NOTHING(L); +} + +bool +JobDeclaration::isLocalToModule() const noexcept +{ + return parentScript.size() == 0; +} diff --git a/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc index 6d7b048f..82910f87 100644 --- a/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc +++ b/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc @@ -148,6 +148,8 @@ ModuleDeclaration::setFunctions(lua_State *const L) noexcept auto *const self = ModuleDeclaration::CHECK(L, 1); IterateOverArray(L, 2, [self, L]() noexcept -> bool { FunctionDeclaration *const fun = FunctionDeclaration::CHECK(L, -1); + if (fun->isLocalToModule()) + fun->parentScript = self->moduleName; self->moduleFunctions.emplace_back(fun); self->addUserValue(L, 1); // Tie the function to the module return true; // The value was popped from the stack @@ -161,6 +163,8 @@ ModuleDeclaration::setJobs(lua_State *const L) noexcept auto *const self = ModuleDeclaration::CHECK(L, 1); IterateOverArray(L, 2, [self, L]() noexcept -> bool { JobDeclaration *const job = JobDeclaration::CHECK(L, -1); + if (job->isLocalToModule()) + job->parentScript = self->moduleName; self->moduleJobs.emplace_back(job); self->addUserValue(L, 1); // Tie the job to the module return true; // The value was popped from the stack @@ -174,12 +178,13 @@ ModuleDeclaration::pushToRuntime(lua_State *const L) noexcept ModuleDeclaration *const self = CHECK(L, 1); auto *const context = LuaContext::getContext(L); - Utils::uniqAndSort<std::string>(self->importNames); + self->importNames.emplace_back(self->moduleName); // You can use localy defined things + Utils::uniqAndSort<std::string>(self->importNames); // Better for all std algorithms if (self->validateModule(L)) { err(context) << "Register module \"" << self->moduleName << "\" in the runtime!\n"; lua_settop(L, 1); - if (context->registerModuleDeclaration(self) == LuaContext::Code::Error) + if (context->registerDeclaration(self) == LuaContext::Code::Error) context->setFailed("Failed to register module " + self->moduleName); } diff --git a/src/Lib/Script/LuaContext.cc b/src/Lib/Script/LuaContext.cc index 3c204739..9ca957e8 100644 --- a/src/Lib/Script/LuaContext.cc +++ b/src/Lib/Script/LuaContext.cc @@ -142,15 +142,51 @@ LuaContext::getState() noexcept return L; } +bool +LuaContext::moduleExists(string_view mod) const noexcept +{ + return modules.count(mod) >= 1; +} + +LuaContext::Code +LuaContext::registerDeclaration(const FunctionDeclaration *const fun) noexcept +{ + FunctionDeclaration::CHECK(L, -1); + return registerToMapTuple(fun->parentScript, fun->name, &functions); +} + +LuaContext::Code +LuaContext::registerDeclaration(const JobDeclaration *const job) noexcept +{ + JobDeclaration::CHECK(L, -1); + return registerToMapTuple(job->parentScript, job->name, &jobs); +} + LuaContext::Code -LuaContext::registerModuleDeclaration(const ModuleDeclaration *const mod) noexcept +LuaContext::registerToMapTuple( + string_view module, string_view name, + std::map<std::tuple<string_view, string_view>, const int> *const map) noexcept { - if (modules.count(mod->moduleName) >= 1) { + if (map->count({ module, name }) >= 1) + return Error; + + streamErr << "Register \"" << module << "::" << name << "\"\n"; + + // WARN: The object needs to be already checked! + const int r = luaL_ref(L, LUA_REGISTRYINDEX); + map->emplace(std::tuple{ module, name }, r); + return Success; +} + +LuaContext::Code +LuaContext::registerDeclaration(const ModuleDeclaration *const mod) noexcept +{ + if (moduleExists(mod->moduleName)) { streamErr << "The module \"" << mod->moduleName << "\" is already registered!"; return Code::Error; } - streamErr << "Try to register module \"" << mod->moduleName << "\"\n"; + streamErr << "Register module \"" << mod->moduleName << "\"\n"; ModuleDeclaration::CHECK(L, -1); const int r = luaL_ref(L, LUA_REGISTRYINDEX); @@ -162,7 +198,7 @@ LuaContext::registerModuleDeclaration(const ModuleDeclaration *const mod) noexce const ModuleDeclaration * LuaContext::getModule(const std::string_view name) const noexcept { - if (modules.count(name) >= 1) { + if (moduleExists(name)) { const int r = modules.at(name); streamErr << "Try to get module \"" << name << "\" with register key " << r << "\n"; lua_rawgeti(L, LUA_REGISTRYINDEX, r); @@ -173,10 +209,41 @@ LuaContext::getModule(const std::string_view name) const noexcept } } +LuaContext::Code +LuaContext::unregisterFunctionDeclaration(const std::string_view module, + const std::string_view name) noexcept +{ + return unregisterFromMapTuple(module, name, &functions); +} + +LuaContext::Code +LuaContext::unregisterJobDeclaration(const std::string_view module, + const std::string_view name) noexcept +{ + return unregisterFromMapTuple(module, name, &jobs); +} + +LuaContext::Code +LuaContext::unregisterFromMapTuple( + string_view module, string_view name, + std::map<std::tuple<string_view, string_view>, const int> *const map) noexcept +{ + if (!moduleExists(module)) + return Error; + + if (map->count({ module, name }) >= 1) { + const int r = map->at({ module, name }); + luaL_unref(L, LUA_REGISTRYINDEX, r); + return Success; + } else { + return Error; + } +} + LuaContext::Code LuaContext::unregisterModuleDeclaration(const std::string_view name) noexcept { - if (modules.count(name) >= 1) { + if (moduleExists(name)) { const int r = modules.at(name); luaL_unref(L, LUA_REGISTRYINDEX, r); return Code::Success; diff --git a/src/Lib/Script/LuaContext.hh b/src/Lib/Script/LuaContext.hh index faf5808c..88362f64 100644 --- a/src/Lib/Script/LuaContext.hh +++ b/src/Lib/Script/LuaContext.hh @@ -16,27 +16,37 @@ class ScriptDocument; namespace Vivy::Script { class ModuleDeclaration; +class FunctionDeclaration; +class JobDeclaration; } namespace Vivy::Script { // New Lua script instance class LuaContext final { + VIVY_UNMOVABLE_OBJECT(LuaContext) + + using string_view = const std::string_view; + lua_State *L{ nullptr }; + std::string failureString{}; std::string currentFile{}; std::string lastLoadedModule{}; - std::map<const std::string_view, const int> modules = {}; + + std::map<string_view, const int> modules = {}; + std::map<std::tuple<string_view, string_view>, const int> functions = {}; + std::map<std::tuple<string_view, string_view>, const int> jobs = {}; + static inline std::map<const lua_State *const, LuaContext *const> contextList = {}; ScriptStore::LoggerType &streamOut; ScriptStore::LoggerType &streamErr; public: - enum class Code { - Success, - Error, - }; + enum class Code { Success, Error }; + static constexpr inline Code Success = Code::Success; + static constexpr inline Code Error = Code::Error; LuaContext(ScriptStore::LoggerType &out, ScriptStore::LoggerType &err) noexcept; ~LuaContext() noexcept; @@ -52,9 +62,14 @@ public: operator lua_State *() noexcept { return L; } static LuaContext *getContext(const lua_State *const) noexcept; - // WARN: Need the ModuleDeclaration to be on top of the stack! - Code registerModuleDeclaration(const ModuleDeclaration *const) noexcept; - Code unregisterModuleDeclaration(const std::string_view) noexcept; + // WARN: Need the ModuleDeclaration, the FunctionDeclaration and the + // JobDeclaration to be on top of the stack! + Code registerDeclaration(const ModuleDeclaration *const) noexcept; + Code registerDeclaration(const FunctionDeclaration *const) noexcept; + Code registerDeclaration(const JobDeclaration *const) noexcept; + Code unregisterModuleDeclaration(string_view) noexcept; + Code unregisterFunctionDeclaration(string_view, string_view) noexcept; + Code unregisterJobDeclaration(string_view, string_view) noexcept; // Returns the module or `nullptr` if not found. const ModuleDeclaration *getModule(const std::string_view) const noexcept; @@ -78,6 +93,14 @@ private: Code loadFile(const char *) noexcept; void loadPackagedFile(const QString &) noexcept; + Code unregisterFromMapTuple( + const std::string_view module, const std::string_view name, + std::map<std::tuple<string_view, string_view>, const int> *const mapPtr) noexcept; + Code registerToMapTuple( + const std::string_view module, const std::string_view name, + std::map<std::tuple<string_view, string_view>, const int> *const mapPtr) noexcept; + bool moduleExists(string_view) const noexcept; + // Swap the env, needed before executing a user script! void swapEnv() noexcept; }; -- GitLab