Rewrite 'getclass' and 'classname' operators. These were flaky and inconsistent.
This commit is contained in:
@@ -81,7 +81,7 @@ BASE_ERIS := \
|
|||||||
|
|
||||||
BASE_CORE := \
|
BASE_CORE := \
|
||||||
invocation spookyv2 eng-malloc debugcollector drivenengine util luastack \
|
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 \
|
json table luasnap animqueue streambuffer source world-core world-accessor \
|
||||||
world-difftab world-diffxmit world-pairtab world-testing lpxserver lpxclient \
|
world-difftab world-diffxmit world-pairtab world-testing lpxserver lpxclient \
|
||||||
eng-tests printbuffer serializelua
|
eng-tests printbuffer serializelua
|
||||||
|
|||||||
@@ -381,103 +381,87 @@ lua_State *LuaCoreStack::newthread(LuaSlot target) const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string LuaCoreStack::classname(LuaSlot input) const {
|
void LuaCoreStack::getclassinfo(LuaSlot classtab,
|
||||||
LuaVar lookup, classtab, classname, metatable;
|
eng::string &classname, eng::string &error, LuaSlot input) const {
|
||||||
LuaExtStack LS(L_, lookup, classtab, classname, metatable);
|
LuaVar lookup, cname;
|
||||||
|
LuaExtStack LS(L_, lookup, cname);
|
||||||
|
|
||||||
|
// Step 1: Resolve input to a class table.
|
||||||
int xt = xtype(input);
|
int xt = xtype(input);
|
||||||
if (xt == LUA_TSTRING) {
|
if (xt == LUA_TSTRING) {
|
||||||
LS.rawget(lookup, LuaRegistry, "classes");
|
LS.rawget(lookup, LuaRegistry, "classes");
|
||||||
LS.rawget(classtab, lookup, input);
|
LS.rawget(classtab, lookup, input);
|
||||||
if (xtype(classtab) != LUA_TT_CLASS) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return LS.ckstring(input);
|
|
||||||
} else if (xt == LUA_TT_TANGIBLE) {
|
} else if (xt == LUA_TT_TANGIBLE) {
|
||||||
if (!LS.getmetatable(lookup, input)) {
|
if (LS.getmetatable(lookup, input)) {
|
||||||
return "";
|
LS.rawget(classtab, lookup, "__index");
|
||||||
|
} else {
|
||||||
|
LS.set(classtab, LuaNil);
|
||||||
}
|
}
|
||||||
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) {
|
} else if (xt == LUA_TT_CLASS) {
|
||||||
LS.rawget(lookup, LuaRegistry, "classnames");
|
LS.set(classtab, input);
|
||||||
LS.rawget(classname, lookup, input);
|
|
||||||
if (!LS.isstring(classname)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return LS.ckstring(classname);
|
|
||||||
} else if (xt == LUA_TT_GENERAL) {
|
} else if (xt == LUA_TT_GENERAL) {
|
||||||
LS.getmetatable(metatable, input);
|
LS.getmetatable(classtab, input);
|
||||||
LS.rawget(lookup, LuaRegistry, "classnames");
|
|
||||||
LS.rawget(classname, lookup, metatable);
|
|
||||||
if (!LS.isstring(classname)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return LS.ckstring(classname);
|
|
||||||
} else {
|
} else {
|
||||||
return "";
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
error = "class does not exist: " + s;
|
||||||
|
}
|
||||||
|
} 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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static eng::string nonexistentclass(eng::string name) {
|
eng::string LuaCoreStack::classname(LuaSlot input) const {
|
||||||
eng::string err;
|
LuaVar tab;
|
||||||
if (!sv::is_lua_classname(name)) {
|
LuaExtStack LS(L_, tab);
|
||||||
err = "invalid class name: " + name;
|
eng::string name, error;
|
||||||
} else {
|
getclassinfo(tab, name, error, input);
|
||||||
err = "not a class: " + name;
|
return name;
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string LuaCoreStack::getclass(LuaSlot classtab, LuaSlot input) const {
|
eng::string LuaCoreStack::getclass(LuaSlot classtab, LuaSlot input) const {
|
||||||
LuaVar lookup;
|
eng::string name, error;
|
||||||
LuaExtStack LS(L_, lookup);
|
getclassinfo(classtab, name, error, input);
|
||||||
|
return error;
|
||||||
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 LuaCoreStack::getclass(LuaSlot classtab, std::string_view classname) const {
|
eng::string LuaCoreStack::getclass(LuaSlot classtab, std::string_view classname) const {
|
||||||
LuaVar lookup;
|
LuaVar input;
|
||||||
LuaExtStack LS(L_, lookup);
|
LuaExtStack LS(L_, input);
|
||||||
LS.rawget(lookup, LuaRegistry, "classes");
|
LS.set(input, classname);
|
||||||
LS.rawget(classtab, lookup, classname);
|
eng::string name, error;
|
||||||
if (xtype(classtab) != LUA_TT_CLASS) {
|
getclassinfo(classtab, name, error, input);
|
||||||
return nonexistentclass(eng::string(classname));
|
return error;
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaCoreStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
|
void LuaCoreStack::makeclass(LuaSlot classtab, LuaSlot classname) const {
|
||||||
|
|||||||
@@ -833,28 +833,42 @@ public:
|
|||||||
//
|
//
|
||||||
static bool validpositiveinteger(int64_t value) { return (value <= MAXINT) && (value >= 1); }
|
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
|
// The object passed in can be:
|
||||||
// empty string. If nonempty, the result is guaranteed to be a
|
//
|
||||||
// validclassname. This can also function as an "isclass" operator.
|
// * 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;
|
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
|
// The object passed in can be:
|
||||||
// of error conditions, including such things as no such class, corrupted
|
|
||||||
// class, classname invalid, etc.
|
|
||||||
//
|
//
|
||||||
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;
|
eng::string getclass(LuaSlot tab, std::string_view name) const;
|
||||||
|
|
||||||
// Create a class, or look up an existing class.
|
// Create a class, or look up an existing class.
|
||||||
//
|
//
|
||||||
// Creates a new class, unless the class already exists. Stores the
|
// Creates a new class, unless the class already exists.
|
||||||
// class in the global environment table. This routine assert-fails if the
|
// Stores the class in the global environment table, and
|
||||||
// parameter is not a valid classname.
|
// 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, LuaSlot name) const;
|
||||||
void makeclass(LuaSlot tab, std::string_view name) const;
|
void makeclass(LuaSlot tab, std::string_view name) const;
|
||||||
@@ -1018,6 +1032,9 @@ public:
|
|||||||
lua_rawseti(L_, tab, key);
|
lua_rawseti(L_, tab, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void getclassinfo(LuaSlot classtab, eng::string &classname, eng::string &error, LuaSlot input) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Assign slots: this is used by the LuaDefStack and LuaExtStack
|
// Assign slots: this is used by the LuaDefStack and LuaExtStack
|
||||||
|
|||||||
Reference in New Issue
Block a user