Skip to content
Extraits de code Groupes Projets
Sélectionner une révision Git
  • 0b4bfb783c5c9a0840e5044d23449b3f3ba6dffa
  • master par défaut
  • script
  • new-devel
  • devel
  • timingView-edit
  • fix-mpv
7 résultats

ScriptStore.hh

Blame
  • CRTPLuaScriptObject.hh 9,78 Kio
    #pragma once
    
    #include "LuaContext.hh"
    #include "ScriptOption.hh"
    
    #include "lua.hpp"
    #include <vector>
    #include <cstdio>
    
    namespace Vivy::Script
    {
    // clang-format off
    #define LUA_DECL_METHOD(class, name)            luaL_Reg{ #name, class ::name   }
    #define LUA_DECL_META_METHOD(class, meta, name) luaL_Reg{ meta,  class ::name   }
    #define LUA_DECL_CREATE(class)                  luaL_Reg{ "new", class ::CREATE }
    #define LUA_RETURN_NOTHING(L)                   { lua_settop(L, 0); return 0; }
    // clang-format on
    
    #define script_class(theClassName) \
        class theClassName final : public CRTPLuaScriptObject<theClassName>
    
    #define method_list static constexpr inline auto
    
    #define LUA_SCRIPTABLE_CLASS(theClassName)                               \
        VIVY_UNMOVABLE_OBJECT(theClassName)                                  \
        static constexpr char className[] = #theClassName;                   \
        friend CRTPLuaScriptObject<theClassName>;                            \
        theClassName(lua_State *L) noexcept                                  \
        {                                                                    \
            err(LuaContext::getContext(L))                                   \
                << "Create instance of " << theClassName::className << "\n"; \
        }                                                                    \
        ~theClassName() noexcept {}
    
    // CRTP to expose objects to Lua
    template <class Object> class CRTPLuaScriptObject {
    protected:
        static void IterateOverArray(lua_State *const L, const int tblIndex,
                                     const auto callback) noexcept
        {
            luaL_checktype(L, tblIndex, LUA_TTABLE);
            const std::size_t count = lua_rawlen(L, tblIndex);
            if (count >= std::numeric_limits<int>::max())
                luaL_error(L, "To many items (%lu) in table to iterate over!", count);
    
            const int countInt = static_cast<const int>(count);
            for (int i = 1; i <= countInt; ++i) {
                luaL_checktype(L, tblIndex, LUA_TTABLE);
                lua_pushinteger(L, i);     // i -> top stack
                lua_gettable(L, tblIndex); // T[i] -> top stack and pop i
    
                if (lua_type(L, -1) == LUA_TNIL)
                    break; // Sentinel check
    
                // If the callback didn't pop the object form the stack, pop
                // it ourself. The value will be accessible at the top of the
                // stack (index -1).
                if (!callback())
                    lua_pop(L, -1);
            }
        }
    
        static int GC(lua_State *const L) noexcept
        {
            const Object *const obj = reinterpret_cast<const Object *>(lua_topointer(L, 1));
            auto *context           = LuaContext::getContext(L);
            err(context) << "Call destructor for " << Object::className << "\n";
            obj->~Object();
            return 0;
        }
    
        static int TOSTRING(lua_State *const L) noexcept
        {
            lua_pushfstring(L, "%s { }", Object::className);
            return 1;
        }
    
        static int CREATE(lua_State *const L) noexcept
        {
            lua_settop(L, 0);
            Object *const obj = reinterpret_cast<Object *>(lua_newuserdata(L, sizeof(Object)));
            new (obj) Object(L);
            luaL_getmetatable(L, Object::className);
            lua_setmetatable(L, 1);
            return 1;
        }
    
        static const std::string_view CHECK_STRING_VIEW(lua_State *const L, int index) noexcept
        {
            std::size_t len       = 0;
            const char *const str = luaL_checklstring(L, index, &len);
            return std::string_view(str, len);
        }
    
        static inline constexpr luaL_Reg luaRegDefaultGC       = { "__gc", GC };
        static inline constexpr luaL_Reg luaRegDefaultTOSTRING = { "__tostring", TOSTRING };
    
    public:
        static Object *CHECK(lua_State *const L, const int index) noexcept
        {
            return reinterpret_cast<Object *>(luaL_checkudata(L, index, Object::className));
        }
    
        static void Register(lua_State *const L) noexcept
        {
            // Fill the method table, newclass = {}
            lua_newtable(L);
            const int methodtable = lua_gettop(L);
    
            // Fill the meta-table, metatable = {}
            {
                luaL_newmetatable(L, Object::className);
                const int metatable = lua_gettop(L);
    
                lua_pushliteral(L, "__metatable");
                lua_pushvalue(L, methodtable);
                lua_settable(L, metatable);
    
                lua_pushliteral(L, "__index");
                lua_pushvalue(L, methodtable);
                lua_settable(L, metatable);
    
                for (const luaL_Reg &meta : Object::metaMethods) {
                    lua_pushstring(L, meta.name);
                    lua_pushcfunction(L, meta.func);
                    lua_settable(L, metatable);
                }
    
                lua_pop(L, 1);
            }
    
            // Fill the method table with specified methods
            for (const luaL_Reg &method : Object::methods) {
                lua_pushstring(L, method.name);
                lua_pushcfunction(L, method.func);
                lua_settable(L, methodtable);
            }
    
            // Last thing to do it seems...
            lua_pop(L, 1);                              // drop method-table
            lua_register(L, Object::className, CREATE); // Register the create method
        }
    
    private:
        // The user value count
        int userValueCount{ 0 };
    
    protected:
        // Add a user value to this object. Do not used lua_setuservalue or
        // lua_setiuservalue directly, use this proxy method.
        void addUserValue(lua_State *const L, const int index) noexcept
        {
            lua_setiuservalue(L, index, ++userValueCount);
        }
    };
    
    // Option declaration
    script_class (OptionDeclaration) {
        LUA_SCRIPTABLE_CLASS(OptionDeclaration)
    
        static int addOptionContent(lua_State *const) noexcept;
    
        static int TOSTRING(lua_State *const) noexcept;
    
        method_list metaMethods = {
            luaRegDefaultGC,
            LUA_DECL_META_METHOD(OptionDeclaration, "__tostring", TOSTRING),
        };
        method_list methods = { LUA_DECL_METHOD(OptionDeclaration, addOptionContent),
                                LUA_DECL_CREATE(OptionDeclaration) };
    
    public:
        // Different option types
        std::unordered_map<std::string, ScriptOption> options;
    };
    
    // Job declaration
    script_class (JobDeclaration) {
        LUA_SCRIPTABLE_CLASS(JobDeclaration)
    
        static int setName(lua_State *) noexcept;
        static int setOptions(lua_State *) noexcept;
        static int setImportFromScript(lua_State *) noexcept;
    
        static int TOSTRING(lua_State *const) noexcept;
    
        method_list metaMethods = { luaRegDefaultGC,
                                    LUA_DECL_META_METHOD(JobDeclaration, "__tostring", TOSTRING) };
        method_list methods     = { LUA_DECL_METHOD(JobDeclaration, setName),
                                LUA_DECL_METHOD(JobDeclaration, setOptions),
                                LUA_DECL_METHOD(JobDeclaration, setImportFromScript),
                                LUA_DECL_CREATE(JobDeclaration) };
    
    public:
        std::string name{};
        std::string parentScript{};
        std::vector<OptionDeclaration *> options{};
    };
    
    // Function declaration
    script_class (FunctionDeclaration) {
        LUA_SCRIPTABLE_CLASS(FunctionDeclaration)
    
        static int setName(lua_State *) noexcept;
        static int setImportFromScript(lua_State *) 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_CREATE(FunctionDeclaration) };
    
    public:
        std::string name{};
        std::string parentScript{};
    };
    
    // Module declaration
    script_class (ModuleDeclaration) {
        LUA_SCRIPTABLE_CLASS(ModuleDeclaration)
    
        static int setName(lua_State *const) noexcept;
        static int setAuthorName(lua_State *const) noexcept;
        static int setRevision(lua_State *const) noexcept;
        static int setDescription(lua_State *const) noexcept;
        static int setImplementationFile(lua_State *const) noexcept;
        static int setImports(lua_State *const) noexcept;
        static int setOptions(lua_State *const) noexcept;
        static int setFunctions(lua_State *const) noexcept;
        static int setJobs(lua_State *const) noexcept;
    
        static int pushToRuntime(lua_State *const) noexcept;
    
        method_list metaMethods = { luaRegDefaultGC };
        method_list methods     = {
            LUA_DECL_METHOD(ModuleDeclaration, setName),
            LUA_DECL_METHOD(ModuleDeclaration, setDescription),
            LUA_DECL_METHOD(ModuleDeclaration, setRevision),
            LUA_DECL_METHOD(ModuleDeclaration, setAuthorName),
            LUA_DECL_METHOD(ModuleDeclaration, setImplementationFile),
            LUA_DECL_METHOD(ModuleDeclaration, setImports),
            LUA_DECL_METHOD(ModuleDeclaration, setOptions),
            LUA_DECL_METHOD(ModuleDeclaration, setFunctions),
            LUA_DECL_METHOD(ModuleDeclaration, setJobs),
            LUA_DECL_METHOD(ModuleDeclaration, pushToRuntime),
            LUA_DECL_CREATE(ModuleDeclaration),
        };
    
        // Will be resolved later
        std::vector<std::string> importNames{};
        std::vector<const ModuleDeclaration *> importedModules{};
    
        bool validateModule(lua_State *const) const noexcept;
    
    public:
        std::string moduleName{};
        std::string authorName{};
        std::string revision{};
        std::string moduleDescription{};
        std::string implementationFile{};
        std::vector<OptionDeclaration *> moduleOptions{};
        std::vector<FunctionDeclaration *> moduleFunctions{};
        std::vector<JobDeclaration *> moduleJobs{};
    
        bool resolvModules(LuaContext *const) noexcept;
    };
    
    // Holds all the free functions (well, not really free functions here...)
    script_class (FreeFunctions) {
        LUA_SCRIPTABLE_CLASS(FreeFunctions)
    
        static int print(lua_State *) noexcept;
    
        method_list metaMethods = { luaRegDefaultGC };
        method_list methods = { LUA_DECL_METHOD(FreeFunctions, print), LUA_DECL_CREATE(FreeFunctions) };
    };
    }