Makeclass cleaned up

This commit is contained in:
2021-02-10 16:22:24 -05:00
parent e838b4ac97
commit 3883f86dee
13 changed files with 120 additions and 54 deletions

View File

@@ -4,10 +4,10 @@
LuaDefine(globaldb_enable, "c") {
LuaVar globaldb;
LuaStack LS(L, globaldb);
LS.getfield(globaldb, LuaRegistry, "globaldb");
LS.rawget(globaldb, LuaRegistry, "globaldb");
if (!LS.istable(globaldb)) {
LS.newtable(globaldb);
LS.setfield(LuaRegistry, "globaldb", globaldb);
LS.rawset(LuaRegistry, "globaldb", globaldb);
}
return LS.result();
}
@@ -26,7 +26,7 @@ LuaDefine(globaldb_global, "f") {
LuaStack LS(L, globalname, globaltab, globaldb);
// Get a pointer to the globaldb.
LS.getfield(globaldb, LuaRegistry, "globaldb");
LS.rawget(globaldb, LuaRegistry, "globaldb");
if (!LS.istable(globaldb)) {
luaL_error(L, "globaldb is not enabled");
}
@@ -44,6 +44,6 @@ LuaDefine(globaldb_global, "f") {
// Create a new globaltab and store it in the globaldb.
LS.newtable(globaltab);
LS.rawset(globaldb, globalname, globaltab);
LS.setfield(globaltab, "__global", globalname);
LS.rawset(globaltab, "__global", globalname);
return LS.result();
}

View File

@@ -17,7 +17,7 @@ LuaDefine(gui_create, "c") {
return LS.result();
}
LuaDefine(gui_add_menu_item, "c") {
LuaDefine(gui_menu_item, "c") {
LuaArg lgui, lid;
LuaStack LS(L, lgui, lid);
Gui *gui = LS.ckuserdata<Gui>(lgui);

View File

@@ -1,6 +1,12 @@
#include <string.h>
#include "luaconsole.hpp"
#include "util.hpp"
static bool is_single_letter(const std::string &s) {
return ((s.size() == 1) && (s[0] >= 'a') && (s[0] <= 'z'));
}
LuaConsole::LuaConsole() {
lua_state_ = lua_open();
@@ -52,14 +58,16 @@ void LuaConsole::add(std::string line) {
// Try to interpret it as a special command.
if (lines_ == 1) {
split_words();
if ((words_.size() >= 1)&&(words_[0].size() == 1)) {
action_ = DO_COMMAND;
return;
if (words_.size() >= 1) {
if (is_single_letter(words_[0]) || (util::validinteger(words_[0]))) {
action_ = DO_COMMAND;
return;
}
}
}
words_.clear();
// Strip the leading punctuation from lua commands.
// Translate lua expression with leading '=' to 'return'
std::string partial;
if (raw_input_[0] == '=') {
partial = std::string("return ") + raw_input_.substr(1);
@@ -67,7 +75,7 @@ void LuaConsole::add(std::string line) {
partial = raw_input_;
}
// Analyze lua expressions.
// Try to parse the lua expression
int top = lua_gettop(lua_state_);
int status = luaL_loadbuffer(lua_state_, partial.c_str(), partial.size(), "=stdin");
if (status == LUA_ERRSYNTAX)

View File

@@ -189,33 +189,17 @@ int LuaStack::next(LuaSlot tab, LuaSlot key, LuaSlot value) const {
return ret;
}
bool LuaStack::isemptytable(LuaSlot tab) const {
if (lua_istable(L_, tab)) {
lua_pushnil(L_);
if (lua_next(L_, tab) == 0) {
return true;
}
lua_pop(L_, 2);
}
return false;
}
void LuaStack::newtable(LuaSlot target) const {
lua_newtable(L_);
lua_replace(L_, target);
}
void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
int top = lua_gettop(L_);
checkstring(classname);
// Special case: if the classname is _G, return global env.
lua_pushstring(L_, "_G");
int eqlg = lua_equal(L_, -1, classname.index());
lua_settop(L_, top);
if (eqlg) {
set(classtab, LuaGlobals);
return;
// Special case: if the classname is _G, detect and error.
if (equal(classname, "_G")) {
luaL_error(L_, "_G is explicitly not allowed as a class name");
}
// Get the classtab from the global environment.
@@ -236,6 +220,19 @@ void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
setfield(classtab, "__class", classname);
}
void LuaStack::makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const {
rawget(sub, tab, name);
if (istable(sub)) {
return;
} else if (isnil(sub)) {
newtable(sub);
rawset(tab, name, sub);
return;
} else {
luaL_error(L_, "%s is not a table", name);
}
}
void LuaStack::setlightuserdata(LuaSlot target, void *p) const {
lua_pushlightuserdata(L_, p);
lua_replace(L_, target);

View File

@@ -426,7 +426,7 @@ public:
void newtable(LuaSlot target) const;
void makeclass(LuaSlot tab, LuaSlot name) const;
void makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const;
void setlightuserdata(LuaSlot target, void *p) const;
@@ -456,11 +456,26 @@ public:
void clearuserdata(LuaSlot target) { clear_tagged_pointer(target); }
int next(LuaSlot tab, LuaSlot key, LuaSlot value) const;
bool isemptytable(LuaSlot s) const;
bool equal(LuaSlot v1, LuaSlot v2) {
void makeclass(LuaSlot tab, LuaSlot name) const;
void makeclass(LuaSlot tab, const char *name) const {
push_any_value(name);
LuaSpecial classname(lua_gettop(L_));
makeclass(tab, classname);
lua_pop(L_, 1);
}
bool equal(LuaSlot v1, LuaSlot v2) const {
return lua_equal(L_, v1, v2);
}
bool equal(LuaSlot v1, const char *name) const {
push_any_value(name);
bool result = lua_equal(L_, v1, -1);
lua_pop(L_, 1);
return result;
}
template<typename T1, typename T2>
void set(T1 &target, T2 value) const {

View File

@@ -40,6 +40,16 @@ LuaDefine(source_makeclass, "f") {
return LS.result();
}
LuaDefine(source_maketangible, "f") {
LuaArg classname;
LuaRet classtab;
LuaVar subtab;
LuaStack LS(L, classname, classtab, subtab);
LS.makeclass(classtab, classname);
LS.makesubtable(subtab, classtab, "action");
return LS.result();
}
// Load the builtins.
static void load_builtin(lua_State *L, const char *name, lua_CFunction func) {
@@ -189,18 +199,22 @@ static void source_clear_globals(lua_State *L) {
// Restore the lua builtins from the backup snapshot.
//
static void source_restore_builtins(lua_State *L) {
LuaVar snapshot, key, value, skey, svalue, subglobal;
LuaStack LS(L, snapshot, key, value, skey, svalue, subglobal);
LuaVar snapshot, key, value, skey, svalue, target;
LuaStack LS(L, snapshot, key, value, skey, svalue, target);
LS.getfield(snapshot, LuaRegistry, "source_snapshot_builtins");
LS.setfield(LuaGlobals, "_G", LuaGlobals);
LS.set(key, LuaNil);
while (LS.next(snapshot, key, value) != 0) {
LS.checktable(value);
LS.makeclass(subglobal, key);
if (LS.equal(key, "_G")) {
LS.set(target, LuaGlobals);
} else {
LS.makeclass(target, key);
}
LS.set(skey, LuaNil);
while (LS.next(value, skey, svalue) != 0) {
LS.rawset(subglobal, skey, svalue);
LS.rawset(target, skey, svalue);
}
}
LS.result();

View File

@@ -109,13 +109,18 @@ void TextGame::do_menu_command(const StringVec &cmd) {
void TextGame::do_choose_command(const StringVec &cmd) {
int64_t index;
if (cmd.size() == 2) {
index = util::strtoint(cmd[1], -1);
if (cmd.size() == 1) {
index = util::strtoint(cmd[0], -1);
} else {
std::cerr << "c command (choose) expects a menu line number" << std::endl;
return;
}
std::cerr << "Choose command (index " << index << ") not implemented yet." << std::endl;
const Gui::EltVec &elts = gui_.elts();
if ((index < 0) || (index >= int(elts.size()))) {
std::cerr << "No menu item #" << index << std::endl;
return;
}
std::cerr << "Choosing menu item: " << elts[index].id() << std::endl;
}
void TextGame::do_snapshot_command(const StringVec &cmd) {
@@ -143,14 +148,13 @@ void TextGame::do_quit_command(const StringVec &cmd) {
}
void TextGame::do_command(const StringVec &words) {
switch (words[0][0]) {
case 'v': do_view_command(words); break;
case 'm': do_menu_command(words); break;
case 'c': do_choose_command(words); break;
case 'q': do_quit_command(words); break;
case 's': do_snapshot_command(words); break;
case 'r': do_rollback_command(words); break;
default:
if (words[0] == "v") do_view_command(words);
else if (words[0] == "m") do_menu_command(words);
else if (words[0] == "q") do_quit_command(words);
else if (words[0] == "s") do_snapshot_command(words);
else if (words[0] == "r") do_rollback_command(words);
else if (util::validinteger(words[0])) do_choose_command(words);
else {
std::cerr << "Unknown command: " << words[0] << std::endl;
}
}

View File

@@ -26,6 +26,12 @@ std::string toupper(std::string input) {
return input;
}
bool validinteger(const std::string &value) {
char *endptr;
strtoll(value.c_str(), &endptr, 10);
return (endptr == value.c_str() + value.size());
}
int64_t strtoint(const std::string &value, int64_t errval) {
char *endptr;
int64_t result = strtoll(value.c_str(), &endptr, 10);

View File

@@ -18,6 +18,9 @@ using stringset = std::set<std::string>;
std::string tolower(std::string input);
std::string toupper(std::string input);
// Return true if the string can be parsed as an integer.
bool validinteger(const std::string &value);
// String to integer. Returns errval if the number is not parseable.
int64_t strtoint(const std::string &value, int64_t errval);

View File

@@ -50,7 +50,7 @@ void Tangible::be_a_player() {
LuaVar classtab, mt, place, tangibles;
LuaStack LS(world_->state(), classtab, mt, place, tangibles);
LS.call(classtab, source_makeclass, "player");
LS.makeclass(classtab, "player");
LS.getfield(tangibles, LuaRegistry, "tangibles");
LS.rawget(place, tangibles, anim_queue_.get_id());
LS.getmetatable(mt, place);

View File

@@ -6,4 +6,4 @@
inspect.lua
ut-table.lua
ut-globaldb.lua
player.lua

View File

@@ -0,0 +1,24 @@
maketangible('player')
function player.interface(actor, place, gui)
gui:menu_item("North")
gui:menu_item("South")
gui:menu_item("East")
gui:menu_item("West")
end
function player.action.north(actor, place, gui)
print("Moving north")
end
function player.action.south(actor, place, gui)
print("Moving south")
end
function player.action.east(actor, place, gui)
print("Moving east")
end
function player.action.west(actor, place, gui)
print("Moving west")
end

View File

@@ -47,11 +47,6 @@
#define LUA_ERRMEM 4
#define LUA_ERRERR 5
/* Additional thread status codes for luprex */
#define LUA_ERRPARTIAL 15
#define LUA_ERREOF 16
typedef struct lua_State lua_State;
typedef int (*lua_CFunction) (lua_State *L);