Files
integration/luprex/cpp/core/luaconsole.cpp

173 lines
4.6 KiB
C++

#include "wrap-string.hpp"
#include "wrap-vector.hpp"
#include "eng-malloc.hpp"
#include "luastack.hpp"
#include "luaconsole.hpp"
#include "util.hpp"
#include <cstring>
#include <iostream>
LuaConsole::LuaConsole() {
lua_state_ = LuaCoreStack::newstate(eng::l_alloc);
clear_raw_input();
}
LuaConsole::~LuaConsole() {
lua_close(lua_state_);
}
static LuaConsole::StringVec split_words(const eng::string &raw) {
LuaConsole::StringVec result;
eng::string acc;
for (char c : raw) {
if ((c == ' ')||(c == '\n')||(c == '\r')) {
if (!acc.empty()) {
result.push_back(acc);
acc = "";
}
} else {
acc += c;
}
}
if (!acc.empty()) {
result.push_back(acc);
}
return result;
}
LuaConsole::StringVec LuaConsole::get_command() {
StringVec result = words_;
words_.clear();
return result;
}
void LuaConsole::synerr(const eng::string &msg) {
words_.clear();
words_.push_back("syntax");
words_.push_back(msg);
}
void LuaConsole::simplify(const StringVec &words) {
words_ = words;
if (words.size() == 0) {
return;
} else if (sv::valid_int64(words[0])) {
if (words.size() == 1) {
words_.clear();
words_.push_back("choose");
words_.push_back(words[0]);
} else {
synerr("/choose command takes no arguments");
}
} else if (words[0] == "choose") {
if ((words.size() == 2)&&(sv::valid_int64(words[1]))) {
// OK
} else {
synerr("/choose [menu-line-number]");
}
} else if (words[0] == "view") {
if (words.size() != 1) {
synerr("/view takes no arguments");
}
} else if (words[0] == "menu") {
if (words.size() == 1) {
words_.push_back("-");
} else if ((words.size() == 2)&&(sv::valid_int64(words[1]))) {
// OK
} else {
synerr("/menu [optional-tangible-id]");
}
} else if (words[0] == "quit") {
if (words.size() != 1) {
synerr("/quit takes no arguments");
}
} else if (words[0] == "tick") {
if (words.size() != 1) {
synerr("/tick takes no arguments");
}
} else if (words[0] == "cpl") {
if (words.size() != 1) {
synerr("/cpl takes no arguments");
}
} else if (words[0] == "work") {
if (words.size() != 1) {
synerr("/work takes no arguments");
}
} else if (words[0] == "display") {
if (words.size() != 1) {
synerr("/display takes no arguments");
}
} else if (words[0] == "aborthttp") {
if (words.size() != 1) {
synerr("/aborthttp takes no arguments");
}
} else {
synerr("unrecognized command");
}
}
void LuaConsole::clear_raw_input() {
raw_input_ = "";
lines_ = 0;
prompt_ = "> ";
}
void LuaConsole::add(eng::string line) {
for (int i = 0; i < int(line.size()); i++) {
if (line[i] == '\n') line[i] = ' ';
}
raw_input_ += line;
raw_input_ += '\n';
lines_ += 1;
prompt_ = ">> ";
words_.clear();
// Try to interpret it as a slash-command.
if ((lines_ == 1)&&(raw_input_[0] == '/')) {
simplify(split_words(raw_input_.substr(1)));
clear_raw_input();
return;
}
// Translate lua expression, deal with initial prefix.
eng::string partial;
eng::string lua_mode;
if (sv::has_prefix(raw_input_, "?=")) {
lua_mode = "luaprobe";
partial = eng::string("return ") + raw_input_.substr(2);
} else if (sv::has_prefix(raw_input_, "?")) {
lua_mode = "luaprobe";
partial = raw_input_.substr(1);
} else if (sv::has_prefix(raw_input_, "=")) {
lua_mode = "luainvoke";
partial = eng::string("return ") + raw_input_.substr(1);
} else {
lua_mode = "luainvoke";
partial = raw_input_;
}
// 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) {
words_.push_back("syntax");
words_.push_back(msg);
clear_raw_input();
}
} else {
words_.push_back(lua_mode);
words_.emplace_back(sv::rtrim(partial));
clear_raw_input();
}
lua_settop(lua_state_, top);
}