#include "lpx-classdb.hpp" #include "lpx-table.hpp" // Get an entry from the class database. // // DB, CLASSNAME // if classname is already present, and is a table, return it. // if classname is already present, and not a table, error. // if classname is not present, create and initialize it. // int lpx_classdb_get(lua_State *L) { LpxArg db, classname; LpxRet classtab; LpxVar action; LpxStackManager LSM(L, db, classname, classtab, action); LSM.checknometa(db); luaL_checktype(L, classname, LUA_TSTRING); LSM.rawget(classtab, db, classname); if (lua_istable(L, classtab)) { return LSM.retval(); } else if (!lua_isnil(L, classtab)) { luaL_error(L, "%s is not a class", lua_tostring(L, classname)); } LSM.newtable(classtab); LSM.rawset(db, classname, classtab); LSM.setfield(classtab, "__index", classtab); LSM.setfield(classtab, "__class", classname); LSM.newtable(action); LSM.setfield(classtab, "action", action); return LSM.retval(); } // Curried version of classdb.get where db is stored in an upvalue. // static int lpx_classdb_class(lua_State *L) { lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, -2); return lpx_classdb_get(L); } int lpx_classdb_accessor(lua_State *L) { luaL_checktype(L, -1, LUA_TTABLE); lua_pushcclosure(L, LpxArgCheck<1, lpx_classdb_class>, 1); return 1; } // Reset a class database: // // Clear out all classes. Instead of replacing the class tables, // it simply deletes all keys. That way, if somebody has a pointer // to a class, the pointer is not invalidated. // // Caution: do not reset the global class database! // int lpx_classdb_reset(lua_State *L) { LpxArg db; LpxVar classname, classtab, action, key; LpxStackManager LSM(L, db, classname, classtab, action, key); luaL_checktype(L, db, LUA_TTABLE); LSM.setnil(classname); while (LSM.next(db, classname, classtab) != 0) { if (lua_istable(L, classtab)) { LSM.setstring(key, "action"); LSM.rawget(action, classtab, key); if (lua_istable(L, action)) { lua_pushvalue(L, action); lpx_table_clear(L); } else { LSM.newtable(action); } lua_pushvalue(L, classtab); lpx_table_clear(L); LSM.setfield(classtab, "__index", classtab); LSM.setfield(classtab, "__class", classname); LSM.setfield(classtab, "action", action); } } return LSM.retval(); } // Create a classdb. That's just an empty table. int lpx_classdb_create(lua_State *L) { lua_newtable(L); return 1; } void luaopen_lpx_classdb(lua_State *L) { LpxStackManager::reg(L, "classdb", "get", LpxArgCheck<2, lpx_classdb_get>); LpxStackManager::reg(L, "classdb", "accessor", LpxArgCheck<1, lpx_classdb_accessor>); LpxStackManager::reg(L, "classdb", "reset", LpxArgCheck<1, lpx_classdb_reset>); LpxStackManager::reg(L, "classdb", "create", LpxArgCheck<0, lpx_classdb_create>); // Insert the global function 'class', which is a closure with an upvalue. lua_pushstring(L, "class"); lua_pushvalue(L, LUA_GLOBALSINDEX); lpx_classdb_accessor(L); lua_rawset(L, LUA_GLOBALSINDEX); }