X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FScript.hh;h=a1b536cf1a3d49786725c6ac8e07f57134ff84f6;hp=b48f5f440ae04b49f3a6f778cf3e3e3eb4d3ccb1;hb=8a1acac01b444dccf8b57cedf08392ada2e473c1;hpb=542e50a284c7f5b144a5c97c17f6d89b2af0175c diff --git a/src/Moof/Script.hh b/src/Moof/Script.hh index b48f5f4..a1b536c 100644 --- a/src/Moof/Script.hh +++ b/src/Moof/Script.hh @@ -39,7 +39,9 @@ */ #include +#include #include +#include #include #include @@ -47,7 +49,7 @@ #include -#include +#include namespace Mf { @@ -61,7 +63,7 @@ struct Script { typedef boost::function Function; - enum TYPE + enum Type { NONE = LUA_TNONE, NIL = LUA_TNIL, @@ -75,7 +77,7 @@ struct Script THREAD = LUA_TTHREAD }; - enum STATUS + enum Status { SUCCESS = 0, YIELD = LUA_YIELD, @@ -86,7 +88,7 @@ struct Script FILE_ERROR = LUA_ERRFILE }; - enum PSEUDO_INDEX + enum PseudoIndex { REGISTRY = LUA_REGISTRYINDEX, ENVIRONMENT = LUA_ENVIRONINDEX, @@ -94,7 +96,7 @@ struct Script }; /** - * This is the most noticeable abstraction on top of the standard Lua API. + * This is the most prominent abstraction on top of the standard Lua API. * A Value object represents a value on the stack. More specifically, it * represents a position on the stack. The distinction is only important * when values are moved around on the stack or if the Value represents a @@ -119,14 +121,22 @@ struct Script * Value will be invalid even if index is manually changed to a valid * index. You have to index the script itself to get a valid Value. */ - Value() : - index(0), - state(0) {} - - Value(lua_State* s, int i) : + Value(lua_State* s = 0, int i = 0) : index(i), state(s) {} + /** + * A copied value presently points to the same value, except the real + * index is used. That means that if a value that refers to a frame + * referenced from the top of the stack will have its normalized index + * copied into the new value object. + */ + + Value(const Value& copy) : + index(copy.getRealIndex()), + state(copy.state) {} + + // check the type of the value bool isBoolean() const { return (bool)lua_isboolean(state, index); } bool isFunction() const { return (bool)lua_isfunction(state, index); } @@ -141,13 +151,82 @@ struct Script bool isData() const { return (bool)lua_isuserdata(state, index); } bool isLightData() const { return (bool)lua_islightuserdata(state, index); } + /** + * Check the value and throw an error if its the wrong type. There's a + * little caveat: This method never returns because it does a long jump. + * Consequently, constructed C++ objects which exist on the stack + * between the current frame and some lua function will not be + * destructed. That's not a problem for objects that only exist on the + * stack, but any objects that allocate memory on the heap (such as + * containers or strings) will leak. Therefore, you should only call + * this method after cleaning up such objects. The best thing to do for + * defining functions is to simply check all the parameters at the + * get-go before any C++ objects are even constructed. + */ + + void requireType(Type type) const + { + if (type != getType()) + { + luaL_typerror(state, index, lua_typename(state, type)); + } + } + + void throwError(const char* error) + { + luaL_argerror(state, index, error); + } + + + Value& requireBoolean() + { + if (!isBoolean()) luaL_typerror(state, index, "boolean"); + return *this; + } + Value& requireNumber() + { + if (!isNumber()) luaL_typerror(state, index, "number"); + return *this; + } + Value& requireString() + { + if (!isString()) luaL_typerror(state, index, "string"); + return *this; + } + Value& requireTable() + { + if (!isTable()) luaL_typerror(state, index, "table"); + return *this; + } + Value& requireFunction() + { + if (!isFunction()) luaL_typerror(state, index, "function"); + return *this; + } + Value& requireData() + { + if (!isData()) luaL_typerror(state, index, "data"); + return *this; + } + Value& requireNil() + { + if (!isNil()) luaL_typerror(state, index, "nil"); + return *this; + } + Value& requireThread() + { + if (!isThread()) luaL_typerror(state, index, "thread"); + return *this; + } + + /** * Get the type of the value. */ - TYPE getType() const + Type getType() const { - return (TYPE)lua_type(state, index); + return (Type)lua_type(state, index); } /** @@ -156,9 +235,26 @@ struct Script std::string getTypeName() const { - return std::string(lua_typename(state, (int)getType())); + return std::string(luaL_typename(state, index)); + } + + + /** + * Get the length of the value according to the definition given by Lua. + */ + + size_t getLength() const + { + return lua_objlen(state, index); } + int getRealIndex() const + { + if (index < 0) return lua_gettop(state) + 1 + index; + else return index; + } + + /** * Get a pointer value (for userdata, tables, threads, and functions). */ @@ -206,61 +302,115 @@ struct Script } - /** - * Get the length of the value according to the definition given by Lua. - */ - - size_t getLength() const - { - return lua_objlen(state, index); - } - - /** * Convert the underlying value to a C++ type. */ template - void get(T& value) const + bool get(T& value) const { - value = (T)lua_tointeger(state, index); + if (isNumber()) + { + value = (T)lua_tointeger(state, index); + return true; + } + return false; } - void get(bool& value) const + bool get(float& value) const { - value = (bool)lua_toboolean(state, index); + if (isNumber()) + { + value = (float)lua_tonumber(state, index); + return true; + } + return false; } - - void get(float& value) const + bool get(double& value) const { - value = (float)lua_tonumber(state, index); + if (isNumber()) + { + value = (double)lua_tonumber(state, index); + return true; + } + return false; } - void get(double& value) const + + bool get(bool& value) const { - value = (double)lua_tonumber(state, index); + if (isBoolean()) + { + value = (bool)lua_toboolean(state, index); + return true; + } + return false; } - void get(std::string& value) const + bool get(std::string& value) const { - size_t size; - const char* str = lua_tolstring(state, index, &size); - value.assign(str, size); + if (isString()) + { + size_t size; + const char* str = lua_tolstring(state, index, &size); + value.assign(str, size); + return true; + } + return false; } + template + bool get(std::vector& array) const + { + if (!isTable()) return false; + + array.clear(); + + Value value(state, -1); + int realIndex = getRealIndex(); + + bool done = false; + for (int i = 1; !done; ++i) + { + lua_rawgeti(state, realIndex, i); + + T v; + if (value.get(v)) array.push_back(v); + else done = true; - void set(std::string& value) + lua_pop(state, 1); + } + + return true; + } + + template + bool get(std::map& dictionary) const { + if (!isTable()) return false; + + dictionary.clear(); + + Value key(state, -2); + Value value(state, -1); + int realIndex = getRealIndex(); + + lua_pushnil(state); + while (lua_next(state, realIndex) != 0) + { + std::string k; + if (!key.isNumber() && key.get(k)) + { + T v; + if (value.get(v)) dictionary[k] = v; + } + lua_pop(state, 1); + } + lua_pop(state, 1); + + return true; } - //template - //void get(const std::string& field, T& value) const - //{ - ////lua_getfield(state_, field.c_str()); - //pushField(field); - //get(-1, value); - //lua_pop(state_, 1); - //} - + /** * Copy the value and push the copy to the stack. @@ -319,15 +469,15 @@ struct Script Script() : - state_(luaL_newstate()) + mState(luaL_newstate()) { - lua_pushlightuserdata(state_, this); - lua_setfield(state_, LUA_REGISTRYINDEX, "_script_obj"); + lua_pushlightuserdata(mState, this); + lua_setfield(mState, LUA_REGISTRYINDEX, "_script_obj"); } ~Script() { - if (isMainThread_) lua_close(state_); + if (mIsMainThread) lua_close(mState); } @@ -339,24 +489,24 @@ struct Script void importStandardLibraries() { - luaL_openlibs(state_); + luaL_openlibs(mState); } void importFunction(const std::string& name, const Function& function) { push(function); - lua_setglobal(state_, name.c_str()); + lua_setglobal(mState, name.c_str()); } - STATUS doString(const std::string& commands) + Status doString(const std::string& commands) { - return (STATUS)luaL_dostring(state_, commands.c_str()); + return (Status)luaL_dostring(mState, commands.c_str()); } - STATUS doFile(const std::string& file) + Status doFile(const std::string& file) { - return (STATUS)luaL_dofile(state_, file.c_str()); + return (Status)luaL_dofile(mState, file.c_str()); } @@ -366,32 +516,48 @@ struct Script Script pushNewThread() { - return Script(state_); + return Script(mState); } void pushThread() { - lua_pushthread(state_); + lua_pushthread(mState); } - STATUS resume(int nargs) + Status resume(int nargs) { - return (STATUS)lua_resume(state_, nargs); + return (Status)lua_resume(mState, nargs); } - STATUS getStatus() const + Status getStatus() const { - return (STATUS)lua_status(state_); + return (Status)lua_status(mState); } int yield(int results) { - return lua_yield(state_, results); + return lua_yield(mState, results); } bool isMainThread() const { - return isMainThread_; + return mIsMainThread; + } + + + /** + * Throw an error with the value at the top of the stack. This method never + * returns because it does a long jump. Consequently, constructed C++ + * objects which exist on the stack between the current frame and some lua + * function will not be destructed. That's not a problem for objects that + * only exist on the stack, but any objects that allocate memory on the heap + * (such as containers or strings) will leak. Therefore, you should only + * call this method after cleaning up such objects. + */ + + void throwError() + { + lua_error(mState); } @@ -401,22 +567,22 @@ struct Script Value getGlobalTable() const { - return Value(state_, GLOBALS); + return Value(mState, GLOBALS); } Value getRegistryTable() const { - return Value(state_, REGISTRY); + return Value(mState, REGISTRY); } Value getEnvironmentTable() const { - return Value(state_, ENVIRONMENT); + return Value(mState, ENVIRONMENT); } Value getTop() const { - return Value(state_, lua_gettop(state_)); + return Value(mState, lua_gettop(mState)); } /** @@ -425,12 +591,12 @@ struct Script int getSize() const { - return lua_gettop(state_); + return lua_gettop(mState); } void setSize(int size) { - lua_settop(state_, size); + lua_settop(mState, size); } void clear() @@ -449,7 +615,7 @@ struct Script bool checkStack(int extra) { - return (bool)lua_checkstack(state_, extra); + return (bool)lua_checkstack(mState, extra); } @@ -459,7 +625,7 @@ struct Script void concat(int n) { - lua_concat(state_, n); + lua_concat(mState, n); } @@ -470,73 +636,77 @@ struct Script template void push(T value) { - lua_pushinteger(state_, lua_Integer(value)); + lua_pushinteger(mState, lua_Integer(value)); } void push(bool value) { - lua_pushboolean(state_, int(value)); + lua_pushboolean(mState, int(value)); } void push(float value) { - lua_pushnumber(state_, (lua_Number)value); + lua_pushnumber(mState, (lua_Number)value); } void push(double value) { - lua_pushnumber(state_, (lua_Number)value); + lua_pushnumber(mState, (lua_Number)value); } void push(const std::string& value) { - lua_pushlstring(state_, value.c_str(), value.length()); + lua_pushlstring(mState, value.c_str(), value.length()); + } + void push(const char* value) + { + lua_pushstring(mState, value); } void push(const char* value, size_t length) { - lua_pushlstring(state_, value, length); + lua_pushlstring(mState, value, length); } void push(const Function& function) { - functions_.push_back(function); + mFunctions.push_back(function); - lua_pushlightuserdata(state_, (void*)&functions_.back()); - lua_pushcclosure(state_, dispatchCall, 1); + lua_pushlightuserdata(mState, (void*)&mFunctions.back()); + lua_pushcclosure(mState, dispatchCall, 1); } void push(void* data) { - lua_pushlightuserdata(state_, data); + lua_pushlightuserdata(mState, data); } void pushNil() { - lua_pushnil(state_); + lua_pushnil(mState); } void pushFromThread(Script& thread, int n) { - lua_xmove(thread.state_, state_, n); + lua_xmove(thread.mState, mState, n); } - STATUS pushCode(const std::string& filename) + Status pushCode(const std::string& filename) { - return (STATUS)luaL_loadfile(state_, filename.c_str()); + return (Status)luaL_loadfile(mState, filename.c_str()); } - STATUS pushCode(const std::string& name, const char* buffer, size_t size) + Status pushCode(const std::string& name, const char* buffer, size_t size) { - return (STATUS)luaL_loadbuffer(state_, buffer, size, name.c_str()); + return (Status)luaL_loadbuffer(mState, buffer, size, name.c_str()); } void* pushNewData(size_t size) { - return lua_newuserdata(state_, size); + return lua_newuserdata(mState, size); } void pushNewTable() { - lua_newtable(state_); + lua_newtable(mState); } @@ -547,9 +717,9 @@ struct Script * is any number of return values, depending on the callee). */ - STATUS call(int nargs, int nresults = LUA_MULTRET) + Status call(int nargs, int nresults = LUA_MULTRET) { - return (STATUS)lua_pcall(state_, nargs, nresults, 0); + return (Status)lua_pcall(mState, nargs, nresults, 0); } @@ -557,9 +727,9 @@ struct Script * Pops n values from the top of the stack. */ - void pop(int n) + void pop(int n = 1) { - lua_pop(state_, n); + lua_pop(mState, n); } @@ -569,7 +739,7 @@ struct Script Value operator [] (int index) const { - return Value(state_, index); + return Value(mState, index); } @@ -579,12 +749,12 @@ struct Script void get(const std::string& field, int index = GLOBALS) const { - lua_getfield(state_, index, field.c_str()); + lua_getfield(mState, index, field.c_str()); } void set(const std::string& field, int index = GLOBALS) { - lua_setfield(state_, index, field.c_str()); + lua_setfield(mState, index, field.c_str()); } @@ -594,55 +764,41 @@ struct Script void collectAll() { - lua_gc(state_, LUA_GCCOLLECT, 0); + lua_gc(mState, LUA_GCCOLLECT, 0); } void stopCollector() { - lua_gc(state_, LUA_GCSTOP, 0); + lua_gc(mState, LUA_GCSTOP, 0); } void restartCollector() { - lua_gc(state_, LUA_GCRESTART, 0); + lua_gc(mState, LUA_GCRESTART, 0); } int getUsedMemory() const { // in kilobytes - return lua_gc(state_, LUA_GCCOUNT, 0); + return lua_gc(mState, LUA_GCCOUNT, 0); } void collectStep(int step) { - lua_gc(state_, LUA_GCSTEP, step); + lua_gc(mState, LUA_GCSTEP, step); } void tuneCollector(int pause, int step) { - lua_gc(state_, LUA_GCSETPAUSE, pause); - lua_gc(state_, LUA_GCSETSTEPMUL, step); + lua_gc(mState, LUA_GCSETPAUSE, pause); + lua_gc(mState, LUA_GCSETSTEPMUL, step); } - - - struct Exception : public Mf::Exception - { - explicit Exception(unsigned error) : - Mf::Exception(error) {} - - void raise() - { - throw *this; - } - }; - - private: Script(lua_State* state) : - state_(lua_newthread(state)), - isMainThread_(false) {} + mState(lua_newthread(state)), + mIsMainThread(false) {} static int dispatchCall(lua_State* state) { @@ -656,9 +812,9 @@ private: return (*function)(*script); } - lua_State* state_; - bool isMainThread_; - std::list functions_; + lua_State* mState; + bool mIsMainThread; + std::list mFunctions; };