]>
Dogcows Code - chaz/yoink/blob - src/Moof/Script.hh
a1b536cf1a3d49786725c6ac8e07f57134ff84f6
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
;
64 typedef boost::function
<int(Script
&)> Function
;
70 BOOLEAN
= LUA_TBOOLEAN
,
71 LIGHTUSERDATA
= LUA_TLIGHTUSERDATA
,
75 FUNCTION
= LUA_TFUNCTION
,
76 USERDATA
= LUA_TUSERDATA
,
84 RUNTIME_ERROR
= LUA_ERRRUN
,
85 SYNTAX_ERROR
= LUA_ERRSYNTAX
,
86 MEMORY_ERROR
= LUA_ERRMEM
,
87 HANDLER_ERROR
= LUA_ERRERR
,
88 FILE_ERROR
= LUA_ERRFILE
93 REGISTRY
= LUA_REGISTRYINDEX
,
94 ENVIRONMENT
= LUA_ENVIRONINDEX
,
95 GLOBALS
= LUA_GLOBALSINDEX
99 * This is the most prominent abstraction on top of the standard Lua API.
100 * A Value object represents a value on the stack. More specifically, it
101 * represents a position on the stack. The distinction is only important
102 * when values are moved around on the stack or if the Value represents a
103 * negative index on the stack (the value of which will change as things are
104 * pushed onto and popped from the stack).
110 * You have direct access to the index of the value on the stack being
118 * A default-constructed Value is invalid until a valid Value is
119 * assigned to it. The only method that should be called on such a
120 * Value is isValid(), otherwise chaos may ensue. In this case, the
121 * Value will be invalid even if index is manually changed to a valid
122 * index. You have to index the script itself to get a valid Value.
124 Value(lua_State
* s
= 0, int i
= 0) :
129 * A copied value presently points to the same value, except the real
130 * index is used. That means that if a value that refers to a frame
131 * referenced from the top of the stack will have its normalized index
132 * copied into the new value object.
135 Value(const Value
& copy
) :
136 index(copy
.getRealIndex()),
140 // check the type of the value
141 bool isBoolean() const { return (bool)lua_isboolean(state
, index
); }
142 bool isFunction() const { return (bool)lua_isfunction(state
, index
); }
143 bool isNil() const { return (bool)lua_isnil(state
, index
); }
144 bool isNone() const { return (bool)lua_isnone(state
, index
); }
145 bool isValid() const { return state
!= 0 && !isNone(); }
146 bool isNoneOrNil() const { return (bool)lua_isnoneornil(state
, index
); }
147 bool isNumber() const { return (bool)lua_isnumber(state
, index
); }
148 bool isString() const { return (bool)lua_isstring(state
, index
); }
149 bool isTable() const { return (bool)lua_istable(state
, index
); }
150 bool isThread() const { return (bool)lua_isthread(state
, index
); }
151 bool isData() const { return (bool)lua_isuserdata(state
, index
); }
152 bool isLightData() const { return (bool)lua_islightuserdata(state
, index
); }
155 * Check the value and throw an error if its the wrong type. There's a
156 * little caveat: This method never returns because it does a long jump.
157 * Consequently, constructed C++ objects which exist on the stack
158 * between the current frame and some lua function will not be
159 * destructed. That's not a problem for objects that only exist on the
160 * stack, but any objects that allocate memory on the heap (such as
161 * containers or strings) will leak. Therefore, you should only call
162 * this method after cleaning up such objects. The best thing to do for
163 * defining functions is to simply check all the parameters at the
164 * get-go before any C++ objects are even constructed.
167 void requireType(Type type
) const
169 if (type
!= getType())
171 luaL_typerror(state
, index
, lua_typename(state
, type
));
175 void throwError(const char* error
)
177 luaL_argerror(state
, index
, error
);
181 Value
& requireBoolean()
183 if (!isBoolean()) luaL_typerror(state
, index
, "boolean");
186 Value
& requireNumber()
188 if (!isNumber()) luaL_typerror(state
, index
, "number");
191 Value
& requireString()
193 if (!isString()) luaL_typerror(state
, index
, "string");
196 Value
& requireTable()
198 if (!isTable()) luaL_typerror(state
, index
, "table");
201 Value
& requireFunction()
203 if (!isFunction()) luaL_typerror(state
, index
, "function");
208 if (!isData()) luaL_typerror(state
, index
, "data");
213 if (!isNil()) luaL_typerror(state
, index
, "nil");
216 Value
& requireThread()
218 if (!isThread()) luaL_typerror(state
, index
, "thread");
224 * Get the type of the value.
229 return (Type
)lua_type(state
, index
);
233 * Get the name of the type of the value as a string.
236 std::string
getTypeName() const
238 return std::string(luaL_typename(state
, index
));
243 * Get the length of the value according to the definition given by Lua.
246 size_t getLength() const
248 return lua_objlen(state
, index
);
251 int getRealIndex() const
253 if (index
< 0) return lua_gettop(state
) + 1 + index
;
259 * Get a pointer value (for userdata, tables, threads, and functions).
262 const void* getIdentifier() const
264 return lua_topointer(state
, index
);
268 bool operator == (const Value
& rhs
) const
270 return (bool)lua_equal(state
, index
, rhs
.index
);
272 bool operator != (const Value
& rhs
) const
274 return !(*this == rhs
);
276 bool operator < (const Value
& rhs
) const
278 return (bool)lua_lessthan(state
, index
, rhs
.index
);
280 bool operator <= (const Value
& rhs
) const
282 return *this < rhs
|| *this == rhs
;
284 bool operator > (const Value
& rhs
) const
286 return !(*this <= rhs
);
288 bool operator >= (const Value
& rhs
) const
290 return !(*this < rhs
);
292 operator bool () const
294 return (bool)lua_toboolean(state
, index
);
297 Value
& operator = (const Value
& rhs
)
306 * Convert the underlying value to a C++ type.
309 template <typename T
>
310 bool get(T
& value
) const
314 value
= (T
)lua_tointeger(state
, index
);
320 bool get(float& value
) const
324 value
= (float)lua_tonumber(state
, index
);
329 bool get(double& value
) const
333 value
= (double)lua_tonumber(state
, index
);
339 bool get(bool& value
) const
343 value
= (bool)lua_toboolean(state
, index
);
349 bool get(std::string
& value
) const
354 const char* str
= lua_tolstring(state
, index
, &size
);
355 value
.assign(str
, size
);
361 template <typename T
>
362 bool get(std::vector
<T
>& array
) const
364 if (!isTable()) return false;
368 Value
value(state
, -1);
369 int realIndex
= getRealIndex();
372 for (int i
= 1; !done
; ++i
)
374 lua_rawgeti(state
, realIndex
, i
);
377 if (value
.get(v
)) array
.push_back(v
);
386 template <typename T
>
387 bool get(std::map
<std::string
,T
>& dictionary
) const
389 if (!isTable()) return false;
393 Value
key(state
, -2);
394 Value
value(state
, -1);
395 int realIndex
= getRealIndex();
398 while (lua_next(state
, realIndex
) != 0)
401 if (!key
.isNumber() && key
.get(k
))
404 if (value
.get(v
)) dictionary
[k
] = v
;
416 * Copy the value and push the copy to the stack.
419 void pushCopy() const
421 lua_pushvalue(state
, index
);
425 * Replace this value with the value at the top of the stack.
428 void replaceWithTop()
430 lua_replace(state
, index
);
435 lua_remove(state
, index
);
439 * Inserts the top-most value on the stack at position index, shifting other
445 lua_insert(state
, index
);
449 void pushMetatable() const
451 lua_getmetatable(state
, index
);
454 void pushField() const
456 lua_gettable(state
, index
);
459 void pushField(const std::string
& name
) const
461 lua_getfield(state
, index
, name
.c_str());
472 mState(luaL_newstate())
474 lua_pushlightuserdata(mState
, this);
475 lua_setfield(mState
, LUA_REGISTRYINDEX
, "_script_obj");
480 if (mIsMainThread
) lua_close(mState
);
484 static ScriptP
alloc()
486 return ScriptP(new Script
);
490 void importStandardLibraries()
492 luaL_openlibs(mState
);
495 void importFunction(const std::string
& name
, const Function
& function
)
498 lua_setglobal(mState
, name
.c_str());
502 Status
doString(const std::string
& commands
)
504 return (Status
)luaL_dostring(mState
, commands
.c_str());
507 Status
doFile(const std::string
& file
)
509 return (Status
)luaL_dofile(mState
, file
.c_str());
514 * Thread-handling methods.
517 Script
pushNewThread()
519 return Script(mState
);
524 lua_pushthread(mState
);
527 Status
resume(int nargs
)
529 return (Status
)lua_resume(mState
, nargs
);
532 Status
getStatus() const
534 return (Status
)lua_status(mState
);
537 int yield(int results
)
539 return lua_yield(mState
, results
);
542 bool isMainThread() const
544 return mIsMainThread
;
549 * Throw an error with the value at the top of the stack. This method never
550 * returns because it does a long jump. Consequently, constructed C++
551 * objects which exist on the stack between the current frame and some lua
552 * function will not be destructed. That's not a problem for objects that
553 * only exist on the stack, but any objects that allocate memory on the heap
554 * (such as containers or strings) will leak. Therefore, you should only
555 * call this method after cleaning up such objects.
565 * Get significant values.
568 Value
getGlobalTable() const
570 return Value(mState
, GLOBALS
);
573 Value
getRegistryTable() const
575 return Value(mState
, REGISTRY
);
578 Value
getEnvironmentTable() const
580 return Value(mState
, ENVIRONMENT
);
585 return Value(mState
, lua_gettop(mState
));
589 * Get the size of the stack; this is also the index of the top-most value.
594 return lua_gettop(mState
);
597 void setSize(int size
)
599 lua_settop(mState
, size
);
609 * Makes sure there is at least extra more places on the stack. Returns
610 * false if space couldn't be created. Just like with the regular Lua API,
611 * you are responsible to make sure the stack is big enough to hold whatever
612 * you want to push on it. This is usually only an issue if you're pushing
616 bool checkStack(int extra
)
618 return (bool)lua_checkstack(mState
, extra
);
623 * Concatenates the top-most n values on the stack.
628 lua_concat(mState
, n
);
633 * Push some values onto the stack.
636 template <typename T
>
639 lua_pushinteger(mState
, lua_Integer(value
));
642 void push(bool value
)
644 lua_pushboolean(mState
, int(value
));
647 void push(float value
)
649 lua_pushnumber(mState
, (lua_Number
)value
);
651 void push(double value
)
653 lua_pushnumber(mState
, (lua_Number
)value
);
656 void push(const std::string
& value
)
658 lua_pushlstring(mState
, value
.c_str(), value
.length());
660 void push(const char* value
)
662 lua_pushstring(mState
, value
);
664 void push(const char* value
, size_t length
)
666 lua_pushlstring(mState
, value
, length
);
669 void push(const Function
& function
)
671 mFunctions
.push_back(function
);
673 lua_pushlightuserdata(mState
, (void*)&mFunctions
.back());
674 lua_pushcclosure(mState
, dispatchCall
, 1);
677 void push(void* data
)
679 lua_pushlightuserdata(mState
, data
);
687 void pushFromThread(Script
& thread
, int n
)
689 lua_xmove(thread
.mState
, mState
, n
);
692 Status
pushCode(const std::string
& filename
)
694 return (Status
)luaL_loadfile(mState
, filename
.c_str());
697 Status
pushCode(const std::string
& name
, const char* buffer
, size_t size
)
699 return (Status
)luaL_loadbuffer(mState
, buffer
, size
, name
.c_str());
702 void* pushNewData(size_t size
)
704 return lua_newuserdata(mState
, size
);
709 lua_newtable(mState
);
714 * Call a function on the stack. The correct procedure is to push a
715 * function onto the stack followed by nargs arguments. This method will
716 * pop them off upon return, leaving up to nresults return values (default
717 * is any number of return values, depending on the callee).
720 Status
call(int nargs
, int nresults
= LUA_MULTRET
)
722 return (Status
)lua_pcall(mState
, nargs
, nresults
, 0);
727 * Pops n values from the top of the stack.
737 * Index into the stack to get a Value.
740 Value
operator [] (int index
) const
742 return Value(mState
, index
);
747 * Getting and setting fields of a table.
750 void get(const std::string
& field
, int index
= GLOBALS
) const
752 lua_getfield(mState
, index
, field
.c_str());
755 void set(const std::string
& field
, int index
= GLOBALS
)
757 lua_setfield(mState
, index
, field
.c_str());
762 * Control over the garbage collection process.
767 lua_gc(mState
, LUA_GCCOLLECT
, 0);
772 lua_gc(mState
, LUA_GCSTOP
, 0);
775 void restartCollector()
777 lua_gc(mState
, LUA_GCRESTART
, 0);
780 int getUsedMemory() const
783 return lua_gc(mState
, LUA_GCCOUNT
, 0);
786 void collectStep(int step
)
788 lua_gc(mState
, LUA_GCSTEP
, step
);
791 void tuneCollector(int pause
, int step
)
793 lua_gc(mState
, LUA_GCSETPAUSE
, pause
);
794 lua_gc(mState
, LUA_GCSETSTEPMUL
, step
);
799 Script(lua_State
* state
) :
800 mState(lua_newthread(state
)),
801 mIsMainThread(false) {}
803 static int dispatchCall(lua_State
* state
)
805 const Function
* function
= (const Function
*)lua_touserdata(state
,
806 lua_upvalueindex(1));
808 lua_getfield(state
, LUA_REGISTRYINDEX
, "_script_obj");
809 Script
* script
= (Script
*)lua_touserdata(state
, -1);
812 return (*function
)(*script
);
817 std::list
<Function
> mFunctions
;
823 #endif // _MOOF_SCRIPT_HH_
825 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.067663 seconds and 4 git commands to generate.