]>
Dogcows Code - chaz/yoink/blob - src/Moof/Script.hh
2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *******************************************************************************/
29 #ifndef _MOOF_SCRIPT_HH_
30 #define _MOOF_SCRIPT_HH_
34 * A thin wrapper over Lua. This is not meant as a complicated binding package
35 * between C++ and Lua. It does not try to make the boundary invisible. It
36 * does not hide the concept of the Lua stack, but rather provides that
37 * mechanism with a certain level of abstraction while also providing a cleaner,
38 * more consistent API.
46 #include <boost/bind.hpp>
47 #include <boost/function.hpp>
48 #include <boost/shared_ptr.hpp>
52 #include <Moof/Log.hh>
59 typedef boost::shared_ptr
<Script
> ScriptP
;
66 typedef boost::function
<int(Script
&)> Function
;
72 BOOLEAN
= LUA_TBOOLEAN
,
73 LIGHTUSERDATA
= LUA_TLIGHTUSERDATA
,
77 FUNCTION
= LUA_TFUNCTION
,
78 USERDATA
= LUA_TUSERDATA
,
86 RUNTIME_ERROR
= LUA_ERRRUN
,
87 SYNTAX_ERROR
= LUA_ERRSYNTAX
,
88 MEMORY_ERROR
= LUA_ERRMEM
,
89 HANDLER_ERROR
= LUA_ERRERR
,
90 FILE_ERROR
= LUA_ERRFILE
95 REGISTRY
= LUA_REGISTRYINDEX
,
96 ENVIRONMENT
= LUA_ENVIRONINDEX
,
97 GLOBALS
= LUA_GLOBALSINDEX
101 * This is the most prominent abstraction on top of the standard Lua API.
102 * A Value object represents a value on the stack. More specifically, it
103 * represents a position on the stack. The distinction is only important
104 * when values are moved around on the stack or if the Value represents a
105 * negative index on the stack (the value of which will change as things are
106 * pushed onto and popped from the stack).
112 * You have direct access to the index of the value on the stack being
120 * A default-constructed Value is invalid until a valid Value is
121 * assigned to it. The only method that should be called on such a
122 * Value is isValid(), otherwise chaos may ensue. In this case, the
123 * Value will be invalid even if index is manually changed to a valid
124 * index. You have to index the script itself to get a valid Value.
126 Value(lua_State
* s
= 0, int i
= 0) :
131 * A copied value presently points to the same value, except the real
132 * index is used. That means that if a value that refers to a frame
133 * referenced from the top of the stack will have its normalized index
134 * copied into the new value object.
137 Value(const Value
& copy
) :
138 index(copy
.getRealIndex()),
142 // check the type of the value
143 bool isBoolean() const { return (bool)lua_isboolean(state
, index
); }
144 bool isFunction() const { return (bool)lua_isfunction(state
, index
); }
145 bool isNil() const { return (bool)lua_isnil(state
, index
); }
146 bool isNone() const { return (bool)lua_isnone(state
, index
); }
147 bool isValid() const { return state
!= 0 && !isNone(); }
148 bool isNoneOrNil() const { return (bool)lua_isnoneornil(state
, index
); }
149 bool isNumber() const { return (bool)lua_isnumber(state
, index
); }
150 bool isString() const { return (bool)lua_isstring(state
, index
); }
151 bool isTable() const { return (bool)lua_istable(state
, index
); }
152 bool isThread() const { return (bool)lua_isthread(state
, index
); }
153 bool isData() const { return (bool)lua_isuserdata(state
, index
); }
154 bool isLightData() const { return (bool)lua_islightuserdata(state
, index
); }
157 * Check the value and throw an error if its the wrong type. There's a
158 * little caveat: This method never returns because it does a long jump.
159 * Consequently, constructed C++ objects which exist on the stack
160 * between the current frame and some lua function will not be
161 * destructed. That's not a problem for objects that only exist on the
162 * stack, but any objects that allocate memory on the heap (such as
163 * containers or strings) will leak. Therefore, you should only call
164 * this method after cleaning up such objects. The best thing to do for
165 * defining functions is to simply check all the parameters at the
166 * get-go before any C++ objects are even constructed.
169 void requireType(Type type
) const
171 if (type
!= getType())
173 luaL_typerror(state
, index
, lua_typename(state
, type
));
177 void throwError(const char* error
)
179 luaL_argerror(state
, index
, error
);
183 Value
& requireBoolean()
185 if (!isBoolean()) luaL_typerror(state
, index
, "boolean");
188 Value
& requireNumber()
190 if (!isNumber()) luaL_typerror(state
, index
, "number");
193 Value
& requireString()
195 if (!isString()) luaL_typerror(state
, index
, "string");
198 Value
& requireTable()
200 if (!isTable()) luaL_typerror(state
, index
, "table");
203 Value
& requireFunction()
205 if (!isFunction()) luaL_typerror(state
, index
, "function");
210 if (!isData()) luaL_typerror(state
, index
, "data");
215 if (!isNil()) luaL_typerror(state
, index
, "nil");
218 Value
& requireThread()
220 if (!isThread()) luaL_typerror(state
, index
, "thread");
226 * Get the type of the value.
231 return (Type
)lua_type(state
, index
);
235 * Get the name of the type of the value as a string.
238 std::string
getTypeName() const
240 return std::string(luaL_typename(state
, index
));
245 * Get the length of the value according to the definition given by Lua.
248 size_t getLength() const
250 return lua_objlen(state
, index
);
253 int getRealIndex() const
255 if (index
< 0) return lua_gettop(state
) + 1 + index
;
261 * Get a pointer value (for userdata, tables, threads, and functions).
264 const void* getIdentifier() const
266 return lua_topointer(state
, index
);
270 bool operator == (const Value
& rhs
) const
272 return (bool)lua_equal(state
, index
, rhs
.index
);
274 bool operator != (const Value
& rhs
) const
276 return !(*this == rhs
);
278 bool operator < (const Value
& rhs
) const
280 return (bool)lua_lessthan(state
, index
, rhs
.index
);
282 bool operator <= (const Value
& rhs
) const
284 return *this < rhs
|| *this == rhs
;
286 bool operator > (const Value
& rhs
) const
288 return !(*this <= rhs
);
290 bool operator >= (const Value
& rhs
) const
292 return !(*this < rhs
);
294 operator bool () const
296 return (bool)lua_toboolean(state
, index
);
299 Value
& operator = (const Value
& 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(state
, index
);
322 bool get(float& value
) const
326 value
= (float)lua_tonumber(state
, index
);
331 bool get(double& value
) const
335 value
= (double)lua_tonumber(state
, index
);
341 bool get(bool& value
) const
345 value
= (bool)lua_toboolean(state
, index
);
351 bool get(std::string
& value
) const
356 const char* str
= lua_tolstring(state
, 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 Value
value(state
, -1);
371 int realIndex
= getRealIndex();
374 for (int i
= 1; !done
; ++i
)
376 lua_rawgeti(state
, 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 Value
key(state
, -2);
396 Value
value(state
, -1);
397 int realIndex
= getRealIndex();
400 while (lua_next(state
, realIndex
) != 0)
403 if (!key
.isNumber() && key
.get(k
))
406 if (value
.get(v
)) dictionary
[k
] = v
;
418 * Copy the value and push the copy to the stack.
421 void pushCopy() const
423 lua_pushvalue(state
, index
);
427 * Replace this value with the value at the top of the stack.
430 void replaceWithTop()
432 lua_replace(state
, index
);
437 lua_remove(state
, index
);
441 * Inserts the top-most value on the stack at position index, shifting other
447 lua_insert(state
, index
);
451 void pushMetatable() const
453 lua_getmetatable(state
, index
);
456 void pushField() const
458 lua_gettable(state
, index
);
461 void pushField(const std::string
& name
) const
463 lua_getfield(state
, index
, name
.c_str());
485 static ScriptP
alloc()
487 return ScriptP(new Script
);
492 if (mState
) destroy();
493 mState
= luaL_newstate();
494 lua_pushlightuserdata(mState
, this);
495 lua_setfield(mState
, LUA_REGISTRYINDEX
, "_script_obj");
499 void importStandardLibraries()
501 luaL_openlibs(mState
);
504 void importBaseLibrary()
506 lua_pushcfunction(mState
, luaopen_base
);
511 void importPackageLibrary()
513 lua_pushcfunction(mState
, luaopen_package
);
514 push(LUA_LOADLIBNAME
);
518 void importStringLibrary()
520 lua_pushcfunction(mState
, luaopen_string
);
521 push(LUA_STRLIBNAME
);
525 void importTableLibrary()
527 lua_pushcfunction(mState
, luaopen_table
);
528 push(LUA_TABLIBNAME
);
532 void importMathLibrary()
534 lua_pushcfunction(mState
, luaopen_math
);
535 push(LUA_MATHLIBNAME
);
539 void importIoLibrary()
541 lua_pushcfunction(mState
, luaopen_io
);
546 void importOsLibrary()
548 lua_pushcfunction(mState
, luaopen_os
);
553 void importDebugLibrary()
555 lua_pushcfunction(mState
, luaopen_debug
);
561 void importFunction(const std::string
& name
, const Function
& function
)
564 lua_setglobal(mState
, name
.c_str());
568 Status
doString(const std::string
& commands
)
570 return (Status
)luaL_dostring(mState
, commands
.c_str());
573 Status
doFile(const std::string
& file
)
575 return (Status
)luaL_dofile(mState
, file
.c_str());
580 * Thread-handling methods.
583 Script
pushNewThread()
585 return Script(mState
);
590 lua_pushthread(mState
);
593 Status
resume(int nargs
)
595 return (Status
)lua_resume(mState
, nargs
);
598 Status
getStatus() const
600 return (Status
)lua_status(mState
);
603 int yield(int results
)
605 return lua_yield(mState
, results
);
608 bool isMainThread() const
610 return mIsMainThread
;
615 * Throw an error with the value at the top of the stack. This method never
616 * returns because it does a long jump. Consequently, constructed C++
617 * objects which exist on the stack between the current frame and some lua
618 * function will not be destructed. That's not a problem for objects that
619 * only exist on the stack, but any objects that allocate memory on the heap
620 * (such as containers or strings) will leak. Therefore, you should only
621 * call this method after cleaning up such objects.
631 * Get significant values.
634 Value
getGlobalTable() const
636 return Value(mState
, GLOBALS
);
639 Value
getRegistryTable() const
641 return Value(mState
, REGISTRY
);
644 Value
getEnvironmentTable() const
646 return Value(mState
, ENVIRONMENT
);
651 return Value(mState
, lua_gettop(mState
));
655 * Get the size of the stack; this is also the index of the top-most value.
660 return lua_gettop(mState
);
663 void setSize(int size
)
665 lua_settop(mState
, size
);
675 * Makes sure there is at least extra more places on the stack. Returns
676 * false if space couldn't be created. Just like with the regular Lua API,
677 * you are responsible to make sure the stack is big enough to hold whatever
678 * you want to push on it. This is usually only an issue if you're pushing
682 bool checkStack(int extra
)
684 return (bool)lua_checkstack(mState
, extra
);
689 * Concatenates the top-most n values on the stack.
694 lua_concat(mState
, n
);
699 * Push some values onto the stack.
702 template <typename T
>
705 lua_pushinteger(mState
, lua_Integer(value
));
708 void push(bool value
)
710 lua_pushboolean(mState
, int(value
));
713 void push(float value
)
715 lua_pushnumber(mState
, (lua_Number
)value
);
717 void push(double value
)
719 lua_pushnumber(mState
, (lua_Number
)value
);
722 void push(const std::string
& value
)
724 lua_pushlstring(mState
, value
.c_str(), value
.length());
726 void push(const char* value
)
728 lua_pushstring(mState
, value
);
730 void push(const char* value
, size_t length
)
732 lua_pushlstring(mState
, value
, length
);
735 void push(const Function
& function
)
737 mFunctions
.push_back(function
);
739 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
740 lua_pushcclosure(mState
, dispatchCall
, 1);
743 void push(void* data
)
745 lua_pushlightuserdata(mState
, data
);
753 void pushFromThread(Script
& thread
, int n
)
755 lua_xmove(thread
.mState
, mState
, n
);
758 Status
pushCode(const std::string
& filename
)
760 return (Status
)luaL_loadfile(mState
, filename
.c_str());
763 Status
pushCode(const std::string
& name
, const char* buffer
, size_t size
)
765 return (Status
)luaL_loadbuffer(mState
, buffer
, size
, name
.c_str());
768 void* pushNewData(size_t size
)
770 return lua_newuserdata(mState
, size
);
775 lua_newtable(mState
);
780 * Call a function on the stack. The correct procedure is to push a
781 * function onto the stack followed by nargs arguments. This method will
782 * pop them off upon return, leaving up to nresults return values (default
783 * is any number of return values, depending on the callee).
786 Status
call(int nargs
, int nresults
= LUA_MULTRET
)
788 return (Status
)lua_pcall(mState
, nargs
, nresults
, 0);
793 * Pops n values from the top of the stack.
803 * Index into the stack to get a Value.
806 Value
operator [] (int index
) const
808 return Value(mState
, index
);
813 * Getting and setting fields of a table.
816 void get(const std::string
& field
, int index
= GLOBALS
) const
818 lua_getfield(mState
, index
, field
.c_str());
821 void set(const std::string
& field
, int index
= GLOBALS
)
823 lua_setfield(mState
, index
, field
.c_str());
828 * Control over the garbage collection process.
833 lua_gc(mState
, LUA_GCCOLLECT
, 0);
838 lua_gc(mState
, LUA_GCSTOP
, 0);
841 void restartCollector()
843 lua_gc(mState
, LUA_GCRESTART
, 0);
846 int getUsedMemory() const
849 return lua_gc(mState
, LUA_GCCOUNT
, 0);
852 void collectStep(int step
)
854 lua_gc(mState
, LUA_GCSTEP
, step
);
857 void tuneCollector(int pause
, int step
)
859 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
860 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
866 Script(lua_State
* state
) :
867 mState(lua_newthread(state
)),
868 mIsMainThread(false) {}
870 static int dispatchCall(lua_State
* state
)
872 const Function
* function
= (const Function
*)lua_touserdata(state
,
873 lua_upvalueindex(1));
875 lua_getfield(state
, LUA_REGISTRYINDEX
, "_script_obj");
876 Script
* script
= (Script
*)lua_touserdata(state
, -1);
879 return (*function
)(*script
);
884 if (mIsMainThread
) lua_close(mState
);
889 std::list
<Function
> mFunctions
;
895 #endif // _MOOF_SCRIPT_HH_
897 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.081407 seconds and 4 git commands to generate.