summaryrefslogtreecommitdiff
path: root/libs/lua/LuaBridge/detail/Namespace.h
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2016-01-11 11:50:50 +0100
committerRobin Gareus <robin@gareus.org>2016-02-22 22:06:47 +0100
commite98f21dd297819fcb4931bd5a87474736c7a450e (patch)
tree018a17a9f67c206cea1394c3f4012c58a1a2f6d4 /libs/lua/LuaBridge/detail/Namespace.h
parentc8973f67a65d911d1b08e1121d1c7da57c58b182 (diff)
add LuaBridge
https://github.com/vinniefalco/LuaBridge
Diffstat (limited to 'libs/lua/LuaBridge/detail/Namespace.h')
-rw-r--r--libs/lua/LuaBridge/detail/Namespace.h1136
1 files changed, 1136 insertions, 0 deletions
diff --git a/libs/lua/LuaBridge/detail/Namespace.h b/libs/lua/LuaBridge/detail/Namespace.h
new file mode 100644
index 0000000000..ff22e6b092
--- /dev/null
+++ b/libs/lua/LuaBridge/detail/Namespace.h
@@ -0,0 +1,1136 @@
+//------------------------------------------------------------------------------
+/*
+ https://github.com/vinniefalco/LuaBridge
+
+ Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
+ Copyright 2007, Nathan Reed
+
+ License: The MIT License (http://www.opensource.org/licenses/mit-license.php)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+//==============================================================================
+
+/** Provides C++ to Lua registration capabilities.
+
+ This class is not instantiated directly, call `getGlobalNamespace` to start
+ the registration process.
+*/
+class Namespace
+{
+private:
+ Namespace& operator= (Namespace const& other);
+
+ lua_State* const L;
+ int mutable m_stackSize;
+
+private:
+ //============================================================================
+ /**
+ Error reporting.
+
+ VF: This function looks handy, why aren't we using it?
+ */
+#if 0
+ static int luaError (lua_State* L, std::string message)
+ {
+ assert (lua_isstring (L, lua_upvalueindex (1)));
+ std::string s;
+
+ // Get information on the caller's caller to format the message,
+ // so the error appears to originate from the Lua source.
+ lua_Debug ar;
+ int result = lua_getstack (L, 2, &ar);
+ if (result != 0)
+ {
+ lua_getinfo (L, "Sl", &ar);
+ s = ar.short_src;
+ if (ar.currentline != -1)
+ {
+ // poor mans int to string to avoid <strstrream>.
+ lua_pushnumber (L, ar.currentline);
+ s = s + ":" + lua_tostring (L, -1) + ": ";
+ lua_pop (L, 1);
+ }
+ }
+
+ s = s + message;
+
+ return luaL_error (L, s.c_str ());
+ }
+#endif
+
+ //----------------------------------------------------------------------------
+ /**
+ Pop the Lua stack.
+ */
+ void pop (int n) const
+ {
+ if (m_stackSize >= n && lua_gettop (L) >= n)
+ {
+ lua_pop (L, n);
+ m_stackSize -= n;
+ }
+ else
+ {
+ throw std::logic_error ("invalid stack");
+ }
+ }
+
+private:
+ /**
+ Factored base to reduce template instantiations.
+ */
+ class ClassBase
+ {
+ private:
+ ClassBase& operator= (ClassBase const& other);
+
+ protected:
+ friend class Namespace;
+
+ lua_State* const L;
+ int mutable m_stackSize;
+
+ protected:
+ //--------------------------------------------------------------------------
+ /**
+ __index metamethod for a class.
+
+ This implements member functions, data members, and property members.
+ Functions are stored in the metatable and const metatable. Data members
+ and property members are in the __propget table.
+
+ If the key is not found, the search proceeds up the hierarchy of base
+ classes.
+ */
+ static int indexMetaMethod (lua_State* L)
+ {
+ int result = 0;
+
+ assert (lua_isuserdata (L, 1)); // warn on security bypass
+ lua_getmetatable (L, 1); // get metatable for object
+ for (;;)
+ {
+ lua_pushvalue (L, 2); // push key arg2
+ lua_rawget (L, -2); // lookup key in metatable
+ if (lua_iscfunction (L, -1)) // ensure its a cfunction
+ {
+ lua_remove (L, -2); // remove metatable
+ result = 1;
+ break;
+ }
+ else if (lua_isnil (L, -1))
+ {
+ lua_pop (L, 1);
+ }
+ else
+ {
+ lua_pop (L, 2);
+ throw std::logic_error ("not a cfunction");
+ }
+
+ rawgetfield (L, -1, "__propget"); // get __propget table
+ if (lua_istable (L, -1)) // ensure it is a table
+ {
+ lua_pushvalue (L, 2); // push key arg2
+ lua_rawget (L, -2); // lookup key in __propget
+ lua_remove (L, -2); // remove __propget
+ if (lua_iscfunction (L, -1)) // ensure its a cfunction
+ {
+ lua_remove (L, -2); // remove metatable
+ lua_pushvalue (L, 1); // push class arg1
+ lua_call (L, 1, 1);
+ result = 1;
+ break;
+ }
+ else if (lua_isnil (L, -1))
+ {
+ lua_pop (L, 1);
+ }
+ else
+ {
+ lua_pop (L, 2);
+
+ // We only put cfunctions into __propget.
+ throw std::logic_error ("not a cfunction");
+ }
+ }
+ else
+ {
+ lua_pop (L, 2);
+
+ // __propget is missing, or not a table.
+ throw std::logic_error ("missing __propget table");
+ }
+
+ // Repeat the lookup in the __parent metafield,
+ // or return nil if the field doesn't exist.
+ rawgetfield (L, -1, "__parent");
+ if (lua_istable (L, -1))
+ {
+ // Remove metatable and repeat the search in __parent.
+ lua_remove (L, -2);
+ }
+ else if (lua_isnil (L, -1))
+ {
+ result = 1;
+ break;
+ }
+ else
+ {
+ lua_pop (L, 2);
+
+ throw std::logic_error ("__parent is not a table");
+ }
+ }
+
+ return result;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ __newindex metamethod for classes.
+
+ This supports writable variables and properties on class objects. The
+ corresponding object is passed in the first parameter to the set function.
+ */
+ static int newindexMetaMethod (lua_State* L)
+ {
+ int result = 0;
+
+ lua_getmetatable (L, 1);
+
+ for (;;)
+ {
+ // Check __propset
+ rawgetfield (L, -1, "__propset");
+ if (!lua_isnil (L, -1))
+ {
+ lua_pushvalue (L, 2);
+ lua_rawget (L, -2);
+ if (!lua_isnil (L, -1))
+ {
+ // found it, call the setFunction.
+ assert (lua_isfunction (L, -1));
+ lua_pushvalue (L, 1);
+ lua_pushvalue (L, 3);
+ lua_call (L, 2, 0);
+ result = 0;
+ break;
+ }
+ lua_pop (L, 1);
+ }
+ lua_pop (L, 1);
+
+ // Repeat the lookup in the __parent metafield.
+ rawgetfield (L, -1, "__parent");
+ if (lua_isnil (L, -1))
+ {
+ // Either the property or __parent must exist.
+ result = luaL_error (L,
+ "no member named '%s'", lua_tostring (L, 2));
+ }
+ lua_remove (L, -2);
+ }
+
+ return result;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Create the const table.
+ */
+ void createConstTable (char const* name)
+ {
+ lua_newtable (L);
+ lua_pushvalue (L, -1);
+ lua_setmetatable (L, -2);
+ lua_pushboolean (L, 1);
+ lua_rawsetp (L, -2, getIdentityKey ());
+ lua_pushstring (L, (std::string ("const ") + name).c_str ());
+ rawsetfield (L, -2, "__type");
+ lua_pushcfunction (L, &indexMetaMethod);
+ rawsetfield (L, -2, "__index");
+ lua_pushcfunction (L, &newindexMetaMethod);
+ rawsetfield (L, -2, "__newindex");
+ lua_newtable (L);
+ rawsetfield (L, -2, "__propget");
+
+ if (Security::hideMetatables ())
+ {
+ lua_pushnil (L);
+ rawsetfield (L, -2, "__metatable");
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Create the class table.
+
+ The Lua stack should have the const table on top.
+ */
+ void createClassTable (char const* name)
+ {
+ lua_newtable (L);
+ lua_pushvalue (L, -1);
+ lua_setmetatable (L, -2);
+ lua_pushboolean (L, 1);
+ lua_rawsetp (L, -2, getIdentityKey ());
+ lua_pushstring (L, name);
+ rawsetfield (L, -2, "__type");
+ lua_pushcfunction (L, &indexMetaMethod);
+ rawsetfield (L, -2, "__index");
+ lua_pushcfunction (L, &newindexMetaMethod);
+ rawsetfield (L, -2, "__newindex");
+ lua_newtable (L);
+ rawsetfield (L, -2, "__propget");
+ lua_newtable (L);
+ rawsetfield (L, -2, "__propset");
+
+ lua_pushvalue (L, -2);
+ rawsetfield (L, -2, "__const"); // point to const table
+
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -3, "__class"); // point const table to class table
+
+ if (Security::hideMetatables ())
+ {
+ lua_pushnil (L);
+ rawsetfield (L, -2, "__metatable");
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Create the static table.
+
+ The Lua stack should have:
+ -1 class table
+ -2 const table
+ -3 enclosing namespace
+ */
+ void createStaticTable (char const* name)
+ {
+ lua_newtable (L);
+ lua_newtable (L);
+ lua_pushvalue (L, -1);
+ lua_setmetatable (L, -3);
+ lua_insert (L, -2);
+ rawsetfield (L, -5, name);
+
+#if 0
+ lua_pushlightuserdata (L, this);
+ lua_pushcclosure (L, &tostringMetaMethod, 1);
+ rawsetfield (L, -2, "__tostring");
+#endif
+ lua_pushcfunction (L, &CFunc::indexMetaMethod);
+ rawsetfield (L, -2, "__index");
+ lua_pushcfunction (L, &CFunc::newindexMetaMethod);
+ rawsetfield (L, -2, "__newindex");
+ lua_newtable (L);
+ rawsetfield (L, -2, "__propget");
+ lua_newtable (L);
+ rawsetfield (L, -2, "__propset");
+
+ lua_pushvalue (L, -2);
+ rawsetfield (L, -2, "__class"); // point to class table
+
+ if (Security::hideMetatables ())
+ {
+ lua_pushnil (L);
+ rawsetfield (L, -2, "__metatable");
+ }
+ }
+
+ //==========================================================================
+ /**
+ lua_CFunction to construct a class object wrapped in a container.
+ */
+ template <class Params, class C>
+ static int ctorContainerProxy (lua_State* L)
+ {
+ typedef typename ContainerTraits <C>::Type T;
+ ArgList <Params, 2> args (L);
+ T* const p = Constructor <T, Params>::call (args);
+ UserdataSharedHelper <C, false>::push (L, p);
+ return 1;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ lua_CFunction to construct a class object in-place in the userdata.
+ */
+ template <class Params, class T>
+ static int ctorPlacementProxy (lua_State* L)
+ {
+ ArgList <Params, 2> args (L);
+ Constructor <T, Params>::call (UserdataValue <T>::place (L), args);
+ return 1;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Pop the Lua stack.
+ */
+ void pop (int n) const
+ {
+ if (m_stackSize >= n && lua_gettop (L) >= n)
+ {
+ lua_pop (L, n);
+ m_stackSize -= n;
+ }
+ else
+ {
+ throw std::logic_error ("invalid stack");
+ }
+ }
+
+ public:
+ //--------------------------------------------------------------------------
+ explicit ClassBase (lua_State* L_)
+ : L (L_)
+ , m_stackSize (0)
+ {
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Copy Constructor.
+ */
+ ClassBase (ClassBase const& other)
+ : L (other.L)
+ , m_stackSize (0)
+ {
+ m_stackSize = other.m_stackSize;
+ other.m_stackSize = 0;
+ }
+
+ ~ClassBase ()
+ {
+ pop (m_stackSize);
+ }
+ };
+
+ //============================================================================
+ //
+ // Class
+ //
+ //============================================================================
+ /**
+ Provides a class registration in a lua_State.
+
+ After contstruction the Lua stack holds these objects:
+ -1 static table
+ -2 class table
+ -3 const table
+ -4 (enclosing namespace)
+ */
+ template <class T>
+ class Class : public ClassBase
+ {
+ public:
+ //==========================================================================
+ /**
+ Register a new class or add to an existing class registration.
+ */
+ Class (char const* name, Namespace const* parent) : ClassBase (parent->L)
+ {
+ m_stackSize = parent->m_stackSize + 3;
+ parent->m_stackSize = 0;
+
+ assert (lua_istable (L, -1));
+ rawgetfield (L, -1, name);
+
+ if (lua_isnil (L, -1))
+ {
+ lua_pop (L, 1);
+
+ createConstTable (name);
+ lua_pushcfunction (L, &CFunc::gcMetaMethod <T>);
+ rawsetfield (L, -2, "__gc");
+
+ createClassTable (name);
+ lua_pushcfunction (L, &CFunc::gcMetaMethod <T>);
+ rawsetfield (L, -2, "__gc");
+
+ createStaticTable (name);
+
+ // Map T back to its tables.
+ lua_pushvalue (L, -1);
+ lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getStaticKey ());
+ lua_pushvalue (L, -2);
+ lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ());
+ lua_pushvalue (L, -3);
+ lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ());
+ }
+ else
+ {
+ rawgetfield (L, -1, "__class");
+ rawgetfield (L, -1, "__const");
+
+ // Reverse the top 3 stack elements
+ lua_insert (L, -3);
+ lua_insert (L, -2);
+ }
+ }
+
+ //==========================================================================
+ /**
+ Derive a new class.
+ */
+ Class (char const* name, Namespace const* parent, void const* const staticKey)
+ : ClassBase (parent->L)
+ {
+ m_stackSize = parent->m_stackSize + 3;
+ parent->m_stackSize = 0;
+
+ assert (lua_istable (L, -1));
+
+ createConstTable (name);
+ lua_pushcfunction (L, &CFunc::gcMetaMethod <T>);
+ rawsetfield (L, -2, "__gc");
+
+ createClassTable (name);
+ lua_pushcfunction (L, &CFunc::gcMetaMethod <T>);
+ rawsetfield (L, -2, "__gc");
+
+ createStaticTable (name);
+
+ lua_rawgetp (L, LUA_REGISTRYINDEX, staticKey);
+ assert (lua_istable (L, -1));
+ rawgetfield (L, -1, "__class");
+ assert (lua_istable (L, -1));
+ rawgetfield (L, -1, "__const");
+ assert (lua_istable (L, -1));
+
+ rawsetfield (L, -6, "__parent");
+ rawsetfield (L, -4, "__parent");
+ rawsetfield (L, -2, "__parent");
+
+ lua_pushvalue (L, -1);
+ lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getStaticKey ());
+ lua_pushvalue (L, -2);
+ lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ());
+ lua_pushvalue (L, -3);
+ lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ());
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Continue registration in the enclosing namespace.
+ */
+ Namespace endClass ()
+ {
+ return Namespace (this);
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a static data member.
+ */
+ template <class U>
+ Class <T>& addStaticData (char const* name, U* pu, bool isWritable = true)
+ {
+ assert (lua_istable (L, -1));
+
+ rawgetfield (L, -1, "__propget");
+ assert (lua_istable (L, -1));
+ lua_pushlightuserdata (L, pu);
+ lua_pushcclosure (L, &CFunc::getVariable <U>, 1);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ rawgetfield (L, -1, "__propset");
+ assert (lua_istable (L, -1));
+ if (isWritable)
+ {
+ lua_pushlightuserdata (L, pu);
+ lua_pushcclosure (L, &CFunc::setVariable <U>, 1);
+ }
+ else
+ {
+ lua_pushstring (L, name);
+ lua_pushcclosure (L, &CFunc::readOnlyError, 1);
+ }
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a static property member.
+
+ If the set function is null, the property is read-only.
+ */
+ template <class U>
+ Class <T>& addStaticProperty (char const* name, U (*get)(), void (*set)(U) = 0)
+ {
+ typedef U (*get_t)();
+ typedef void (*set_t)(U);
+
+ assert (lua_istable (L, -1));
+
+ rawgetfield (L, -1, "__propget");
+ assert (lua_istable (L, -1));
+ new (lua_newuserdata (L, sizeof (get))) get_t (get);
+ lua_pushcclosure (L, &CFunc::Call <U (*) (void)>::f, 1);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ rawgetfield (L, -1, "__propset");
+ assert (lua_istable (L, -1));
+ if (set != 0)
+ {
+ new (lua_newuserdata (L, sizeof (set))) set_t (set);
+ lua_pushcclosure (L, &CFunc::Call <void (*) (U)>::f, 1);
+ }
+ else
+ {
+ lua_pushstring (L, name);
+ lua_pushcclosure (L, &CFunc::readOnlyError, 1);
+ }
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a static member function.
+ */
+ template <class FP>
+ Class <T>& addStaticFunction (char const* name, FP const fp)
+ {
+ new (lua_newuserdata (L, sizeof (fp))) FP (fp);
+ lua_pushcclosure (L, &CFunc::Call <FP>::f, 1);
+ rawsetfield (L, -2, name);
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a lua_CFunction.
+ */
+ Class <T>& addStaticCFunction (char const* name, int (*const fp)(lua_State*))
+ {
+ lua_pushcfunction (L, fp);
+ rawsetfield (L, -2, name);
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a data member.
+ */
+ template <class U>
+ Class <T>& addData (char const* name, const U T::* mp, bool isWritable = true)
+ {
+ typedef const U T::*mp_t;
+
+ // Add to __propget in class and const tables.
+ {
+ rawgetfield (L, -2, "__propget");
+ rawgetfield (L, -4, "__propget");
+ new (lua_newuserdata (L, sizeof (mp_t))) mp_t (mp);
+ lua_pushcclosure (L, &CFunc::getProperty <T,U>, 1);
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -4, name);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 2);
+ }
+
+ if (isWritable)
+ {
+ // Add to __propset in class table.
+ rawgetfield (L, -2, "__propset");
+ assert (lua_istable (L, -1));
+ new (lua_newuserdata (L, sizeof (mp_t))) mp_t (mp);
+ lua_pushcclosure (L, &CFunc::setProperty <T,U>, 1);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+ }
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a property member.
+ */
+ template <class TG, class TS>
+ Class <T>& addProperty (char const* name, TG (T::* get) () const, void (T::* set) (TS))
+ {
+ // Add to __propget in class and const tables.
+ {
+ rawgetfield (L, -2, "__propget");
+ rawgetfield (L, -4, "__propget");
+ typedef TG (T::*get_t) () const;
+ new (lua_newuserdata (L, sizeof (get_t))) get_t (get);
+ lua_pushcclosure (L, &CFunc::CallConstMember <get_t>::f, 1);
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -4, name);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 2);
+ }
+
+ {
+ // Add to __propset in class table.
+ rawgetfield (L, -2, "__propset");
+ assert (lua_istable (L, -1));
+ typedef void (T::* set_t) (TS);
+ new (lua_newuserdata (L, sizeof (set_t))) set_t (set);
+ lua_pushcclosure (L, &CFunc::CallMember <set_t>::f, 1);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+ }
+
+ return *this;
+ }
+
+ // read-only
+ template <class TG>
+ Class <T>& addProperty (char const* name, TG (T::* get) () const)
+ {
+ // Add to __propget in class and const tables.
+ rawgetfield (L, -2, "__propget");
+ rawgetfield (L, -4, "__propget");
+ typedef TG (T::*get_t) () const;
+ new (lua_newuserdata (L, sizeof (get_t))) get_t (get);
+ lua_pushcclosure (L, &CFunc::CallConstMember <get_t>::f, 1);
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -4, name);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 2);
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a property member, by proxy.
+
+ When a class is closed for modification and does not provide (or cannot
+ provide) the function signatures necessary to implement get or set for
+ a property, this will allow non-member functions act as proxies.
+
+ Both the get and the set functions require a T const* and T* in the first
+ argument respectively.
+ */
+ template <class TG, class TS>
+ Class <T>& addProperty (char const* name, TG (*get) (T const*), void (*set) (T*, TS))
+ {
+ // Add to __propget in class and const tables.
+ {
+ rawgetfield (L, -2, "__propget");
+ rawgetfield (L, -4, "__propget");
+ typedef TG (*get_t) (T const*);
+ new (lua_newuserdata (L, sizeof (get_t))) get_t (get);
+ lua_pushcclosure (L, &CFunc::Call <get_t>::f, 1);
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -4, name);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 2);
+ }
+
+ if (set != 0)
+ {
+ // Add to __propset in class table.
+ rawgetfield (L, -2, "__propset");
+ assert (lua_istable (L, -1));
+ typedef void (*set_t) (T*, TS);
+ new (lua_newuserdata (L, sizeof (set_t))) set_t (set);
+ lua_pushcclosure (L, &CFunc::Call <set_t>::f, 1);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+ }
+
+ return *this;
+ }
+
+ // read-only
+ template <class TG, class TS>
+ Class <T>& addProperty (char const* name, TG (*get) (T const*))
+ {
+ // Add to __propget in class and const tables.
+ rawgetfield (L, -2, "__propget");
+ rawgetfield (L, -4, "__propget");
+ typedef TG (*get_t) (T const*);
+ new (lua_newuserdata (L, sizeof (get_t))) get_t (get);
+ lua_pushcclosure (L, &CFunc::Call <get_t>::f, 1);
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -4, name);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 2);
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a member function.
+ */
+ template <class MemFn>
+ Class <T>& addFunction (char const* name, MemFn mf)
+ {
+ CFunc::CallMemberFunctionHelper <MemFn, FuncTraits <MemFn>::isConstMemberFunction>::add (L, name, mf);
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a member lua_CFunction.
+ */
+ Class <T>& addCFunction (char const* name, int (T::*mfp)(lua_State*))
+ {
+ typedef int (T::*MFP)(lua_State*);
+ assert (lua_istable (L, -1));
+ new (lua_newuserdata (L, sizeof (mfp))) MFP (mfp);
+ lua_pushcclosure (L, &CFunc::CallMemberCFunction <T>::f, 1);
+ rawsetfield (L, -3, name); // class table
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a const member lua_CFunction.
+ */
+ Class <T>& addCFunction (char const* name, int (T::*mfp)(lua_State*) const)
+ {
+ typedef int (T::*MFP)(lua_State*) const;
+ assert (lua_istable (L, -1));
+ new (lua_newuserdata (L, sizeof (mfp))) MFP (mfp);
+ lua_pushcclosure (L, &CFunc::CallConstMemberCFunction <T>::f, 1);
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -5, name); // const table
+ rawsetfield (L, -3, name); // class table
+
+ return *this;
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ Add or replace a primary Constructor.
+
+ The primary Constructor is invoked when calling the class type table
+ like a function.
+
+ The template parameter should be a function pointer type that matches
+ the desired Constructor (since you can't take the address of a Constructor
+ and pass it as an argument).
+ */
+ template <class MemFn, class C>
+ Class <T>& addConstructor ()
+ {
+ lua_pushcclosure (L,
+ &ctorContainerProxy <typename FuncTraits <MemFn>::Params, C>, 0);
+ rawsetfield(L, -2, "__call");
+
+ return *this;
+ }
+
+ template <class MemFn>
+ Class <T>& addConstructor ()
+ {
+ lua_pushcclosure (L,
+ &ctorPlacementProxy <typename FuncTraits <MemFn>::Params, T>, 0);
+ rawsetfield(L, -2, "__call");
+
+ return *this;
+ }
+ };
+
+private:
+ //----------------------------------------------------------------------------
+ /**
+ Open the global namespace for registrations.
+ */
+ explicit Namespace (lua_State* L_)
+ : L (L_)
+ , m_stackSize (0)
+ {
+ lua_getglobal (L, "_G");
+ ++m_stackSize;
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Open a namespace for registrations.
+
+ The namespace is created if it doesn't already exist.
+ The parent namespace is at the top of the Lua stack.
+ */
+ Namespace (char const* name, Namespace const* parent)
+ : L (parent->L)
+ , m_stackSize (0)
+ {
+ m_stackSize = parent->m_stackSize + 1;
+ parent->m_stackSize = 0;
+
+ assert (lua_istable (L, -1));
+ rawgetfield (L, -1, name);
+ if (lua_isnil (L, -1))
+ {
+ lua_pop (L, 1);
+
+ lua_newtable (L);
+ lua_pushvalue (L, -1);
+ lua_setmetatable (L, -2);
+ lua_pushcfunction (L, &CFunc::indexMetaMethod);
+ rawsetfield (L, -2, "__index");
+ lua_pushcfunction (L, &CFunc::newindexMetaMethod);
+ rawsetfield (L, -2, "__newindex");
+ lua_newtable (L);
+ rawsetfield (L, -2, "__propget");
+ lua_newtable (L);
+ rawsetfield (L, -2, "__propset");
+ lua_pushvalue (L, -1);
+ rawsetfield (L, -3, name);
+#if 0
+ lua_pushcfunction (L, &tostringMetaMethod);
+ rawsetfield (L, -2, "__tostring");
+#endif
+ }
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Creates a continued registration from a child namespace.
+ */
+ explicit Namespace (Namespace const* child)
+ : L (child->L)
+ , m_stackSize (0)
+ {
+ m_stackSize = child->m_stackSize - 1;
+ child->m_stackSize = 1;
+ child->pop (1);
+
+ // It is not necessary or valid to call
+ // endNamespace() for the global namespace!
+ //
+ assert (m_stackSize != 0);
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Creates a continued registration from a child class.
+ */
+ explicit Namespace (ClassBase const* child)
+ : L (child->L)
+ , m_stackSize (0)
+ {
+ m_stackSize = child->m_stackSize - 3;
+ child->m_stackSize = 3;
+ child->pop (3);
+ }
+
+public:
+ //----------------------------------------------------------------------------
+ /**
+ Copy Constructor.
+
+ Ownership of the stack is transferred to the new object. This happens
+ when the compiler emits temporaries to hold these objects while chaining
+ registrations across namespaces.
+ */
+ Namespace (Namespace const& other) : L (other.L)
+ {
+ m_stackSize = other.m_stackSize;
+ other.m_stackSize = 0;
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Closes this namespace registration.
+ */
+ ~Namespace ()
+ {
+ pop (m_stackSize);
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Open the global namespace.
+ */
+ static Namespace getGlobalNamespace (lua_State* L)
+ {
+ return Namespace (L);
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Open a new or existing namespace for registrations.
+ */
+ Namespace beginNamespace (char const* name)
+ {
+ return Namespace (name, this);
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Continue namespace registration in the parent.
+
+ Do not use this on the global namespace.
+ */
+ Namespace endNamespace ()
+ {
+ return Namespace (this);
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Add or replace a variable.
+ */
+ template <class T>
+ Namespace& addVariable (char const* name, T* pt, bool isWritable = true)
+ {
+ assert (lua_istable (L, -1));
+
+ rawgetfield (L, -1, "__propget");
+ assert (lua_istable (L, -1));
+ lua_pushlightuserdata (L, pt);
+ lua_pushcclosure (L, &CFunc::getVariable <T>, 1);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ rawgetfield (L, -1, "__propset");
+ assert (lua_istable (L, -1));
+ if (isWritable)
+ {
+ lua_pushlightuserdata (L, pt);
+ lua_pushcclosure (L, &CFunc::setVariable <T>, 1);
+ }
+ else
+ {
+ lua_pushstring (L, name);
+ lua_pushcclosure (L, &CFunc::readOnlyError, 1);
+ }
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ return *this;
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Add or replace a property.
+
+ If the set function is omitted or null, the property is read-only.
+ */
+ template <class TG, class TS>
+ Namespace& addProperty (char const* name, TG (*get) (), void (*set)(TS) = 0)
+ {
+ assert (lua_istable (L, -1));
+
+ rawgetfield (L, -1, "__propget");
+ assert (lua_istable (L, -1));
+ typedef TG (*get_t) ();
+ new (lua_newuserdata (L, sizeof (get_t))) get_t (get);
+ lua_pushcclosure (L, &CFunc::Call <TG (*) (void)>::f, 1);
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ rawgetfield (L, -1, "__propset");
+ assert (lua_istable (L, -1));
+ if (set != 0)
+ {
+ typedef void (*set_t) (TS);
+ new (lua_newuserdata (L, sizeof (set_t))) set_t (set);
+ lua_pushcclosure (L, &CFunc::Call <void (*) (TS)>::f, 1);
+ }
+ else
+ {
+ lua_pushstring (L, name);
+ lua_pushcclosure (L, &CFunc::readOnlyError, 1);
+ }
+ rawsetfield (L, -2, name);
+ lua_pop (L, 1);
+
+ return *this;
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Add or replace a free function.
+ */
+ template <class FP>
+ Namespace& addFunction (char const* name, FP const fp)
+ {
+ assert (lua_istable (L, -1));
+
+ new (lua_newuserdata (L, sizeof (fp))) FP (fp);
+ lua_pushcclosure (L, &CFunc::Call <FP>::f, 1);
+ rawsetfield (L, -2, name);
+
+ return *this;
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Add or replace a lua_CFunction.
+ */
+ Namespace& addCFunction (char const* name, int (*const fp)(lua_State*))
+ {
+ lua_pushcfunction (L, fp);
+ rawsetfield (L, -2, name);
+
+ return *this;
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Open a new or existing class for registrations.
+ */
+ template <class T>
+ Class <T> beginClass (char const* name)
+ {
+ return Class <T> (name, this);
+ }
+
+ //----------------------------------------------------------------------------
+ /**
+ Derive a new class for registrations.
+
+ To continue registrations for the class later, use beginClass().
+ Do not call deriveClass() again.
+ */
+ template <class T, class U>
+ Class <T> deriveClass (char const* name)
+ {
+ return Class <T> (name, this, ClassInfo <U>::getStaticKey ());
+ }
+};
+
+//------------------------------------------------------------------------------
+/**
+ Retrieve the global namespace.
+
+ It is recommended to put your namespace inside the global namespace, and
+ then add your classes and functions to it, rather than adding many classes
+ and functions directly to the global namespace.
+*/
+inline Namespace getGlobalNamespace (lua_State* L)
+{
+ return Namespace::getGlobalNamespace (L);
+}