]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Script.hh
removed logging from script to fix compile error
[chaz/yoink] / src / Moof / Script.hh
index 553e31a0717be1b242a5e0f8a2377212f4492157..974dce78d6e8e12c1151035adb162591524eb6ae 100644 (file)
@@ -1,43 +1,28 @@
 
-/*******************************************************************************
-
- 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 is not meant to obscure the division
+ * between C++ and Lua but rather to clarify it and make it more
+ * manageable.  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 <iostream>
 #include <list>
 #include <map>
 #include <string>
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
-
 #include <lua.hpp>
 
-#include <Moof/Exception.hh>
-#include <Moof/Log.hh>
-
 
 namespace Mf {
 
@@ -60,11 +41,13 @@ class Script;
 typedef boost::shared_ptr<Script> ScriptP;
 
 
-struct Script
+class Script
 {
+public:
+
        typedef boost::function<int(Script&)> Function;
 
-       enum TYPE
+       enum Type
        {
                NONE                    = LUA_TNONE,
                NIL                             = LUA_TNIL,
@@ -78,7 +61,7 @@ struct Script
                THREAD                  = LUA_TTHREAD
        };
 
-       enum STATUS
+       enum Result
        {
                SUCCESS                 = 0,
                YIELD                   = LUA_YIELD,
@@ -89,7 +72,7 @@ struct Script
                FILE_ERROR              = LUA_ERRFILE
        };
 
-       enum PSEUDO_INDEX
+       enum PseudoIndex
        {
                REGISTRY                = LUA_REGISTRYINDEX,
                ENVIRONMENT             = LUA_ENVIRONINDEX,
@@ -97,112 +80,158 @@ struct Script
        };
 
        /**
-        * This is the most noticeable 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;
 
 
+               Slot(const Script& s, int i = 0) :
+                       index(i),
+                       mScript(const_cast<Script&>(s)) {}
+
                /**
-                * A default-constructed Value is invalid until a valid Value 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.
+                * 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(lua_State* s = 0, int i = 0) :
-                       index(i),
-                       state(s) {}
+
+               //Slot(const Slot& copy) :
+                       //index(copy.positiveIndex()),
+                       //mScript(copy.mScript) {}
+
 
                // 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(mScript.mState, index); }
+               bool isImportedFunction() const
+               { return (bool)lua_iscfunction(mScript.mState, index); }
+               bool isFunction() const
+               { return (bool)lua_isfunction(mScript.mState, index); }
+               bool isNil() const
+               { return (bool)lua_isnil(mScript.mState, index); }
+               bool isNone() const
+               { return (bool)lua_isnone(mScript.mState, index); }
+               bool isNoneOrNil() const
+               { return (bool)lua_isnoneornil(mScript.mState, index); }
+               bool isNumber() const
+               { return (bool)lua_isnumber(mScript.mState, index); }
+               bool isString() const
+               { return (bool)lua_isstring(mScript.mState, index); }
+               bool isTable() const
+               { return (bool)lua_istable(mScript.mState, index); }
+               bool isThread() const
+               { return (bool)lua_isthread(mScript.mState, index); }
+               bool isData() const
+               { return (bool)lua_isuserdata(mScript.mState, index); }
+               bool isLightData() const
+               { return (bool)lua_islightuserdata(mScript.mState, index); }
 
                /**
-                * Check the value and throw and error if its the wrong type.  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.
+                * 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
+               void requireType(Type t) const
                {
-                       if (type != getType())
+                       if (t != type())
                        {
-                               luaL_typerror(state, index, lua_typename(state, type));
+                               luaL_typerror(mScript.mState, index,
+                                                         lua_typename(mScript.mState, t));
                        }
                }
 
-               void throwError(const char* error)
+               void raise(const char* error)
                {
-                       luaL_argerror(state, index, error);
+                       luaL_argerror(mScript.mState, index, error);
                }
 
 
-               Value& requireBoolean()
+               Slot& requireBoolean()
                {
-                       if (!isBoolean()) luaL_typerror(state, index, "boolean");
+                       if (!isBoolean())
+                       {
+                               luaL_typerror(mScript.mState, index, "boolean");
+                       }
                        return *this;
                }
-               Value& requireNumber()
+               Slot& requireNumber()
                {
-                       if (!isNumber()) luaL_typerror(state, index, "number");
+                       if (!isNumber())
+                       {
+                               luaL_typerror(mScript.mState, index, "number");
+                       }
                        return *this;
                }
-               Value& requireString()
+               Slot& requireString()
                {
-                       if (!isString()) luaL_typerror(state, index, "string");
+                       if (!isString())
+                       {
+                               luaL_typerror(mScript.mState, index, "string");
+                       }
                        return *this;
                }
-               Value& requireTable()
+               Slot& requireTable()
                {
-                       if (!isTable()) luaL_typerror(state, index, "table");
+                       if (!isTable())
+                       {
+                               luaL_typerror(mScript.mState, index, "table");
+                       }
                        return *this;
                }
-               Value& requireFunction()
+               Slot& requireFunction()
                {
-                       if (!isFunction()) luaL_typerror(state, index, "function");
+                       if (!isFunction())
+                       {
+                               luaL_typerror(mScript.mState, index, "function");
+                       }
                        return *this;
                }
-               Value& requireData()
+               Slot& requireData()
                {
-                       if (!isData()) luaL_typerror(state, index, "data");
+                       if (!isData())
+                       {
+                               luaL_typerror(mScript.mState, index, "data");
+                       }
                        return *this;
                }
-               Value& requireNil()
+               Slot& requireNil()
                {
-                       if (!isNil()) luaL_typerror(state, index, "nil");
+                       if (!isNil())
+                       {
+                               luaL_typerror(mScript.mState, index, "nil");
+                       }
                        return *this;
                }
-               Value& requireThread()
+               Slot& requireThread()
                {
-                       if (!isThread()) luaL_typerror(state, index, "thread");
+                       if (!isThread())
+                       {
+                               luaL_typerror(mScript.mState, index, "thread");
+                       }
                        return *this;
                }
 
@@ -211,94 +240,96 @@ struct Script
                 * Get the type of the value.
                 */
 
