ClassDB is now in C++

This commit is contained in:
2020-11-13 18:17:47 -05:00
parent 9523e367f1
commit a784f12aed
13 changed files with 217 additions and 78 deletions

View File

@@ -0,0 +1,131 @@
#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) {
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);
// Remove arguments, leaving new table on stack.
lua_replace(L, db);
lua_settop(L, db);
return 1;
}
// 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);
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);
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) {
const int db = lua_gettop(L);
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);
lpx_table_clear(L);
} else {
lua_pop(L, 1);
lua_newtable(L);
}
lua_pushvalue(L, cls);
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);
}
lua_settop(L, cname);
}
// Remove arguments, leave nothing on stack.
lua_settop(L, db - 1);
return 0;
}
// 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) {
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;
}

View File

@@ -0,0 +1,13 @@
#ifndef LPX_CLASSDB_HPP
#define LPX_CLASSDB_HPP
#include "lua-headers.hpp"
int lpx_classdb_get(lua_State *L);
int lpx_classdb_reset(lua_State *L);
int lpx_classdb_accessor(lua_State *L);
int luaopen_lpx_classdb(lua_State *L);
#endif // LPX_CLASSDB_HPP

View File

@@ -0,0 +1,43 @@
#include "lpx-table.hpp"
// Clear the table. Removes metatable and all key-value pairs.
int lpx_table_clear(lua_State *L) {
const int tab = lua_gettop(L);
luaL_checktype(L, tab, LUA_TTABLE);
// Clear the metatable.
lua_pushnil(L);
lua_setmetatable(L, tab);
// Clear the elements.
lua_pushnil(L);
while (lua_next(L, tab) != 0) {
lua_pop(L, 1); // Pop the old value.
lua_pushvalue(L, -1); // Clone the key
lua_pushnil(L); // Push the new value.
lua_settable(L, tab);
}
// Remove the arguments and return nothing.
lua_remove(L, tab);
return 0;
}
int lpx_table_coerce(lua_State *L) {
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
lua_newtable(L);
}
return 1;
}
static const struct luaL_Reg lpx_table_lib [] = {
{"clear", lpx_table_clear},
{"coerce", lpx_table_coerce},
{NULL, NULL} /* sentinel */
};
int luaopen_lpx_table (lua_State *L) {
luaL_openlib(L, "table", lpx_table_lib, 0);
return 1;
}

View File

@@ -0,0 +1,10 @@
#ifndef LPX_TABLE_HPP
#define LPX_TABLE_HPP
#include "lua-headers.hpp"
int lpx_table_clear(lua_State *L);
int lpx_table_coerce(lua_State *L);
int luaopen_lpx_table (lua_State *L);
#endif // LPX_TABLE_HPP

View File

@@ -0,0 +1,9 @@
#ifndef LUA_HEADERS_HPP
#define LUA_HEADERS_HPP
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "luajit.h"
}
#endif // LUA_HEADERS_HPP

View File

@@ -10,17 +10,12 @@
#include <stdlib.h>
#include <string.h>
#include <signal.h>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "luajit.h"
}
#include <vector>
#include <string>
#include "lua-headers.hpp"
#include "util.hpp"
#include "lpx-table.hpp"
#include "lpx-classdb.hpp"
// Add another error status.
@@ -223,14 +218,16 @@ static int pmain(lua_State *L)
lua_gc(L, LUA_GCSTOP, 0);
luaopen_base(L);
// luaopen_package(L); // Omitted because we use our own package system.
luaopen_table(L);
// luaopen_io(L); // Not safe for the sandbox.
// luaopen_os(L); // Not safe for the sandbox.
luaopen_table(L); // Standard table operations.
luaopen_lpx_table(L); // Supplemental table operations.
// luaopen_io(L); // Not safe for the sandbox.
// luaopen_os(L); // Not safe for the sandbox.
luaopen_string(L);
luaopen_math(L);
// luaopen_debug(L); // Not safe for the sandbox.
luaopen_bit(L);
// luaopen_jit(L); // Don't know what it's for.
luaopen_lpx_classdb(L);
lua_gc(L, LUA_GCRESTART, -1);
loadmain(L);

View File

@@ -1,4 +1,5 @@
#ifndef UTIL_HPP
#define UTIL_HPP
#include <string>
#include <algorithm>