]>
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 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
103 * A default-constructed Slot is invalid until a valid Slot is
104 * assigned to it. The only method that should be called on such a
105 * Slot is isValid(), otherwise chaos may ensue. In this case, the
106 * Slot will be invalid even if index is manually changed to a
107 * valid index. You have to index the script itself to get a valid
110 Slot(lua_State
* s
= 0, int i
= 0) :
115 * A copied value presently points to the same value, except the
116 * real index is used. That means that if a value that refers to a
117 * frame referenced from the top of the stack will have its
118 * normalized index copied into the new value object.
121 Slot(const Slot
& copy
) :
122 index(copy
.getRealIndex()),
123 mState(copy
.mState
) {}
126 // check the type of the value
127 bool isBoolean() const
128 { return (bool)lua_isboolean(mState
, index
); }
129 bool isFunction() const
130 { return (bool)lua_isfunction(mState
, index
); }
132 { return (bool)lua_isnil(mState
, index
); }
134 { return (bool)lua_isnone(mState
, index
); }
136 { return mState
!= 0 && !isNone(); }
137 bool isNoneOrNil() const
138 { return (bool)lua_isnoneornil(mState
, index
); }
139 bool isNumber() const
140 { return (bool)lua_isnumber(mState
, index
); }
141 bool isString() const
142 { return (bool)lua_isstring(mState
, index
); }
144 { return (bool)lua_istable(mState
, index
); }
145 bool isThread() const
146 { return (bool)lua_isthread(mState
, index
); }
148 { return (bool)lua_isuserdata(mState
, index
); }
149 bool isLightData() const
150 { return (bool)lua_islightuserdata(mState
, index
); }
153 * Check the value and throw an error if its the wrong type.
154 * There's a little caveat: This method never returns because it
155 * does a long jump. Consequently, constructed C++ objects which
156 * exist on the stack between the current frame and some lua
157 * function will not be destructed. That's not a problem for
158 * objects that only exist on the stack, but any objects that
159 * allocate memory on the heap (such as containers or strings) will
160 * leak. Therefore, you should only call this method after
161 * cleaning up such objects. The best thing to do for defining
162 * functions is to simply check all the parameters at the get-go
163 * before any C++ objects are even constructed.
166 void requireType(Type type
) const
168 if (type
!= getType())
170 luaL_typerror(mState
, index
, lua_typename(mState
, type
));
174 void throwError(const char* error
)
176 luaL_argerror(mState
, index
, error
);
180 Slot
& requireBoolean()
182 if (!isBoolean()) luaL_typerror(mState
, index
, "boolean");
185 Slot
& requireNumber()
187 if (!isNumber()) luaL_typerror(mState
, index
, "number");
190 Slot
& requireString()
192 if (!isString()) luaL_typerror(mState
, index
, "string");
197 if (!isTable()) luaL_typerror(mState
, index
, "table");
200 Slot
& requireFunction()
202 if (!isFunction()) luaL_typerror(mState
, index
, "function");
207 if (!isData()) luaL_typerror(mState
, index
, "data");
212 if (!isNil()) luaL_typerror(mState
, index
, "nil");
215 Slot
& requireThread()
217 if (!isThread()) luaL_typerror(mState
, index
, "thread");
223 * Get the type of the value.
228 return (Type
)lua_type(mState
, index
);
232 * Get the name of the type of the value as a string.
235 std::string
getTypeName() const
237 return std::string(luaL_typename(mState
, index
));
242 * Get the length of the value according to the definition given by
246 size_t getLength() const
248 return lua_objlen(mState
, index
);
251 int getRealIndex() const
253 if (index
< 0) return lua_gettop(mState
) + 1 + index
;
259 * Get a pointer value (for userdata, tables, threads, and
263 const void* getIdentifier() const
265 return lua_topointer(mState
, index
);
269 bool operator == (const Slot
& rhs
) const
271 return (bool)lua_equal(mState
, index
, rhs
.index
);
273 bool operator != (const Slot
& rhs
) const
275 return !(*this == rhs
);
277 bool operator < (const Slot
& rhs
) const
279 return (bool)lua_lessthan(mState
, index
, rhs
.index
);
281 bool operator <= (const Slot
& rhs
) const
283 return *this < rhs
|| *this == rhs
;
285 bool operator > (const Slot
& rhs
) const
287 return !(*this <= rhs
);
289 bool operator >= (const Slot
& rhs
) const
291 return !(*this < rhs
);
293 operator bool () const
295 return (bool)lua_toboolean(mState
, index
);
298 Slot
& operator = (const Slot
& rhs
)
307 * Convert the underlying value to a C++ type.
310 template <typename T
>
311 bool get(T
& value
) const
315 value
= (T
)lua_tointeger(mState
, index
);
321 bool get(float& value
) const
325 value
= (float)lua_tonumber(mState
, index
);
330 bool get(double& value
) const
334 value
= (double)lua_tonumber(mState
, index
);
340 bool get(bool& value
) const
344 value
= (bool)lua_toboolean(mState
, index
);
350 bool get(std::string
& value
) const
355 const char* str
= lua_tolstring(mState
, index
, &size
);
356 value
.assign(str
, size
);
362 template <typename T
>
363 bool get(std::vector
<T
>& array
) const
365 if (!isTable()) return false;
369 Slot
value(mState
, -1);
370 int realIndex
= getRealIndex();
373 for (int i
= 1; !done
; ++i
)
375 lua_rawgeti(mState
, realIndex
, i
);
378 if (value
.get(v
)) array
.push_back(v
);
387 template <typename T
>
388 bool get(std::map
<std::string
,T
>& dictionary
) const
390 if (!isTable()) return false;
394 Slot
key(mState
, -2);
395 Slot
value(mState
, -1);
396 int realIndex
= getRealIndex();
399 while (lua_next(mState
, realIndex
) != 0)
402 if (!key
.isNumber() && key
.get(k
))
405 if (value
.get(v
)) dictionary
[k
] = v
;
415 * Get the value of a field from the table.
418 template <typename T
, typename V
>
419 bool get(T
& value
, V field
) const
422 bool ret
= Slot(mState
, -1).get(value
);
429 * Copy the value and push the copy to the stack.
432 void pushCopy() const
434 lua_pushvalue(mState
, index
);
438 * Replace this value with the value at the top of the stack.
441 void replaceWithTop()
443 lua_replace(mState
, index
);
448 lua_remove(mState
, index
);
452 * Inserts the top-most value on the stack at position index,
453 * shifting other values as needed.
458 lua_insert(mState
, index
);
462 void pushMetaTable() const
464 lua_getmetatable(mState
, index
);
467 void pushField() const
469 lua_gettable(mState
, index
);
472 void pushField(const std::string
& name
) const
474 lua_getfield(mState
, index
, name
.c_str());
477 void pushField(size_t index
) const
479 lua_pushinteger(mState
, lua_Integer(index
));
502 static ScriptP
alloc()
504 return ScriptP(new Script
);
509 if (mState
) destroy();
510 mState
= luaL_newstate();
511 lua_pushlightuserdata(mState
, this);
512 lua_setfield(mState
, LUA_REGISTRYINDEX
, "Script_hh_Object");
516 void importStandardLibraries()
518 luaL_openlibs(mState
);
521 void importBaseLibrary()
523 lua_pushcfunction(mState
, luaopen_base
);
528 void importPackageLibrary()
530 lua_pushcfunction(mState
, luaopen_package
);
531 push(LUA_LOADLIBNAME
);
535 void importStringLibrary()
537 lua_pushcfunction(mState
, luaopen_string
);
538 push(LUA_STRLIBNAME
);
542 void importTableLibrary()
544 lua_pushcfunction(mState
, luaopen_table
);
545 push(LUA_TABLIBNAME
);
549 void importMathLibrary()
551 lua_pushcfunction(mState
, luaopen_math
);
552 push(LUA_MATHLIBNAME
);
556 void importIoLibrary()
558 lua_pushcfunction(mState
, luaopen_io
);
563 void importOsLibrary()
565 lua_pushcfunction(mState
, luaopen_os
);
570 void importDebugLibrary()
572 lua_pushcfunction(mState
, luaopen_debug
);
578 void importFunction(const std::string
& name
, const Function
& function
)
581 lua_setglobal(mState
, name
.c_str());
584 Result
doString(const std::string
& commands
)
586 return (Result
)luaL_dostring(mState
, commands
.c_str());
589 Result
doFile(const std::string
& file
)
591 return (Result
)luaL_dofile(mState
, file
.c_str());
596 * Thread-handling methods.
599 Script
pushNewThread()
601 return Script(mState
);
606 lua_pushthread(mState
);
609 Result
resume(int nargs
)
611 return (Result
)lua_resume(mState
, nargs
);
614 Result
getStatus() const
616 return (Result
)lua_status(mState
);
619 int yield(int results
)
621 return lua_yield(mState
, results
);
624 bool isMainThread() const
626 return mIsMainThread
;
631 * Throw an error with the value at the top of the stack. This method
632 * never returns because it does a long jump. Consequently,
633 * constructed C++ objects which exist on the stack between the
634 * current frame and some lua function will not be destructed. That's
635 * not a problem for objects that only exist on the stack, but any
636 * objects that allocate memory on the heap (such as containers or
637 * strings) will leak. Therefore, you should only call this method
638 * after cleaning up such objects.
648 * Get significant values.
651 Slot
getGlobalTable() const
653 return Slot(mState
, GLOBALS
);
656 Slot
getRegistryTable() const
658 return Slot(mState
, REGISTRY
);
661 Slot
getEnvironmentTable() const
663 return Slot(mState
, ENVIRONMENT
);
668 return Slot(mState
, lua_gettop(mState
));
672 * Get the size of the stack; this is also the index of the top-most
678 return lua_gettop(mState
);
681 void setSize(int size
)
683 lua_settop(mState
, size
);
693 * Makes sure there is at least extra more places on the stack.
694 * Returns false if space couldn't be created. Just like with the
695 * regular Lua API, you are responsible to make sure the stack is big
696 * enough to hold whatever you want to push on it. This is usually
697 * only an issue if you're pushing stuff in a loop.
700 bool checkStack(int extra
)
702 return (bool)lua_checkstack(mState
, extra
);
707 * Concatenates the top-most n slots on the stack.
710 void concat(int n
= 2)
712 lua_concat(mState
, n
);
717 * Push some values onto the stack.
720 template <typename T
>
723 lua_pushinteger(mState
, lua_Integer(value
));
726 void push(bool value
)
728 lua_pushboolean(mState
, int(value
));
731 void push(float value
)
733 lua_pushnumber(mState
, (lua_Number
)value
);
735 void push(double value
)
737 lua_pushnumber(mState
, (lua_Number
)value
);
740 void push(const std::string
& value
)
742 lua_pushlstring(mState
, value
.c_str(), value
.length());
744 void push(const char* value
)
746 lua_pushstring(mState
, value
);
748 void push(const char* value
, size_t length
)
750 lua_pushlstring(mState
, value
, length
);
753 void push(const Function
& function
)
755 mFunctions
.push_back(function
);
757 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
758 lua_pushcclosure(mState
, dispatchCall
, 1);
761 void push(void* data
)
763 lua_pushlightuserdata(mState
, data
);
771 void pushFromThread(Script
& thread
, int n
)
773 lua_xmove(thread
.mState
, mState
, n
);
776 Result
pushCode(const std::string
& filename
)
778 return (Result
)luaL_loadfile(mState
, filename
.c_str());
781 Result
pushCode(const std::string
& name
, const char* buffer
,
784 return (Result
)luaL_loadbuffer(mState
, buffer
, size
, name
.c_str());
787 void* pushNewData(size_t size
)
789 return lua_newuserdata(mState
, size
);
794 lua_newtable(mState
);
799 * Call a function on the stack. The correct procedure is to push a
800 * function onto the stack followed by nargs arguments. This method
801 * will pop them off upon return, leaving up to nresults return values
802 * (default is any number of return values, depending on the callee).
805 Result
call(int nargs
= 0, int nresults
= LUA_MULTRET
)
807 return (Result
)lua_pcall(mState
, nargs
, nresults
, 0);
812 * Pops n values from the top of the stack.
822 * Index into the stack to get a Slot.
825 Slot
operator [] (int index
) const
827 return Slot(mState
, index
);
832 * Getting and setting fields of a table.
835 void pushField(const std::string
& field
, int index
= GLOBALS
) const
837 lua_getfield(mState
, index
, field
.c_str());
840 void set(const std::string
& field
, int index
= GLOBALS
)
842 lua_setfield(mState
, index
, field
.c_str());
847 * Control over the garbage collection process.
852 lua_gc(mState
, LUA_GCCOLLECT
, 0);
857 lua_gc(mState
, LUA_GCSTOP
, 0);
860 void restartCollector()
862 lua_gc(mState
, LUA_GCRESTART
, 0);
865 int getUsedMemory() const
868 return lua_gc(mState
, LUA_GCCOUNT
, 0);
871 void collectStep(int step
)
873 lua_gc(mState
, LUA_GCSTEP
, step
);
876 void tuneCollector(int pause
, int step
)
878 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
879 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
885 Script(lua_State
* state
) :
886 mState(lua_newthread(state
)),
887 mIsMainThread(false) {}
889 static int dispatchCall(lua_State
* state
)
891 const Function
* function
= (const Function
*)lua_touserdata(state
,
892 lua_upvalueindex(1));
894 lua_getfield(state
, LUA_REGISTRYINDEX
, "Script_hh_Object");
895 Script
* script
= (Script
*)lua_touserdata(state
, -1);
898 return (*function
)(*script
);
903 if (mIsMainThread
) lua_close(mState
);
908 std::list
<Function
> mFunctions
;
912 inline std::ostream
& operator << (std::ostream
& stream
,
913 const Script::Slot
& slot
)
921 else if (slot
.isBoolean())
923 if (slot
) stream
<< "true";
924 else stream
<< "false";
926 else if (slot
.isNil())
932 stream
<< slot
.getTypeName() << " (" << slot
.getIdentifier() << ")";
941 #endif // _MOOF_SCRIPT_HH_
This page took 0.073075 seconds and 5 git commands to generate.