Compare commits

...

5 commits

4 changed files with 43 additions and 30 deletions

View file

@ -7,6 +7,9 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
extern const char* WRAPPER_SRC; // TODO: Move this to a shared header
int script_errhandler(lua_State*); // extern
SignalSource::SignalSource() : std::shared_ptr<Signal>(std::make_shared<Signal>()) {} SignalSource::SignalSource() : std::shared_ptr<Signal>(std::make_shared<Signal>()) {}
SignalSource::~SignalSource() = default; SignalSource::~SignalSource() = default;
@ -22,16 +25,13 @@ LuaSignalConnection::LuaSignalConnection(lua_State* L, std::weak_ptr<Signal> par
// https://stackoverflow.com/a/31952046/16255372 // https://stackoverflow.com/a/31952046/16255372
// Save function and current thread so they don't get GC'd // Save function so it doesn't get GC'd
function = luaL_ref(L, LUA_REGISTRYINDEX); function = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushthread(L);
thread = luaL_ref(L, LUA_REGISTRYINDEX);
} }
LuaSignalConnection::~LuaSignalConnection() { LuaSignalConnection::~LuaSignalConnection() {
// Remove LuaSignalConnectionthread so that it can get properly GC'd // Remove LuaSignalConnectionthread so that it can get properly GC'd
luaL_unref(state, LUA_REGISTRYINDEX, function); luaL_unref(state, LUA_REGISTRYINDEX, function);
luaL_unref(state, LUA_REGISTRYINDEX, thread);
} }
#if 0 #if 0
@ -56,18 +56,21 @@ static void stackdump(lua_State* L) {
void LuaSignalConnection::Call(std::vector<Variant> args) { void LuaSignalConnection::Call(std::vector<Variant> args) {
lua_State* thread = lua_newthread(state); lua_State* thread = lua_newthread(state);
// Push function // Push wrapepr as thread function
luaL_loadbuffer(thread, WRAPPER_SRC, strlen(WRAPPER_SRC), "=PCALL_WRAPPER");
// Push function as upvalue for wrapper
lua_rawgeti(thread, LUA_REGISTRYINDEX, function); lua_rawgeti(thread, LUA_REGISTRYINDEX, function);
// Also push our error handler and generate wrapped function
lua_pushcfunction(thread, script_errhandler);
lua_call(thread, 2, 1);
for (Variant arg : args) { for (Variant arg : args) {
arg.PushLuaValue(thread); arg.PushLuaValue(thread);
} }
int status = lua_resume(thread, args.size()); lua_resume(thread, args.size());
if (status > LUA_YIELD) {
Logger::error(lua_tostring(thread, -1));
lua_pop(thread, 1); // Pop return value
}
lua_pop(state, 1); // Pop thread lua_pop(state, 1); // Pop thread
} }
@ -152,11 +155,7 @@ void Signal::Fire(std::vector<Variant> args) {
arg.PushLuaValue(thread); arg.PushLuaValue(thread);
} }
int status = lua_resume(thread, args.size()); lua_resume(thread, args.size());
if (status > LUA_YIELD) {
Logger::error(lua_tostring(thread, -1));
lua_pop(thread, 1); // Pop return value
}
// Remove thread from registry // Remove thread from registry
luaL_unref(thread, LUA_REGISTRYINDEX, threadId); luaL_unref(thread, LUA_REGISTRYINDEX, threadId);

View file

