]>
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.
47 #include <boost/bind.hpp>
48 #include <boost/function.hpp>
49 #include <boost/shared_ptr.hpp>
53 #include <Moof/Log.hh>
60 typedef boost::shared_ptr
<Script
> ScriptP
;
67 typedef boost::function
<int(Script
&)> Function
;
73 BOOLEAN
= LUA_TBOOLEAN
,
74 LIGHTUSERDATA
= LUA_TLIGHTUSERDATA
,
78 FUNCTION
= LUA_TFUNCTION
,
79 USERDATA
= LUA_TUSERDATA
,
87 RUNTIME_ERROR
= LUA_ERRRUN
,
88 SYNTAX_ERROR
= LUA_ERRSYNTAX
,
89 MEMORY_ERROR
= LUA_ERRMEM
,
90 HANDLER_ERROR
= LUA_ERRERR
,
91 FILE_ERROR
= LUA_ERRFILE
96 REGISTRY
= LUA_REGISTRYINDEX
,
97 ENVIRONMENT
= LUA_ENVIRONINDEX
,
98 GLOBALS
= LUA_GLOBALSINDEX
102 * This is the most prominent abstraction on top of the standard Lua API.
103 * A Slot object represents a value on the stack. More specifically, it
104 * represents a position on the stack. The distinction is only important
105 * when objects are moved around on the stack or if the Slot represents a
106 * negative index on the stack (the value of which will change as things are
107 * pushed onto and popped from the stack).
113 * You have direct access to the index of the value on the stack being
121 * A default-constructed Slot is invalid until a valid Slot is assigned
122 * to it. The only method that should be called on such a Slot is
123 * isValid(), otherwise chaos may ensue. In this case, the Slot will be
124 * invalid even if index is manually changed to a valid index. You have
125 * to index the script itself to get a valid Slot.
127 Slot(lua_State
* s
= 0, int i
= 0) :
132 * A copied value presently points to the same value, except the real
133 * index is used. That means that if a value that refers to a frame
134 * referenced from the top of the stack will have its normalized index
135 * copied into the new value object.
138 Slot(const Slot
& copy
) :
139 index(copy
.getRealIndex()),
140 mState(copy
.mState
) {}
143 // check the type of the value
144 bool isBoolean() const { return (bool)lua_isboolean(mState
, index
); }
145 bool isFunction() const { return (bool)lua_isfunction(mState
, index
); }
146 bool isNil() const { return (bool)lua_isnil(mState
, index
); }
147 bool isNone() const { return (bool)lua_isnone(mState
, index
); }
148 bool isValid() const { return mState
!= 0 && !isNone(); }
149 bool isNoneOrNil() const { return (bool)lua_isnoneornil(mState
, index
); }
150 bool isNumber() const { return (bool)lua_isnumber(mState
, index
); }
151 bool isString() const { return (bool)lua_isstring(mState
, index
); }
152 bool isTable() const { return (bool)lua_istable(mState
, index
); }
153 bool isThread() const { return (bool)lua_isthread(mState
, index
); }
154 bool isData() const { return (bool)lua_isuserdata(mState
, index
); }
155 bool isLightData() const { return (bool)lua_islightuserdata(mState
, index
); }
158 * Check the value and throw an error if its the wrong type. There's a
159 * little caveat: This method never returns because it does a long jump.
160 * Consequently, constructed C++ objects which exist on the stack
161 * between the current frame and some lua function will not be
162 * destructed. That's not a problem for objects that only exist on the
163 * stack, but any objects that allocate memory on the heap (such as
164 * containers or strings) will leak. Therefore, you should only call
165 * this method after cleaning up such objects. The best thing to do for
166 * defining functions is to simply check all the parameters at the
167 * get-go before any C++ objects are even constructed.
170 void requireType(Type type
) const
172 if (type
!= getType())
174 luaL_typerror(mState
, index
, lua_typename(mState
, type
));
178 void throwError(const char* error
)
180 luaL_argerror(mState
, index
, error
);
184 Slot
& requireBoolean()
186 if (!isBoolean()) luaL_typerror(mState
, index
, "boolean");
189 Slot
& requireNumber()
191 if (!isNumber()) luaL_typerror(mState
, index
, "number");
194 Slot
& requireString()
196 if (!isString()) luaL_typerror(mState
, index
, "string");
201 if (!isTable()) luaL_typerror(mState
, index
, "table");
204 Slot
& requireFunction()
206 if (!isFunction()) luaL_typerror(mState
, index
, "function");
211 if (!isData()) luaL_typerror(mState
, index
, "data");
216 if (!isNil()) luaL_typerror(mState
, index
, "nil");
219 Slot
& requireThread()
221 if (!isThread()) luaL_typerror(mState
, index
, "thread");
227 * Get the type of the value.
232 return (Type
)lua_type(mState
, index
);
236 * Get the name of the type of the value as a string.
239 std::string
getTypeName() const
241 return std::string(luaL_typename(mState
, index
));
246 * Get the length of the value according to the definition given by Lua.
249 size_t getLength() const
251 return lua_objlen(mState
, index
);
254 int getRealIndex() const
256 if (index
< 0) return lua_gettop(mState
) + 1 + index
;
262 * Get a pointer value (for userdata, tables, threads, and functions).
265 const void* getIdentifier() const
267 return lua_topointer(mState
, index
);
271 bool operator == (const Slot
& rhs
) const
273 return (bool)lua_equal(mState
, index
, rhs
.index
);
275 bool operator != (const Slot
& rhs
) const
277 return !(*this == rhs
);
279 bool operator < (const Slot
& rhs
) const
281 return (bool)lua_lessthan(mState
, index
, rhs
.index
);
283 bool operator <= (const Slot
& rhs
) const
285 return *this < rhs
|| *this == rhs
;
287 bool operator > (const Slot
& rhs
) const
289 return !(*this <= rhs
);
291 bool operator >= (const Slot
& rhs
) const
293 return !(*this < rhs
);
295 operator bool () const
297 return (bool)lua_toboolean(mState
, index
);
300 Slot
& operator = (const Slot
& rhs
)
309 * Convert the underlying value to a C++ type.
312 template <typename T
>
313 bool get(T
& value
) const
317 value
= (T
)lua_tointeger(mState
, index
);
323 bool get(float& value
) const
327 value
= (float)lua_tonumber(mState
, index
);
332 bool get(double& value
) const
336 value
= (double)lua_tonumber(mState
, index
);
342 bool get(bool& value
) const
346 value
= (bool)lua_toboolean(mState
, index
);
352 bool get(std::string
& value
) const
357 const char* str
= lua_tolstring(mState
, index
, &size
);
358 value
.assign(str
, size
);
364 template <typename T
>
365 bool get(std::vector
<T
>& array
) const
367 if (!isTable()) return false;
371 Slot
value(mState
, -1);
372 int realIndex
= getRealIndex();
375 for (int i
= 1; !done
; ++i
)
377 lua_rawgeti(mState
, realIndex
, i
);
380 if (value
.get(v
)) array
.push_back(v
);
389 template <typename T
>
390 bool get(std::map
<std::string
,T
>& dictionary
) const
392 if (!isTable()) return false;
396 Slot
key(mState
, -2);
397 Slot
value(mState
, -1);
398 int realIndex
= getRealIndex();
401 while (lua_next(mState
, realIndex
) != 0)
404 if (!key
.isNumber() && key
.get(k
))
407 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(mState
, index
);
427 * Replace this value with the value at the top of the stack.
430 void replaceWithTop()
432 lua_replace(mState
, index
);
437 lua_remove(mState
, index
);
441 * Inserts the top-most value on the stack at position index, shifting other
447 lua_insert(mState
, index
);
451 void pushMetatable() const
453 lua_getmetatable(mState
, index
);
456 void pushField() const
458 lua_gettable(mState
, index
);
461 void pushField(const std::string
& name
) const
463 lua_getfield(mState
, index
, name
.c_str());
466 void pushField(size_t index
) const
468 lua_pushinteger(mState
, lua_Integer(index
));
491 static ScriptP
alloc()
493 return ScriptP(new Script
);
498 if (mState
) destroy();
499 mState
= luaL_newstate();
500 lua_pushlightuserdata(mState
, this);
501 lua_setfield(mState
, LUA_REGISTRYINDEX
, "Script_hh_Object");
505 void importStandardLibraries()
507 luaL_openlibs(mState
);
510 void importBaseLibrary()
512 lua_pushcfunction(mState
, luaopen_base
);
517 void importPackageLibrary()
519 lua_pushcfunction(mState
, luaopen_package
);
520 push(LUA_LOADLIBNAME
);
524 void importStringLibrary()
526 lua_pushcfunction(mState
, luaopen_string
);
527 push(LUA_STRLIBNAME
);
531 void importTableLibrary()
533 lua_pushcfunction(mState
, luaopen_table
);
534 push(LUA_TABLIBNAME
);
538 void importMathLibrary()
540 lua_pushcfunction(mState
, luaopen_math
);
541 push(LUA_MATHLIBNAME
);
545 void importIoLibrary()
547 lua_pushcfunction(mState
, luaopen_io
);
552 void importOsLibrary()
554 lua_pushcfunction(mState
, luaopen_os
);
559 void importDebugLibrary()
561 lua_pushcfunction(mState
, luaopen_debug
);
567 void importFunction(const std::string
& name
, const Function
& function
)
570 lua_setglobal(mState
, name
.c_str());
574 Result
doString(const std::string
& commands
)
576 return (Result
)luaL_dostring(mState
, commands
.c_str());
579 Result
doFile(const std::string
& file
)
581 return (Result
)luaL_dofile(mState
, file
.c_str());
586 * Thread-handling methods.
589 Script
pushNewThread()
591 return Script(mState
);
596 lua_pushthread(mState
);
599 Result
resume(int nargs
)
601 return (Result
)lua_resume(mState
, nargs
);
604 Result
getStatus() const
606 return (Result
)lua_status(mState
);
609 int yield(int results
)
611 return lua_yield(mState
, results
);
614 bool isMainThread() const
616 return mIsMainThread
;
621 * Throw an error with the value at the top of the stack. This method never
622 * returns because it does a long jump. Consequently, constructed C++
623 * objects which exist on the stack between the current frame and some lua
624 * function will not be destructed. That's not a problem for objects that
625 * only exist on the stack, but any objects that allocate memory on the heap
626 * (such as containers or strings) will leak. Therefore, you should only
627 * call this method 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 value.
666 return lua_gettop(mState
);
669 void setSize(int size
)
671 lua_settop(mState
, size
);
681 * Makes sure there is at least extra more places on the stack. Returns
682 * false if space couldn't be created. Just like with the regular Lua API,
683 * you are responsible to make sure the stack is big enough to hold whatever
684 * you want to push on it. This is usually only an issue if you're pushing
688 bool checkStack(int extra
)
690 return (bool)lua_checkstack(mState
, extra
);
695 * Concatenates the top-most n slots on the stack.
698 void concat(int n
= 2)
700 lua_concat(mState
, n
);
705 * Push some values onto the stack.
708 template <typename T
>
711 lua_pushinteger(mState
, lua_Integer(value
));
714 void push(bool value
)
716 lua_pushboolean(mState
, int(value
));
719 void push(float value
)
721 lua_pushnumber(mState
, (lua_Number
)value
);
723 void push(double value
)
725 lua_pushnumber(mState
, (lua_Number
)value
);
728 void push(const std::string
& value
)
730 lua_pushlstring(mState
, value
.c_str(), value
.length());
732 void push(const char* value
)
734 lua_pushstring(mState
, value
);
736 void push(const char* value
, size_t length
)
738 lua_pushlstring(mState
, value
, length
);
741 void push(const Function
& function
)
743 mFunctions
.push_back(function
);
745 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
746 lua_pushcclosure(mState
, dispatchCall
, 1);
749 void push(void* data
)
751 lua_pushlightuserdata(mState
, data
);
759 void pushFromThread(Script
& thread
, int n
)
761 lua_xmove(thread
.mState
, mState
, n
);
764 Result
pushCode(const std::string
& filename
)
766 return (Result
)luaL_loadfile(mState
, filename
.c_str());
769 Result
pushCode(const std::string
& name
, const char* buffer
, size_t size
)
771 return (Result
)luaL_loadbuffer(mState
, buffer
, size
, name
.c_str());
774 void* pushNewData(size_t size
)
776 return lua_newuserdata(mState
, size
);
781 lua_newtable(mState
);
786 * Call a function on the stack. The correct procedure is to push a
787 * function onto the stack followed by nargs arguments. This method will
788 * pop them off upon return, leaving up to nresults return values (default
789 * is any number of return values, depending on the callee).
792 Result
call(int nargs
= 0, int nresults
= LUA_MULTRET
)
794 return (Result
)lua_pcall(mState
, nargs
, nresults
, 0);
799 * Pops n values from the top of the stack.
809 * Index into the stack to get a Slot.
812 Slot
operator [] (int index
) const
814 return Slot(mState
, index
);
819 * Getting and setting fields of a table.
822 void pushField(const std::string
& field
, int index
= GLOBALS
) const
824 lua_getfield(mState
, index
, field
.c_str());
827 void set(const std::string
& field
, int index
= GLOBALS
)
829 lua_setfield(mState
, index
, field
.c_str());
834 * Control over the garbage collection process.
839 lua_gc(mState
, LUA_GCCOLLECT
, 0);
844 lua_gc(mState
, LUA_GCSTOP
, 0);
847 void restartCollector()
849 lua_gc(mState
, LUA_GCRESTART
, 0);
852 int getUsedMemory() const
855 return lua_gc(mState
, LUA_GCCOUNT
, 0);
858 void collectStep(int step
)
860 lua_gc(mState
, LUA_GCSTEP
, step
);
863 void tuneCollector(int pause
, int step
)
865 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
866 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
872 Script(lua_State
* state
) :
873 mState(lua_newthread(state
)),
874 mIsMainThread(false) {}
876 static int dispatchCall(lua_State
* state
)
878 const Function
* function
= (const Function
*)lua_touserdata(state
,
879 lua_upvalueindex(1));
881 lua_getfield(state
, LUA_REGISTRYINDEX
, "Script_hh_Object");
882 Script
* script
= (Script
*)lua_touserdata(state
, -1);
885 return (*function
)(*script
);
890 if (mIsMainThread
) lua_close(mState
);
895 std::list
<Function
> mFunctions
;
899 inline std::ostream
& operator << (std::ostream
& stream
,
900 const Script::Slot
& slot
)
908 else if (slot
.isBoolean())
910 if (slot
) stream
<< "true";
911 else stream
<< "false";
913 else if (slot
.isNil())
919 stream
<< slot
.getTypeName() << " (" << slot
.getIdentifier() << ")";
928 #endif // _MOOF_SCRIPT_HH_
930 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.082939 seconds and 4 git commands to generate.