Une erreur est survenue de notre côté
Sélectionner une révision Git
-
Loris TICHADOU a rédigéLoris TICHADOU a rédigé
CRTPLuaScriptObject.hh 6,48 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 }
#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 *) noexcept; \
~theClassName() noexcept;
// clang-format on
// CRTP to expose objects to Lua
template <class Object> class CRTPLuaScriptObject {
protected:
static int GC(lua_State *L) noexcept
{
const Object *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 *L) noexcept
{
Object *obj = reinterpret_cast<Object *>(lua_newuserdata(L, sizeof(Object)));
new (obj) Object(L);
luaL_getmetatable(L, Object::className);
lua_setmetatable(L, -2);
return 1;
}
static Object *CHECK(lua_State *L, int index) noexcept
{
luaL_checktype(L, index, LUA_TUSERDATA);
auto *context = LuaContext::getContext(L);
Object *obj = reinterpret_cast<Object *>(luaL_checkudata(L, index, Object::className));
if (obj == nullptr) {
err(context) << "Type error, userdata is not of class " << Object::className << "\n";
luaL_typeerror(L, index, Object::className);
}
return obj;
}
static inline constexpr luaL_Reg luaRegDefaultGC = { "__gc", GC };
public:
static void Register(lua_State *L) noexcept
{
auto *context = LuaContext::getContext(L);
// 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) {
err(context) << "Register " << Object::className << "::" << meta.name << "\n";
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) {
err(context) << "Register " << Object::className << "::" << method.name << "\n";
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
err(context) << "Register constructor " << Object::className << "()\n";
}
};
// 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) };
};
// 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, LUA_DECL_CREATE(JobDeclaration) };
method_list methods = { LUA_DECL_METHOD(JobDeclaration, setName),
LUA_DECL_METHOD(JobDeclaration, setOptions),
LUA_DECL_METHOD(JobDeclaration, setImportFromScript) };
};
// 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, LUA_DECL_CREATE(FunctionDeclaration) };
method_list methods = { LUA_DECL_METHOD(FunctionDeclaration, setName),
LUA_DECL_METHOD(FunctionDeclaration, setImportFromScript) };
};
// 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, LUA_DECL_CREATE(ModuleDeclaration) };
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),
};
};
// 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, LUA_DECL_CREATE(FreeFunctions) };
method_list methods = { LUA_DECL_METHOD(FreeFunctions, print) };
};
}