Skip to content

Instantly share code, notes, and snippets.

@seikichi
Created May 16, 2011 23:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seikichi/975612 to your computer and use it in GitHub Desktop.
Save seikichi/975612 to your computer and use it in GitHub Desktop.
#ifndef LUAHELPER_HPP
#define LUAHELPER_HPP
#include <iostream>
#include <memory>
#include <string>
#include <tuple>
#include <lua.hpp>
namespace kichi {
template<class... RetTypes> class LuaCaller;
template<class... RetTypes> class LuaFileExecuter;
class LuaHelper {
public:
LuaHelper(std::shared_ptr<lua_State>);
template<class... RetTypes>
LuaCaller<RetTypes...> CallFunc(const char*);
template<class... RetTypes>
LuaFileExecuter<RetTypes...> DoFile(const char*);
private:
const std::shared_ptr<lua_State> L;
lua_CFunction stack_trace_func;
};
template<class... RetTypes>
class LuaCaller {
public:
LuaCaller(std::shared_ptr<lua_State>,
const std::string&,
lua_CFunction);
template<class... Args>
std::tuple<bool, RetTypes...> operator()(Args... args);
private:
const std::shared_ptr<lua_State> L;
const std::string funcname;
const lua_CFunction stack_trace_func;
};
template<class... RetTypes>
class LuaFileExecuter {
public:
LuaFileExecuter(std::shared_ptr<lua_State>,
const std::string&,
lua_CFunction);
template<class... Args>
std::tuple<bool, RetTypes...> operator()(Args... args);
private:
const std::shared_ptr<lua_State> L;
const std::string filename;
const lua_CFunction stack_trace_func;
};
};
namespace {
void err(const std::string& location,
const std::string& message) {
std::cerr << location << " : " << message << std::endl;
}
void analyzeError(std::shared_ptr<lua_State> L,
int res_call,
const std::string& location) {
std::string reason;
switch (res_call) {
case LUA_ERRRUN: reason = "SCRIPT RUNTIME ERROR"; break;
case LUA_ERRSYNTAX: reason = "SCRIPT SYNTAX ERROR"; break;
case LUA_ERRMEM: reason = "SCRIPT MEMORY ERROR"; break;
case LUA_ERRFILE: reason = "SCRIPT FILE ERROR"; break;
default: break;
}
const char *mes = lua_tostring(L.get(), -1);
err(location, reason + " : " + mes);
}
template <unsigned int N>
struct getFromStack {
template<class... RetTypes>
static void apply(std::shared_ptr<lua_State> L,
std::tuple<bool, RetTypes...>& t) {
getLuaValue(L, -(sizeof...(RetTypes))+N-1, std::get<N>(t));
getFromStack<N-1>::apply(L, t);
}
};
template<>
struct getFromStack<0> {
template<class... RetTypes>
static void apply(std::shared_ptr<lua_State>,
std::tuple<bool, RetTypes...>&) {
return;
}
};
template<class... RetTypes>
void getLuaValue(std::shared_ptr<lua_State> L, int index, bool& val) {
if (!lua_isboolean(L.get(), index)) {
std::cerr << "TypeError(Lua->C++)" << std::endl;
}
val = lua_toboolean(L.get(), index);
}
template<class... RetTypes>
void getLuaValue(std::shared_ptr<lua_State> L, int index, int& val) {
if (!lua_isnumber(L.get(), index)) {
std::cerr << "TypeError(Lua->C++)" << std::endl;
}
val = static_cast<int>(lua_tonumber(L.get(), index));
}
template<class... RetTypes>
void getLuaValue(std::shared_ptr<lua_State> L, int index, float& val) {
if (!lua_isnumber(L.get(), index)) {
std::cerr << "TypeError(Lua->C++)" << std::endl;
}
val = static_cast<float>(lua_tonumber(L.get(), index));
}
template<class... RetTypes>
void getLuaValue(std::shared_ptr<lua_State> L, int index, double& val) {
if (!lua_isnumber(L.get(), index)) {
std::cerr << "TypeError(Lua->C++)" << std::endl;
}
val = lua_tonumber(L.get(), index);
}
template<class... RetTypes>
void getLuaValue(std::shared_ptr<lua_State> L,
int index, std::string& val) {
if (!lua_isstring(L.get(), index)) {
std::cerr << "TypeError(Lua->C++)" << std::endl;
}
val = lua_tostring(L.get(), index);
}
void pushToStack(std::shared_ptr<lua_State>) { }
template<class... Args>
void pushToStack(std::shared_ptr<lua_State> L, bool next, Args... rest) {
lua_pushboolean(L.get(), next);
pushToStack(L, rest...);
}
template<class... Args>
void pushToStack(std::shared_ptr<lua_State> L, int next, Args... rest) {
lua_pushnumber(L.get(), next);
pushToStack(L, rest...);
}
template<class... Args>
void pushToStack(std::shared_ptr<lua_State> L, float next, Args... rest) {
lua_pushnumber(L.get(), next);
pushToStack(L, rest...);
}
template<class... Args>
void pushToStack(std::shared_ptr<lua_State> L, double next, Args... rest) {
lua_pushnumber(L.get(), next);
pushToStack(L, rest...);
}
template<class... Args>
void pushToStack(std::shared_ptr<lua_State> L, const char* next, Args... rest) {
lua_pushstring(L.get(), next);
pushToStack(L, rest...);
}
template<class... Args>
void pushToStack(std::shared_ptr<lua_State> L,
const std::string& next, Args... rest) {
lua_pushstring(L.get(), next.c_str());
pushToStack(L, rest...);
}
};
namespace kichi {
LuaHelper::LuaHelper(std::shared_ptr<lua_State> L)
: L(L)
, stack_trace_func(NULL) {
lua_getglobal(L.get(), "debug");
if (!lua_isnil(L.get(), -1)) {
lua_getfield(L.get(), -1, "traceback");
stack_trace_func = lua_tocfunction(L.get(), -1);
}
}
template<class... RetTypes>
LuaCaller<RetTypes...> LuaHelper::CallFunc(const char* name) {
return LuaCaller<RetTypes...>(L, name, stack_trace_func);
}
template<class... RetTypes>
LuaFileExecuter<RetTypes...> LuaHelper::DoFile(const char* name) {
return LuaFileExecuter<RetTypes...>(L, name, stack_trace_func);
}
template<class... RetTypes>
LuaCaller<RetTypes...>::LuaCaller(std::shared_ptr<lua_State> L,
const std::string& funcname,
lua_CFunction stack_trace_func)
: L(L)
, funcname(funcname)
, stack_trace_func(stack_trace_func) {
}
template<class... RetTypes>
template<class... Args>
std::tuple<bool, RetTypes...>
LuaCaller<RetTypes...>::operator()(Args...args) {
std::tuple<bool, RetTypes...> ret;
std::get<0>(ret) = false;
int old_top = lua_gettop(L.get());
lua_pushcfunction(L.get(), stack_trace_func);
lua_getglobal(L.get(), funcname.c_str());
if (!lua_isfunction(L.get(), -1)) {
err("calling function<"
+ funcname
+ ">", "the function not found.");
return ret;
}
pushToStack(L, args...);
int res_call = lua_pcall(L.get(),
sizeof...(Args),
sizeof...(RetTypes),
old_top);
if (res_call != 0) {
analyzeError(L, res_call,
"calling function<"
+ funcname
+ ">");
lua_settop(L.get(), old_top);
return ret;
}
std::get<0>(ret) = true;
getFromStack<sizeof...(RetTypes)>::apply(L, ret);
lua_settop(L.get(), old_top);
return ret;
}
template<class... RetTypes>
LuaFileExecuter<RetTypes...>::LuaFileExecuter(std::shared_ptr<lua_State> L,
const std::string& filename,
lua_CFunction stack_trace_func)
: L(L)
, filename(filename)
, stack_trace_func(stack_trace_func) {
}
template<class... RetTypes>
template<class... Args>
std::tuple<bool, RetTypes...>
LuaFileExecuter<RetTypes...>::operator()(Args...args) {
std::tuple<bool, RetTypes...> ret;
std::get<0>(ret) = false;
int old_top = lua_gettop(L.get());
lua_pushcfunction(L.get(), stack_trace_func);
int res_load = luaL_loadfile(L.get(), filename.c_str());
if (res_load != 0) {
analyzeError(L, res_load, "loading file<" + filename + ">");
return ret;
}
pushToStack(L, args...);
int res_call = lua_pcall(L.get(),
sizeof...(Args),
sizeof...(RetTypes),
old_top+1);
if (res_call != 0) {
analyzeError(L, res_call, "execting file<" + filename + ">");
lua_settop(L.get(), old_top);
return ret;
}
std::get<0>(ret) = true;
getFromStack<sizeof...(RetTypes)>::apply(L, ret);
lua_settop(L.get(), old_top);
return ret;
}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment