Rewrite 'getclass' and 'classname' operators. These were flaky and inconsistent.
This commit is contained in:
@@ -81,7 +81,7 @@ BASE_ERIS := \
|
||||
|
||||
BASE_CORE := \
|
||||
invocation spookyv2 eng-malloc debugcollector drivenengine util luastack \
|
||||
traceback planemap pprint luavector idalloc globaldb sched http \
|
||||
traceback planemap pprint luavector idalloc sched http \
|
||||
json table luasnap animqueue streambuffer source world-core world-accessor \
|
||||
world-difftab world-diffxmit world-pairtab world-testing lpxserver lpxclient \
|
||||
eng-tests printbuffer serializelua
|
||||
|
||||
@@ -381,103 +381,87 @@ lua_State *LuaCoreStack::newthread(LuaSlot target) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
eng::string LuaCoreStack::classname(LuaSlot input) const {
|
||||
LuaVar lookup, classtab, classname, metatable;
|
||||
LuaExtStack LS(L_, lookup, classtab, classname, metatable);
|
||||
void LuaCoreStack::getclassinfo(LuaSlot classtab,
|
||||
eng::string &classname, eng::string &error, LuaSlot input) const {
|
||||
LuaVar lookup, cname;
|
||||
LuaExtStack LS(L_, lookup, cname);
|
||||
|
||||
// Step 1: Resolve input to a class table.
|
||||
int xt = xtype(input);
|
||||
if (xt == LUA_TSTRING) {
|
||||
LS.rawget(lookup, LuaRegistry, "classes");
|
||||
LS.rawget(classtab, lookup, input);
|
||||
if (xtype(classtab) != LUA_TT_CLASS) {
|
||||
return "";
|
||||
}
|
||||
return LS.ckstring(input);
|
||||
} else if (xt == LUA_TT_TANGIBLE) {
|
||||
if (!LS.getmetatable(lookup, input)) {
|
||||
return "";
|
||||
}
|
||||
if (LS.getmetatable(lookup, input)) {
|
||||
LS.rawget(classtab, lookup, "__index");
|
||||
if (xtype(classtab) != LUA_TT_CLASS) {
|
||||
return "";
|
||||
}
|
||||
LS.rawget(lookup, LuaRegistry, "classnames");
|
||||
LS.rawget(classname, lookup, classtab);
|
||||
if (!LS.isstring(classname)) {
|
||||
return "";
|
||||
}
|
||||
return LS.ckstring(classname);
|
||||
} else if (xt == LUA_TT_CLASS) {
|
||||
LS.rawget(lookup, LuaRegistry, "classnames");
|
||||
LS.rawget(classname, lookup, input);
|
||||
if (!LS.isstring(classname)) {
|
||||
return "";
|
||||
}
|
||||
return LS.ckstring(classname);
|
||||
} else if (xt == LUA_TT_GENERAL) {
|
||||
LS.getmetatable(metatable, input);
|
||||
LS.rawget(lookup, LuaRegistry, "classnames");
|
||||
LS.rawget(classname, lookup, metatable);
|
||||
if (!LS.isstring(classname)) {
|
||||
return "";
|
||||
}
|
||||
return LS.ckstring(classname);
|
||||
} else {
|
||||
return "";
|
||||
LS.set(classtab, LuaNil);
|
||||
}
|
||||
} else if (xt == LUA_TT_CLASS) {
|
||||
LS.set(classtab, input);
|
||||
} else if (xt == LUA_TT_GENERAL) {
|
||||
LS.getmetatable(classtab, input);
|
||||
} else {
|
||||
LS.set(classtab, LuaNil);
|
||||
}
|
||||
|
||||
// Step 2: Validate classtab and get classname, or generate error.
|
||||
// A class table is only valid if it's registered in classnames.
|
||||
if (xtype(classtab) == LUA_TT_CLASS) {
|
||||
LS.rawget(lookup, LuaRegistry, "classnames");
|
||||
LS.rawget(cname, lookup, classtab);
|
||||
auto name = LS.trystring(cname);
|
||||
if (name) {
|
||||
classname = *name;
|
||||
error = "";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static eng::string nonexistentclass(eng::string name) {
|
||||
eng::string err;
|
||||
if (!sv::is_lua_classname(name)) {
|
||||
err = "invalid class name: " + name;
|
||||
// Step 3: We didn't find a valid classtab and classname.
|
||||
// Clear the classtab and classname return-values, then
|
||||
// figure out what went wrong and generate an error message.
|
||||
LS.set(classtab, LuaNil);
|
||||
classname = "";
|
||||
if (xt == LUA_TSTRING) {
|
||||
eng::string s = LS.ckstring(input);
|
||||
if (!sv::is_lua_classname(s)) {
|
||||
error = "invalid class name: " + s;
|
||||
} else {
|
||||
err = "not a class: " + name;
|
||||
error = "class does not exist: " + s;
|
||||
}
|
||||
return err;
|
||||
} else if (xt == LUA_TT_TANGIBLE) {
|
||||
error = "tangible has no valid class";
|
||||
} else if (xt == LUA_TT_GENERAL) {
|
||||
error = "table has no valid class";
|
||||
} else if (xt == LUA_TT_CLASS) {
|
||||
error = "class is no longer valid";
|
||||
} else {
|
||||
error = "expected a string, class, tangible, or table";
|
||||
}
|
||||
}
|
||||
|
||||
eng::string LuaCoreStack::classname(LuaSlot input) const {
|
||||
LuaVar tab;
|
||||
LuaExtStack LS(L_, tab);
|
||||
eng::string name, error;
|
||||
getclassinfo(tab, name, error, input);
|
||||
return name;
|
||||
}
|
||||
|
||||
eng::string LuaCoreStack::getclass(LuaSlot classtab, LuaSlot input) const {
|
||||
LuaVar lookup;
|
||||
LuaExtStack LS(L_, lookup);
|
||||
|
||||
int xt = xtype(input);
|
||||
if (xt == LUA_TSTRING) {
|
||||
LS.rawget(lookup, LuaRegistry, "classes");
|
||||
LS.rawget(classtab, lookup, input);
|
||||
if (xtype(classtab) != LUA_TT_CLASS) {
|
||||
eng::string classname = LS.ckstring(input);
|
||||
return nonexistentclass(LS.ckstring(input));
|
||||
}
|
||||
return "";
|
||||
} else if (xt == LUA_TT_TANGIBLE) {
|
||||
if (!LS.getmetatable(lookup, input)) {
|
||||
eng::string err = "inactive tangible has no class";
|
||||
return err;
|
||||
}
|
||||
LS.rawget(classtab, lookup, "__index");
|
||||
if (xtype(classtab) != LUA_TT_CLASS) {
|
||||
eng::string err = "tangible has invalid class";
|
||||
}
|
||||
return "";
|
||||
} else if (xt == LUA_TT_CLASS) {
|
||||
LS.set(classtab, input);
|
||||
return "";
|
||||
} else {
|
||||
eng::string err = "getclass must be passed a string, class, or tangible";
|
||||
return err;
|
||||
}
|
||||
eng::string name, error;
|
||||
getclassinfo(classtab, name, error, input);
|
||||
return error;
|
||||
}
|
||||
|
||||
eng::string LuaCoreStack::getclass(LuaSlot classtab, std::string_view classname) const {
|
||||
LuaVar lookup;
|
||||
LuaExtStack LS(L_, lookup);
|
||||
LS.rawget(lookup, LuaRegistry, "classes");
|
||||
LS.rawget(classtab, lookup, classname);
|
||||
if (xtype(classtab) != LUA_TT_CLASS) {
|
||||
return nonexistentclass(eng::string(classname));
|
||||
}
|
||||
return "";
|
||||
LuaVar input;
|
||||
LuaExtStack LS(L_, input);
|
||||
LS.set(input, classname);
|
||||
eng::string name, error;
|
||||
getclassinfo(classtab, name, error, input);
|
||||
return error;
|
||||
}
|
||||
|
||||
void LuaCoreStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
|
||||
|
||||
@@ -833,28 +833,42 @@ public:
|
||||
//
|
||||
static bool validpositiveinteger(int64_t value) { return (value <= MAXINT) && (value >= 1); }
|
||||
|
||||
// Get the class name given a class table.
|
||||
// Get the class name of X.
|
||||
//
|
||||
// Return the class name if x is a valid class table. Otherwise, returns
|
||||
// empty string. If nonempty, the result is guaranteed to be a
|
||||
// validclassname. This can also function as an "isclass" operator.
|
||||
// The object passed in can be:
|
||||
//
|
||||
// * A valid class table.
|
||||
// * A valid, existing class name.
|
||||
// * A tangible that has a class.
|
||||
// * A normal table with a class metatable.
|
||||
//
|
||||
// If the object is none of these, returns empty string.
|
||||
//
|
||||
eng::string classname(LuaSlot x) const;
|
||||
|
||||
// Look for a class by class-name.
|
||||
// Get the class table of X.
|
||||
//
|
||||
// If there is a problem, returns an error message. There are lots
|
||||
// of error conditions, including such things as no such class, corrupted
|
||||
// class, classname invalid, etc.
|
||||
// The object passed in can be:
|
||||
//
|
||||
eng::string getclass(LuaSlot tab, LuaSlot name) const;
|
||||
// * A valid class table.
|
||||
// * A valid, existing class name.
|
||||
// * A tangible that has a class.
|
||||
// *
|
||||
//
|
||||
// If there is a problem, returns an error message.
|
||||
// There are lots of error conditions, including such
|
||||
// things as no such class, corrupted class, classname
|
||||
// invalid, etc.
|
||||
//
|
||||
eng::string getclass(LuaSlot tab, LuaSlot obj) const;
|
||||
eng::string getclass(LuaSlot tab, std::string_view name) const;
|
||||
|
||||
// Create a class, or look up an existing class.
|
||||
//
|
||||
// Creates a new class, unless the class already exists. Stores the
|
||||
// class in the global environment table. This routine assert-fails if the
|
||||
// parameter is not a valid classname.
|
||||
// Creates a new class, unless the class already exists.
|
||||
// Stores the class in the global environment table, and
|
||||
// in the class database. This routine assert-fails if
|
||||
// the parameter is not a valid classname.
|
||||
//
|
||||
void makeclass(LuaSlot tab, LuaSlot name) const;
|
||||
void makeclass(LuaSlot tab, std::string_view name) const;
|
||||
@@ -1018,6 +1032,9 @@ public:
|
||||
lua_rawseti(L_, tab, key);
|
||||
}
|
||||
|
||||
private:
|
||||
void getclassinfo(LuaSlot classtab, eng::string &classname, eng::string &error, LuaSlot input) const;
|
||||
|
||||
protected:
|
||||
|
||||
// Assign slots: this is used by the LuaDefStack and LuaExtStack
|
||||
|
||||
Reference in New Issue
Block a user