From ee16970a8adb5624359cafb47dbc7aca2b61bf20 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Tue, 10 Aug 2021 10:41:06 -0400 Subject: [PATCH] Implement tabletype tagging --- luprex/core/cpp/globaldb.cpp | 1 + luprex/core/cpp/luastack.cpp | 56 ++++++++++++++++++++++-------------- luprex/core/cpp/luastack.hpp | 29 +++++++++++-------- luprex/core/cpp/world.cpp | 42 +++++++++++++++++++++++++-- 4 files changed, 92 insertions(+), 36 deletions(-) diff --git a/luprex/core/cpp/globaldb.cpp b/luprex/core/cpp/globaldb.cpp index c72c30c4..0b368a25 100644 --- a/luprex/core/cpp/globaldb.cpp +++ b/luprex/core/cpp/globaldb.cpp @@ -45,5 +45,6 @@ LuaDefine(globaldb_global, "f") { LS.newtable(globaltab); LS.rawset(globaldb, globalname, globaltab); LS.rawset(globaltab, "__global", globalname); + LS.settabletype(globaltab, LuaStack::TAB_GLOBALDB); return LS.result(); } diff --git a/luprex/core/cpp/luastack.cpp b/luprex/core/cpp/luastack.cpp index 7d2ea35c..8c0fc5cc 100644 --- a/luprex/core/cpp/luastack.cpp +++ b/luprex/core/cpp/luastack.cpp @@ -171,29 +171,22 @@ void LuaStack::getclass(LuaSlot classtab, LuaSlot classname) const { LuaVar globtab, cname; LuaStack LS(L_, globtab, cname); + if (!LS.isstring(classname)) { + luaL_error(L_, "Not a class name: %s", lua_tostring(L_, classname)); + } + // Convert class name to a table. - if (LS.isstring(classname)) { - if (LS.rawequal(classname, "_G")) { - luaL_error(L_, "_G is explicitly not allowed as a class name"); - } - LS.getglobaltable(globtab); - LS.rawget(classtab, globtab, classname); - if (!LS.istable(classtab)) { - luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); - } - LS.rawget(cname, classtab, "__class"); - if (!LS.rawequal(cname, classname)) { - luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); - } - } else { - LS.set(classtab, classname); - if (!LS.istable(classtab)) { - luaL_error(L_, "class can be a string or a table"); - } - LS.rawget(cname, classtab, "__class"); - if (!LS.isstring(cname)) { - luaL_error(L_, "table is not a class"); - } + if (LS.rawequal(classname, "_G")) { + luaL_error(L_, "_G is explicitly not allowed as a class name"); + } + LS.getglobaltable(globtab); + LS.rawget(classtab, globtab, classname); + if (!LS.istable(classtab)) { + luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); + } + LS.rawget(cname, classtab, "__class"); + if (!LS.rawequal(cname, classname)) { + luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); } // OK, we're done. @@ -230,6 +223,7 @@ void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const { } // Repair the special fields. + LS.settabletype(classtab, TAB_CLASS); LS.rawset(classtab, "__index", classtab); LS.rawset(classtab, "__class", classname); @@ -271,3 +265,21 @@ void LuaStack::check_nret(int xnret, int otop, int nret) const { luaL_error(L_, "expected %d return values", xnret); } } + +LuaStack::TableType LuaStack::gettabletype(LuaSlot tab) { + uint16_t bits = lua_getflagbits(L_, tab.index()); + return TableType(bits & 0x000F); +} + +void LuaStack::settabletype(LuaSlot tab, TableType t) { + lua_modflagbits(L_, tab.index(), 0x000F, t); +} + +bool LuaStack::getvisited(LuaSlot tab) { + uint16_t bits = lua_getflagbits(L_, tab.index()); + return (bits & 0x0010); +} + +void LuaStack::setvisited(LuaSlot tab, bool visited) { + lua_modflagbits(L_, tab.index(), 0x0010, visited ? 0x0010 : 0); +} diff --git a/luprex/core/cpp/luastack.hpp b/luprex/core/cpp/luastack.hpp index a48124b3..34d583d5 100644 --- a/luprex/core/cpp/luastack.hpp +++ b/luprex/core/cpp/luastack.hpp @@ -463,18 +463,6 @@ public: lua_rawseti(L_, tab, key); } - // template - // void rawset(LuaSlot tab, const char *field, VT value) const { - // push_any_value(value); - // lua_rawset(L_, tab, field); - // } - - // template - // void rawget(RT &target, LuaSlot tab, const char *field) const { - // lua_rawget(L_, tab, field); - // pop_any_value(target); - // } - // Call invokes any C function. It pushes the arguments on the stack, // calls the cfunction, verifies that the number of return values is as // expected, and pops the return values into LuaVars. @@ -482,6 +470,23 @@ public: void call(T&... args) { call_cfunction<0>(lua_gettop(L_), args...); } + + // Lua flagbits manipulation: Table types. + enum TableType { + TAB_GENERAL, // A general-purpose table. + TAB_REGISTRY, // The registry table. + TAB_GLOBALENV, // The global environment table. + TAB_TANGIBLE, // A tangible's database. + TAB_TANGIBLEMETA, // A tangible's metatable. + TAB_GLOBALDB, // Part of the globaldb. + TAB_CLASS, // A class which is directly reachable from the global environment. + }; + TableType gettabletype(LuaSlot tab); + void settabletype(LuaSlot tab, TableType t); + + // Lua flagbits manipulation: visited bit. + bool getvisited(LuaSlot tab); + void setvisited(LuaSlot tab, bool visited); }; diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index 0117ae2f..02b9ae0a 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -38,8 +38,8 @@ World::World(util::WorldType wt) { } // Prepare to manipulate the lua state. - LuaVar world; - LuaStack LS(state(), world); + LuaVar world, globtab; + LuaStack LS(state(), world, globtab); // Put the world pointer into the lua registry. World::store_global_pointer(state(), this); @@ -47,6 +47,13 @@ World::World(util::WorldType wt) { // Clear the global GUI pointer. Gui::store_global_pointer(state(), nullptr); + // Set the tabletype of the registry. + LS.settabletype(LuaRegistry, LuaStack::TAB_REGISTRY); + + // Set the tabletype of the global environment. + LS.getglobaltable(globtab); + LS.settabletype(globtab, LuaStack::TAB_GLOBALENV); + // Create the tangibles table in the registry. LS.rawset(LuaRegistry, "tangibles", LuaNewTable); @@ -230,6 +237,10 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) { LS.set(metatab, LuaNewTable); LS.setmetatable(database, metatab); + // Mark the tangible using the tabletype field. + LS.settabletype(database, LuaStack::TAB_TANGIBLE); + LS.settabletype(metatab, LuaStack::TAB_TANGIBLEMETA); + // Store the database into the tangibles table. LS.rawget(tangibles, LuaRegistry, "tangibles"); LS.rawset(tangibles, id, database); @@ -857,6 +868,33 @@ LuaDefine(world_getregistry, "f") { return 1; } +LuaDefine(world_gettabletype, "f") { + LuaArg tab; + LuaRet ttype; + LuaStack LS(L, tab, ttype); + if (LS.istable(tab)) { + LuaStack::TableType tt = LS.gettabletype(tab); + LS.set(ttype, int(tt)); + } else { + luaL_error(L, "Not a table"); + } + return LS.result(); +} + +LuaDefine(world_settabletype, "f") { + LuaArg tab, ttype; + LuaStack LS(L, tab, ttype); + if (!LS.istable(tab)) { + luaL_error(L, "Not a table"); + } + int tt = LS.ckinteger(ttype); + if ((tt < 0) || (tt > 15)) { + luaL_error(L, "table type out of range"); + } + LS.settabletype(tab, LuaStack::TableType(tt)); + return LS.result(); +} + static bool worlds_identical(const std::unique_ptr &w1, const std::unique_ptr &w2) { StreamBuffer sbw1, sbw2; w1->serialize(&sbw1);