-               TYPE getType() const
+               Type type() const
                {
-                       return (TYPE)lua_type(state, index);
+                       return (Type)lua_type(mScript.mState, index);
                }
 
                /**
                 * Get the name of the type of the value as a string.
                 */
 
-               std::string getTypeName() const
+               std::string typeName() const
                {
-                       return std::string(luaL_typename(state, index));
+                       return std::string(luaL_typename(mScript.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
+               size_t length() const
                {
-                       return lua_objlen(state, index);
+                       return lua_objlen(mScript.mState, index);
                }
 
-               int getRealIndex() const
+               int positiveIndex() const
                {
-                       if (index < 0) return lua_gettop(state) + 1 + index;
+                       if (index < 0) return index + lua_gettop(mScript.mState) + 1;
                        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
+               const void* id() const
                {
-                       return lua_topointer(state, index);
+                       return lua_topointer(mScript.mState, index);
                }
 
+               bool isIdentical(const Slot& rhs) const
+               {
+                       return &mScript == &(rhs.mScript) && index == rhs.index;
+               }
 
-               bool operator == (const Value& rhs) const
+               operator bool () const
                {
-                       return (bool)lua_equal(state, index, rhs.index);
+                       return !isNone();
                }
-               bool operator != (const Value& rhs) const
+
+
+               bool operator == (const Slot& rhs) const
+               {
+                       return (bool)lua_equal(mScript.mState, index, rhs.index);
+               }
+               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(mScript.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);
-               }
-
-               Value& operator = (const Value& rhs)
-               {
-                       rhs.pushCopy();
-                       replaceWithTop();
-                       return *this;
-               }
 
 
                /**
                 * Convert the underlying value to a C++ type.
                 */
 
-               template <typename T>
+               template <class T>
                bool get(T& value) const
                {
                        if (isNumber())
                        {
-                               value = (T)lua_tointeger(state, index);
+                               value = (T)lua_tointeger(mScript.mState, index);
                                return true;
                        }
                        return false;
@@ -308,7 +339,7 @@ struct Script
                {
                        if (isNumber())
                        {
-                               value = (float)lua_tonumber(state, index);
+                               value = (float)lua_tonumber(mScript.mState, index);
                                return true;
                        }
                        return false;
@@ -317,7 +348,7 @@ struct Script
                {
                        if (isNumber())
                        {
-                               value = (double)lua_tonumber(state, index);
+                               value = (double)lua_tonumber(mScript.mState, index);
                                return true;
                        }
                        return false;
@@ -327,62 +358,82 @@ struct Script
                {
                        if (isBoolean())
                        {
-                               value = (bool)lua_toboolean(state, index);
+                               value = (bool)lua_toboolean(mScript.mState, index);
                                return true;
                        }
                        return false;
                }
 
-               bool get(std::string& value) const
+               bool get(const char*& value, size_t& size) const
                {
                        if (isString())
                        {
-                               size_t size;
-                               const char* str = lua_tolstring(state, index, &size);
+                               value = lua_tolstring(mScript.mState, index, &size);
+                               return true;
+                       }
+                       return false;
+               }
+
+               bool get(std::string& value) const
+               {
+                       const char*     str;
+                       size_t          size;
+                       if (get(str, size))
+                       {
                                value.assign(str, size);
                                return true;
                        }
                        return false;
                }
 
-               template <typename T>
+               bool get(void*& value) const
+               {
+                       if (isData())
+                       {
+                               value = lua_touserdata(mScript.mState, index);
+                               return true;
+                       }
+                       return false;
+               }
+
+               template <class T>
                bool get(std::vector<T>& array) const
                {
                        if (!isTable()) return false;
 
                        array.clear();
 
-                       Value   value(state, -1);
-                       int             realIndex = getRealIndex();
+                       Slot    value = mScript[-1];
+                       int             realIndex = positiveIndex();
 
                        bool done = false;
                        for (int i = 1; !done; ++i)
                        {
-                               lua_rawgeti(state, realIndex, i);
+                               lua_rawgeti(mScript.mState, realIndex, i);
 
                                T v;
                                if (value.get(v)) array.push_back(v);
                                else              done = true;
 
-                               lua_pop(state, 1);
+                               mScript.pop();
                        }
 
                        return true;
                }
 
-               template <typename T>
+               template <class T>
                bool get(std::map<std::string,T>& dictionary) const
                {
                        if (!isTable()) return false;
 
                        dictionary.clear();
 
-                       Value   key(state, -2);
-                       Value   value(state, -1);
-                       int             realIndex = getRealIndex();
+                       Slot    key = mScript[-2];
+                       Slot    value = mScript[-1];
+                       int             realIndex = positiveIndex();
 
-                       lua_pushnil(state);
-                       while (lua_next(state, realIndex) != 0)
+                       mScript.pushNil();
+                       while (lua_next(mScript.mState, realIndex) != 0)
                        {
                                std::string k;
                                if (!key.isNumber() && key.get(k))
@@ -390,81 +441,173 @@ struct Script
                                        T v;
                                        if (value.get(v)) dictionary[k] = v;
                                }
-                               lua_pop(state, 1);
+                               mScript.pop();
                        }
-                       lua_pop(state, 1);
+                       mScript.pop();
 
                        return true;
                }
 
+               /**
+                * Get the value of a field from the table.
+                */
+
+               template <class T, class V>
+               bool get(T& value, V field) const
+               {
+                       bool ret = pushField(field).get(value);
+                       mScript.pop();
+                       return ret;
+               }
+
+
+               template <class T, class V>
+               void setField(T field, V value)
+               {
+                       mScript.push(field);
+                       mScript.push(value);
+                       setField();
+               }
+
+               void setField()
+               {
+                       lua_settable(mScript.mState, index);
+               }
+
+
+               template <class T>
+               void setField(const std::string& field, T value)
+               {
+                       setField(field.c_str(), value);
+               }
+               template <class T>
+               void setField(const char* field, T value)
+               {
+                       mScript.push(value);
+                       lua_setfield(mScript.mState, index, field);
+               }
 
 
                /**
-                * Copy the value and push the copy to the stack.
+                * This set method, as opposed to the others, sets the value of the
+                * actual slot.  The others set table values.
                 */
+               template <class T>
+               void set(T value)
+               {
+                       mScript.push(value);
+                       replace();
+               }
 
-               void pushCopy() const
+               void set()
                {
-                       lua_pushvalue(state, index);
+                       replace();
                }
 
+
                /**
                 * Replace this value with the value at the top of the stack.
                 */
 
-               void replaceWithTop()
+               void replace()
                {
-                       lua_replace(state, index);
+                       lua_replace(mScript.mState, index);
                }
 
                void remove()
                {
-                       lua_remove(state, index);
+                       lua_remove(mScript.mState, index);
+               }
+
+               void pop()
+               {
+                       // removes this slot, taking with it everything above it
+                       mScript.pop(mScript.stackSize() - index + 1);
                }
 
                /**
-                * 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(mScript.mState, index);
                }
 
+
+               /**
+                * Copy the value and push the copy to the stack.
+                */
+
+               Slot pushCopy() const
+               {
+                       lua_pushvalue(mScript.mState, index);
+                       return mScript.top();
+               }
                
-               void pushMetatable() const
+               Slot pushMetaTable() const
                {
-                       lua_getmetatable(state, index);
+                       lua_getmetatable(mScript.mState, index);
+                       return mScript.top();
                }
 
-               void pushField() const
+               Slot pushEnvironment() const
                {
-                       lua_gettable(state, index);
+                       lua_getfenv(mScript.mState, index);
+                       return mScript.top();
                }
 
-               void pushField(const std::string& name) const
+
+               Slot pushField() const
                {
-                       lua_getfield(state, index, name.c_str());
+                       lua_gettable(mScript.mState, index);
+                       return mScript.top();
                }
 
+               template <class T>
+               Slot pushField(T index) const
+               {
+                       mScript.push(index);
+                       return pushField();
+               }
+
+               Slot pushField(const std::string& name) const
+               {
+                       return pushField(name.c_str());
+               }
+               Slot pushField(const char* name) const
+               {
+                       lua_getfield(mScript.mState, index, name);
+                       return mScript.top();
+               }
+
+
+               Script& script()
+               {
+                       return mScript;
+               }
+
+               const Script& script() const
+               {
+                       return mScript;
+               }
 
        private:
 
-               lua_State* state;
+               Script& mScript;
        };
 
 
        Script() :
-               state_(luaL_newstate())
+               mState(0)
        {
-               lua_pushlightuserdata(state_, this);
-               lua_setfield(state_, LUA_REGISTRYINDEX, "_script_obj");
+               reset();
        }
 
        ~Script()
        {
-               if (isMainThread_) lua_close(state_);
+               destroy();
        }
 
 
@@ -473,27 +616,90 @@ struct Script
                return ScriptP(new Script);
        }
 
+       void reset()
+       {
+               if (mState) destroy();
+               mState = luaL_newstate();
+               registry().setField("Script_hh_Object", (void*)this);
+       }
+
 
        void importStandardLibraries()
        {
-               luaL_openlibs(state_);
+               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);
-               lua_setglobal(state_, name.c_str());
+               lua_setglobal(mState, name.c_str());
        }
 
-
-       STATUS doString(const std::string& commands)
+       Result doString(const std::string& commands)
        {
-               return (STATUS)luaL_dostring(state_, 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(state_, file.c_str());
+               return (Result)luaL_dofile(mState, file.c_str());
        }
 
 
@@ -503,48 +709,49 @@ struct Script
 
        Script pushNewThread()
        {
-               return Script(state_);
+               return Script(mState);
        }
 
        void pushThread()
        {
-               lua_pushthread(state_);
+               lua_pushthread(mState);
        }
 
-       STATUS resume(int nargs)
+       Result resume(int nargs)
        {
-               return (STATUS)lua_resume(state_, nargs);
+               return (Result)lua_resume(mState, nargs);
        }
 
-       STATUS getStatus() const
+       Result getStatus() const
        {
-               return (STATUS)lua_status(state_);
+               return (Result)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.
+        * 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()
+       void raise()
        {
-               lua_error(state_);
+               lua_error(mState);
        }
 
 
@@ -552,67 +759,68 @@ struct Script
         * Get significant values.
         */
 
-       Value getGlobalTable() const
+       Slot globals() const
        {
-               return Value(state_, GLOBALS);
+               return Slot(*this, GLOBALS);
        }
 
-       Value getRegistryTable() const
+       Slot registry() const
        {
-               return Value(state_, REGISTRY);
+               return Slot(*this, REGISTRY);
        }
 
-       Value getEnvironmentTable() const
+       Slot environment() const
        {
-               return Value(state_, ENVIRONMENT);
+               return Slot(*this, ENVIRONMENT);
        }
 
-       Value getTop() const
+       Slot top() const
        {
-               return Value(state_, lua_gettop(state_));
+               return Slot(*this, stackSize());
        }
 
        /**
-        * 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
+       int stackSize() const
        {
-               return lua_gettop(state_);
+               return lua_gettop(mState);
        }
 
-       void setSize(int size)
+       void setStackSize(int size)
        {
-               lua_settop(state_, size);
+               lua_settop(mState, size);
        }
 
-       void clear()
+       void clearStack()
        {
-               setSize(0);
+               setStackSize(0);
        }
 
 
        /**
-        * 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)
        {
-               return (bool)lua_checkstack(state_, extra);
+               return (bool)lua_checkstack(mState, extra);
        }
 
 
        /**
-        * Concatenates the top-most n values on the stack.
+        * Concatenates the top-most n slots on the stack.
         */
 
-       void concat(int n)
+       void concatenate(int n = 2)
        {
-               lua_concat(state_, n);
+               lua_concat(mState, n);
        }
 
 
@@ -620,93 +828,109 @@ struct Script
         * Push some values onto the stack.
         */
 
-       template <typename T>
-       void push(T value)
+       template <class T>
+       Slot push(T value)
        {
-               lua_pushinteger(state_, lua_Integer(value));
+               lua_pushinteger(mState, lua_Integer(value));
+               return top();
        }
 
-       void push(bool value)
+       Slot push(bool value)
        {
-               lua_pushboolean(state_, int(value));
+               lua_pushboolean(mState, int(value));
+               return top();
        }
 
-       void push(float value)
+       Slot push(float value)
        {
-               lua_pushnumber(state_, (lua_Number)value);
+               lua_pushnumber(mState, (lua_Number)value);
+               return top();
        }
-       void push(double value)
+       Slot push(double value)
        {
-               lua_pushnumber(state_, (lua_Number)value);
+               lua_pushnumber(mState, (lua_Number)value);
+               return top();
        }
 
-       void push(const std::string& value)
+       Slot push(const std::string& value)
        {
-               lua_pushlstring(state_, value.c_str(), value.length());
+               lua_pushlstring(mState, value.c_str(), value.length());
+               return top();
        }
-       void push(const char* value)
+       Slot push(const char* value)
        {
-               lua_pushstring(state_, value);
+               lua_pushstring(mState, value);
+               return top();
        }
-       void push(const char* value, size_t length)
+       Slot push(const char* value, size_t length)
        {
-               lua_pushlstring(state_, value, length);
+               lua_pushlstring(mState, value, length);
+               return top();
        }
 
-       void push(const Function& function)
+       Slot push(const Function& function)
        {
-               functions_.push_back(function);
-
-               lua_pushlightuserdata(state_, (void*)&functions_.back());
-               lua_pushcclosure(state_, dispatchCall, 1);
+               mFunctions.push_back(function);
+               lua_pushlightuserdata(mState, (void*)&mFunctions.back());
+               lua_pushcclosure(mState, dispatchCall, 1);
+               return top();
        }
 
-       void push(void* data)
+       Slot push(void* data)
        {
-               lua_pushlightuserdata(state_, data);
+               lua_pushlightuserdata(mState, data);
+               return top();
        }
 
-       void pushNil()
+       Slot pushNil()
        {
-               lua_pushnil(state_);
+               lua_pushnil(mState);
+               return top();
        }
 
-       void pushFromThread(Script& thread, int n)
+       Slot pushFromThread(Script& thread, int n)
        {
-               lua_xmove(thread.state_, state_, n);
+               lua_xmove(thread.mState, mState, n);
+               return top();
        }
 
-       STATUS pushCode(const std::string& filename)
+       Slot pushCode(const std::string& file, Result& result)
        {
-               return (STATUS)luaL_loadfile(state_, filename.c_str());
+               result = (Result)luaL_loadfile(mState, file.c_str());
+               return top();
        }
 
-       STATUS pushCode(const std::string& name, const char* buffer, size_t size)
+       Slot pushCode(const std::string& name, const char* buffer,
+                                 size_t size, Result& result)
        {
-               return (STATUS)luaL_loadbuffer(state_, buffer, size, name.c_str());
+               result = (Result)luaL_loadbuffer(mState,
+                                                                                buffer, size, name.c_str());
+               return top();
        }
 
-       void* pushNewData(size_t size)
+       Slot pushNewData(void*& data, size_t size)
        {
-               return lua_newuserdata(state_, size);
+               data = lua_newuserdata(mState, size);
+               return top();
        }
 
-       void pushNewTable()
+       Slot pushNewTable(int narr = 0, int nrec = 0)
        {
-               lua_newtable(state_);
+               lua_createtable(mState, narr, nrec);
+               return top();
        }
 
 
        /**
         * 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(state_, nargs, nresults, 0);
+               return (Result)lua_pcall(mState, nargs, nresults, 0);
        }
 
 
@@ -716,32 +940,17 @@ struct Script
 
        void pop(int n = 1)
        {
-               lua_pop(state_, n);
+               lua_pop(mState, n);
        }
 
 
        /**
-        * 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(state_, index);
-       }
-
-
-       /**
-        * Getting and setting fields of a table.
-        */
-
-       void get(const std::string& field,  int index = GLOBALS) const
-       {
-               lua_getfield(state_, index, field.c_str());
-       }
-
-       void set(const std::string& field, int index = GLOBALS)
-       {
-               lua_setfield(state_, index, field.c_str());
+               return Slot(*this, index);
        }
 
 
@@ -751,77 +960,96 @@ 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)
        {
                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);
        }
 
-       lua_State*                      state_;
-       bool                            isMainThread_;
-       std::list<Function>     functions_;
+       void destroy()
+       {
+               if (mIsMainThread) lua_close(mState);
+       }
+
+       lua_State*                      mState;
+       bool                            mIsMainThread;
+       std::list<Function>     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())
+       {
+               bool value;
+               slot.get(value);
+               if (value) stream << "true";
+               else       stream << "false";
+       }
+       else if (slot.isNil())
+       {
+               stream << "nil";
+       }
+       else
+       {
+               stream << slot.typeName() << " (" << slot.id() << ")";
+       }
+
+       return stream;
+}
+
+
 } // namespace Mf
 
 #endif // _MOOF_SCRIPT_HH_
 
-/** vim: set ts=4 sw=4 tw=80: *************************************************/
-
This page took 0.054001 seconds and 4 git commands to generate.