1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #ifndef RZ_LUA_HELPER_H
18 #define RZ_LUA_HELPER_H
21 #include "nel/misc/types_nl.h"
22 #include "nel/misc/smart_ptr.h"
32 // ***************************************************************************
33 /** Helper class to see if a stack is restored at its initial size (or with n return results).
34 * Check that the stack size remains unchanged when the object goes out of scope
36 class CLuaStackChecker
39 CLuaStackChecker(CLuaState
*state
, int numWantedResults
= 0);
41 /** Increment exception context counter
42 * When an exception is thrown, lua stack checker do any assert bu will
43 * rather restore the lua stack at its original size, and will
44 * let the exception a chance to propagate
46 static void incrementExceptionContextCounter();
47 static void decrementExceptionContextCounter();
52 static uint _ExceptionContextCounter
;
56 // **************************************************************************
57 /** Helper class to restore the lua stack to the desired size when this object goes out of scope
59 class CLuaStackRestorer
62 CLuaStackRestorer(CLuaState
*state
, int finalSize
);
73 class ELuaError
: public NLMISC::Exception
76 ELuaError() { CLuaStackChecker::incrementExceptionContextCounter(); }
77 virtual ~ELuaError() throw() { CLuaStackChecker::decrementExceptionContextCounter(); }
78 ELuaError(const std::string
&reason
) : Exception(reason
) { CLuaStackChecker::incrementExceptionContextCounter(); }
79 // what(), plus append the Reason
80 virtual std::string
luaWhat() const throw() {return NLMISC::toString("LUAError: %s", what());}
83 // A parse error occurred
84 class ELuaParseError
: public ELuaError
88 ELuaParseError(const std::string
&reason
) : ELuaError(reason
) {}
89 virtual ~ELuaParseError() throw() { }
90 // what(), plus append the Reason
91 virtual std::string
luaWhat() const throw() {return NLMISC::toString("ELuaParseError: %s", what());}
94 /** Exception thrown when something went wrong inside a wrapped function called by lua
96 class ELuaWrappedFunctionException
: public ELuaError
99 ELuaWrappedFunctionException(CLuaState
*luaState
);
100 ELuaWrappedFunctionException(CLuaState
*luaState
, const std::string
&reason
);
101 ELuaWrappedFunctionException(CLuaState
*luaState
, const char *format
, ...);
102 virtual ~ELuaWrappedFunctionException() throw() { }
103 virtual const char *what() const throw() {return _Reason
.c_str();}
105 void init(CLuaState
*ls
, const std::string
&reason
);
110 // A execution error occurred
111 class ELuaExecuteError
: public ELuaError
114 ELuaExecuteError() {}
115 ELuaExecuteError(const std::string
&reason
) : ELuaError(reason
) {}
116 virtual ~ELuaExecuteError() throw() { }
117 // what(), plus append the Reason
118 virtual std::string
luaWhat() const throw() {return NLMISC::toString("ELuaExecuteError: %s", what());}
121 // A bad cast occurred when using lua_checkcast
122 class ELuaBadCast
: public ELuaError
126 ELuaBadCast(const std::string
&reason
) : ELuaError(reason
) {}
127 // what(), plus append the Reason
128 virtual std::string
luaWhat() const throw() {return NLMISC::toString("ELuaBadCast: %s", what());}
131 // Error when trying to indexate an object that is not a table
132 class ELuaNotATable
: public ELuaError
136 ELuaNotATable(const std::string
&reason
) : ELuaError(reason
) {}
137 // what(), plus append the Reason
138 virtual std::string
luaWhat() const throw() {return NLMISC::toString("ELuaNotATable: %s", what());}
142 // ***************************************************************************
143 // a function to be used with a CLuaState instance
144 typedef int (* TLuaWrappedFunction
) (CLuaState
&ls
);
147 // ***************************************************************************
148 /** C++ version of a lua state
150 class CLuaState
: public NLMISC::CRefCount
153 typedef NLMISC::CRefPtr
<CLuaState
> TRefPtr
;
155 // Create a new environement
160 /// \name Registering
162 // register a wrapped function
163 void registerFunc(const char *name
, TLuaWrappedFunction function
);
167 /// \name Script execution
170 /** Parse a script and push as a function in top of the LUA stack
171 * \throw ELuaParseError
172 * \param dbgSrc is a string for debug. Should be a filename (preceded with '@'), or a short script.
174 void loadScript(const std::string
&code
, const std::string
&dbgSrc
);
176 /** Execute a script from a string, possibly throwing an exception if there's a parse error
177 * \throw ELuaParseError, ELuaExecuteError
179 void executeScript(const std::string
&code
, int numRet
= 0);
181 /** Execute a script from a string. If an errors occurs it is printed in the log
182 * \return true if script execution was successful
184 bool executeScriptNoThrow(const std::string
&code
, int numRet
= 0);
186 /** Load a Script from a File (maybe in a BNP), and execute it
187 * \return false if file not found
188 * \throw ELuaParseError, ELuaExecuteError
190 bool executeFile(const std::string
&pathName
);
192 /** execute a very Small Script (a function call for instance)
193 * It is different from doString() in such there is a cache (where the key is the script itself)
194 * so that the second time this script is executed, there is no parsing
195 * Note: I experienced optim with about 10 times faster than a executeScript() on a simple "a= a+1;" script
196 * \throw ELuaParseError, ELuaExecuteError
198 void executeSmallScript(const std::string
&script
);
203 /// \name Stack Manipulation
205 // stack manipulation (indices start at 1)
206 void setTop(int index
); // set new size of stack
207 void clear() { setTop(0); }
209 bool empty() { return getTop() == 0; }
210 void pushValue(int index
); // copie nth element of stack to the top of the stack
211 void remove(int index
); // remove nth element of stack
212 void insert(int index
); // insert last element of the stack before the given position
213 void replace(int index
); // replace nth element of the stack with the top of the stack
214 void pop(int numElem
= 1); // remove n elements from the top of the stack
215 // test the type of an element in the stack
216 // return one of the following values :
225 // LUA_TLIGHTUSERDATA
226 int type(int index
= -1);
227 const char *getTypename(int type
);
228 bool isNil(int index
= -1);
229 bool isBoolean(int index
= -1);
230 bool isNumber(int index
= -1);
231 bool isString(int index
= -1);
232 bool isTable(int index
= -1);
233 bool isFunction(int index
= -1);
234 bool isCFunction(int index
= -1);
235 bool isUserData(int index
= -1);
236 bool isLightUserData(int index
= -1);
237 // converting then getting a value from the stack
238 bool toBoolean(int index
= -1);
239 lua_Number
toNumber(int index
= -1);
240 const char *toString(int index
= -1);
241 void toString(int index
, std::string
&str
); // convert to a std::string, with a NULL check.
242 size_t strlen(int index
= -1);
243 lua_CFunction
toCFunction(int index
= -1);
244 void *toUserData(int index
= -1);
245 const void *toPointer(int index
= -1);
246 /** Helper functions : get value of the wanted type in the top table after conversion
247 * A default value is used if the stack entry is NULL.
248 * If conversion fails then an exception is thrown (with optional msg)
250 bool getTableBooleanValue(const char *name
, bool defaultValue
= false);
251 double getTableNumberValue(const char *name
, double defaultValue
= 0);
252 const char *getTableStringValue(const char *name
, const char *defaultValue
= NULL
);
253 // pushing value onto the stack
254 void push(bool value
);
255 void push(lua_Number value
);
256 void push(const char *str
);
257 void push(const char *str
, int length
);
258 void push(const std::string
&str
);
260 void push(lua_CFunction f
);
261 void push(TLuaWrappedFunction function
);
262 void pushLightUserData(void *); // push a light user data (use newUserData to push a full userdata)
264 bool getMetaTable(int index
= -1);
265 bool setMetaTable(int index
= -1); // set the metatable at top of stack to the object at 'index' (usually -2), then pop the metatable
266 // even if asignment failed
268 bool equal(int index1
, int index2
);
269 bool rawEqual(int index1
, int index2
);
270 bool lessThan(int index1
, int index2
);
271 // concatenation of the n element at the top of the stack (using lua semantic)
272 void concat(int numElem
);
274 void newTable(); // create a new table at top of the stack
275 void getTable(int index
); // get value from a table at index 'index' (key is at top)
276 void rawGet(int index
);
277 void setTable(int index
); // set (key, value) from top of the stack into the given table
278 // both key and value are poped
279 void rawSet(int index
);
280 bool next(int index
); // table traversal
282 void *newUserData(uint size
);
283 // seting value by int index in a table
284 void rawSetI(int index
, int n
);
285 void rawGetI(int index
, int n
);
286 /** Calling functions (it's up to the caller to clear the results)
287 * The function should have been pushed on the stack
289 void call(int nargs
, int nresults
);
290 int pcall(int nargs
, int nresults
, int errfunc
= 0);
291 /** Helper : Execute a function by name. Lookup for the function is done in the table at the index 'funcTableIndex'
292 * the behaviour is the same than with call of pcall.
294 int pcallByName(const char *functionName
, int nargs
, int nresults
, int funcTableIndex
= LUA_GLOBALSINDEX
, int errfunc
= 0);
296 // push a C closure (pop n element from the stack and associate with the function)
297 void pushCClosure(lua_CFunction function
, int n
);
303 /** Retrieve pointer to a CLuaState environment from its lua_State pointer, or NULL
304 * if there no such environment
306 static CLuaState
*fromStatePointer(lua_State
*state
);
307 // Get state pointer. The state should not be closed (this object has ownership)
308 lua_State
*getStatePointer() const {return _State
;}
309 // check that an index is valid when accessing the stack
310 // an assertion is raised if the index is not valid
311 void checkIndex(int index
);
313 // registering C function to use with a lua state pointer
314 void registerFunc(const char *name
, lua_CFunction function
);
317 int getGCCount(); // get memory in use in KB
318 int getGCThreshold(); // get max memory in KB
319 void setGCThreshold(int kb
); // set max memory in KB (no-op with ref-counted version)
321 // handle garbage collector for ref-counted version of lua (no-op with standard version, in which case gc handling is automatic)
324 /** For Debug: get the Stack context of execution (filename / line)
325 * \param stackLevel: get the context of execution of the given stackLevel.
326 * 0 for the current function
327 * 1 for the function that called 0
329 * NB: if called from a C function called from LUA, remember that stackLevel 0 is the current function.
330 * Hence if you want to know what LUA context called you, pass stackLevel=1!
331 * \param ret string cleared if any error, else filled with formated FileName / LineNumber
333 void getStackContext(std::string
&ret
, uint stackLevel
);
336 // for debug : dump the current content of the stack (no recursion)
338 static void dumpStack(lua_State
*ls
);
339 void getStackAsString(std::string
&dest
);
345 // Small Script Cache
346 uint _SmallScriptPool
;
347 typedef std::map
<std::string
, uint
> TSmallScriptCache
;
348 TSmallScriptCache _SmallScriptCache
;
349 static const char * _NELSmallScriptTableName
;
352 // this object isn't intended to be copied
353 CLuaState(const CLuaState
&/* other */):NLMISC::CRefCount() { nlassert(0); }
354 CLuaState
&operator=(const CLuaState
&/* other */) { nlassert(0); return *this; }
356 void executeScriptInternal(const std::string
&code
, const std::string
&dbgSrc
, int numRet
= 0);
361 // Access to lua function
362 // one should not include lua.h directly because if a debugger is present, lua
363 // function pointer will be taken from a dynamic library.
367 //=============================================================================================
368 // include implementation
369 #define RZ_INCLUDE_LUA_HELPER_INLINE
370 #include "lua_helper_inline.h"
371 #undef RZ_INCLUDE_LUA_HELPER_INLINE