Skip to content

Commit

Permalink
Extracted methods for calling Lua functions (#56)
Browse files Browse the repository at this point in the history
* Added a more generic method to call Lua functions

RunLuaFunction as static Tracker method, Overload with an out value

Added extra comments

* Created an even more generic internal version of RunLuaFunction

* Updated Tracker::ProviderCountForCode using new method

* Renamed methods to comply with contributing.md

* Fixed use of workingString and output variable
  • Loading branch information
JBarrows authored Nov 18, 2023
1 parent 944cc15 commit a50e7a4
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 49 deletions.
130 changes: 81 additions & 49 deletions src/core/tracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,84 @@ Tracker::~Tracker()
{
}

static int lua_error_handler(lua_State *L)
{
luaL_traceback(L, L, NULL, 1);
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L, 1);
return 1;
}

// This functaion can be used internally when the return type is uncertain.
// Use carefully; the return value(s) and error handler will still be on the lua stack
static int RunLuaFunction_inner(lua_State *L, const std::string name)
{
lua_pushcfunction(L, lua_error_handler);

// Trim excess characters (such as $) and extract function name
std::string workingString = name;
if (workingString[0] == '$') {
workingString = workingString.substr(1);
}
auto pos = workingString.find('|');
std::string funcName = workingString.substr(0, pos);

// Acquire the Lua function
int t = lua_getglobal(L, funcName.c_str());
if (t != LUA_TFUNCTION) {
fprintf(stderr, "Missing Lua function for %s\n", name.c_str());
lua_pop(L, 2); // non-function variable or nil, lua_error_handler
return -1;
}

// Parse arguments, if any
int argc = 0;
if (pos < std::string::npos) {
std::string::size_type next;
while ((next = workingString.find('|', pos+1)) != std::string::npos) {
lua_pushstring(L, workingString.substr(pos+1, next-pos-1).c_str());
++argc;
pos = next;
}
// Get the last arg
lua_pushstring(L, workingString.substr(pos+1).c_str());
++argc;
}

return lua_pcall(L, argc, 1, -argc-2);
}

/// Attempts to run a lua function by name and return an integer value
int Tracker::runLuaFunction(lua_State *L, const std::string name)
{
int out = 0;
auto callStatus = runLuaFunction(L, name, out);
if (callStatus == LUA_OK)
return out;
else
return 0;
}

int Tracker::runLuaFunction(lua_State* L, const std::string name, int &out)
{
int callStatus = RunLuaFunction_inner(L, name);
if (callStatus != LUA_OK) {
auto err = lua_tostring(L, -1);
fprintf(stderr, "Error running %s:\n%s\n", name.c_str(), err ? err : "Unknown error");
lua_pop(L, 2); // error object, lua_error_handler
return callStatus;
}

// This version of the function is set to accept a number if possible
int isnum = 0;
out = lua_tonumberx(L, -1, &isnum); // || (lua_isboolean(L, -1) && lua_toboolean(L, -1));
if (!isnum && lua_isboolean(L, -1) && lua_toboolean(L, -1))
out = 1;
lua_pop(L, 2); // result, lua_error_handler

return callStatus;
}

bool Tracker::AddItems(const std::string& file) {
printf("Loading items from \"%s\"...\n", file.c_str());
std::string s;
Expand Down Expand Up @@ -281,14 +359,6 @@ bool Tracker::AddLayouts(const std::string& file) {
return false;
}

static int lua_error_handler(lua_State *L)
{
luaL_traceback(L, L, NULL, 1);
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L, 1);
return 1;
}

int Tracker::ProviderCountForCode(const std::string& code)
{
// cache this, because inefficient use can make the Lua script hang
Expand All @@ -297,47 +367,9 @@ int Tracker::ProviderCountForCode(const std::string& code)
return it->second;
// "codes" starting with $ run Lua functions
if (!code.empty() && code[0] == '$') {
// TODO: use a helper to access Lua instead of having _L here
int args = 0;
auto pos = code.find('|');
int t;
lua_pushcfunction(_L, lua_error_handler);
if (pos == code.npos) {
t = lua_getglobal(_L, code.c_str()+1);
} else {
t = lua_getglobal(_L, code.substr(1, pos-1).c_str());
if (t == LUA_TFUNCTION) {
std::string::size_type next;
while ((next = code.find('|', pos+1)) != code.npos) {
lua_pushstring(_L, code.substr(pos+1, next-pos-1).c_str());
args++;
pos = next;
}
lua_pushstring(_L, code.substr(pos+1).c_str());
args++;
}
}
if (t != LUA_TFUNCTION) {
fprintf(stderr, "Missing Lua function for %s\n", code.c_str());
lua_pop(_L, 2); // non-function variable or nil, lua_error_handler
_providerCountCache[code] = 0;
return 0;
}
if (lua_pcall(_L, args, 1, -args-2) != LUA_OK) {
auto err = lua_tostring(_L, -1);
fprintf(stderr, "Error running %s:\n%s\n",
code.c_str(), err ? err : "Unknown error");
lua_pop(_L, 2); // error object, lua_error_handler
_providerCountCache[code] = 0;
return 0;
} else {
int isnum = 0;
int n = lua_tonumberx(_L, -1, &isnum);
if (!isnum && lua_isboolean(_L, -1) && lua_toboolean(_L, -1)) n = 1;
lua_pop(_L, 2); // result, lua_error_handler
_providerCountCache[code] = n;
return n;
}
int res = Tracker::runLuaFunction(_L, code);
_providerCountCache[code] = res;
return res;
}
// other codes count items
int res=0;
Expand Down
6 changes: 6 additions & 0 deletions src/core/tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ class Tracker final : public LuaInterface<Tracker> {
Tracker(Pack* pack, lua_State *L);
virtual ~Tracker();

// TODO: Use a helper to access Lua. This code doesn't belong in tracker
// Attempt to call a lua func and return an integer value
static int runLuaFunction(lua_State *L, const std::string name);
// Attempt to call a lua func. Returns 0 on success
// arg out is an output that gives the returned value from lua
static int runLuaFunction(lua_State *L, const std::string name, int &out);

struct Object final : public LuaType {
// NOTE: we could use (something like) std::variant<...> ?
Expand Down

0 comments on commit a50e7a4

Please sign in to comment.