Add VALIDATE_LUA as a function in lpxserver and lpxclient
This commit is contained in:
@@ -46,7 +46,8 @@
|
|||||||
"--compile-commands-dir=[INTEGRATION]/.vscode",
|
"--compile-commands-dir=[INTEGRATION]/.vscode",
|
||||||
"--header-insertion=never"
|
"--header-insertion=never"
|
||||||
],
|
],
|
||||||
"C_Cpp.autocomplete": "disabled"
|
"C_Cpp.autocomplete": "disabled",
|
||||||
|
"search.useIgnoreFiles": false
|
||||||
},
|
},
|
||||||
"extensions": {
|
"extensions": {
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ enum class AccessKind {
|
|||||||
INVOKE_LUA_SOURCE,
|
INVOKE_LUA_SOURCE,
|
||||||
PROBE_LUA_CALL,
|
PROBE_LUA_CALL,
|
||||||
CONNECT_TO_SERVER,
|
CONNECT_TO_SERVER,
|
||||||
|
VALIDATE_LUA,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrivenEngine;
|
class DrivenEngine;
|
||||||
|
|||||||
@@ -20,14 +20,21 @@ public:
|
|||||||
LuaConsole console_;
|
LuaConsole console_;
|
||||||
PrintChanneler print_channeler_;
|
PrintChanneler print_channeler_;
|
||||||
eng::vector<Invocation> delayed_invocations_;
|
eng::vector<Invocation> delayed_invocations_;
|
||||||
|
lua_State *lua_syntax_checker_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LpxClient() {
|
LpxClient() {
|
||||||
|
lua_syntax_checker_ = LuaCoreStack::newstate(eng::l_alloc);
|
||||||
|
|
||||||
set_console_prompt(console_.get_prompt());
|
set_console_prompt(console_.get_prompt());
|
||||||
|
|
||||||
set_initial_state_standalone();
|
set_initial_state_standalone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~LpxClient() {
|
||||||
|
lua_close(lua_syntax_checker_);
|
||||||
|
}
|
||||||
|
|
||||||
void set_initial_state_connect(const eng::string &hostspec) {
|
void set_initial_state_connect(const eng::string &hostspec) {
|
||||||
// Create the world model.
|
// Create the world model.
|
||||||
world_.reset(new World(WORLD_TYPE_PREDICTIVE));
|
world_.reset(new World(WORLD_TYPE_PREDICTIVE));
|
||||||
@@ -256,6 +263,13 @@ public:
|
|||||||
set_initial_state_connect(util::ss("nocert:", datapk, ":8085"));
|
set_initial_state_connect(util::ss("nocert:", datapk, ":8085"));
|
||||||
break;
|
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: {
|
default: {
|
||||||
util::dprint("Invalid event_access: ", int(kind));
|
util::dprint("Invalid event_access: ", int(kind));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "luaconsole.hpp"
|
#include "luaconsole.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "printbuffer.hpp"
|
#include "printbuffer.hpp"
|
||||||
|
#include "luastack.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -33,10 +34,14 @@ public:
|
|||||||
eng::vector<Invocation> delayed_invocations_;
|
eng::vector<Invocation> delayed_invocations_;
|
||||||
int64_t admin_id_ = 0;
|
int64_t admin_id_ = 0;
|
||||||
double next_tick_ = 0;
|
double next_tick_ = 0;
|
||||||
|
lua_State *lua_syntax_checker_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LpxServer()
|
LpxServer()
|
||||||
{
|
{
|
||||||
|
// Create a little lua interpreter for syntax checking only.
|
||||||
|
lua_syntax_checker_ = LuaCoreStack::newstate(eng::l_alloc);
|
||||||
|
|
||||||
// Create the master world model.
|
// Create the master world model.
|
||||||
master_.reset(new World(WORLD_TYPE_MASTER));
|
master_.reset(new World(WORLD_TYPE_MASTER));
|
||||||
|
|
||||||
@@ -62,6 +67,10 @@ public:
|
|||||||
rescan_lua_source(true);
|
rescan_lua_source(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~LpxServer() {
|
||||||
|
lua_close(lua_syntax_checker_);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void do_syntax_error(std::string_view error) override {
|
virtual void do_syntax_error(std::string_view error) override {
|
||||||
stdostream() << "Syntax error: " << error << std::endl;
|
stdostream() << "Syntax error: " << error << std::endl;
|
||||||
}
|
}
|
||||||
@@ -178,6 +187,13 @@ public:
|
|||||||
master_->rollback();
|
master_->rollback();
|
||||||
break;
|
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: {
|
default: {
|
||||||
stdostream() << "Invalid event_access: " << int(kind) << std::endl;
|
stdostream() << "Invalid event_access: " << int(kind) << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,26 +89,23 @@ void LuaConsole::add(eng::string line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse the lua expression
|
// 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>";
|
LuaVar result;
|
||||||
int leof = strlen(eof);
|
LuaDefStack LS(lua_state_, result);
|
||||||
size_t lmsg;
|
eng::string errmsg = LS.load(result, partial, "stdin");
|
||||||
const char *msg = lua_tolstring(lua_state_, -1, &lmsg);
|
if (errmsg.empty()) {
|
||||||
const char *tp = msg + lmsg - leof;
|
|
||||||
if (strstr(msg, eof) != tp) {
|
|
||||||
words_.push_back("syntax");
|
|
||||||
words_.push_back(msg);
|
|
||||||
clear_raw_input();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
words_.push_back(lua_mode);
|
words_.push_back(lua_mode);
|
||||||
words_.emplace_back(sv::rtrim(partial));
|
words_.emplace_back(sv::rtrim(partial));
|
||||||
clear_raw_input();
|
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(errmsg);
|
||||||
|
clear_raw_input();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lua_settop(lua_state_, top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommonCommands::do_command(const StringVec &words) {
|
void CommonCommands::do_command(const StringVec &words) {
|
||||||
|
|||||||
@@ -323,6 +323,29 @@ bool LuaCoreStack::next(LuaSlot tab, LuaSlot key, LuaSlot value) const {
|
|||||||
return (ret != 0);
|
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 {
|
void LuaCoreStack::getglobaltable(LuaSlot target) const {
|
||||||
lua_pushglobaltable(L_);
|
lua_pushglobaltable(L_);
|
||||||
lua_replace(L_, target);
|
lua_replace(L_, target);
|
||||||
|
|||||||
@@ -792,6 +792,19 @@ public:
|
|||||||
//
|
//
|
||||||
bool next(LuaSlot tab, LuaSlot key, LuaSlot val) const;
|
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.
|
// Return true if the int64 can be stored losslessly in a lua_Number.
|
||||||
//
|
//
|
||||||
// Lua numbers are actually double-precision floating point. double
|
// 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 == "") {
|
if (code == "") {
|
||||||
LS.rawset(info, "loadresult", "missing or empty source file");
|
LS.rawset(info, "loadresult", "missing or empty source file");
|
||||||
} else {
|
} else {
|
||||||
eng::string chunk = "=" + fn;
|
LS.load(loadresult, code, fn);
|
||||||
luaL_loadbuffer(LS.state(), code.c_str(), code.size(), chunk.c_str());
|
|
||||||
lua_replace(LS.state(), loadresult.index());
|
|
||||||
LS.rawset(info, "loadresult", loadresult);
|
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;
|
LuaVar closure;
|
||||||
LuaExtStack LS(L, closure);
|
LuaExtStack LS(L, closure);
|
||||||
|
eng::string errmsg = LS.load(closure, lua, "probe");
|
||||||
// create the compiled closure.
|
if (!errmsg.empty()) {
|
||||||
int status = luaL_loadbuffer(L, lua.data(), lua.size(), "=probe");
|
// This should normally not happen: the front end should
|
||||||
lua_replace(L, closure.index());
|
// filter expressions for syntactic lua validity.
|
||||||
if (status != LUA_OK) {
|
|
||||||
// The closure is actually an error message. Do nothing.
|
|
||||||
// This should normally not happen: LuaConsole should filter
|
|
||||||
// out syntax errors.
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user