]>
Dogcows Code - chaz/yoink/blob - src/Moof/Script.hh
08284117359418234f4df58b2d84b04bbd34ca7d
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
)
467 logWarning
<< "setting " << field
<< ", " << value
<< std::endl
;
475 lua_settable(mScript
.mState
, index
);
480 void setField(const std::string
& field
, T value
)
482 setField(field
.c_str(), value
);
485 void setField(const char* field
, T value
)
487 logWarning
<< "setfield " << field
<< ", " << value
<< std::endl
;
489 lua_setfield(mScript
.mState
, index
, field
);
494 * This set method, as opposed to the others, sets the value of the
495 * actual slot. The others set table values.
511 * Replace this value with the value at the top of the stack.
516 lua_replace(mScript
.mState
, index
);
521 lua_remove(mScript
.mState
, index
);
526 // removes this slot, taking with it everything above it
527 mScript
.pop(mScript
.stackSize() - index
+ 1);
531 * Inserts the top-most value on the stack at position index,
532 * shifting other values as needed.
537 lua_insert(mScript
.mState
, index
);
542 * Copy the value and push the copy to the stack.
545 Slot
pushCopy() const
547 lua_pushvalue(mScript
.mState
, index
);
548 return mScript
.top();
551 Slot
pushMetaTable() const
553 lua_getmetatable(mScript
.mState
, index
);
554 return mScript
.top();
557 Slot
pushEnvironment() const
559 lua_getfenv(mScript
.mState
, index
);
560 return mScript
.top();
564 Slot
pushField() const
566 lua_gettable(mScript
.mState
, index
);
567 return mScript
.top();
571 Slot
pushField(T index
) const
577 Slot
pushField(const std::string
& name
) const
579 return pushField(name
.c_str());
581 Slot
pushField(const char* name
) const
583 lua_getfield(mScript
.mState
, index
, name
);
584 return mScript
.top();
593 const Script
& script() const
616 static ScriptP
alloc()
618 return ScriptP(new Script
);
623 if (mState
) destroy();
624 mState
= luaL_newstate();
625 registry().setField("Script_hh_Object", (void*)this);
629 void importStandardLibraries()
631 luaL_openlibs(mState
);
634 void importBaseLibrary()
636 lua_pushcfunction(mState
, luaopen_base
);
641 void importPackageLibrary()
643 lua_pushcfunction(mState
, luaopen_package
);
644 push(LUA_LOADLIBNAME
);
648 void importStringLibrary()
650 lua_pushcfunction(mState
, luaopen_string
);
651 push(LUA_STRLIBNAME
);
655 void importTableLibrary()
657 lua_pushcfunction(mState
, luaopen_table
);
658 push(LUA_TABLIBNAME
);
662 void importMathLibrary()
664 lua_pushcfunction(mState
, luaopen_math
);
665 push(LUA_MATHLIBNAME
);
669 void importIoLibrary()
671 lua_pushcfunction(mState
, luaopen_io
);
676 void importOsLibrary()
678 lua_pushcfunction(mState
, luaopen_os
);
683 void importDebugLibrary()
685 lua_pushcfunction(mState
, luaopen_debug
);
691 void importFunction(const std::string
& name
, const Function
& function
)
694 lua_setglobal(mState
, name
.c_str());
697 Result
doString(const std::string
& commands
)
699 return (Result
)luaL_dostring(mState
, commands
.c_str());
702 Result
doFile(const std::string
& file
)
704 return (Result
)luaL_dofile(mState
, file
.c_str());
709 * Thread-handling methods.
712 Script
pushNewThread()
714 return Script(mState
);
719 lua_pushthread(mState
);
722 Result
resume(int nargs
)
724 return (Result
)lua_resume(mState
, nargs
);
727 Result
getStatus() const
729 return (Result
)lua_status(mState
);
732 int yield(int results
)
734 return lua_yield(mState
, results
);
737 bool isMainThread() const
739 return mIsMainThread
;
744 * Throw an error with the value at the top of the stack. This method
745 * never returns because it does a long jump. Consequently,
746 * constructed C++ objects which exist on the stack between the
747 * current frame and some lua function will not be destructed. That's
748 * not a problem for objects that only exist on the stack, but any
749 * objects that allocate memory on the heap (such as containers or
750 * strings) will leak. Therefore, you should only call this method
751 * after cleaning up such objects.
761 * Get significant values.
766 return Slot(*this, GLOBALS
);
769 Slot
registry() const
771 return Slot(*this, REGISTRY
);
774 Slot
environment() const
776 return Slot(*this, ENVIRONMENT
);
781 return Slot(*this, stackSize());
785 * Get the size of the stack; this is also the index of the top-most
789 int stackSize() const
791 return lua_gettop(mState
);
794 void setStackSize(int size
)
796 lua_settop(mState
, size
);
806 * Makes sure there is at least extra more places on the stack.
807 * Returns false if space couldn't be created. Just like with the
808 * regular Lua API, you are responsible to make sure the stack is big
809 * enough to hold whatever you want to push on it. This is usually
810 * only an issue if you're pushing stuff in a loop.
813 bool checkStack(int extra
)
815 return (bool)lua_checkstack(mState
, extra
);
820 * Concatenates the top-most n slots on the stack.
823 void concatenate(int n
= 2)
825 lua_concat(mState
, n
);
830 * Push some values onto the stack.
836 lua_pushinteger(mState
, lua_Integer(value
));
840 Slot
push(bool value
)
842 lua_pushboolean(mState
, int(value
));
846 Slot
push(float value
)
848 lua_pushnumber(mState
, (lua_Number
)value
);
851 Slot
push(double value
)
853 lua_pushnumber(mState
, (lua_Number
)value
);
857 Slot
push(const std::string
& value
)
859 lua_pushlstring(mState
, value
.c_str(), value
.length());
862 Slot
push(const char* value
)
864 lua_pushstring(mState
, value
);
867 Slot
push(const char* value
, size_t length
)
869 lua_pushlstring(mState
, value
, length
);
873 Slot
push(const Function
& function
)
875 mFunctions
.push_back(function
);
876 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
877 lua_pushcclosure(mState
, dispatchCall
, 1);
881 Slot
push(void* data
)
883 lua_pushlightuserdata(mState
, data
);
893 Slot
pushFromThread(Script
& thread
, int n
)
895 lua_xmove(thread
.mState
, mState
, n
);
899 Slot
pushCode(const std::string
& file
, Result
& result
)
901 result
= (Result
)luaL_loadfile(mState
, file
.c_str());
905 Slot
pushCode(const std::string
& name
, const char* buffer
,
906 size_t size
, Result
& result
)
908 result
= (Result
)luaL_loadbuffer(mState
,
909 buffer
, size
, name
.c_str());
913 Slot
pushNewData(void*& data
, size_t size
)
915 data
= lua_newuserdata(mState
, size
);
919 Slot
pushNewTable(int narr
= 0, int nrec
= 0)
921 lua_createtable(mState
, narr
, nrec
);
927 * Call a function on the stack. The correct procedure is to push a
928 * function onto the stack followed by nargs arguments. This method
929 * will pop them off upon return, leaving up to nresults return values
930 * (default is any number of return values, depending on the callee).
933 Result
call(int nargs
= 0, int nresults
= LUA_MULTRET
)
935 return (Result
)lua_pcall(mState
, nargs
, nresults
, 0);
940 * Pops n values from the top of the stack.
950 * Index into the stack to get a Slot.
953 Slot
operator [] (int index
) const
955 return Slot(*this, index
);
960 * Control over the garbage collection process.
965 lua_gc(mState
, LUA_GCCOLLECT
, 0);
970 lua_gc(mState
, LUA_GCSTOP
, 0);
973 void restartCollector()
975 lua_gc(mState
, LUA_GCRESTART
, 0);
978 int getUsedMemory() const
981 return lua_gc(mState
, LUA_GCCOUNT
, 0);
984 void collectStep(int step
)
986 lua_gc(mState
, LUA_GCSTEP
, step
);
989 void tuneCollector(int pause
, int step
)
991 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
992 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
998 Script(lua_State
* state
) :
999 mState(lua_newthread(state
)),
1000 mIsMainThread(false) {}
1002 static int dispatchCall(lua_State
* state
)
1004 const Function
* function
= (const Function
*)lua_touserdata(state
,
1005 lua_upvalueindex(1));
1007 lua_getfield(state
, LUA_REGISTRYINDEX
, "Script_hh_Object");
1008 Script
* script
= (Script
*)lua_touserdata(state
, -1);
1011 return (*function
)(*script
);
1016 if (mIsMainThread
) lua_close(mState
);
1021 std::list
<Function
> mFunctions
;
1025 inline std::ostream
& operator << (std::ostream
& stream
,
1026 const Script::Slot
& slot
)
1028 if (slot
.isString())
1034 else if (slot
.isBoolean())
1038 if (value
) stream
<< "true";
1039 else stream
<< "false";
1041 else if (slot
.isNil())
1047 stream
<< slot
.typeName() << " (" << slot
.id() << ")";
1056 #endif // _MOOF_SCRIPT_HH_
This page took 0.082306 seconds and 4 git commands to generate.