Created
May 16, 2011 23:47
-
-
Save seikichi/975612 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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