X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FScript.hh;h=9af54402ae74846e88418531d8b679e71595c02d;hp=df00619d69e59b4dafcf644d5782e2ab53ac1eac;hb=837bae9f2bf7b25e1d3d2625eeaf39c1d2f48827;hpb=2fdb5f5824826a6c54f5afde8c62eafd24c1a152 diff --git a/src/Moof/Script.hh b/src/Moof/Script.hh index df00619..9af5440 100644 --- a/src/Moof/Script.hh +++ b/src/Moof/Script.hh @@ -1,43 +1,27 @@ -/******************************************************************************* - - Copyright (c) 2009, Charles McGarvey - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*******************************************************************************/ +/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +**] All rights reserved. +* +* vi:ts=4 sw=4 tw=75 +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +**************************************************************************/ #ifndef _MOOF_SCRIPT_HH_ #define _MOOF_SCRIPT_HH_ /** * @file Script.hh - * A thin wrapper over Lua. This is not meant as a complicated binding package - * between C++ and Lua. It does not try to make the boundary invisible. It - * does not hide the concept of the Lua stack, but rather provides that - * mechanism with a certain level of abstraction while also providing a cleaner, - * more consistent API. + * A thin wrapper over Lua. This is not meant as a complicated binding + * package between C++ and Lua. It does not try to make the boundary + * invisible. It does not hide the concept of the Lua stack, but rather + * provides that mechanism with a certain level of abstraction while also + * providing a cleaner, more consistent API. */ +#include #include #include #include @@ -46,7 +30,6 @@ #include #include #include - #include #include @@ -79,7 +62,7 @@ public: THREAD = LUA_TTHREAD }; - enum Status + enum Result { SUCCESS = 0, YIELD = LUA_YIELD, @@ -98,126 +81,141 @@ public: }; /** - * 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 - * negative index on the stack (the value of which will change as things are - * pushed onto and popped from the stack). + * This is the most prominent abstraction on top of the standard Lua + * API. A Slot object represents a value on the stack. More + * specifically, it represents a position on the stack. The + * distinction is only important when objects are moved around on the + * stack or if the Slot represents a negative index on the stack (the + * value of which will change as things are pushed onto and popped from + * the stack). */ - struct Value + struct Slot { /** - * You have direct access to the index of the value on the stack being - * represented. + * You have direct access to the index of the value on the stack + * being represented. */ int index; /** - * A default-constructed Value is invalid until a valid Value is + * A default-constructed Slot is invalid until a valid Slot is * assigned to it. The only method that should be called on such a - * Value is isValid(), otherwise chaos may ensue. In this case, the - * 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. + * Slot is isValid(), otherwise chaos may ensue. In this case, the + * Slot will be invalid even if index is manually changed to a + * valid index. You have to index the script itself to get a valid + * Slot. */ - Value(lua_State* s = 0, int i = 0) : + Slot(lua_State* s = 0, int i = 0) : index(i), - state(s) {} + mState(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. + * 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) : + Slot(const Slot& copy) : index(copy.getRealIndex()), - state(copy.state) {} + mState(copy.mState) {} // check the type of the value - bool isBoolean() const { return (bool)lua_isboolean(state, index); } - bool isFunction() const { return (bool)lua_isfunction(state, index); } - bool isNil() const { return (bool)lua_isnil(state, index); } - bool isNone() const { return (bool)lua_isnone(state, index); } - bool isValid() const { return state != 0 && !isNone(); } - bool isNoneOrNil() const { return (bool)lua_isnoneornil(state, index); } - bool isNumber() const { return (bool)lua_isnumber(state, index); } - bool isString() const { return (bool)lua_isstring(state, index); } - bool isTable() const { return (bool)lua_istable(state, index); } - bool isThread() const { return (bool)lua_isthread(state, index); } - bool isData() const { return (bool)lua_isuserdata(state, index); } - bool isLightData() const { return (bool)lua_islightuserdata(state, index); } + bool isBoolean() const + { return (bool)lua_isboolean(mState, index); } + bool isFunction() const + { return (bool)lua_isfunction(mState, index); } + bool isNil() const + { return (bool)lua_isnil(mState, index); } + bool isNone() const + { return (bool)lua_isnone(mState, index); } + bool isValid() const + { return mState != 0 && !isNone(); } + bool isNoneOrNil() const + { return (bool)lua_isnoneornil(mState, index); } + bool isNumber() const + { return (bool)lua_isnumber(mState, index); } + bool isString() const + { return (bool)lua_isstring(mState, index); } + bool isTable() const + { return (bool)lua_istable(mState, index); } + bool isThread() const + { return (bool)lua_isthread(mState, index); } + bool isData() const + { return (bool)lua_isuserdata(mState, index); } + bool isLightData() const + { return (bool)lua_islightuserdata(mState, 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. + * 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)); + luaL_typerror(mState, index, lua_typename(mState, type)); } } void throwError(const char* error) { - luaL_argerror(state, index, error); + luaL_argerror(mState, index, error); } - Value& requireBoolean() + Slot& requireBoolean() { - if (!isBoolean()) luaL_typerror(state, index, "boolean"); + if (!isBoolean()) luaL_typerror(mState, index, "boolean"); return *this; } - Value& requireNumber() + Slot& requireNumber() { - if (!isNumber()) luaL_typerror(state, index, "number"); + if (!isNumber()) luaL_typerror(mState, index, "number"); return *this; } - Value& requireString() + Slot& requireString() { - if (!isString()) luaL_typerror(state, index, "string"); + if (!isString()) luaL_typerror(mState, index, "string"); return *this; } - Value& requireTable() + Slot& requireTable() { - if (!isTable()) luaL_typerror(state, index, "table"); + if (!isTable()) luaL_typerror(mState, index, "table"); return *this; } - Value& requireFunction() + Slot& requireFunction() { - if (!isFunction()) luaL_typerror(state, index, "function"); + if (!isFunction()) luaL_typerror(mState, index, "function"); return *this; } - Value& requireData() + Slot& requireData() { - if (!isData()) luaL_typerror(state, index, "data"); + if (!isData()) luaL_typerror(mState, index, "data"); return *this; } - Value& requireNil() + Slot& requireNil() { - if (!isNil()) luaL_typerror(state, index, "nil"); + if (!isNil()) luaL_typerror(mState, index, "nil"); return *this; } - Value& requireThread() + Slot& requireThread() { - if (!isThread()) luaL_typerror(state, index, "thread"); + if (!isThread()) luaL_typerror(mState, index, "thread"); return *this; } @@ -228,7 +226,7 @@ public: Type getType() const { - return (Type)lua_type(state, index); + return (Type)lua_type(mState, index); } /** @@ -237,66 +235,68 @@ public: std::string getTypeName() const { - return std::string(luaL_typename(state, index)); + return std::string(luaL_typename(mState, index)); } /** - * Get the length of the value according to the definition given by Lua. + * Get the length of the value according to the definition given by + * Lua. */ size_t getLength() const { - return lua_objlen(state, index); + return lua_objlen(mState, index); } int getRealIndex() const { - if (index < 0) return lua_gettop(state) + 1 + index; + if (index < 0) return lua_gettop(mState) + 1 + index; else return index; } /** - * Get a pointer value (for userdata, tables, threads, and functions). + * Get a pointer value (for userdata, tables, threads, and + * functions). */ const void* getIdentifier() const { - return lua_topointer(state, index); + return lua_topointer(mState, index); } - bool operator == (const Value& rhs) const + bool operator == (const Slot& rhs) const { - return (bool)lua_equal(state, index, rhs.index); + return (bool)lua_equal(mState, index, rhs.index); } - bool operator != (const Value& rhs) const + bool operator != (const Slot& rhs) const { return !(*this == rhs); } - bool operator < (const Value& rhs) const + bool operator < (const Slot& rhs) const { - return (bool)lua_lessthan(state, index, rhs.index); + return (bool)lua_lessthan(mState, index, rhs.index); } - bool operator <= (const Value& rhs) const + bool operator <= (const Slot& rhs) const { return *this < rhs || *this == rhs; } - bool operator > (const Value& rhs) const + bool operator > (const Slot& rhs) const { return !(*this <= rhs); } - bool operator >= (const Value& rhs) const + bool operator >= (const Slot& rhs) const { return !(*this < rhs); } operator bool () const { - return (bool)lua_toboolean(state, index); + return (bool)lua_toboolean(mState, index); } - Value& operator = (const Value& rhs) + Slot& operator = (const Slot& rhs) { rhs.pushCopy(); replaceWithTop(); @@ -313,7 +313,7 @@ public: { if (isNumber()) { - value = (T)lua_tointeger(state, index); + value = (T)lua_tointeger(mState, index); return true; } return false; @@ -323,7 +323,7 @@ public: { if (isNumber()) { - value = (float)lua_tonumber(state, index); + value = (float)lua_tonumber(mState, index); return true; } return false; @@ -332,7 +332,7 @@ public: { if (isNumber()) { - value = (double)lua_tonumber(state, index); + value = (double)lua_tonumber(mState, index); return true; } return false; @@ -342,7 +342,7 @@ public: { if (isBoolean()) { - value = (bool)lua_toboolean(state, index); + value = (bool)lua_toboolean(mState, index); return true; } return false; @@ -353,7 +353,7 @@ public: if (isString()) { size_t size; - const char* str = lua_tolstring(state, index, &size); + const char* str = lua_tolstring(mState, index, &size); value.assign(str, size); return true; } @@ -367,19 +367,19 @@ public: array.clear(); - Value value(state, -1); + Slot value(mState, -1); int realIndex = getRealIndex(); bool done = false; for (int i = 1; !done; ++i) { - lua_rawgeti(state, realIndex, i); + lua_rawgeti(mState, realIndex, i); T v; if (value.get(v)) array.push_back(v); else done = true; - lua_pop(state, 1); + lua_pop(mState, 1); } return true; @@ -392,12 +392,12 @@ public: dictionary.clear(); - Value key(state, -2); - Value value(state, -1); + Slot key(mState, -2); + Slot value(mState, -1); int realIndex = getRealIndex(); - lua_pushnil(state); - while (lua_next(state, realIndex) != 0) + lua_pushnil(mState); + while (lua_next(mState, realIndex) != 0) { std::string k; if (!key.isNumber() && key.get(k)) @@ -405,22 +405,21 @@ public: T v; if (value.get(v)) dictionary[k] = v; } - lua_pop(state, 1); + lua_pop(mState, 1); } - lua_pop(state, 1); + lua_pop(mState, 1); return true; } - /** * Copy the value and push the copy to the stack. */ void pushCopy() const { - lua_pushvalue(state, index); + lua_pushvalue(mState, index); } /** @@ -429,57 +428,62 @@ public: void replaceWithTop() { - lua_replace(state, index); + lua_replace(mState, index); } void remove() { - lua_remove(state, index); + lua_remove(mState, index); } /** - * Inserts the top-most value on the stack at position index, shifting other - * values as needed. + * Inserts the top-most value on the stack at position index, + * shifting other values as needed. */ void insertTopHere() { - lua_insert(state, index); + lua_insert(mState, index); } void pushMetatable() const { - lua_getmetatable(state, index); + lua_getmetatable(mState, index); } void pushField() const { - lua_gettable(state, index); + lua_gettable(mState, index); } void pushField(const std::string& name) const { - lua_getfield(state, index, name.c_str()); + lua_getfield(mState, index, name.c_str()); + } + + void pushField(size_t index) const + { + lua_pushinteger(mState, lua_Integer(index)); + pushField(); } private: - lua_State* state; + lua_State* mState; }; Script() : - mState(luaL_newstate()) + mState(0) { - lua_pushlightuserdata(mState, this); - lua_setfield(mState, LUA_REGISTRYINDEX, "_script_obj"); + reset(); } ~Script() { - if (mIsMainThread) lua_close(mState); + destroy(); } @@ -488,12 +492,77 @@ public: return ScriptP(new Script); } + void reset() + { + if (mState) destroy(); + mState = luaL_newstate(); + lua_pushlightuserdata(mState, this); + lua_setfield(mState, LUA_REGISTRYINDEX, "Script_hh_Object"); + } + void importStandardLibraries() { luaL_openlibs(mState); } + void importBaseLibrary() + { + lua_pushcfunction(mState, luaopen_base); + push(LUA_COLIBNAME); + call(1, 0); + } + + void importPackageLibrary() + { + lua_pushcfunction(mState, luaopen_package); + push(LUA_LOADLIBNAME); + call(1, 0); + } + + void importStringLibrary() + { + lua_pushcfunction(mState, luaopen_string); + push(LUA_STRLIBNAME); + call(1, 0); + } + + void importTableLibrary() + { + lua_pushcfunction(mState, luaopen_table); + push(LUA_TABLIBNAME); + call(1, 0); + } + + void importMathLibrary() + { + lua_pushcfunction(mState, luaopen_math); + push(LUA_MATHLIBNAME); + call(1, 0); + } + + void importIoLibrary() + { + lua_pushcfunction(mState, luaopen_io); + push(LUA_IOLIBNAME); + call(1, 0); + } + + void importOsLibrary() + { + lua_pushcfunction(mState, luaopen_os); + push(LUA_OSLIBNAME); + call(1, 0); + } + + void importDebugLibrary() + { + lua_pushcfunction(mState, luaopen_debug); + push(LUA_DBLIBNAME); + call(1, 0); + } + + void importFunction(const std::string& name, const Function& function) { push(function); @@ -501,14 +570,14 @@ public: } - Status doString(const std::string& commands) + Result doString(const std::string& commands) { - return (Status)luaL_dostring(mState, commands.c_str()); + return (Result)luaL_dostring(mState, commands.c_str()); } - Status doFile(const std::string& file) + Result doFile(const std::string& file) { - return (Status)luaL_dofile(mState, file.c_str()); + return (Result)luaL_dofile(mState, file.c_str()); } @@ -526,14 +595,14 @@ public: lua_pushthread(mState); } - Status resume(int nargs) + Result resume(int nargs) { - return (Status)lua_resume(mState, nargs); + return (Result)lua_resume(mState, nargs); } - Status getStatus() const + Result getStatus() const { - return (Status)lua_status(mState); + return (Result)lua_status(mState); } int yield(int results) @@ -548,13 +617,14 @@ public: /** - * 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. + * 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() @@ -567,28 +637,29 @@ public: * Get significant values. */ - Value getGlobalTable() const + Slot getGlobalTable() const { - return Value(mState, GLOBALS); + return Slot(mState, GLOBALS); } - Value getRegistryTable() const + Slot getRegistryTable() const { - return Value(mState, REGISTRY); + return Slot(mState, REGISTRY); } - Value getEnvironmentTable() const + Slot getEnvironmentTable() const { - return Value(mState, ENVIRONMENT); + return Slot(mState, ENVIRONMENT); } - Value getTop() const + Slot getTop() const { - return Value(mState, lua_gettop(mState)); + return Slot(mState, lua_gettop(mState)); } /** - * Get the size of the stack; this is also the index of the top-most value. + * Get the size of the stack; this is also the index of the top-most + * value. */ int getSize() const @@ -608,11 +679,11 @@ public: /** - * Makes sure there is at least extra more places on the stack. Returns - * false if space couldn't be created. Just like with the regular Lua API, - * you are responsible to make sure the stack is big enough to hold whatever - * you want to push on it. This is usually only an issue if you're pushing - * stuff in a loop. + * Makes sure there is at least extra more places on the stack. + * Returns false if space couldn't be created. Just like with the + * regular Lua API, you are responsible to make sure the stack is big + * enough to hold whatever you want to push on it. This is usually + * only an issue if you're pushing stuff in a loop. */ bool checkStack(int extra) @@ -622,10 +693,10 @@ public: /** - * Concatenates the top-most n values on the stack. + * Concatenates the top-most n slots on the stack. */ - void concat(int n) + void concat(int n = 2) { lua_concat(mState, n); } @@ -691,14 +762,15 @@ public: lua_xmove(thread.mState, mState, n); } - Status pushCode(const std::string& filename) + Result pushCode(const std::string& filename) { - return (Status)luaL_loadfile(mState, filename.c_str()); + return (Result)luaL_loadfile(mState, filename.c_str()); } - Status pushCode(const std::string& name, const char* buffer, size_t size) + Result pushCode(const std::string& name, const char* buffer, + size_t size) { - return (Status)luaL_loadbuffer(mState, buffer, size, name.c_str()); + return (Result)luaL_loadbuffer(mState, buffer, size, name.c_str()); } void* pushNewData(size_t size) @@ -714,14 +786,14 @@ public: /** * Call a function on the stack. The correct procedure is to push a - * function onto the stack followed by nargs arguments. This method will - * pop them off upon return, leaving up to nresults return values (default - * is any number of return values, depending on the callee). + * function onto the stack followed by nargs arguments. This method + * will pop them off upon return, leaving up to nresults return values + * (default is any number of return values, depending on the callee). */ - Status call(int nargs, int nresults = LUA_MULTRET) + Result call(int nargs = 0, int nresults = LUA_MULTRET) { - return (Status)lua_pcall(mState, nargs, nresults, 0); + return (Result)lua_pcall(mState, nargs, nresults, 0); } @@ -736,12 +808,12 @@ public: /** - * Index into the stack to get a Value. + * Index into the stack to get a Slot. */ - Value operator [] (int index) const + Slot operator [] (int index) const { - return Value(mState, index); + return Slot(mState, index); } @@ -749,7 +821,7 @@ public: * Getting and setting fields of a table. */ - void get(const std::string& field, int index = GLOBALS) const + void pushField(const std::string& field, int index = GLOBALS) const { lua_getfield(mState, index, field.c_str()); } @@ -808,22 +880,52 @@ private: const Function* function = (const Function*)lua_touserdata(state, lua_upvalueindex(1)); - lua_getfield(state, LUA_REGISTRYINDEX, "_script_obj"); + lua_getfield(state, LUA_REGISTRYINDEX, "Script_hh_Object"); Script* script = (Script*)lua_touserdata(state, -1); lua_pop(state, 1); return (*function)(*script); } + void destroy() + { + if (mIsMainThread) lua_close(mState); + } + lua_State* mState; bool mIsMainThread; std::list mFunctions; }; +inline std::ostream& operator << (std::ostream& stream, + const Script::Slot& slot) +{ + if (slot.isString()) + { + std::string str; + slot.get(str); + stream << str; + } + else if (slot.isBoolean()) + { + if (slot) stream << "true"; + else stream << "false"; + } + else if (slot.isNil()) + { + stream << "nil"; + } + else + { + stream << slot.getTypeName() << " (" << slot.getIdentifier() << ")"; + } + + return stream; +} + + } // namespace Mf #endif // _MOOF_SCRIPT_HH_ -/** vim: set ts=4 sw=4 tw=80: *************************************************/ -