Rewrite 'getclass' and 'classname' operators. These were flaky and inconsistent.

This commit is contained in:
2026-02-21 23:37:55 -05:00
parent afa8c698be
commit b1a132e252
3 changed files with 92 additions and 91 deletions

View File

@@ -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");
} 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) {
LS.rawget(lookup, LuaRegistry, "classnames");
LS.rawget(classname, lookup, input);
if (!LS.isstring(classname)) {
return "";
}
return LS.ckstring(classname);
LS.set(classtab, input);
} 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);
LS.getmetatable(classtab, input);
} 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 err;
if (!sv::is_lua_classname(name)) {
err = "invalid class name: " + name;
} else {
err = "not a class: " + name;
}
return err;
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 {