131 lines
No EOL
3.4 KiB
C++
131 lines
No EOL
3.4 KiB
C++
#include "script.h"
|
|
#include "common.h"
|
|
#include "datatypes/variant.h"
|
|
#include "lauxlib.h"
|
|
#include "logger.h"
|
|
#include "objects/base/instance.h"
|
|
#include "objects/base/member.h"
|
|
#include "objects/service/script/scriptcontext.h"
|
|
#include "objects/service/workspace.h"
|
|
#include "objects/datamodel.h"
|
|
#include "datatypes/ref.h"
|
|
#include "luaapis.h" // IWYU pragma: keep
|
|
#include <algorithm>
|
|
#include <memory>
|
|
|
|
int script_errhandler(lua_State*);
|
|
|
|
Script::Script(): Instance(&TYPE) {
|
|
source = "print(\"Hello, world!\")";
|
|
}
|
|
|
|
Script::~Script() {
|
|
}
|
|
|
|
void Script::Run() {
|
|
std::shared_ptr<ScriptContext> scriptContext = dataModel()->GetService<ScriptContext>();
|
|
|
|
lua_State* L = scriptContext->state;
|
|
int top = lua_gettop(L);
|
|
|
|
// Create thread
|
|
this->thread = lua_newthread(L);
|
|
lua_State* Lt = thread;
|
|
|
|
// Push wrapper as thread function
|
|
lua_getfield(Lt, LUA_REGISTRYINDEX, "LuaPCallWrapper");
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Initialize script globals
|
|
scriptContext->NewEnvironment(Lt); // Pushes envtable, metatable
|
|
|
|
// Set script in metatable source
|
|
InstanceRef(shared_from_this()).PushLuaValue(Lt);
|
|
lua_setfield(Lt, -2, "source");
|
|
|
|
lua_pop(Lt, 1); // Pop metatable
|
|
|
|
// Set script in environment
|
|
InstanceRef(shared_from_this()).PushLuaValue(Lt);
|
|
lua_setfield(Lt, -2, "script");
|
|
|
|
lua_setfenv(Lt, -2); // Set env of loaded function
|
|
|
|
// 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_pop(L, 1); // Pop the thread
|
|
lua_settop(L, top);
|
|
}
|
|
|
|
void Script::Stop() {
|
|
// TODO:
|
|
}
|
|
|
|
static std::shared_ptr<Script> getfsource(lua_State* L, lua_Debug* dbg) {
|
|
int top = lua_gettop(L);
|
|
|
|
lua_getinfo(L, "f", dbg);
|
|
lua_getfenv(L, -1); // Get fenv of stack pos
|
|
if (lua_isnil(L, -1)) { // No env could be found
|
|
lua_settop(L, top);
|
|
return nullptr;
|
|
}
|
|
|
|
// Get source from metatable
|
|
lua_getmetatable(L, -1);
|
|
lua_getfield(L, -1, "source");
|
|
|
|
auto result = InstanceRef::FromLuaValue(L, -1);
|
|
if (!result) {
|
|
lua_settop(L, top);
|
|
return nullptr;
|
|
}
|
|
|
|
lua_settop(L, top);
|
|
|
|
std::shared_ptr<Instance> ref = result.expect().get<InstanceRef>();
|
|
if (!ref->IsA<Script>()) return nullptr;
|
|
|
|
return ref->CastTo<Script>().expect();
|
|
}
|
|
|
|
int script_errhandler(lua_State* L) {
|
|
std::string errorMessage = lua_tostring(L, -1);
|
|
Logger::error(errorMessage);
|
|
|
|
// Traceback
|
|
|
|
Logger::trace("Stack start");
|
|
|
|
lua_Debug dbg;
|
|
int stack = 1;
|
|
while (lua_getstack(L, stack++, &dbg)) {
|
|
lua_getinfo(L, "nlSu", &dbg);
|
|
// Ignore C frames and internal wrappers
|
|
if (strcmp(dbg.what, "C") == 0 || strcmp(dbg.source, "=PCALL_WRAPPER") == 0)
|
|
continue;
|
|
|
|
// Find script source
|
|
std::shared_ptr<Script> source = getfsource(L, &dbg);
|
|
|
|
Logger::scriptLogf("'%s', Line %d", Logger::LogLevel::TRACE, {source, dbg.currentline}, dbg.source, dbg.currentline);
|
|
}
|
|
|
|
Logger::trace("Stack end");
|
|
|
|
return 0;
|
|
} |