ClassDB is now in C++
This commit is contained in:
@@ -1 +1 @@
|
|||||||
g++ -std=c++17 -g -o main syscpp/util.cpp syscpp/main.cpp -Iinc -Llib lib/libluajit-dbg.a -Isyscpp
|
g++ -std=c++17 -g -o main syscpp/util.cpp syscpp/main.cpp syscpp/lpx-table.cpp syscpp/lpx-classdb.cpp -Iinc -Llib lib/libluajit-dbg.a -Isyscpp
|
||||||
|
|||||||
131
luprex/syscpp/lpx-classdb.cpp
Normal file
131
luprex/syscpp/lpx-classdb.cpp
Normal 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;
|
||||||
|
}
|
||||||
13
luprex/syscpp/lpx-classdb.hpp
Normal file
13
luprex/syscpp/lpx-classdb.hpp
Normal 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
|
||||||
|
|
||||||
|
|
||||||
43
luprex/syscpp/lpx-table.cpp
Normal file
43
luprex/syscpp/lpx-table.cpp
Normal 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;
|
||||||
|
}
|
||||||
10
luprex/syscpp/lpx-table.hpp
Normal file
10
luprex/syscpp/lpx-table.hpp
Normal 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
|
||||||
9
luprex/syscpp/lua-headers.hpp
Normal file
9
luprex/syscpp/lua-headers.hpp
Normal 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
|
||||||
@@ -10,17 +10,12 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
#include "lualib.h"
|
|
||||||
#include "luajit.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "lua-headers.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
#include "lpx-table.hpp"
|
||||||
|
#include "lpx-classdb.hpp"
|
||||||
|
|
||||||
|
|
||||||
// Add another error status.
|
// Add another error status.
|
||||||
@@ -223,14 +218,16 @@ static int pmain(lua_State *L)
|
|||||||
lua_gc(L, LUA_GCSTOP, 0);
|
lua_gc(L, LUA_GCSTOP, 0);
|
||||||
luaopen_base(L);
|
luaopen_base(L);
|
||||||
// luaopen_package(L); // Omitted because we use our own package system.
|
// luaopen_package(L); // Omitted because we use our own package system.
|
||||||
luaopen_table(L);
|
luaopen_table(L); // Standard table operations.
|
||||||
// luaopen_io(L); // Not safe for the sandbox.
|
luaopen_lpx_table(L); // Supplemental table operations.
|
||||||
// luaopen_os(L); // Not safe for the sandbox.
|
// luaopen_io(L); // Not safe for the sandbox.
|
||||||
|
// luaopen_os(L); // Not safe for the sandbox.
|
||||||
luaopen_string(L);
|
luaopen_string(L);
|
||||||
luaopen_math(L);
|
luaopen_math(L);
|
||||||
// luaopen_debug(L); // Not safe for the sandbox.
|
// luaopen_debug(L); // Not safe for the sandbox.
|
||||||
luaopen_bit(L);
|
luaopen_bit(L);
|
||||||
// luaopen_jit(L); // Don't know what it's for.
|
// luaopen_jit(L); // Don't know what it's for.
|
||||||
|
luaopen_lpx_classdb(L);
|
||||||
lua_gc(L, LUA_GCRESTART, -1);
|
lua_gc(L, LUA_GCRESTART, -1);
|
||||||
|
|
||||||
loadmain(L);
|
loadmain(L);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#ifndef UTIL_HPP
|
#ifndef UTIL_HPP
|
||||||
|
#define UTIL_HPP
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
|
|
||||||
classdb = table.coerce(classdb)
|
|
||||||
|
|
||||||
-- classdb.create: creates a new class database.
|
|
||||||
function classdb.create()
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Given a class database, removes all the functions that have
|
|
||||||
-- been inserted into it, but keeps the class and action tables.
|
|
||||||
function classdb.reset(db)
|
|
||||||
for name,maybeclass in pairs(db) do
|
|
||||||
local class = table.coerce(maybeclass)
|
|
||||||
local action = table.coerce(rawget(class, "action"))
|
|
||||||
table.rawclear(class)
|
|
||||||
table.rawclear(action)
|
|
||||||
rawset(db, name, class)
|
|
||||||
class.action = action
|
|
||||||
class.__index = class
|
|
||||||
class.__class = name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Given a class_db, makes an accessor that fetches classes
|
|
||||||
-- from that class db.
|
|
||||||
function classdb.accessor(db)
|
|
||||||
return function(name)
|
|
||||||
local class = rawget(db, name)
|
|
||||||
if type(class) ~= "table" then
|
|
||||||
class = {}
|
|
||||||
rawset(db, name, class)
|
|
||||||
class.action = {}
|
|
||||||
class.__index = class
|
|
||||||
class.__class = name
|
|
||||||
end
|
|
||||||
return class
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Make a global class database to use for the super.
|
|
||||||
classdb.database = {}
|
|
||||||
class = classdb.accessor(classdb.database)
|
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
# in the order that they're supposed to be loaded.
|
# in the order that they're supposed to be loaded.
|
||||||
#
|
#
|
||||||
|
|
||||||
tableutil.lua
|
|
||||||
classdb.lua
|
|
||||||
inspect.lua
|
inspect.lua
|
||||||
main.lua
|
main.lua
|
||||||
|
|
||||||
|
|||||||
@@ -331,5 +331,5 @@ function inspect.inspect(root, options)
|
|||||||
return table.concat(inspector.buffer)
|
return table.concat(inspector.buffer)
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
|
_G.inspect = inspect.inspect
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
-- Coerce T to be a table.
|
|
||||||
-- If T is a table, return it. If not, return a blank table.
|
|
||||||
function table.coerce(t)
|
|
||||||
if type(t) == "table" then
|
|
||||||
return t
|
|
||||||
else
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Clear the table out. Deletes all keys, removes any metatable.
|
|
||||||
-- TODO: this doesn't work on tables that have __metatable metamethod.
|
|
||||||
function table.rawclear(t)
|
|
||||||
for k in pairs(t) do
|
|
||||||
rawset(t, k, nil)
|
|
||||||
end
|
|
||||||
setmetatable(t, nil)
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user