/* * Copyright (c) 2010-2013 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef LUAINTERFACE_H #define LUAINTERFACE_H #include "declarations.h" struct lua_State; typedef int (*LuaCFunction) (lua_State *L); /// Class that manages LUA stuff class LuaInterface { public: LuaInterface(); ~LuaInterface(); void init(); void terminate(); /// Register core script functions void registerFunctions(); // functions that will register all script stuff in lua global environment void registerSingletonClass(const std::string& className); void registerClass(const std::string& className, const std::string& baseClass = "LuaObject"); void registerClassStaticFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function); void registerClassMemberFunction(const std::string& className, const std::string& functionName, const LuaCppFunction& function); void registerClassMemberField(const std::string& className, const std::string& field, const LuaCppFunction& getFunction, const LuaCppFunction& setFunction); void registerGlobalFunction(const std::string& functionName, const LuaCppFunction& function); // register shortcuts using templates template void registerClass() { registerClass(stdext::demangle_type(), stdext::demangle_type()); } template void registerClassStaticFunction(const std::string& functionName, const LuaCppFunction& function) { registerClassStaticFunction(stdext::demangle_type(), functionName, function); } template void registerClassMemberFunction(const std::string& functionName, const LuaCppFunction& function) { registerClassMemberFunction(stdext::demangle_type(), functionName, function); } template void registerClassMemberField(const std::string& field, const LuaCppFunction& getFunction, const LuaCppFunction& setFunction) { registerClassMemberField(stdext::demangle_type(), field, getFunction, setFunction); } // methods for binding functions template void bindSingletonFunction(const std::string& functionName, F C::*function, C *instance); template void bindSingletonFunction(const std::string& className, const std::string& functionName, F C::*function, C *instance); template void bindClassStaticFunction(const std::string& functionName, const F& function); template void bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function); template void bindClassMemberFunction(const std::string& functionName, F FC::*function); template void bindClassMemberFunction(const std::string& className, const std::string& functionName, F FC::*function); template void bindClassMemberField(const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction); template void bindClassMemberField(const std::string& className, const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction); template void bindClassMemberGetField(const std::string& fieldName, F FC::*getFunction); template void bindClassMemberGetField(const std::string& className, const std::string& fieldName, F FC::*getFunction); template void bindClassMemberSetField(const std::string& fieldName, F FC::*setFunction); template void bindClassMemberSetField(const std::string& className, const std::string& fieldName, F FC::*setFunction); template void bindGlobalFunction(const std::string& functionName, const F& function); private: /// Metamethod that will retrieve fields values (that include functions) from the object when using '.' or ':' static int luaObjectGetEvent(LuaInterface* lua); /// Metamethod that is called when setting a field of the object by using the keyword '=' static int luaObjectSetEvent(LuaInterface* lua); /// Metamethod that will check equality of objects by using the keyword '==' static int luaObjectEqualEvent(LuaInterface* lua); /// Metamethod that is called every two lua garbage collections /// for any LuaObject that have no references left in lua environment /// anymore, thus this creates the possibility of holding an object /// existence by lua until it got no references left static int luaObjectCollectEvent(LuaInterface* lua); public: /// Loads and runs a script, any errors are printed to stdout and returns false bool safeRunScript(const std::string& fileName); /// Loads and runs a script /// @exception LuaException is thrown on any lua error void runScript(const std::string& fileName); /// Loads and runs the script from buffer /// @exception LuaException is thrown on any lua error void runBuffer(const std::string& buffer, const std::string& source); /// Loads a script file and pushes it's main function onto stack, /// @exception LuaException is thrown on any lua error void loadScript(const std::string& fileName); /// Loads a function from buffer and pushes it onto stack, /// @exception LuaException is thrown on any lua error void loadFunction(const std::string& buffer, const std::string& source = "lua function buffer"); /// Evaluates a lua expression and pushes the result value onto the stack /// @exception LuaException is thrown on any lua error void evaluateExpression(const std::string& expression, const std::string& source = "lua expression"); /// Generates a traceback message for the current call stack /// @param errorMessage is an additional error message /// @param level is the level of the traceback, 0 means trace from calling function /// @return the generated traceback message std::string traceback(const std::string& errorMessage = "", int level = 0); /// Throw a lua error if inside a lua call or generates an C++ stdext::exception /// @param message is the error message wich will be displayed before the error traceback /// @exception stdext::exception is thrown with the error message if the error is not captured by lua void throwError(const std::string& message); /// Searches for the source of the current running function std::string getCurrentSourcePath(int level = 0); /// @brief Calls a function /// The function and arguments must be on top of the stack in order, /// results are pushed onto the stack. /// @exception LuaException is thrown on any lua error /// @return number of results int safeCall(int numArgs = 0, int numRets = -1); /// Same as safeCall but catches exceptions and can also calls a table of functions, /// if any error occurs it will be reported to stdout and returns 0 results /// @param requestedResults is the number of results requested to pushes onto the stack, /// if supplied, the call will always pushes that number of results, even if it fails int signalCall(int numArgs = 0, int numRets = -1); /// @brief Creates a new environment table /// The new environment table is redirected to the global environment (aka _G), /// this allows to access global variables from _G in the new environment and /// prevents new variables in this new environment to be set on the global environment int newSandboxEnv(); template int luaCallGlobalField(const std::string& global, const std::string& field, const T&... args); template void callGlobalField(const std::string& global, const std::string& field, const T&... args); template R callGlobalField(const std::string& global, const std::string& field, const T&... args); bool isInCppCallback() { return m_cppCallbackDepth != 0; } private: /// Load scripts requested by lua 'require' static int luaScriptLoader(lua_State* L); /// Run scripts requested by lua 'dofile' static int lua_dofile(lua_State* L); /// Run scripts requested by lua 'dofiles' static int lua_dofiles(lua_State* L); /// Run scripts requested by lua 'dofiles' static int lua_loadfile(lua_State* L); /// Handle lua errors from safeCall static int luaErrorHandler(lua_State* L); /// Handle bound cpp functions callbacks static int luaCppFunctionCallback(lua_State* L); /// Collect bound cpp function pointers static int luaCollectCppFunction(lua_State* L); public: void createLuaState(); void closeLuaState(); void collectGarbage(); void loadBuffer(const std::string& buffer, const std::string& source); int pcall(int numArgs = 0, int numRets = 0, int errorFuncIndex = 0); void call(int numArgs = 0, int numRets = 0); void error(); int ref(); int weakRef(); void unref(int ref); void useValue() { pushValue(); ref(); } const char* typeName(int index = -1); std::string functionSourcePath(); void insert(int index); void remove(int index); bool next(int index = -2); void checkStack() { assert(getTop() <= 20); } void getStackFunction(int level = 0); void getRef(int ref); void getWeakRef(int weakRef); int getGlobalEnvironment() { return m_globalEnv; } void setGlobalEnvironment(int env); void resetGlobalEnvironment() { setGlobalEnvironment(m_globalEnv); } void setMetatable(int index = -2); void getMetatable(int index = -1); void getField(const char* key, int index = -1); void getField(const std::string& key, int index = -1) { return getField(key.c_str(), index); } void setField(const char* key, int index = -2); void setField(const std::string& key, int index = -2) { return setField(key.c_str(), index); } void getTable(int index = -2); void setTable(int index = -3); void clearTable(int index = -1); void getEnv(int index = -1); void setEnv(int index = -2); void getGlobal(const std::string& key); void getGlobalField(const std::string& globalKey, const std::string& fieldKey); void setGlobal(const std::string& key); void rawGet(int index = -1); void rawGeti(int n, int index = -1); void rawSet(int index = -3); void rawSeti(int n, int index = -2); void newTable(); void* newUserdata(int size); void pop(int n = 1); long popInteger(); double popNumber(); bool popBoolean(); std::string popString(); void* popUserdata(); void* popUpvalueUserdata(); LuaObjectPtr popObject(); void pushNil(); void pushInteger(long v); void pushNumber(double v); void pushBoolean(bool v); void pushCString(const char* v); void pushString(const std::string& v); void pushLightUserdata(void* p); void pushThread(); void pushValue(int index = -1); void pushObject(const LuaObjectPtr& obj); void pushCFunction(LuaCFunction func, int n = 0); void pushCppFunction(const LuaCppFunction& func); bool isNil(int index = -1); bool isBoolean(int index = -1); bool isNumber(int index = -1); bool isString(int index = -1); bool isTable(int index = -1); bool isFunction(int index = -1); bool isCFunction(int index = -1); bool isLuaFunction(int index = -1) { return (isFunction() && !isCFunction()); } bool isUserdata(int index = -1); bool toBoolean(int index = -1); int toInteger(int index = -1); double toNumber(int index = -1); const char* toCString(int index = -1); std::string toString(int index = -1); void* toUserdata(int index = -1); LuaObjectPtr toObject(int index = -1); int getTop(); int stackSize() { return getTop(); } void clearStack() { pop(stackSize()); } bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); } void loadFiles(std::string directory, bool recursive = false, std::string contains = ""); /// Pushes any type onto the stack template int polymorphicPush(const T& v, const Args&... args); int polymorphicPush() { return 0; } /// Casts a value from stack to any type /// @exception LuaBadValueCastException thrown if the cast fails template T castValue(int index = -1); /// Same as castValue but also pops template T polymorphicPop() { T v = castValue(); pop(1); return v; } private: lua_State* L; int m_weakTableRef; int m_cppCallbackDepth; int m_totalObjRefs; int m_totalFuncRefs; int m_globalEnv; }; extern LuaInterface g_lua; // must be included after, because they need LuaInterface fully declared #include "luaexception.h" #include "luabinder.h" #include "luavaluecasts.h" template int LuaInterface::polymorphicPush(const T& v, const Args&... args) { int r = push_luavalue(v); return r + polymorphicPush(args...); } // next templates must be defined after above includes template void LuaInterface::bindSingletonFunction(const std::string& functionName, F C::*function, C *instance) { registerClassStaticFunction(functionName, luabinder::bind_singleton_mem_fun(function, instance)); } template void LuaInterface::bindSingletonFunction(const std::string& className, const std::string& functionName, F C::*function, C *instance) { registerClassStaticFunction(className, functionName, luabinder::bind_singleton_mem_fun(function, instance)); } template void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) { registerClassStaticFunction(functionName, luabinder::bind_fun(function)); } template void LuaInterface::bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function) { registerClassStaticFunction(className, functionName, luabinder::bind_fun(function)); } template void LuaInterface::bindClassMemberFunction(const std::string& functionName, F FC::*function) { registerClassMemberFunction(functionName, luabinder::bind_mem_fun(function)); } template void LuaInterface::bindClassMemberFunction(const std::string& className, const std::string& functionName, F FC::*function) { registerClassMemberFunction(className, functionName, luabinder::bind_mem_fun(function)); } template void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction) { registerClassMemberField(fieldName, luabinder::bind_mem_fun(getFunction), luabinder::bind_mem_fun(setFunction)); } template void LuaInterface::bindClassMemberField(const std::string& className, const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction) { registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), luabinder::bind_mem_fun(setFunction)); } template void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F FC::*getFunction) { registerClassMemberField(fieldName, luabinder::bind_mem_fun(getFunction), LuaCppFunction()); } template void LuaInterface::bindClassMemberGetField(const std::string& className, const std::string& fieldName, F FC::*getFunction) { registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), LuaCppFunction()); } template void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F FC::*setFunction) { registerClassMemberField(fieldName, LuaCppFunction(), luabinder::bind_mem_fun(setFunction)); } template void LuaInterface::bindClassMemberSetField(const std::string& className, const std::string& fieldName, F FC::*setFunction) { registerClassMemberField(className, fieldName, LuaCppFunction(), luabinder::bind_mem_fun(setFunction)); } template void LuaInterface::bindGlobalFunction(const std::string& functionName, const F& function) { registerGlobalFunction(functionName, luabinder::bind_fun(function)); } template T LuaInterface::castValue(int index) { T o; if(!luavalue_cast(index, o)) throw LuaBadValueCastException(typeName(index), stdext::demangle_type()); return o; } template int LuaInterface::luaCallGlobalField(const std::string& global, const std::string& field, const T&... args) { g_lua.getGlobalField(global, field); if(!g_lua.isNil()) { int numArgs = g_lua.polymorphicPush(args...); return g_lua.signalCall(numArgs); } else g_lua.pop(1); return 0; } template void LuaInterface::callGlobalField(const std::string& global, const std::string& field, const T&... args) { int rets = luaCallGlobalField(global, field, args...); if(rets > 0) pop(rets); } template R LuaInterface::callGlobalField(const std::string& global, const std::string& field, const T&... args) { R result; int rets = luaCallGlobalField(global, field, args...); if(rets > 0) { assert(rets == 1); result = g_lua.polymorphicPop(); } else result = R(); return result; } #endif