This commit is contained in:
2020-11-15 16:49:42 -05:00
parent a784f12aed
commit f690fb147b
12 changed files with 431 additions and 168 deletions

View File

@@ -7,56 +7,41 @@
// 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) {
const int db = lua_gettop(L) - 1;
const int cname = lua_gettop(L);
luaL_checktype(L, db, LUA_TTABLE);
luaL_checktype(L, cname, LUA_TSTRING);
lua_pushvalue(L, cname);
lua_rawget(L, db);
if (lua_istable(L, -1)) {
return 1;
} else if (!lua_isnil(L, -1)) {
lua_pushfstring(L, "%s is not a class", lua_tostring(L, cname));
lua_error(L);
}
lua_pop(L, 1);
lua_newtable(L);
int cls = lua_gettop(L);
lua_pushvalue(L, cname);
lua_pushvalue(L, cls);
lua_rawset(L, db);
lua_pushstring(L, "__index");
lua_pushvalue(L, cls);
lua_rawset(L, cls);
lua_pushstring(L, "__class");
lua_pushvalue(L, cname);
lua_rawset(L, cls);
lua_pushstring(L, "action");
lua_newtable(L);
lua_rawset(L, cls);
LpxArg db, classname;
LpxRet classtab;
LpxVar action;
LpxStackManager LSM(L, db, classname, classtab, action);
// Remove arguments, leaving new table on stack.
lua_replace(L, db);
lua_settop(L, db);
return 1;
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) {
const int cname = lua_gettop(L);
lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, cname);
lua_insert(L, -2);
return lpx_classdb_get(L);
}
int lpx_classdb_accessor(lua_State *L) {
const int db = lua_gettop(L);
luaL_checktype(L, db, LUA_TTABLE);
lua_pushcclosure(L, lpx_classdb_class, 1);
luaL_checktype(L, -1, LUA_TTABLE);
lua_pushcclosure(L, LpxArgCheck<1, lpx_classdb_class>, 1);
return 1;
}
@@ -69,63 +54,47 @@ int lpx_classdb_accessor(lua_State *L) {
// Caution: do not reset the global class database!
//
int lpx_classdb_reset(lua_State *L) {
const int db = lua_gettop(L);
LpxArg db;
LpxVar classname, classtab, action, key;
LpxStackManager LSM(L, db, classname, classtab, action, key);
luaL_checktype(L, db, LUA_TTABLE);
lua_pushnil(L);
while (lua_next(L, db) != 0) {
int cname = lua_gettop(L) - 1;
int cls = lua_gettop(L);
if (lua_istable(L, cls)) {
lua_pushstring(L, "action");
lua_rawget(L, cls);
int actn = lua_gettop(L);
if (lua_istable(L, actn)) {
lua_pushvalue(L, actn);
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 {
lua_pop(L, 1);
lua_newtable(L);
LSM.newtable(action);
}
lua_pushvalue(L, cls);
lua_pushvalue(L, classtab);
lpx_table_clear(L);
lua_pushstring(L, "__index");
lua_pushvalue(L, cls);
lua_rawset(L, cls);
lua_pushstring(L, "__class");
lua_pushvalue(L, cname);
lua_rawset(L, cls);
lua_pushstring(L, "action");
lua_pushvalue(L, actn);
lua_rawset(L, cls);
LSM.setfield(classtab, "__index", classtab);
LSM.setfield(classtab, "__class", classname);
LSM.setfield(classtab, "action", action);
}
lua_settop(L, cname);
}
// Remove arguments, leave nothing on stack.
lua_settop(L, db - 1);
return 0;
return LSM.retval();
}
// Create the global function 'class'.
//
// This version of 'class' creates classes in the global environment.
// Note that this is lua 5.1 specific.
//
static int lpx_create_global_class(lua_State *L) {
// 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);
}
static const struct luaL_Reg lpx_classdb_lib [] = {
{"get", lpx_classdb_get},
{"accessor", lpx_classdb_accessor},
{"reset", lpx_classdb_reset},
{NULL, NULL} /* sentinel */
};
int luaopen_lpx_classdb(lua_State *L) {
luaL_openlib(L, "classdb", lpx_classdb_lib, 0);
lpx_create_global_class(L);
return 1;
}