Add VALIDATE_LUA as a function in lpxserver and lpxclient
This commit is contained in:
@@ -32,6 +32,7 @@ enum class AccessKind {
|
||||
INVOKE_LUA_SOURCE,
|
||||
PROBE_LUA_CALL,
|
||||
CONNECT_TO_SERVER,
|
||||
VALIDATE_LUA,
|
||||
};
|
||||
|
||||
class DrivenEngine;
|
||||
|
||||
@@ -20,14 +20,21 @@ public:
|
||||
LuaConsole console_;
|
||||
PrintChanneler print_channeler_;
|
||||
eng::vector<Invocation> delayed_invocations_;
|
||||
lua_State *lua_syntax_checker_;
|
||||
|
||||
public:
|
||||
LpxClient() {
|
||||
lua_syntax_checker_ = LuaCoreStack::newstate(eng::l_alloc);
|
||||
|
||||
set_console_prompt(console_.get_prompt());
|
||||
|
||||
set_initial_state_standalone();
|
||||
}
|
||||
|
||||
~LpxClient() {
|
||||
lua_close(lua_syntax_checker_);
|
||||
}
|
||||
|
||||
void set_initial_state_connect(const eng::string &hostspec) {
|
||||
// Create the world model.
|
||||
world_.reset(new World(WORLD_TYPE_PREDICTIVE));
|
||||
@@ -256,6 +263,13 @@ public:
|
||||
set_initial_state_connect(util::ss("nocert:", datapk, ":8085"));
|
||||
break;
|
||||
}
|
||||
case AccessKind::VALIDATE_LUA: {
|
||||
LuaVar closure;
|
||||
LuaDefStack LS(lua_syntax_checker_, closure);
|
||||
eng::string errmsg = LS.load(closure, datapk, "stdin");
|
||||
retpk->write_bytes(errmsg);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
util::dprint("Invalid event_access: ", int(kind));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "luaconsole.hpp"
|
||||
#include "util.hpp"
|
||||
#include "printbuffer.hpp"
|
||||
#include "luastack.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -33,10 +34,14 @@ public:
|
||||
eng::vector<Invocation> delayed_invocations_;
|
||||
int64_t admin_id_ = 0;
|
||||
double next_tick_ = 0;
|
||||
lua_State *lua_syntax_checker_;
|
||||
|
||||
public:
|
||||
LpxServer()
|
||||
{
|
||||
// Create a little lua interpreter for syntax checking only.
|
||||
lua_syntax_checker_ = LuaCoreStack::newstate(eng::l_alloc);
|
||||
|
||||
// Create the master world model.
|
||||
master_.reset(new World(WORLD_TYPE_MASTER));
|
||||
|
||||
@@ -62,6 +67,10 @@ public:
|
||||
rescan_lua_source(true);
|
||||
}
|
||||
|
||||
~LpxServer() {
|
||||
lua_close(lua_syntax_checker_);
|
||||
}
|
||||
|
||||
virtual void do_syntax_error(std::string_view error) override {
|
||||
stdostream() << "Syntax error: " << error << std::endl;
|
||||
}
|
||||
@@ -178,6 +187,13 @@ public:
|
||||
master_->rollback();
|
||||
break;
|
||||
}
|
||||
case AccessKind::VALIDATE_LUA: {
|
||||
LuaVar closure;
|
||||
LuaDefStack LS(lua_syntax_checker_, closure);
|
||||
eng::string errmsg = LS.load(closure, datapk, "stdin");
|
||||
retpk->write_bytes(errmsg);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
stdostream() << "Invalid event_access: " << int(kind) << std::endl;
|
||||
}
|
||||
|
||||
@@ -89,26 +89,23 @@ void LuaConsole::add(eng::string line) {
|
||||
}
|
||||
|
||||
// Try to parse the lua expression
|
||||
int top = lua_gettop(lua_state_);
|
||||
int status = luaL_loadbuffer(lua_state_, partial.c_str(), partial.size(), "=stdin");
|
||||
if (status == LUA_ERRSYNTAX)
|
||||
{
|
||||
const char *eof = "<eof>";
|
||||
int leof = strlen(eof);
|
||||
size_t lmsg;
|
||||
const char *msg = lua_tolstring(lua_state_, -1, &lmsg);
|
||||
const char *tp = msg + lmsg - leof;
|
||||
if (strstr(msg, eof) != tp) {
|
||||
LuaVar result;
|
||||
LuaDefStack LS(lua_state_, result);
|
||||
eng::string errmsg = LS.load(result, partial, "stdin");
|
||||
if (errmsg.empty()) {
|
||||
words_.push_back(lua_mode);
|
||||
words_.emplace_back(sv::rtrim(partial));
|
||||
clear_raw_input();
|
||||
} else if (errmsg.find("<eof>") != std::string::npos) {
|
||||
// We have an incomplete expression.
|
||||
// Do nothing, just let the user type more stuff.
|
||||
} else {
|
||||
words_.push_back("syntax");
|
||||
words_.push_back(msg);
|
||||
words_.push_back(errmsg);
|
||||
clear_raw_input();
|
||||
}
|
||||
} else {
|
||||
words_.push_back(lua_mode);
|
||||
words_.emplace_back(sv::rtrim(partial));
|
||||
clear_raw_input();
|
||||
}
|
||||
lua_settop(lua_state_, top);
|
||||
}
|
||||
|
||||
void CommonCommands::do_command(const StringVec &words) {
|
||||
|
||||
@@ -323,6 +323,29 @@ bool LuaCoreStack::next(LuaSlot tab, LuaSlot key, LuaSlot value) const {
|
||||
return (ret != 0);
|
||||
}
|
||||
|
||||
eng::string LuaCoreStack::load(LuaSlot result, std::string_view code, std::string_view context)
|
||||
{
|
||||
eng::string fullcontext = eng::string("=") + eng::string(context);
|
||||
luaL_loadbuffer(L_, code.data(), code.size(), fullcontext.c_str());
|
||||
int type = lua_type(L_, -1);
|
||||
if (type == LUA_TFUNCTION) {
|
||||
// compiler returned a closure.
|
||||
lua_replace(L_, result.index());
|
||||
return "";
|
||||
} else if (type == LUA_TSTRING) {
|
||||
// compiler returned an error message.
|
||||
size_t len;
|
||||
const char *str = lua_tolstring(L_, -1, &len);
|
||||
eng::string message(str, len);
|
||||
lua_pop(L_, 1);
|
||||
if (message.empty()) message = "unknown compiler error";
|
||||
set(result, message);
|
||||
return message;
|
||||
} else {
|
||||
assert(false && "lua compiler didn't return a closure, but didn't return an error message either");
|
||||
}
|
||||
}
|
||||
|
||||
void LuaCoreStack::getglobaltable(LuaSlot target) const {
|
||||
lua_pushglobaltable(L_);
|
||||
lua_replace(L_, target);
|
||||
|
||||
@@ -792,6 +792,19 @@ public:
|
||||
//
|
||||
bool next(LuaSlot tab, LuaSlot key, LuaSlot val) const;
|
||||
|
||||
// Compile lua code.
|
||||
//
|
||||
// If the code contains a syntax error, then the result variable
|
||||
// is set to the error message, and the error message is returned.
|
||||
//
|
||||
// If the code is valid, then the result variable is set to a
|
||||
// closure, and an empty string is returned.
|
||||
//
|
||||
// If a syntax error occurs, the error message may contain the
|
||||
// token <eof>. If so, the problem is an incomplete expression.
|
||||
//
|
||||
eng::string load(LuaSlot result, std::string_view code, std::string_view context);
|
||||
|
||||
// Return true if the int64 can be stored losslessly in a lua_Number.
|
||||
//
|
||||
// Lua numbers are actually double-precision floating point. double
|
||||
|
||||
@@ -78,9 +78,7 @@ static void calculate_loadresult(LuaCoreStack &LS0, LuaSlot info, const eng::str
|
||||
if (code == "") {
|
||||
LS.rawset(info, "loadresult", "missing or empty source file");
|
||||
} else {
|
||||
eng::string chunk = "=" + fn;
|
||||
luaL_loadbuffer(LS.state(), code.c_str(), code.size(), chunk.c_str());
|
||||
lua_replace(LS.state(), loadresult.index());
|
||||
LS.load(loadresult, code, fn);
|
||||
LS.rawset(info, "loadresult", loadresult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,14 +377,10 @@ eng::string World::probe_lua_expr(int64_t actor_id, std::string_view lua) {
|
||||
|
||||
LuaVar closure;
|
||||
LuaExtStack LS(L, closure);
|
||||
|
||||
// create the compiled closure.
|
||||
int status = luaL_loadbuffer(L, lua.data(), lua.size(), "=probe");
|
||||
lua_replace(L, closure.index());
|
||||
if (status != LUA_OK) {
|
||||
// The closure is actually an error message. Do nothing.
|
||||
// This should normally not happen: LuaConsole should filter
|
||||
// out syntax errors.
|
||||
eng::string errmsg = LS.load(closure, lua, "probe");
|
||||
if (!errmsg.empty()) {
|
||||
// This should normally not happen: the front end should
|
||||
// filter expressions for syntactic lua validity.
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user