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);