// // Created by koncord on 08.05.16. // #include <iostream> #include "LangLua.hpp" #include <Script/Script.hpp> #include <Script/Types.hpp> using namespace std; std::set<std::string> LangLua::packagePath; std::set<std::string> LangLua::packageCPath; void setLuaPath(lua_State* L, const char* path, bool cpath = false) { string field = cpath ? "cpath" : "path"; lua_getglobal(L, "package"); lua_getfield(L, -1, field.c_str()); std::string cur_path = lua_tostring(L, -1); cur_path.append(";"); cur_path.append(path); lua_pop(L, 1); lua_pushstring(L, cur_path.c_str()); lua_setfield(L, -2, field.c_str()); lua_pop(L, 1); } lib_t LangLua::GetInterface() { return reinterpret_cast<lib_t>(lua); } LangLua::LangLua(lua_State *lua) { this->lua = lua; } LangLua::LangLua() { lua = luaL_newstate(); luaL_openlibs(lua); // load all lua std libs std::string p, cp; for (auto& path : packagePath) p += path + ';'; for (auto& path : packageCPath) cp += path + ';'; setLuaPath(lua, p.c_str()); setLuaPath(lua, cp.c_str(), true); } LangLua::~LangLua() { } template<unsigned int I, unsigned int F> struct Lua_dispatch_ { template<typename R, typename... Args> inline static R Lua_dispatch(lua_State*&& lua, Args&&... args) noexcept { constexpr ScriptFunctionData const& F_ = ScriptFunctions::functions[F]; auto arg = luabridge::Stack<typename CharType<F_.func.types[I - 1]>::type>::get(lua, I); return Lua_dispatch_<I - 1, F>::template Lua_dispatch<R>( forward<lua_State*>(lua), arg, forward<Args>(args)...); } }; template<unsigned int F> struct Lua_dispatch_<0, F> { template<typename R, typename... Args> inline static R Lua_dispatch(lua_State*&&, Args&&... args) noexcept { constexpr ScriptFunctionData const& F_ = ScriptFunctions::functions[F]; return reinterpret_cast<FunctionEllipsis<R>>(F_.func.addr)(forward<Args>(args)...); } }; template<unsigned int I> static typename enable_if<ScriptFunctions::functions[I].func.ret == 'v', int>::type wrapper(lua_State* lua) noexcept { Lua_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template Lua_dispatch<void>(forward<lua_State*>(lua)); return 0; } template<unsigned int I> static typename enable_if<ScriptFunctions::functions[I].func.ret != 'v', int>::type wrapper(lua_State* lua) noexcept { auto ret = Lua_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template Lua_dispatch< typename CharType<ScriptFunctions::functions[I].func.ret>::type>(forward<lua_State*>(lua)); luabridge::Stack <typename CharType<ScriptFunctions::functions[I].func.ret>::type>::push (lua, ret); return 1; } template<unsigned int I> struct F_ { static constexpr LuaFuctionData F{ScriptFunctions::functions[I].name, wrapper<I>}; }; template<> struct F_<0> { static constexpr LuaFuctionData F{"CreateTimer", LangLua::CreateTimer}; }; template<> struct F_<1> { static constexpr LuaFuctionData F{"CreateTimerEx", LangLua::CreateTimerEx}; }; template<> struct F_<2> { static constexpr LuaFuctionData F{"MakePublic", LangLua::MakePublic}; }; template<> struct F_<3> { static constexpr LuaFuctionData F{"CallPublic", LangLua::CallPublic}; }; template<unsigned int I> struct C { constexpr C(LuaFuctionData *functions_) { functions_[I] = F_<I>::F; C<I - 1>::C(functions_); } }; template<> struct C<0> { constexpr C(LuaFuctionData *functions_) { functions_[0] = F_<0>::F; } }; template<size_t LastI> LuaFuctionData *functions() { static LuaFuctionData functions_[LastI]; C<LastI - 1>::C(functions_); static_assert( sizeof(functions_) / sizeof(functions_[0]) == sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]), "Not all functions have been mapped to Lua"); return functions_; } void LangLua::LoadProgram(const char *filename) { int err = 0; if ((err =luaL_loadfile(lua, filename)) != 0) throw runtime_error("Lua script " + string(filename) + " error (" + to_string(err) + "): \"" + string(lua_tostring(lua, -1)) + "\""); constexpr auto functions_n = sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]); LuaFuctionData *functions_ = functions<sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0])>(); luabridge::Namespace tes3mp = luabridge::getGlobalNamespace(lua).beginNamespace("tes3mp"); for (unsigned i = 0; i < functions_n; i++) tes3mp.addCFunction(functions_[i].name, functions_[i].func); tes3mp.endNamespace(); if ((err = lua_pcall(lua, 0, 0, 0)) != 0) // Run once script for load in memory. throw runtime_error("Lua script " + string(filename) + " error (" + to_string(err) + "): \"" + string(lua_tostring(lua, -1)) + "\""); } int LangLua::FreeProgram() { lua_close(lua); return 0; } bool LangLua::IsCallbackPresent(const char *name) { return luabridge::getGlobal(lua, name).isFunction(); } boost::any LangLua::Call(const char *name, const char *argl, int buf, ...) { va_list vargs; va_start(vargs, buf); int n_args = (int)(strlen(argl)); lua_getglobal(lua, name); for (int index = 0; index < n_args; index++) { switch (argl[index]) { case 'i': luabridge::Stack<unsigned int>::push(lua,va_arg(vargs, unsigned int)); break; case 'q': luabridge::Stack<signed int>::push(lua,va_arg(vargs, signed int)); break; case 'l': luabridge::Stack<unsigned long long>::push(lua, va_arg(vargs, unsigned long long)); break; case 'w': luabridge::Stack<signed long long>::push(lua, va_arg(vargs, signed long long)); break; case 'f': luabridge::Stack<double>::push(lua, va_arg(vargs, double)); break; case 'p': luabridge::Stack<void*>::push(lua, va_arg(vargs, void*)); break; case 's': luabridge::Stack<const char*>::push(lua, va_arg(vargs, const char*)); break; case 'b': luabridge::Stack<bool>::push(lua, (bool) va_arg(vargs, int)); break; default: throw runtime_error("C++ call: Unknown argument identifier " + argl[index]); } } va_end(vargs); luabridge::LuaException::pcall(lua, n_args, 1); return boost::any(luabridge::LuaRef::fromStack(lua, -1)); } boost::any LangLua::Call(const char *name, const char *argl, const std::vector<boost::any> &args) { int n_args = (int)(strlen(argl)); lua_getglobal(lua, name); for (int index = 0; index < n_args; index++) { switch (argl[index]) { case 'i': luabridge::Stack<unsigned int>::push(lua, boost::any_cast<unsigned int>(args.at(index))); break; case 'q': luabridge::Stack<signed int>::push(lua, boost::any_cast<signed int>(args.at(index))); break; case 'l': luabridge::Stack<unsigned long long>::push(lua, boost::any_cast<unsigned long long>(args.at(index))); break; case 'w': luabridge::Stack<signed long long>::push(lua, boost::any_cast<signed long long>(args.at(index))); break; case 'f': luabridge::Stack<double>::push(lua, boost::any_cast<double>(args.at(index))); break; case 'p': luabridge::Stack<void *>::push(lua, boost::any_cast<void *>(args.at(index))); break; case 's': luabridge::Stack<const char *>::push(lua, boost::any_cast<const char *>(args.at(index))); break; case 'b': luabridge::Stack<bool>::push(lua, boost::any_cast<int>(args.at(index))); break; default: throw runtime_error("Lua call: Unknown argument identifier " + argl[index]); } } luabridge::LuaException::pcall(lua, n_args, 1); return boost::any(luabridge::LuaRef::fromStack(lua, -1)); } void LangLua::AddPackagePath(const std::string& path) { packagePath.emplace(path); } void LangLua::AddPackageCPath(const std::string& path) { packageCPath.emplace(path); }