]>
Dogcows Code - chaz/yoink/blob - 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 is not meant to obscure the division
19 * between C++ and Lua but rather to clarify it and make it more
20 * manageable. It does not hide the concept of the Lua stack, but rather
21 * provides that mechanism with a certain level of abstraction while also
22 * providing a cleaner, more consistent API.
31 #include <boost/bind.hpp>
32 #include <boost/function.hpp>
33 #include <boost/shared_ptr.hpp>
41 typedef boost::shared_ptr
<Script
> ScriptP
;
48 typedef boost::function
<int(Script
&)> Function
;
54 BOOLEAN
= LUA_TBOOLEAN
,
55 LIGHTUSERDATA
= LUA_TLIGHTUSERDATA
,
59 FUNCTION
= LUA_TFUNCTION
,
60 USERDATA
= LUA_TUSERDATA
,
68 RUNTIME_ERROR
= LUA_ERRRUN
,
69 SYNTAX_ERROR
= LUA_ERRSYNTAX
,
70 MEMORY_ERROR
= LUA_ERRMEM
,
71 HANDLER_ERROR
= LUA_ERRERR
,
72 FILE_ERROR
= LUA_ERRFILE
77 REGISTRY
= LUA_REGISTRYINDEX
,
78 ENVIRONMENT
= LUA_ENVIRONINDEX
,
79 GLOBALS
= LUA_GLOBALSINDEX
83 * This is the most prominent abstraction on top of the standard Lua
84 * API. A Slot object represents a value on the stack. More
85 * specifically, it represents a position on the stack. The
86 * distinction is only important when objects are moved around on the
87 * stack or if the Slot represents a negative index on the stack (the
88 * value of which will change as things are pushed onto and popped from
95 * You have direct access to the index of the value on the stack
102 Slot(const Script
& s
, int i
= 0) :
104 mScript(const_cast<Script
&>(s
)) {}
107 * A copied value presently points to the same value, except the
108 * real index is used. That means that if a value that refers to a
109 * frame referenced from the top of the stack will have its
110 * normalized index copied into the new value object.
113 //Slot(const Slot& copy) :
114 //index(copy.positiveIndex()),
115 //mScript(copy.mScript) {}
118 // check the type of the value
119 bool isBoolean() const
120 { return (bool)lua_isboolean(mScript
.mState
, index
); }
121 bool isImportedFunction() const
122 { return (bool)lua_iscfunction(mScript
.mState
, index
); }
123 bool isFunction() const
124 { return (bool)lua_isfunction(mScript
.mState
, index
); }
126 { return (bool)lua_isnil(mScript
.mState
, index
); }
128 { return (bool)lua_isnone(mScript
.mState
, index
); }
129 bool isNoneOrNil() const
130 { return (bool)lua_isnoneornil(mScript
.mState
, index
); }
131 bool isNumber() const
132 { return (bool)lua_isnumber(mScript
.mState
, index
); }
133 bool isString() const
134 { return (bool)lua_isstring(mScript
.mState
, index
); }
136 { return (bool)lua_istable(mScript
.mState
, index
); }
137 bool isThread() const
138 { return (bool)lua_isthread(mScript
.mState
, index
); }
140 { return (bool)lua_isuserdata(mScript
.mState
, index
); }
141 bool isLightData() const
142 { return (bool)lua_islightuserdata(mScript
.mState
, index
); }
145 * Check the value and throw an error if its the wrong type.
146 * There's a little caveat: This method never returns because it
147 * does a long jump. Consequently, constructed C++ objects which
148 * exist on the stack between the current frame and some lua
149 * function will not be destructed. That's not a problem for
150 * objects that only exist on the stack, but any objects that
151 * allocate memory on the heap (such as containers or strings) will
152 * leak. Therefore, you should only call this method after
153 * cleaning up such objects. The best thing to do for defining
154 * functions is to simply check all the parameters at the get-go
155 * before any C++ objects are even constructed.
158 void requireType(Type t
) const
162 luaL_typerror(mScript
.mState
, index
,
163 lua_typename(mScript
.mState
, t
));
167 void raise(const char* error
)
169 luaL_argerror(mScript
.mState
, index
, error
);
173 Slot
& requireBoolean()
177 luaL_typerror(mScript
.mState
, index
, "boolean");
181 Slot
& requireNumber()
185 luaL_typerror(mScript
.mState
, index
, "number");
189 Slot
& requireString()
193 luaL_typerror(mScript
.mState
, index
, "string");
201 luaL_typerror(mScript
.mState
, index
, "table");
205 Slot
& requireFunction()
209 luaL_typerror(mScript
.mState
, index
, "function");
217 luaL_typerror(mScript
.mState
, index
, "data");
225 luaL_typerror(mScript
.mState
, index
, "nil");
229 Slot
& requireThread()
233 luaL_typerror(mScript
.mState
, index
, "thread");
240 * Get the type of the value.
245 return (Type
)lua_type(mScript
.mState
, index
);
249 * Get the name of the type of the value as a string.
252 std::string
typeName() const
254 return std::string(luaL_typename(mScript
.mState
, index
));
259 * Get the length of the value according to the definition given by
263 size_t length() const
265 return lua_objlen(mScript
.mState
, index
);
268 int positiveIndex() const
270 if (index
< 0) return index
+ lua_gettop(mScript
.mState
) + 1;
276 * Get a pointer value (for userdata, tables, threads, and
280 const void* id() const
282 return lua_topointer(mScript
.mState
, index
);
285 bool isIdentical(const Slot
& rhs
) const
287 return &mScript
== &(rhs
.mScript
) && index
== rhs
.index
;
290 operator bool () const
296 bool operator == (const Slot
& rhs
) const
298 return (bool)lua_equal(mScript
.mState
, index
, rhs
.index
);
300 bool operator != (const Slot
& rhs
) const
302 return !(*this == rhs
);
305 bool operator < (const Slot
& rhs
) const
307 return (bool)lua_lessthan(mScript
.mState
, index
, rhs
.index
);
309 bool operator <= (const Slot
& rhs
) const
311 return *this < rhs
|| *this == rhs
;
313 bool operator > (const Slot
& rhs
) const
315 return !(*this <= rhs
);
317 bool operator >= (const Slot
& rhs
) const
319 return !(*this < rhs
);
324 * Convert the underlying value to a C++ type.
328 bool get(T
& value
) const
332 value
= (T
)lua_tointeger(mScript
.mState
, index
);
338 bool get(float& value
) const
342 value
= (float)lua_tonumber(mScript
.mState
, index
);
347 bool get(double& value
) const
351 value
= (double)lua_tonumber(mScript
.mState
, index
);
357 bool get(bool& value
) const
361 value
= (bool)lua_toboolean(mScript
.mState
, index
);
367 bool get(const char*& value
, size_t& size
) const
371 value
= lua_tolstring(mScript
.mState
, index
, &size
);
377 bool get(std::string
& value
) const
383 value
.assign(str
, size
);
389 bool get(void*& value
) const
393 value
= lua_touserdata(mScript
.mState
, index
);
400 bool get(std::vector
<T
>& array
) const
402 if (!isTable()) return false;
406 Slot value
= mScript
[-1];
407 int realIndex
= positiveIndex();
410 for (int i
= 1; !done
; ++i
)
412 lua_rawgeti(mScript
.mState
, realIndex
, i
);
415 if (value
.get(v
)) array
.push_back(v
);
425 bool get(std::map
<std::string
,T
>& dictionary
) const
427 if (!isTable()) return false;
431 Slot key
= mScript
[-2];
432 Slot value
= mScript
[-1];
433 int realIndex
= positiveIndex();
436 while (lua_next(mScript
.mState
, realIndex
) != 0)
439 if (!key
.isNumber() && key
.get(k
))
442 if (value
.get(v
)) dictionary
[k
] = v
;
452 * Get the value of a field from the table.
455 template <class T
, class V
>
456 bool get(T
& value
, V field
) const
458 bool ret
= pushField(field
).get(value
);
464 template <class T
, class V
>
465 void setField(T field
, V value
)
474 lua_settable(mScript
.mState
, index
);
479 void setField(const std::string
& field
, T value
)
481 setField(field
.c_str(), value
);
484 void setField(const char* field
, T value
)
487 lua_setfield(mScript
.mState
, index
, field
);
492 * This set method, as opposed to the others, sets the value of the
493 * actual slot. The others set table values.
509 * Replace this value with the value at the top of the stack.
514 lua_replace(mScript
.mState
, index
);
519 lua_remove(mScript
.mState
, index
);
524 // removes this slot, taking with it everything above it
525 mScript
.pop(mScript
.stackSize() - index
+ 1);
529 * Inserts the top-most value on the stack at position index,
530 * shifting other values as needed.
535 lua_insert(mScript
.mState
, index
);
540 * Copy the value and push the copy to the stack.
543 Slot
pushCopy() const
545 lua_pushvalue(mScript
.mState
, index
);
546 return mScript
.top();
549 Slot
pushMetaTable() const
551 lua_getmetatable(mScript
.mState
, index
);
552 return mScript
.top();
555 Slot
pushEnvironment() const
557 lua_getfenv(mScript
.mState
, index
);
558 return mScript
.top();
562 Slot
pushField() const
564 lua_gettable(mScript
.mState
, index
);
565 return mScript
.top();
569 Slot
pushField(T index
) const
575 Slot
pushField(const std::string
& name
) const
577 return pushField(name
.c_str());
579 Slot
pushField(const char* name
) const
581 lua_getfield(mScript
.mState
, index
, name
);
582 return mScript
.top();
591 const Script
& script() const
614 static ScriptP
alloc()
616 return ScriptP(new Script
);
621 if (mState
) destroy();
622 mState
= luaL_newstate();
623 registry().setField("Script_hh_Object", (void*)this);
627 void importStandardLibraries()
629 luaL_openlibs(mState
);
632 void importBaseLibrary()
634 lua_pushcfunction(mState
, luaopen_base
);
639 void importPackageLibrary()
641 lua_pushcfunction(mState
, luaopen_package
);
642 push(LUA_LOADLIBNAME
);
646 void importStringLibrary()
648 lua_pushcfunction(mState
, luaopen_string
);
649 push(LUA_STRLIBNAME
);
653 void importTableLibrary()
655 lua_pushcfunction(mState
, luaopen_table
);
656 push(LUA_TABLIBNAME
);
660 void importMathLibrary()
662 lua_pushcfunction(mState
, luaopen_math
);
663 push(LUA_MATHLIBNAME
);
667 void importIoLibrary()
669 lua_pushcfunction(mState
, luaopen_io
);
674 void importOsLibrary()
676 lua_pushcfunction(mState
, luaopen_os
);
681 void importDebugLibrary()
683 lua_pushcfunction(mState
, luaopen_debug
);
689 void importFunction(const std::string
& name
, const Function
& function
)
692 lua_setglobal(mState
, name
.c_str());
695 Result
doString(const std::string
& commands
)
697 return (Result
)luaL_dostring(mState
, commands
.c_str());
700 Result
doFile(const std::string
& file
)
702 return (Result
)luaL_dofile(mState
, file
.c_str());
707 * Thread-handling methods.
710 Script
pushNewThread()
712 return Script(mState
);
717 lua_pushthread(mState
);
720 Result
resume(int nargs
)
722 return (Result
)lua_resume(mState
, nargs
);
725 Result
getStatus() const
727 return (Result
)lua_status(mState
);
730 int yield(int results
)
732 return lua_yield(mState
, results
);
735 bool isMainThread() const
737 return mIsMainThread
;
742 * Throw an error with the value at the top of the stack. This method
743 * never returns because it does a long jump. Consequently,
744 * constructed C++ objects which exist on the stack between the
745 * current frame and some lua function will not be destructed. That's
746 * not a problem for objects that only exist on the stack, but any
747 * objects that allocate memory on the heap (such as containers or
748 * strings) will leak. Therefore, you should only call this method
749 * after cleaning up such objects.
759 * Get significant values.
764 return Slot(*this, GLOBALS
);
767 Slot
registry() const
769 return Slot(*this, REGISTRY
);
772 Slot
environment() const
774 return Slot(*this, ENVIRONMENT
);
779 return Slot(*this, stackSize());
783 * Get the size of the stack; this is also the index of the top-most
787 int stackSize() const
789 return lua_gettop(mState
);
792 void setStackSize(int size
)
794 lua_settop(mState
, size
);
804 * Makes sure there is at least extra more places on the stack.
805 * Returns false if space couldn't be created. Just like with the
806 * regular Lua API, you are responsible to make sure the stack is big
807 * enough to hold whatever you want to push on it. This is usually
808 * only an issue if you're pushing stuff in a loop.
811 bool checkStack(int extra
)
813 return (bool)lua_checkstack(mState
, extra
);
818 * Concatenates the top-most n slots on the stack.
821 void concatenate(int n
= 2)
823 lua_concat(mState
, n
);
828 * Push some values onto the stack.
834 lua_pushinteger(mState
, lua_Integer(value
));
838 Slot
push(bool value
)
840 lua_pushboolean(mState
, int(value
));
844 Slot
push(float value
)
846 lua_pushnumber(mState
, (lua_Number
)value
);
849 Slot
push(double value
)
851 lua_pushnumber(mState
, (lua_Number
)value
);
855 Slot
push(const std::string
& value
)
857 lua_pushlstring(mState
, value
.c_str(), value
.length());
860 Slot
push(const char* value
)
862 lua_pushstring(mState
, value
);
865 Slot
push(const char* value
, size_t length
)
867 lua_pushlstring(mState
, value
, length
);
871 Slot
push(const Function
& function
)
873 mFunctions
.push_back(function
);
874 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
875 lua_pushcclosure(mState
, dispatchCall
, 1);
879 Slot
push(void* data
)
881 lua_pushlightuserdata(mState
, data
);
891 Slot
pushFromThread(Script
& thread
, int n
)
893 lua_xmove(thread
.mState
, mState
, n
);
897 Slot
pushCode(const std::string
& file
, Result
& result
)
899 result
= (Result
)luaL_loadfile(mState
, file
.c_str());
903 Slot
pushCode(const std::string
& name
, const char* buffer
,
904 size_t size
, Result
& result
)
906 result
= (Result
)luaL_loadbuffer(mState
,
907 buffer
, size
, name
.c_str());
911 Slot
pushNewData(void*& data
, size_t size
)
913 data
= lua_newuserdata(mState
, size
);
917 Slot
pushNewTable(int narr
= 0, int nrec
= 0)
919 lua_createtable(mState
, narr
, nrec
);
925 * Call a function on the stack. The correct procedure is to push a
926 * function onto the stack followed by nargs arguments. This method
927 * will pop them off upon return, leaving up to nresults return values
928 * (default is any number of return values, depending on the callee).
931 Result
call(int nargs
= 0, int nresults
= LUA_MULTRET
)
933 return (Result
)lua_pcall(mState
, nargs
, nresults
, 0);
938 * Pops n values from the top of the stack.
948 * Index into the stack to get a Slot.
951 Slot
operator [] (int index
) const
953 return Slot(*this, index
);
958 * Control over the garbage collection process.
963 lua_gc(mState
, LUA_GCCOLLECT
, 0);
968 lua_gc(mState
, LUA_GCSTOP
, 0);
971 void restartCollector()
973 lua_gc(mState
, LUA_GCRESTART
, 0);
976 int getUsedMemory() const
979 return lua_gc(mState
, LUA_GCCOUNT
, 0);
982 void collectStep(int step
)
984 lua_gc(mState
, LUA_GCSTEP
, step
);
987 void tuneCollector(int pause
, int step
)
989 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
990 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
996 Script(lua_State
* state
) :
997 mState(lua_newthread(state
)),
998 mIsMainThread(false) {}
1000 static int dispatchCall(lua_State
* state
)
1002 const Function
* function
= (const Function
*)lua_touserdata(state
,
1003 lua_upvalueindex(1));
1005 lua_getfield(state
, LUA_REGISTRYINDEX
, "Script_hh_Object");
1006 Script
* script
= (Script
*)lua_touserdata(state
, -1);
1009 return (*function
)(*script
);
1014 if (mIsMainThread
) lua_close(mState
);
1019 std::list
<Function
> mFunctions
;
1023 inline std::ostream
& operator << (std::ostream
& stream
,
1024 const Script::Slot
& slot
)
1026 if (slot
.isString())
1032 else if (slot
.isBoolean())
1036 if (value
) stream
<< "true";
1037 else stream
<< "false";
1039 else if (slot
.isNil())
1045 stream
<< slot
.typeName() << " (" << slot
.id() << ")";
1054 #endif // _MOOF_SCRIPT_HH_
This page took 0.077673 seconds and 4 git commands to generate.