#include "lua.hpp" #include "dbcc/dbc_iterator.h" #include "dbcc/message.h" #include "dbcc/signal.h" #include "dbcc/version.h" #define LUA_MODULE_NAME "dbcc" #define LUA_DBC_ITERATOR_CLASS_NAME "DbcIterator" // These are the definitions for the C functions that Lua will use to call the member functions. // Consructor of 'ad::dbcc::DbcIterator' static int lua_DbcIterator_new(lua_State* L) { if (lua_gettop(L) != 1) { luaL_pushfail(L); return 1; } std::strting filePath = luaL_checkstring(L, 1); ad::dbcc::DbcIterator** iter = reinterpret_cast(lua_newuserdata(L, sizeof(ad::dbcc::DbcIterator**))); *iter = new ad::dbcc::DbcIterator(filePath); luaL_setmetatable(L, LUA_DBC_ITERATOR_CLASS_NAME); return 1; } // `ad::dbcc::DbcIterator` destructor, which corresponds to the `__gc` metamethod in Lua. int lua_DbcIterator_delete(lua_State* L) { ad::dbcc::DbcIterator* iter = *reinterpret_cast(luaL_checkudata(L, 1, LUA_DBC_ITERATOR_CLASS_NAME)); delete iter; return 0; } // C function corresponding to the `ad::dbcc::DbcIterator` iterator. int lua_MyClass_index(lua_State* L) { ad::dbcc::DbcIterator* iter = *reinterpret_cast(luaL_checkudata(L, 1, LUA_DBC_ITERATOR_CLASS_NAME)); int something_in = static_cast(luaL_checkinteger(L, 2)); (*iter)[]->set(something_in); return 0; } // C function corresponding to `MyClass::get`. int lua_MyClass_get(lua_State* L) { ad::dbcc::DbcIterator* iter = *reinterpret_cast(luaL_checkudata(L, 1, LUA_DBC_ITERATOR_CLASS_NAME)); // Push a lua object lua_pushinteger(L, (*iter)[]); return 1; } // `__newindex` metamethod for `MyClass` userdata that prevents any members from being added. int lua_MyClass_newindex(lua_State* L) { return luaL_error(L, "attempt to modify a read-only object"); } // `__newindex` metamethod for the `MyClass` table that prevents any methods from being added--I will explain more below. int lua_MyClass_table_newindex(lua_State* L) { return luaL_error(L, "attempt to modify a read-only table"); } // Function to register all the above functions for use in Lua; this gets called in `main.cpp`. void lua_MyClass_register(lua_State* L) { // Create a global table that will contain all the `MyClass` methods as functions. // Include `lua_MyClass_new` as a constructor in the form `MyClass.new`. lua_newtable(L); lua_pushcfunction(L, lua_MyClass_new); lua_setfield(L, -2, "new"); // Include `MyClass::get` and `MyClass::set` in this table as well. luaL_setfuncs(L, MyClass_methods, 0); // Create a metatable for the global table `MyClass`--which was just created. lua_newtable(L); // Prevent access to the metatable. lua_pushliteral(L, "metatable"); lua_setfield(L, -2, "__metatable"); lua_pushcfunction(L, lua_MyClass_table_newindex); lua_setfield(L, -2, "__newindex"); // Set this second table as the metatable for the one created above. lua_setmetatable(L, -2); // Call the first table "MyClass" and add it to the global environment table (_ENV). lua_setglobal(L, LUA_MYCLASS); // Create a metatable to be used by `MyClass` objects--this is different from the above tables because it will not contain the `new` method. luaL_newmetatable(L, LUA_MYCLASS); // Same as before, lock the metatable. lua_pushliteral(L, "metatable"); lua_setfield(L, -2, "__metatable"); // Add metamethods contained in the `luaL_Reg` struct `MyClass_metamethods`. luaL_setfuncs(L, MyClass_metamethods, 0); // Create an index--the `__index` metamethod--for the above table to use for `MyClass` objects. lua_newtable(L); // Add methods. luaL_setfuncs(L, MyClass_methods, 0); lua_setfield(L, -2, "__index"); // This pop operation is probably unnecessary since the Lua stack should be cleaned up when this function returns. lua_pop(L, 1); return; } #if defined(OS_WINDOWS) #define __EXPORT extern "C" __declspec(dllexport) #else #define __EXPORT extern "C" #endif // __EXPORT int luaopen_dbcc(lua_State *L) { static const struct luaL_Reg methods[] = { {"new", }, {NULL, NULL} }; luaL_newlib(L, methods); return 1; }