@ -45,7 +45,7 @@ public:
class LuaSignalConnection : public SignalConnection { class LuaSignalConnection : public SignalConnection {
lua_State* state; lua_State* state;
int function, thread; int function;
friend Signal; friend Signal;
protected: protected:

View file

@ -1,5 +1,6 @@
#include "script.h" #include "script.h"
#include "common.h" #include "common.h"
#include "lauxlib.h"
#include "logger.h" #include "logger.h"
#include "objects/base/instance.h" #include "objects/base/instance.h"
#include "objects/base/member.h" #include "objects/base/member.h"
@ -13,9 +14,11 @@
int script_wait(lua_State*); int script_wait(lua_State*);
int script_delay(lua_State*); int script_delay(lua_State*);
int script_wrapper(lua_State*);
int script_errhandler(lua_State*); int script_errhandler(lua_State*);
// TODO: Move this to a shared header
const char* WRAPPER_SRC = "local func, errhandler = ... return function(...) local args = {...} xpcall(function() func(unpack(args)) end, errhandler) end";
Script::Script(): Instance(&TYPE) { Script::Script(): Instance(&TYPE) {
source = "print(\"Hello, world!\")"; source = "print(\"Hello, world!\")";
} }
@ -27,6 +30,7 @@ void Script::Run() {
std::shared_ptr<ScriptContext> scriptContext = dataModel().value()->GetService<ScriptContext>(); std::shared_ptr<ScriptContext> scriptContext = dataModel().value()->GetService<ScriptContext>();
lua_State* L = scriptContext->state; lua_State* L = scriptContext->state;
int top = lua_gettop(L);
// Create thread // Create thread
this->thread = lua_newthread(L); this->thread = lua_newthread(L);
@ -54,13 +58,28 @@ void Script::Run() {
lua_pop(Lt, 1); // _G lua_pop(Lt, 1); // _G
// Load source and push onto thread stack as upvalue for wrapper closure // Push wrapper as thread function
luaL_loadbuffer(Lt, source.c_str(), source.size(), this->GetFullName().c_str()); luaL_loadbuffer(Lt, WRAPPER_SRC, strlen(WRAPPER_SRC), "=PCALL_WRAPPER");
lua_pushcclosure(Lt, script_wrapper, 1);
// Load source code and push onto thread as upvalue for wrapper
int status = luaL_loadbuffer(Lt, source.c_str(), source.size(), this->GetFullName().c_str());
if (status != LUA_OK) {
// Failed to parse/load chunk
Logger::error(lua_tostring(Lt, -1));
lua_settop(L, top);
return;
}
// Push our error handler and then generate the wrapped function
lua_pushcfunction(Lt, script_errhandler);
lua_call(Lt, 2, 1);
// Resume the thread
lua_resume(Lt, 0); lua_resume(Lt, 0);
lua_pop(L, 1); // Pop the thread lua_pop(L, 1); // Pop the thread
lua_settop(L, top);
} }
void Script::Stop() { void Script::Stop() {
@ -96,13 +115,6 @@ int script_delay(lua_State* L) {
return 0; return 0;
} }
int script_wrapper(lua_State* L) {
lua_pushcfunction(L, script_errhandler);
lua_pushvalue(L, lua_upvalueindex(1));
lua_pcall(L, 0, 0, -2);
return 0;
}
int script_errhandler(lua_State* L) { int script_errhandler(lua_State* L) {
std::string errorMessage = lua_tostring(L, -1); std::string errorMessage = lua_tostring(L, -1);
Logger::error(errorMessage); Logger::error(errorMessage);
@ -115,8 +127,9 @@ int script_errhandler(lua_State* L) {
int stack = 1; int stack = 1;
while (lua_getstack(L, stack++, &dbg)) { while (lua_getstack(L, stack++, &dbg)) {
lua_getinfo(L, "nlSu", &dbg); lua_getinfo(L, "nlSu", &dbg);
if (strcmp(dbg.what, "C") == 0) // Ignore C frames and internal wrappers
continue; // Ignore C frames if (strcmp(dbg.what, "C") == 0 || strcmp(dbg.source, "=PCALL_WRAPPER") == 0)
continue;
Logger::trace(dbg.source, dbg.currentline); Logger::trace(dbg.source, dbg.currentline);
} }

View file

@ -151,7 +151,8 @@ ScriptDocument::ScriptDocument(std::shared_ptr<Script> script, QWidget* parent):
scintilla->setCaretForegroundColor(palette().text().color()); scintilla->setCaretForegroundColor(palette().text().color());
scintilla->setFont(font); scintilla->setFont(font);
scintilla->setTabWidth(4); scintilla->setTabWidth(4);
scintilla->setEolMode(QsciScintilla::EolUnix); // LF endings
scintilla->setText(QString::fromStdString(script->source)); scintilla->setText(QString::fromStdString(script->source));
ObLuaLexer* lexer = new ObLuaLexer; ObLuaLexer* lexer = new ObLuaLexer;