]>
Dogcows Code - chaz/yoink/blob - src/Moof/Script.hh
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
10 **************************************************************************/
12 #ifndef _MOOF_SCRIPT_HH_
13 #define _MOOF_SCRIPT_HH_
17 * A thin wrapper over Lua. This is not meant as a complicated binding
18 * package between C++ and Lua. It does not try to make the boundary
19 * invisible. It does not hide the concept of the Lua stack, but rather
20 * provides that mechanism with a certain level of abstraction while also
21 * providing a cleaner, more consistent API.
30 #include <boost/bind.hpp>
31 #include <boost/function.hpp>
32 #include <boost/shared_ptr.hpp>
35 #include <Moof/Log.hh>
42 typedef boost::shared_ptr
<Script
> ScriptP
;
49 typedef boost::function
<int(Script
&)> Function
;
55 BOOLEAN
= LUA_TBOOLEAN
,
56 LIGHTUSERDATA
= LUA_TLIGHTUSERDATA
,
60 FUNCTION
= LUA_TFUNCTION
,
61 USERDATA
= LUA_TUSERDATA
,
69 RUNTIME_ERROR
= LUA_ERRRUN
,
70 SYNTAX_ERROR
= LUA_ERRSYNTAX
,
71 MEMORY_ERROR
= LUA_ERRMEM
,
72 HANDLER_ERROR
= LUA_ERRERR
,
73 FILE_ERROR
= LUA_ERRFILE
78 REGISTRY
= LUA_REGISTRYINDEX
,
79 ENVIRONMENT
= LUA_ENVIRONINDEX
,
80 GLOBALS
= LUA_GLOBALSINDEX
84 * This is the most prominent abstraction on top of the standard Lua
85 * API. A Slot object represents a value on the stack. More
86 * specifically, it represents a position on the stack. The
87 * distinction is only important when objects are moved around on the
88 * stack or if the Slot represents a negative index on the stack (the
89 * value of which will change as things are pushed onto and popped from
96 * You have direct access to the index of the value on the stack
104 * A default-constructed Slot is invalid until a valid Slot is
105 * assigned to it. The only method that should be called on such a
106 * Slot is isValid(), otherwise chaos may ensue. In this case, the
107 * Slot will be invalid even if index is manually changed to a
108 * valid index. You have to index the script itself to get a valid
111 Slot(lua_State
* s
= 0, int i
= 0) :
116 * A copied value presently points to the same value, except the
117 * real index is used. That means that if a value that refers to a
118 * frame referenced from the top of the stack will have its
119 * normalized index copied into the new value object.
122 Slot(const Slot
& copy
) :
123 index(copy
.getRealIndex()),
124 mState(copy
.mState
) {}
127 // check the type of the value
128 bool isBoolean() const
129 { return (bool)lua_isboolean(mState
, index
); }
130 bool isFunction() const
131 { return (bool)lua_isfunction(mState
, index
); }
133 { return (bool)lua_isnil(mState
, index
); }
135 { return (bool)lua_isnone(mState
, index
); }
137 { return mState
!= 0 && !isNone(); }
138 bool isNoneOrNil() const
139 { return (bool)lua_isnoneornil(mState
, index
); }
140 bool isNumber() const
141 { return (bool)lua_isnumber(mState
, index
); }
142 bool isString() const
143 { return (bool)lua_isstring(mState
, index
); }
145 { return (bool)lua_istable(mState
, index
); }
146 bool isThread() const
147 { return (bool)lua_isthread(mState
, index
); }
149 { return (bool)lua_isuserdata(mState
, index
); }
150 bool isLightData() const
151 { return (bool)lua_islightuserdata(mState
, index
); }
154 * Check the value and throw an error if its the wrong type.
155 * There's a little caveat: This method never returns because it
156 * does a long jump. Consequently, constructed C++ objects which
157 * exist on the stack between the current frame and some lua
158 * function will not be destructed. That's not a problem for
159 * objects that only exist on the stack, but any objects that
160 * allocate memory on the heap (such as containers or strings) will
161 * leak. Therefore, you should only call this method after
162 * cleaning up such objects. The best thing to do for defining
163 * functions is to simply check all the parameters at the get-go
164 * before any C++ objects are even constructed.
167 void requireType(Type type
) const
169 if (type
!= getType())
171 luaL_typerror(mState
, index
, lua_typename(mState
, type
));
175 void throwError(const char* error
)
177 luaL_argerror(mState
, index
, error
);
181 Slot
& requireBoolean()
183 if (!isBoolean()) luaL_typerror(mState
, index
, "boolean");
186 Slot
& requireNumber()
188 if (!isNumber()) luaL_typerror(mState
, index
, "number");
191 Slot
& requireString()
193 if (!isString()) luaL_typerror(mState
, index
, "string");
198 if (!isTable()) luaL_typerror(mState
, index
, "table");
201 Slot
& requireFunction()
203 if (!isFunction()) luaL_typerror(mState
, index
, "function");
208 if (!isData()) luaL_typerror(mState
, index
, "data");
213 if (!isNil()) luaL_typerror(mState
, index
, "nil");
216 Slot
& requireThread()
218 if (!isThread()) luaL_typerror(mState
, index
, "thread");
224 * Get the type of the value.
229 return (Type
)lua_type(mState
, index
);
233 * Get the name of the type of the value as a string.
236 std::string
getTypeName() const
238 return std::string(luaL_typename(mState
, index
));
243 * Get the length of the value according to the definition given by
247 size_t getLength() const
249 return lua_objlen(mState
, index
);
252 int getRealIndex() const
254 if (index
< 0) return lua_gettop(mState
) + 1 + index
;
260 * Get a pointer value (for userdata, tables, threads, and
264 const void* getIdentifier() const
266 return lua_topointer(mState
, index
);
270 bool operator == (const Slot
& rhs
) const
272 return (bool)lua_equal(mState
, index
, rhs
.index
);
274 bool operator != (const Slot
& rhs
) const
276 return !(*this == rhs
);
278 bool operator < (const Slot
& rhs
) const
280 return (bool)lua_lessthan(mState
, index
, rhs
.index
);
282 bool operator <= (const Slot
& rhs
) const
284 return *this < rhs
|| *this == rhs
;
286 bool operator > (const Slot
& rhs
) const
288 return !(*this <= rhs
);
290 bool operator >= (const Slot
& rhs
) const
292 return !(*this < rhs
);
294 operator bool () const
296 return (bool)lua_toboolean(mState
, index
);
299 Slot
& operator = (const Slot
& rhs
)
308 * Convert the underlying value to a C++ type.
311 template <typename T
>
312 bool get(T
& value
) const
316 value
= (T
)lua_tointeger(mState
, index
);
322 bool get(float& value
) const
326 value
= (float)lua_tonumber(mState
, index
);
331 bool get(double& value
) const
335 value
= (double)lua_tonumber(mState
, index
);
341 bool get(bool& value
) const
345 value
= (bool)lua_toboolean(mState
, index
);
351 bool get(std::string
& value
) const
356 const char* str
= lua_tolstring(mState
, index
, &size
);
357 value
.assign(str
, size
);
363 template <typename T
>
364 bool get(std::vector
<T
>& array
) const
366 if (!isTable()) return false;
370 Slot
value(mState
, -1);
371 int realIndex
= getRealIndex();
374 for (int i
= 1; !done
; ++i
)
376 lua_rawgeti(mState
, realIndex
, i
);
379 if (value
.get(v
)) array
.push_back(v
);
388 template <typename T
>
389 bool get(std::map
<std::string
,T
>& dictionary
) const
391 if (!isTable()) return false;
395 Slot
key(mState
, -2);
396 Slot
value(mState
, -1);
397 int realIndex
= getRealIndex();
400 while (lua_next(mState
, realIndex
) != 0)
403 if (!key
.isNumber() && key
.get(k
))
406 if (value
.get(v
)) dictionary
[k
] = v
;
417 * Copy the value and push the copy to the stack.
420 void pushCopy() const
422 lua_pushvalue(mState
, index
);
426 * Replace this value with the value at the top of the stack.
429 void replaceWithTop()
431 lua_replace(mState
, index
);
436 lua_remove(mState
, index
);
440 * Inserts the top-most value on the stack at position index,
441 * shifting other values as needed.
446 lua_insert(mState
, index
);
450 void pushMetatable() const
452 lua_getmetatable(mState
, index
);
455 void pushField() const
457 lua_gettable(mState
, index
);
460 void pushField(const std::string
& name
) const
462 lua_getfield(mState
, index
, name
.c_str());
465 void pushField(size_t index
) const
467 lua_pushinteger(mState
, lua_Integer(index
));
490 static ScriptP
alloc()
492 return ScriptP(new Script
);
497 if (mState
) destroy();
498 mState
= luaL_newstate();
499 lua_pushlightuserdata(mState
, this);
500 lua_setfield(mState
, LUA_REGISTRYINDEX
, "Script_hh_Object");
504 void importStandardLibraries()
506 luaL_openlibs(mState
);
509 void importBaseLibrary()
511 lua_pushcfunction(mState
, luaopen_base
);
516 void importPackageLibrary()
518 lua_pushcfunction(mState
, luaopen_package
);
519 push(LUA_LOADLIBNAME
);
523 void importStringLibrary()
525 lua_pushcfunction(mState
, luaopen_string
);
526 push(LUA_STRLIBNAME
);
530 void importTableLibrary()
532 lua_pushcfunction(mState
, luaopen_table
);
533 push(LUA_TABLIBNAME
);
537 void importMathLibrary()
539 lua_pushcfunction(mState
, luaopen_math
);
540 push(LUA_MATHLIBNAME
);
544 void importIoLibrary()
546 lua_pushcfunction(mState
, luaopen_io
);
551 void importOsLibrary()
553 lua_pushcfunction(mState
, luaopen_os
);
558 void importDebugLibrary()
560 lua_pushcfunction(mState
, luaopen_debug
);
566 void importFunction(const std::string
& name
, const Function
& function
)
569 lua_setglobal(mState
, name
.c_str());
573 Result
doString(const std::string
& commands
)
575 return (Result
)luaL_dostring(mState
, commands
.c_str());
578 Result
doFile(const std::string
& file
)
580 return (Result
)luaL_dofile(mState
, file
.c_str());
585 * Thread-handling methods.
588 Script
pushNewThread()
590 return Script(mState
);
595 lua_pushthread(mState
);
598 Result
resume(int nargs
)
600 return (Result
)lua_resume(mState
, nargs
);
603 Result
getStatus() const
605 return (Result
)lua_status(mState
);
608 int yield(int results
)
610 return lua_yield(mState
, results
);
613 bool isMainThread() const
615 return mIsMainThread
;
620 * Throw an error with the value at the top of the stack. This method
621 * never returns because it does a long jump. Consequently,
622 * constructed C++ objects which exist on the stack between the
623 * current frame and some lua function will not be destructed. That's
624 * not a problem for objects that only exist on the stack, but any
625 * objects that allocate memory on the heap (such as containers or
626 * strings) will leak. Therefore, you should only call this method
627 * after cleaning up such objects.
637 * Get significant values.
640 Slot
getGlobalTable() const
642 return Slot(mState
, GLOBALS
);
645 Slot
getRegistryTable() const
647 return Slot(mState
, REGISTRY
);
650 Slot
getEnvironmentTable() const
652 return Slot(mState
, ENVIRONMENT
);
657 return Slot(mState
, lua_gettop(mState
));
661 * Get the size of the stack; this is also the index of the top-most
667 return lua_gettop(mState
);
670 void setSize(int size
)
672 lua_settop(mState
, size
);
682 * Makes sure there is at least extra more places on the stack.
683 * Returns false if space couldn't be created. Just like with the
684 * regular Lua API, you are responsible to make sure the stack is big
685 * enough to hold whatever you want to push on it. This is usually
686 * only an issue if you're pushing stuff in a loop.
689 bool checkStack(int extra
)
691 return (bool)lua_checkstack(mState
, extra
);
696 * Concatenates the top-most n slots on the stack.
699 void concat(int n
= 2)
701 lua_concat(mState
, n
);
706 * Push some values onto the stack.
709 template <typename T
>
712 lua_pushinteger(mState
, lua_Integer(value
));
715 void push(bool value
)
717 lua_pushboolean(mState
, int(value
));
720 void push(float value
)
722 lua_pushnumber(mState
, (lua_Number
)value
);
724 void push(double value
)
726 lua_pushnumber(mState
, (lua_Number
)value
);
729 void push(const std::string
& value
)
731 lua_pushlstring(mState
, value
.c_str(), value
.length());
733 void push(const char* value
)
735 lua_pushstring(mState
, value
);
737 void push(const char* value
, size_t length
)
739 lua_pushlstring(mState
, value
, length
);
742 void push(const Function
& function
)
744 mFunctions
.push_back(function
);
746 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
747 lua_pushcclosure(mState
, dispatchCall
, 1);
750 void push(void* data
)
752 lua_pushlightuserdata(mState
, data
);
760 void pushFromThread(Script
& thread
, int n
)
762 lua_xmove(thread
.mState
, mState
, n
);
765 Result
pushCode(const std::string
& filename
)
767 return (Result
)luaL_loadfile(mState
, filename
.c_str());
770 Result
pushCode(const std::string
& name
, const char* buffer
,
773 return (Result
)luaL_loadbuffer(mState
, buffer
, size
, name
.c_str());
776 void* pushNewData(size_t size
)
778 return lua_newuserdata(mState
, size
);
783 lua_newtable(mState
);
788 * Call a function on the stack. The correct procedure is to push a
789 * function onto the stack followed by nargs arguments. This method
790 * will pop them off upon return, leaving up to nresults return values
791 * (default is any number of return values, depending on the callee).
794 Result
call(int nargs
= 0, int nresults
= LUA_MULTRET
)
796 return (Result
)lua_pcall(mState
, nargs
, nresults
, 0);
801 * Pops n values from the top of the stack.
811 * Index into the stack to get a Slot.
814 Slot
operator [] (int index
) const
816 return Slot(mState
, index
);
821 * Getting and setting fields of a table.
824 void pushField(const std::string
& field
, int index
= GLOBALS
) const
826 lua_getfield(mState
, index
, field
.c_str());
829 void set(const std::string
& field
, int index
= GLOBALS
)
831 lua_setfield(mState
, index
, field
.c_str());
836 * Control over the garbage collection process.
841 lua_gc(mState
, LUA_GCCOLLECT
, 0);
846 lua_gc(mState
, LUA_GCSTOP
, 0);
849 void restartCollector()
851 lua_gc(mState
, LUA_GCRESTART
, 0);
854 int getUsedMemory() const
857 return lua_gc(mState
, LUA_GCCOUNT
, 0);
860 void collectStep(int step
)
862 lua_gc(mState
, LUA_GCSTEP
, step
);
865 void tuneCollector(int pause
, int step
)
867 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
868 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
874 Script(lua_State
* state
) :
875 mState(lua_newthread(state
)),
876 mIsMainThread(false) {}
878 static int dispatchCall(lua_State
* state
)
880 const Function
* function
= (const Function
*)lua_touserdata(state
,
881 lua_upvalueindex(1));
883 lua_getfield(state
, LUA_REGISTRYINDEX
, "Script_hh_Object");
884 Script
* script
= (Script
*)lua_touserdata(state
, -1);
887 return (*function
)(*script
);
892 if (mIsMainThread
) lua_close(mState
);
897 std::list
<Function
> mFunctions
;
901 inline std::ostream
& operator << (std::ostream
& stream
,
902 const Script::Slot
& slot
)
910 else if (slot
.isBoolean())
912 if (slot
) stream
<< "true";
913 else stream
<< "false";
915 else if (slot
.isNil())
921 stream
<< slot
.getTypeName() << " (" << slot
.getIdentifier() << ")";
930 #endif // _MOOF_SCRIPT_HH_
This page took 0.077552 seconds and 4 git commands to generate.