First attempt at error-resistant /cpl directive
This commit is contained in:
@@ -132,16 +132,6 @@ static void get_info_table(LuaCoreStack &LS, LuaSlot db, LuaSlot info, const eng
|
||||
LS.rawset(info, "name", fn);
|
||||
}
|
||||
|
||||
static void calculate_loadresult(LuaCoreStack &LS0, LuaSlot info, const eng::string &fn, const eng::string &code) {
|
||||
LuaVar loadresult;
|
||||
LuaExtStack LS(LS0.state(), loadresult);
|
||||
if (code == "") {
|
||||
LS.rawset(info, "loadresult", "missing or empty source file");
|
||||
} else {
|
||||
LS.load(loadresult, code, fn);
|
||||
LS.rawset(info, "loadresult", loadresult);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceDB::diff(const SourceDB &auth, StreamBuffer *sb) {
|
||||
LuaVar sdb, sfn, sinfo, shash, sseq;
|
||||
@@ -202,8 +192,8 @@ void SourceDB::diff(const SourceDB &auth, StreamBuffer *sb) {
|
||||
|
||||
bool SourceDB::patch(StreamBuffer *sb, DebugCollector *dbc) {
|
||||
lua_State *L = lua_state_;
|
||||
LuaVar db, info;
|
||||
LuaExtStack LS(L, db, info);
|
||||
LuaVar db, info, closure;
|
||||
LuaExtStack LS(L, db, info, closure);
|
||||
LS.rawget(db, LuaRegistry, "sourcedb");
|
||||
int nupdates = sb->read_int32();
|
||||
for (int i = 0; i < nupdates; i++) {
|
||||
@@ -219,24 +209,27 @@ bool SourceDB::patch(StreamBuffer *sb, DebugCollector *dbc) {
|
||||
if (code != "\001") {
|
||||
LS.rawset(info, "code", code);
|
||||
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
||||
calculate_loadresult(LS, info, fn, code);
|
||||
LS.load(closure, code, fn);
|
||||
LS.rawset(info, "loadresult", closure);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nupdates > 0) rebuild();
|
||||
return (nupdates > 0);
|
||||
}
|
||||
|
||||
void SourceDB::set(const eng::string &fn, const eng::string &code, int sequence) {
|
||||
lua_State *L = lua_state_;
|
||||
LuaVar db, info;
|
||||
LuaExtStack LS(L, db, info);
|
||||
LuaVar db, info, closure;
|
||||
LuaExtStack LS(L, db, info, closure);
|
||||
LS.rawget(db, LuaRegistry, "sourcedb");
|
||||
get_info_table(LS, db, info, fn);
|
||||
LS.rawset(info, "sequence", sequence);
|
||||
LS.rawset(info, "code", code);
|
||||
LS.rawset(info, "fingerprint", "");
|
||||
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
||||
calculate_loadresult(LS, info, fn, code);
|
||||
LS.load(closure, code, fn);
|
||||
LS.rawset(info, "loadresult", closure);
|
||||
}
|
||||
|
||||
eng::string SourceDB::get(const eng::string &fn) {
|
||||
@@ -262,19 +255,15 @@ eng::string SourceDB::get(const eng::string &fn) {
|
||||
return util::ss(seqno, ":", ccode, ":", cloadresult);
|
||||
}
|
||||
|
||||
void SourceDB::update(const util::LuaSourceVec &source) {
|
||||
eng::string SourceDB::update(const util::LuaSourceVec &source) {
|
||||
lua_State *L = lua_state_;
|
||||
LuaVar sourcedb, info;
|
||||
LuaExtStack LS(L, sourcedb, info);
|
||||
LuaVar newsourcedb, oldsourcedb, info, closure;
|
||||
LuaExtStack LS(L, newsourcedb, oldsourcedb, info, closure);
|
||||
|
||||
// Get and clear the source database.
|
||||
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
||||
if (!LS.istable(sourcedb)) {
|
||||
LS.newtable(sourcedb);
|
||||
LS.rawset(LuaRegistry, "sourcedb", sourcedb);
|
||||
}
|
||||
LS.cleartable(sourcedb, true);
|
||||
eng::ostringstream errors;
|
||||
|
||||
// Step one. Build the new sourcedb.
|
||||
LS.newtable(newsourcedb);
|
||||
for (int i = 0; i < int(source.size()); i++) {
|
||||
const eng::string &file = source[i].first;
|
||||
const eng::string &code = source[i].second;
|
||||
@@ -283,9 +272,32 @@ void SourceDB::update(const util::LuaSourceVec &source) {
|
||||
LS.rawset(info, "code", code);
|
||||
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
||||
LS.rawset(info, "sequence", i + 1);
|
||||
calculate_loadresult(LS, info, file, code);
|
||||
LS.rawset(sourcedb, file, info);
|
||||
LS.load(closure, code, file);
|
||||
LS.rawset(info, "loadresult", closure);
|
||||
if (LS.isstring(closure)) {
|
||||
errors << file << ":" << LS.ckstring(closure) << std::endl;
|
||||
}
|
||||
LS.rawset(newsourcedb, file, info);
|
||||
}
|
||||
|
||||
// If there were compile errors, return the errors and don't update the env.
|
||||
if (!errors.view().empty()) {
|
||||
return errors.str();
|
||||
}
|
||||
|
||||
// Cache the old source database and store the new one.
|
||||
LS.rawget(oldsourcedb, LuaRegistry, "sourcedb");
|
||||
LS.rawset(LuaRegistry, "sourcedb", newsourcedb);
|
||||
|
||||
// Rebuild the source database.
|
||||
eng::string rebuild_errors = rebuild();
|
||||
|
||||
// Restore the old state, if there were errors.
|
||||
if (!rebuild_errors.empty()) {
|
||||
LS.rawset(LuaRegistry, "sourcedb", oldsourcedb);
|
||||
rebuild();
|
||||
}
|
||||
return rebuild_errors;
|
||||
}
|
||||
|
||||
// Delete everything from the global environment.
|
||||
@@ -411,14 +423,11 @@ eng::string SourceDB::get_source(const eng::string &fn)
|
||||
return LS.ckstring(code);
|
||||
}
|
||||
|
||||
|
||||
eng::vector<eng::string> SourceDB::modules() {
|
||||
eng::vector<eng::string> result;
|
||||
LuaVar sourcedb, key, info, seq;
|
||||
LuaExtStack LS(lua_state_, sourcedb, key, info, seq);
|
||||
|
||||
result.push_back("CORE");
|
||||
|
||||
// Get the source database.
|
||||
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
||||
if (!LS.istable(sourcedb)) {
|
||||
@@ -439,35 +448,38 @@ eng::vector<eng::string> SourceDB::modules() {
|
||||
return result;
|
||||
}
|
||||
|
||||
void SourceDB::rebuild_core() {
|
||||
eng::string SourceDB::rebuild_module(const eng::string &mod) {
|
||||
LuaVar sourcedb, info, closure;
|
||||
LuaExtStack LS(lua_state_, sourcedb, info, closure);
|
||||
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
||||
LS.rawget(info, sourcedb, mod);
|
||||
if (!LS.istable(info)) {
|
||||
return util::ss("No such module: ", mod);
|
||||
}
|
||||
LS.rawget(closure, info, "loadresult");
|
||||
if (!LS.isfunction(closure)) {
|
||||
return util::ss(mod, ":", LS.ckstring(closure));
|
||||
}
|
||||
lua_pushvalue(lua_state_, closure.index());
|
||||
return traceback_pcall(lua_state_, 0, 0);
|
||||
}
|
||||
|
||||
eng::string SourceDB::rebuild() {
|
||||
source_clear_globals(lua_state_);
|
||||
source_load_cfunctions(lua_state_);
|
||||
source_load_cconstants(lua_state_);
|
||||
|
||||
eng::ostringstream errors;
|
||||
|
||||
for (const eng::string &mod: modules()) {
|
||||
eng::string err = rebuild_module(mod);
|
||||
if (!err.empty()) errors << err << std::endl;
|
||||
}
|
||||
|
||||
rebuild_funcnames();
|
||||
return errors.str();
|
||||
}
|
||||
|
||||
eng::string SourceDB::rebuild_module(const eng::string &mod) {
|
||||
if (mod == "CORE") {
|
||||
rebuild_core();
|
||||
return "";
|
||||
} else {
|
||||
LuaVar sourcedb, info, closure;
|
||||
LuaExtStack LS(lua_state_, sourcedb, info, closure);
|
||||
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
||||
if (!LS.istable(sourcedb)) {
|
||||
return "SourceDB not initialized";
|
||||
}
|
||||
LS.rawget(info, sourcedb, mod);
|
||||
if (!LS.istable(info)) {
|
||||
return util::ss("No such module: ", mod);
|
||||
}
|
||||
LS.rawget(closure, info, "loadresult");
|
||||
if (!LS.isfunction(closure)) {
|
||||
return util::ss(mod, ":", LS.ckstring(closure));
|
||||
}
|
||||
lua_pushvalue(lua_state_, closure.index());
|
||||
return traceback_pcall(lua_state_, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceDB::init(lua_State *L) {
|
||||
register_lua_builtins();
|
||||
@@ -482,8 +494,7 @@ void SourceDB::init(lua_State *L) {
|
||||
LS.set(nullstring, "");
|
||||
LS.setmetatable(nullstring, classtab);
|
||||
|
||||
// Rebuild the global environment.
|
||||
rebuild_core();
|
||||
rebuild();
|
||||
|
||||
// We need to register all C functions with the eris permanents tables.
|
||||
LS.rawget(persist, LuaRegistry, "persist");
|
||||
@@ -516,15 +527,22 @@ void SourceDB::serialize_source(const util::LuaSourceVec &sv, StreamBuffer *sb)
|
||||
}
|
||||
}
|
||||
|
||||
void SourceDB::deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb) {
|
||||
sv->clear();
|
||||
int count = sb->read_int32();
|
||||
if ((count < 0) || (count > 10000)) throw StreamCorruption();
|
||||
for (int i = 0; i < count; i++) {
|
||||
eng::string fn = sb->read_string();
|
||||
eng::string code = sb->read_string();
|
||||
sv->emplace_back(fn, code);
|
||||
util::LuaSourceVec SourceDB::deserialize_source(std::string_view datapack) {
|
||||
StreamBuffer sb(datapack);
|
||||
util::LuaSourceVec sv;
|
||||
try {
|
||||
sv.clear();
|
||||
int count = sb.read_int32();
|
||||
if ((count < 0) || (count > 10000)) throw StreamCorruption();
|
||||
for (int i = 0; i < count; i++) {
|
||||
eng::string fn = sb.read_string();
|
||||
eng::string code = sb.read_string();
|
||||
sv.emplace_back(fn, code);
|
||||
}
|
||||
} catch (const StreamException &ex) {
|
||||
sv.clear();
|
||||
}
|
||||
return sv;
|
||||
}
|
||||
|
||||
// Register lua builtins.
|
||||
@@ -630,7 +648,6 @@ bool SourceDB::search_docs(const eng::string &substring, std::ostream &ostream)
|
||||
|
||||
// Search the lua source code.
|
||||
for (const eng::string &module : modules()) {
|
||||
if (module == "CORE") continue;
|
||||
eng::string code = get_source(module);
|
||||
if (code.empty()) continue;
|
||||
util::StringVec lines = util::split_lines(code);
|
||||
|
||||
Reference in New Issue
Block a user