Reworking the keyword parser, also fixed some dynamic linking issues
This commit is contained in:
@@ -10,6 +10,9 @@
|
||||
LuaSpecial LuaRegistry(LUA_REGISTRYINDEX);
|
||||
LuaNilMarker LuaNil;
|
||||
LuaNewTableMarker LuaNewTable;
|
||||
static LuaToken token_error("error");
|
||||
static LuaToken token_found("found");
|
||||
|
||||
|
||||
LuaFunctionReg::LuaFunctionReg(const char *n, const char *a, const char *d, bool s, lua_CFunction f) {
|
||||
name_ = n;
|
||||
@@ -650,52 +653,101 @@ void LuaCoreStack::guard_nopredict(const char *fn) {
|
||||
}
|
||||
}
|
||||
|
||||
LuaKeywordParser::LuaKeywordParser(lua_State *L, int slot) {
|
||||
L_ = L;
|
||||
slot_ = slot;
|
||||
not_table_ = !lua_istable(L_, slot_);
|
||||
if (not_table_) {
|
||||
lua_newtable(L_);
|
||||
lua_replace(L_, slot_);
|
||||
LuaKeywordParser::LuaKeywordParser(const LuaCoreStack &LS0, LuaSlot slot)
|
||||
: keytab(slot.index()), LS(LS0.state(), found, error, key, val) {
|
||||
istable = LS.istable(keytab);
|
||||
if (istable) {
|
||||
LS.rawget(found, keytab, token_found);
|
||||
if (!LS.istable(found)) {
|
||||
LS.set(found, LuaNewTable);
|
||||
LS.rawset(keytab, token_found, found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LuaKeywordParser::parse(LuaSlot out, const char *kw) {
|
||||
lua_pushstring(L_, kw);
|
||||
lua_rawget(L_, slot_);
|
||||
lua_replace(L_, out.index());
|
||||
if (!lua_isnil(L_, out.index())) {
|
||||
parsed_.insert(kw);
|
||||
bool LuaKeywordParser::optional(LuaSlot out, const char *kw) {
|
||||
if (!istable) {
|
||||
LS.set(out, LuaNil);
|
||||
return false;
|
||||
}
|
||||
|
||||
LS.rawget(out, keytab, kw);
|
||||
if (!LS.isnil(out)) {
|
||||
LS.rawset(found, kw, true);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
eng::string LuaKeywordParser::final_check() {
|
||||
if (not_table_) {
|
||||
return "expected a keyword table";
|
||||
bool LuaKeywordParser::required(LuaSlot out, const char *kw) {
|
||||
if (!istable) {
|
||||
LS.set(out, LuaNil);
|
||||
return false;
|
||||
}
|
||||
lua_pushnil(L_);
|
||||
while (lua_next(L_, slot_) != 0) {
|
||||
lua_pop(L_, 1); // Don't need the value.
|
||||
if (!lua_isstring(L_, -1)) {
|
||||
return "keyword table contains non-string key";
|
||||
|
||||
LS.rawget(out, keytab, kw);
|
||||
if (!LS.isnil(out)) {
|
||||
LS.rawset(found, kw, true);
|
||||
return true;
|
||||
} else {
|
||||
LS.rawget(error, keytab, token_error);
|
||||
if (!LS.isstring(error)) {
|
||||
LS.rawset(keytab, token_error, util::ss("required keyword argument not present: ", kw));
|
||||
}
|
||||
const char *kw = lua_tostring(L_, -1);
|
||||
if (parsed_.find(kw) == parsed_.end()) {
|
||||
eng::ostringstream oss;
|
||||
oss << "keyword " << kw << " not known";
|
||||
return oss.str();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
eng::string LuaKeywordParser::check() {
|
||||
if (!istable) {
|
||||
return "keyword arguments must be a table";
|
||||
}
|
||||
|
||||
LS.rawget(error, keytab, token_error);
|
||||
auto str = LS.trystring(error);
|
||||
if (str.has_value()) return str.value();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
eng::string LuaKeywordParser::final_check() {
|
||||
if (!istable) {
|
||||
return "keyword arguments must be a table";
|
||||
}
|
||||
|
||||
LS.rawget(error, keytab, token_error);
|
||||
auto str = LS.trystring(error);
|
||||
if (str.has_value()) return str.value();
|
||||
|
||||
LS.set(key, LuaNil);
|
||||
while (LS.next(keytab, key, val)) {
|
||||
if (LS.istoken(key)) {
|
||||
continue;
|
||||
}
|
||||
auto kw = LS.trystringview(key);
|
||||
if (!kw.has_value()) {
|
||||
return "keyword arguments include a non-string key";
|
||||
}
|
||||
LS.rawget(val, found, key);
|
||||
if (!LS.rawequal(val, true)) {
|
||||
return util::ss("unrecognized keyword argument: ", kw.value());
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void LuaKeywordParser::check_throw() {
|
||||
eng::string err = check();
|
||||
if (!err.empty()) {
|
||||
luaL_error(LS.state(), "%s", err.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void LuaKeywordParser::final_check_throw() {
|
||||
eng::string err = final_check();
|
||||
if (!err.empty()) {
|
||||
luaL_error(L_, "%s", err.c_str());
|
||||
luaL_error(LS.state(), "%s", err.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user