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

CRTPLuaScriptObject.hh

Blame
  • CRTPLuaScriptObject.hh 8,72 Kio
    #pragma once
    
    #include "LuaContext.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_CREATE(class)       luaL_Reg{ "new", class ::CREATE }
    // 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) {
                lua_pushinteger(L, i);     // i -> top stack
                lua_gettable(L, tblIndex); // T[i] -> top stack
    
                // Sentinel check
                if (lua_type(L, -1) == LUA_TNIL)
                    break;
    
                // 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);
    
                // Pop i from the stack
                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 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 };
    
    public:
        static Object *CHECK(lua_State *L, int index) noexcept
        {
            return reinterpret_cast<Object *>(luaL_checkudata(L, index, Object::className));
        }
    
        static void Register(lua_State *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
        }
    };
    
    // The options
    class ScriptOption {
        enum class Type { String, Number, Boolean };
    
    private:
        std::string string;
        double number;
        bool boolean;
    
        Type type;
    
    public:
        ScriptOption(const std::string &) noexcept;
        ScriptOption(const std::string_view) noexcept;
        ScriptOption(bool) noexcept;
        ScriptOption(double) noexcept;
    
        std::string *getString() noexcept;
        double *getNumber() noexcept;
        bool *getBoolean() noexcept;
    
        std::string_view getSignature() const noexcept;
    };
    
    // Option declaration
    script_class (OptionDeclaration) {
        LUA_SCRIPTABLE_CLASS(OptionDeclaration)
    
        static int addOptionContent(lua_State *) noexcept;
    
        method_list metaMethods = { luaRegDefaultGC, LUA_DECL_CREATE(OptionDeclaration) };
        method_list methods     = { LUA_DECL_METHOD(OptionDeclaration, addOptionContent) };
    
    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;
    
        method_list metaMethods = { luaRegDefaultGC };
        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;
    
        method_list metaMethods = { luaRegDefaultGC };
        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 *) noexcept;
        static int setAuthorName(lua_State *) noexcept;
        static int setRevision(lua_State *) noexcept;
        static int setDescription(lua_State *) noexcept;
        static int setImplementationFile(lua_State *) noexcept;
        static int setImports(lua_State *) noexcept;
        static int setOptions(lua_State *) noexcept;
        static int setFunctions(lua_State *) noexcept;
        static int setJobs(lua_State *) 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_CREATE(ModuleDeclaration),
        };
    
        // Will be resolved later
        std::vector<std::string> importNames{};
    
    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{};
    };
    
    // 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) };
    };
    }