order 3lp dirs
This commit is contained in:
1252
3rd/LuaBridge/detail/Namespace.h
Normal file
1252
3rd/LuaBridge/detail/Namespace.h
Normal file
@@ -0,0 +1,1252 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
https://github.com/vinniefalco/LuaBridge
|
||||
|
||||
Copyright 2019, Dmitry Tarakanov
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LuaBridge/detail/Config.h>
|
||||
#include <LuaBridge/detail/ClassInfo.h>
|
||||
#include <LuaBridge/detail/LuaException.h>
|
||||
#include <LuaBridge/detail/Security.h>
|
||||
#include <LuaBridge/detail/TypeTraits.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace luabridge {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Base for class and namespace registration.
|
||||
* Maintains Lua stack in the proper state.
|
||||
* Once beginNamespace, beginClass or deriveClass is called the parent
|
||||
* object upon its destruction may no longer clear the Lua stack.
|
||||
* Then endNamespace or endClass is called, a new parent is created
|
||||
* and the child transfers the responsibility for clearing stack to it.
|
||||
* So there can be maximum one "active" registrar object.
|
||||
*/
|
||||
class Registrar
|
||||
{
|
||||
protected:
|
||||
lua_State* const L;
|
||||
int mutable m_stackSize;
|
||||
|
||||
Registrar (lua_State* L)
|
||||
: L (L)
|
||||
, m_stackSize (0)
|
||||
{
|
||||
}
|
||||
|
||||
Registrar (const Registrar& rhs)
|
||||
: L (rhs.L)
|
||||
, m_stackSize (rhs.m_stackSize)
|
||||
{
|
||||
rhs.m_stackSize = 0;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// MS compiler thinks it's the 2nd copy ctor
|
||||
Registrar(Registrar& rhs)
|
||||
: L (rhs.L)
|
||||
, m_stackSize (rhs.m_stackSize)
|
||||
{
|
||||
rhs.m_stackSize = 0;
|
||||
}
|
||||
#endif // ifndef _MSC_VER
|
||||
|
||||
Registrar& operator= (const Registrar& rhs)
|
||||
{
|
||||
Registrar tmp (rhs);
|
||||
std::swap (m_stackSize, tmp.m_stackSize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Registrar ()
|
||||
{
|
||||
if (m_stackSize > 0)
|
||||
{
|
||||
assert (m_stackSize <= lua_gettop (L));
|
||||
lua_pop (L, m_stackSize);
|
||||
}
|
||||
}
|
||||
|
||||
void assertIsActive () const
|
||||
{
|
||||
if (m_stackSize == 0)
|
||||
{
|
||||
throw std::logic_error ("Unable to continue registration");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Provides C++ to Lua registration capabilities.
|
||||
|
||||
This class is not instantiated directly, call `getGlobalNamespace` to start
|
||||
the registration process.
|
||||
*/
|
||||
class Namespace : public detail::Registrar
|
||||
{
|
||||
//============================================================================
|
||||
/**
|
||||
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
|
||||
|
||||
/**
|
||||
Factored base to reduce template instantiations.
|
||||
*/
|
||||
class ClassBase : public detail::Registrar
|
||||
{
|
||||
public:
|
||||
explicit ClassBase (Namespace& parent)
|
||||
: Registrar (parent)
|
||||
{
|
||||
}
|
||||
|
||||
using Registrar::operator=;
|
||||
|
||||
protected:
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Create the const table.
|
||||
*/
|
||||
void createConstTable (const char* name, bool trueConst = true)
|
||||
{
|
||||
std::string type_name = std::string (trueConst ? "const " : "") + name;
|
||||
|
||||
// Stack: namespace table (ns)
|
||||
lua_newtable (L); // Stack: ns, const table (co)
|
||||
lua_pushvalue (L, -1); // Stack: ns, co, co
|
||||
lua_setmetatable (L, -2); // co.__metatable = co. Stack: ns, co
|
||||
|
||||
lua_pushstring (L, type_name.c_str ());
|
||||
lua_rawsetp (L, -2, getTypeKey ()); // co [typeKey] = name. Stack: ns, co
|
||||
|
||||
lua_pushcfunction (L, &CFunc::indexMetaMethod);
|
||||
rawsetfield (L, -2, "__index");
|
||||
|
||||
lua_pushcfunction (L, &CFunc::newindexObjectMetaMethod);
|
||||
rawsetfield (L, -2, "__newindex");
|
||||
|
||||
lua_newtable (L);
|
||||
lua_rawsetp (L, -2, getPropgetKey ());
|
||||
|
||||
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)
|
||||
{
|
||||
// Stack: namespace table (ns), const table (co)
|
||||
|
||||
// Class table is the same as const table except the propset table
|
||||
createConstTable (name, false); // Stack: ns, co, cl
|
||||
|
||||
lua_newtable (L); // Stack: ns, co, cl, propset table (ps)
|
||||
lua_rawsetp (L, -2, getPropsetKey ()); // cl [propsetKey] = ps. Stack: ns, co, cl
|
||||
|
||||
lua_pushvalue (L, -2); // Stack: ns, co, cl, co
|
||||
lua_rawsetp(L, -2, getConstKey ()); // cl [constKey] = co. Stack: ns, co, cl
|
||||
|
||||
lua_pushvalue (L, -1); // Stack: ns, co, cl, cl
|
||||
lua_rawsetp (L, -3, getClassKey ()); // co [classKey] = cl. Stack: ns, co, cl
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Create the static table.
|
||||
*/
|
||||
void createStaticTable (char const* name)
|
||||
{
|
||||
// Stack: namespace table (ns), const table (co), class table (cl)
|
||||
lua_newtable (L); // Stack: ns, co, cl, visible static table (vst)
|
||||
lua_newtable (L); // Stack: ns, co, cl, st, static metatable (st)
|
||||
lua_pushvalue (L, -1); // Stack: ns, co, cl, vst, st, st
|
||||
lua_setmetatable (L, -3); // st.__metatable = mt. Stack: ns, co, cl, vst, st
|
||||
lua_insert (L, -2); // Stack: ns, co, cl, st, vst
|
||||
rawsetfield (L, -5, name); // ns [name] = vst. Stack: ns, co, cl, st
|
||||
|
||||
#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::newindexStaticMetaMethod);
|
||||
rawsetfield (L, -2, "__newindex");
|
||||
|
||||
lua_newtable (L); // Stack: ns, co, cl, st, proget table (pg)
|
||||
lua_rawsetp (L, -2, getPropgetKey ()); // st [propgetKey] = pg. Stack: ns, co, cl, st
|
||||
|
||||
lua_newtable (L); // Stack: ns, co, cl, st, propset table (ps)
|
||||
lua_rawsetp (L, -2, getPropsetKey ()); // st [propsetKey] = pg. Stack: ns, co, cl, st
|
||||
|
||||
lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl
|
||||
lua_rawsetp(L, -2, getClassKey()); // st [classKey] = cl. Stack: ns, co, cl, st
|
||||
|
||||
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);
|
||||
UserdataValue <T>* value = UserdataValue <T>::place (L);
|
||||
Constructor <T, Params>::call (value->getObject (), args);
|
||||
value->commit ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void assertStackState () const
|
||||
{
|
||||
// Stack: const table (co), class table (cl), static table (st)
|
||||
assert (lua_istable (L, -3));
|
||||
assert (lua_istable (L, -2));
|
||||
assert (lua_istable (L, -1));
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Class
|
||||
//
|
||||
//============================================================================
|
||||
/**
|
||||
Provides a class registration in a lua_State.
|
||||
|
||||
After construction the Lua stack holds these objects:
|
||||
-1 static table
|
||||
-2 class table
|
||||
-3 const table
|
||||
-4 enclosing namespace table
|
||||
*/
|
||||
template <class T>
|
||||
class Class : public ClassBase
|
||||
{
|
||||
public:
|
||||
//==========================================================================
|
||||
/**
|
||||
Register a new class or add to an existing class registration.
|
||||
*/
|
||||
Class (char const* name, Namespace& parent)
|
||||
: ClassBase (parent)
|
||||
{
|
||||
assert (lua_istable (L, -1)); // Stack: namespace table (ns)
|
||||
rawgetfield (L, -1, name); // Stack: ns, static table (st) | nil
|
||||
|
||||
if (lua_isnil (L, -1)) // Stack: ns, nil
|
||||
{
|
||||
lua_pop (L, 1); // Stack: ns
|
||||
|
||||
createConstTable (name); // Stack: ns, const table (co)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, function
|
||||
rawsetfield (L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co
|
||||
++m_stackSize;
|
||||
|
||||
createClassTable (name); // Stack: ns, co, class table (cl)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, cl, function
|
||||
rawsetfield (L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl
|
||||
++m_stackSize;
|
||||
|
||||
createStaticTable (name); // Stack: ns, co, cl, st
|
||||
++m_stackSize;
|
||||
|
||||
// Map T back to its tables.
|
||||
lua_pushvalue (L, -1); // Stack: ns, co, cl, st, st
|
||||
lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getStaticKey ()); // Stack: ns, co, cl, st
|
||||
lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl
|
||||
lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); // Stack: ns, co, cl, st
|
||||
lua_pushvalue (L, -3); // Stack: ns, co, cl, st, co
|
||||
lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); // Stack: ns, co, cl, st
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (lua_istable (L, -1)); // Stack: ns, st
|
||||
++m_stackSize;
|
||||
|
||||
// Map T back from its stored tables
|
||||
|
||||
lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); // Stack: ns, st, co
|
||||
lua_insert (L, -2); // Stack: ns, co, st
|
||||
++m_stackSize;
|
||||
|
||||
lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); // Stack: ns, co, st, cl
|
||||
lua_insert (L, -2); // Stack: ns, co, cl, st
|
||||
++m_stackSize;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
/**
|
||||
Derive a new class.
|
||||
*/
|
||||
Class (char const* name, Namespace& parent, void const* const staticKey)
|
||||
: ClassBase (parent)
|
||||
{
|
||||
assert (lua_istable (L, -1)); // Stack: namespace table (ns)
|
||||
|
||||
createConstTable (name); // Stack: ns, const table (co)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, function
|
||||
rawsetfield (L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co
|
||||
++m_stackSize;
|
||||
|
||||
createClassTable (name); // Stack: ns, co, class table (cl)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); // Stack: ns, co, cl, function
|
||||
rawsetfield (L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl
|
||||
++m_stackSize;
|
||||
|
||||
createStaticTable (name); // Stack: ns, co, cl, st
|
||||
++m_stackSize;
|
||||
|
||||
lua_rawgetp (L, LUA_REGISTRYINDEX, staticKey); // Stack: ns, co, cl, st, parent st (pst) | nil
|
||||
if (lua_isnil (L, -1)) // Stack: ns, co, cl, st, nil
|
||||
{
|
||||
++m_stackSize;
|
||||
throw std::runtime_error ("Base class is not registered");
|
||||
}
|
||||
|
||||
assert (lua_istable (L, -1)); // Stack: ns, co, cl, st, pst
|
||||
|
||||
lua_rawgetp (L, -1, getClassKey ()); // Stack: ns, co, cl, st, pst, parent cl (pcl)
|
||||
assert (lua_istable (L, -1));
|
||||
|
||||
lua_rawgetp (L, -1, getConstKey ()); // Stack: ns, co, cl, st, pst, pcl, parent co (pco)
|
||||
assert (lua_istable (L, -1));
|
||||
|
||||
lua_rawsetp (L, -6, getParentKey ()); // co [parentKey] = pco. Stack: ns, co, cl, st, pst, pcl
|
||||
lua_rawsetp (L, -4, getParentKey ()); // cl [parentKey] = pcl. Stack: ns, co, cl, st, pst
|
||||
lua_rawsetp (L, -2, getParentKey ()); // st [parentKey] = pst. Stack: ns, co, cl, st
|
||||
|
||||
lua_pushvalue (L, -1); // Stack: ns, co, cl, st, st
|
||||
lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getStaticKey ()); // Stack: ns, co, cl, st
|
||||
lua_pushvalue (L, -2); // Stack: ns, co, cl, st, cl
|
||||
lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); // Stack: ns, co, cl, st
|
||||
lua_pushvalue (L, -3); // Stack: ns, co, cl, st, co
|
||||
lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); // Stack: ns, co, cl, st
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Continue registration in the enclosing namespace.
|
||||
*/
|
||||
Namespace endClass ()
|
||||
{
|
||||
assert (m_stackSize > 3);
|
||||
m_stackSize -= 3;
|
||||
lua_pop (L, 3);
|
||||
return Namespace (*this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a static data member.
|
||||
*/
|
||||
template <class U>
|
||||
Class <T>& addStaticProperty (char const* name, U* pu, bool isWritable = true)
|
||||
{
|
||||
return addStaticData (name, pu, isWritable);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a static data member.
|
||||
*/
|
||||
template <class U>
|
||||
Class <T>& addStaticData (char const* name, U* pu, bool isWritable = true)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
lua_pushlightuserdata (L, pu); // Stack: co, cl, st, pointer
|
||||
lua_pushcclosure (L, &CFunc::getVariable <U>, 1); // Stack: co, cl, st, getter
|
||||
CFunc::addGetter (L, name, -2); // Stack: co, cl, st
|
||||
|
||||
if (isWritable)
|
||||
{
|
||||
lua_pushlightuserdata (L, pu); // Stack: co, cl, st, ps, pointer
|
||||
lua_pushcclosure (L, &CFunc::setVariable <U>, 1); // Stack: co, cl, st, ps, setter
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushstring (L, name); // Stack: co, cl, st, name
|
||||
lua_pushcclosure (L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn
|
||||
}
|
||||
CFunc::addSetter (L, name, -2); // Stack: co, cl, st
|
||||
|
||||
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)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (get)); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <U (*) ()>::f, 1); // Stack: co, cl, st, getter
|
||||
CFunc::addGetter (L, name, -2); // Stack: co, cl, st
|
||||
|
||||
if (set != 0)
|
||||
{
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (set)); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <void (*) (U)>::f, 1); // Stack: co, cl, st, setter
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushstring (L, name); // Stack: co, cl, st, ps, name
|
||||
lua_pushcclosure (L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn
|
||||
}
|
||||
CFunc::addSetter (L, name, -2); // Stack: co, cl, st
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a static member function.
|
||||
*/
|
||||
template <class FP>
|
||||
Class <T>& addStaticFunction (char const* name, FP const fp)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (fp)); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <FP>::f, 1); // co, cl, st, function
|
||||
rawsetfield (L, -2, name); // co, cl, st
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a lua_CFunction.
|
||||
*/
|
||||
Class <T>& addStaticFunction (char const* name, int (*const fp) (lua_State*))
|
||||
{
|
||||
return addStaticCFunction (name, fp);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a lua_CFunction.
|
||||
*/
|
||||
Class <T>& addStaticCFunction (char const* name, int (*const fp) (lua_State*))
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
lua_pushcfunction (L, fp); // co, cl, st, function
|
||||
rawsetfield (L, -2, name); // co, cl, st
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a data member.
|
||||
*/
|
||||
template <class U>
|
||||
Class <T>& addProperty (char const* name, U T::* mp, bool isWritable = true)
|
||||
{
|
||||
return addData (name, mp, isWritable);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a data member.
|
||||
*/
|
||||
template <class U>
|
||||
Class <T>& addData (char const* name, U T::* mp, bool isWritable = true)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
typedef const U T::*mp_t;
|
||||
new (lua_newuserdata (L, sizeof (mp_t))) mp_t (mp); // Stack: co, cl, st, field ptr
|
||||
lua_pushcclosure (L, &CFunc::getProperty <T, U>, 1); // Stack: co, cl, st, getter
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter
|
||||
CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter
|
||||
CFunc::addGetter (L, name, -3); // Stack: co, cl, st
|
||||
|
||||
if (isWritable)
|
||||
{
|
||||
new (lua_newuserdata (L, sizeof (mp_t))) mp_t (mp); // Stack: co, cl, st, field ptr
|
||||
lua_pushcclosure (L, &CFunc::setProperty <T, U>, 1); // Stack: co, cl, st, setter
|
||||
CFunc::addSetter (L, name, -3); // Stack: co, cl, st
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a property member.
|
||||
*/
|
||||
template <class TG, class TS = TG>
|
||||
Class <T>& addProperty (char const* name, TG (T::* get) () const, void (T::* set) (TS) = 0)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
typedef TG (T::*get_t) () const;
|
||||
new (lua_newuserdata (L, sizeof (get_t))) get_t (get); // Stack: co, cl, st, funcion ptr
|
||||
lua_pushcclosure (L, &CFunc::CallConstMember <get_t>::f, 1); // Stack: co, cl, st, getter
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter
|
||||
CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter
|
||||
CFunc::addGetter (L, name, -3); // Stack: co, cl, st
|
||||
|
||||
if (set != 0)
|
||||
{
|
||||
typedef void (T::* set_t) (TS);
|
||||
new (lua_newuserdata (L, sizeof (set_t))) set_t (set); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::CallMember <set_t>::f, 1); // Stack: co, cl, st, setter
|
||||
CFunc::addSetter (L, name, -3); // Stack: co, cl, st
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a property member.
|
||||
*/
|
||||
template <class TG, class TS = TG>
|
||||
Class <T>& addProperty (char const* name, TG (T::* get) (lua_State*) const, void (T::* set) (TS, lua_State*) = 0)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
typedef TG (T::*get_t) (lua_State*) const;
|
||||
new (lua_newuserdata (L, sizeof (get_t))) get_t (get); // Stack: co, cl, st, funcion ptr
|
||||
lua_pushcclosure (L, &CFunc::CallConstMember <get_t>::f, 1); // Stack: co, cl, st, getter
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter
|
||||
CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter
|
||||
CFunc::addGetter (L, name, -3); // Stack: co, cl, st
|
||||
|
||||
if (set != 0)
|
||||
{
|
||||
typedef void (T::* set_t) (TS, lua_State*);
|
||||
new (lua_newuserdata (L, sizeof (set_t))) set_t (set); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::CallMember <set_t>::f, 1); // Stack: co, cl, st, setter
|
||||
CFunc::addSetter (L, name, -3); // Stack: co, cl, st
|
||||
}
|
||||
|
||||
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 = TG>
|
||||
Class <T>& addProperty (char const* name, TG (*get) (T const*), void (*set) (T*, TS) = 0)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (get)); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <TG (*) (const T*)>::f, 1); // Stack: co, cl, st, getter
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st,, getter, getter
|
||||
CFunc::addGetter (L, name, -5); // Stack: co, cl, st, getter
|
||||
CFunc::addGetter (L, name, -3); // Stack: co, cl, st
|
||||
|
||||
if (set != 0)
|
||||
{
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (set)); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <void (*) (T*, TS)>::f, 1); // Stack: co, cl, st, setter
|
||||
CFunc::addSetter (L, name, -3); // Stack: co, cl, st
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a property member, by proxy C-function.
|
||||
|
||||
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.
|
||||
|
||||
The object userdata ('this') value is at the index 1.
|
||||
The new value for set function is at the index 2.
|
||||
*/
|
||||
Class <T>& addProperty (char const* name, int (*get) (lua_State*), int (*set) (lua_State*) = 0)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
lua_pushcfunction (L, get);
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st,, getter, getter
|
||||
CFunc::addGetter (L, name, -5); // Stack: co, cl, st,, getter
|
||||
CFunc::addGetter (L, name, -3); // Stack: co, cl, st,
|
||||
|
||||
if (set != 0)
|
||||
{
|
||||
lua_pushcfunction (L, set);
|
||||
CFunc::addSetter (L, name, -3); // Stack: co, cl, st,
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef LUABRIDGE_CXX11
|
||||
template <class TG, class TS = TG>
|
||||
Class <T>& addProperty (char const* name,
|
||||
std::function <TG (const T*)> get,
|
||||
std::function <void (T*, TS)> set = nullptr)
|
||||
{
|
||||
using GetType = decltype (get);
|
||||
new (lua_newuserdata (L, sizeof (get))) GetType (std::move (get)); // Stack: co, cl, st, function userdata (ud)
|
||||
lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethodAny <GetType>); // Stack: co, cl, st, ud, mt, gc function
|
||||
rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt
|
||||
lua_setmetatable (L, -2); // Stack: co, cl, st, ud
|
||||
lua_pushcclosure (L, &CFunc::CallProxyFunctor <GetType>::f, 1); // Stack: co, cl, st, getter
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st, getter, getter
|
||||
CFunc::addGetter (L, name, -4); // Stack: co, cl, st, getter
|
||||
CFunc::addGetter (L, name, -4); // Stack: co, cl, st
|
||||
|
||||
if (set != nullptr)
|
||||
{
|
||||
using SetType = decltype (set);
|
||||
new (lua_newuserdata (L, sizeof (set))) SetType (std::move (set)); // Stack: co, cl, st, function userdata (ud)
|
||||
lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethodAny <SetType>); // Stack: co, cl, st, ud, mt, gc function
|
||||
rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt
|
||||
lua_setmetatable (L, -2); // Stack: co, cl, st, ud
|
||||
lua_pushcclosure (L, &CFunc::CallProxyFunctor <SetType>::f, 1); // Stack: co, cl, st, setter
|
||||
CFunc::addSetter (L, name, -3); // Stack: co, cl, st
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // LUABRIDGE_CXX11
|
||||
|
||||
#ifndef LUABRIDGE_CXX11
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a member function.
|
||||
*/
|
||||
template <class MemFn>
|
||||
Class <T>& addFunction (char const* name, MemFn mf)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
static const std::string GC = "__gc";
|
||||
if (name == GC)
|
||||
{
|
||||
throw std::logic_error (GC + " metamethod registration is forbidden");
|
||||
}
|
||||
CFunc::CallMemberFunctionHelper <MemFn, FuncTraits <MemFn>::isConstMemberFunction>::add (L, name, mf);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#else // ifndef LUABRIDGE_CXX11
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a member function by std::function.
|
||||
*/
|
||||
template <class ReturnType, class... Params>
|
||||
Class <T>& addFunction (char const* name, std::function <ReturnType (T*, Params...)> function)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
using FnType = decltype (function);
|
||||
new (lua_newuserdata (L, sizeof (function))) FnType (std::move (function)); // Stack: co, cl, st, function userdata (ud)
|
||||
lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethodAny <FnType>); // Stack: co, cl, st, ud, mt, gc function
|
||||
rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt
|
||||
lua_setmetatable (L, -2); // Stack: co, cl, st, ud
|
||||
lua_pushcclosure (L, &CFunc::CallProxyFunctor <FnType>::f, 1); // Stack: co, cl, st, function
|
||||
rawsetfield (L, -3, name); // Stack: co, cl, st
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a const member function by std::function.
|
||||
*/
|
||||
template <class ReturnType, class... Params>
|
||||
Class <T>& addFunction (char const* name, std::function <ReturnType (const T*, Params...)> function)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
using FnType = decltype (function);
|
||||
new (lua_newuserdata (L, sizeof (function))) FnType (std::move (function)); // Stack: co, cl, st, function userdata (ud)
|
||||
lua_newtable (L); // Stack: co, cl, st, ud, ud metatable (mt)
|
||||
lua_pushcfunction (L, &CFunc::gcMetaMethodAny <FnType>); // Stack: co, cl, st, ud, mt, gc function
|
||||
rawsetfield (L, -2, "__gc"); // Stack: co, cl, st, ud, mt
|
||||
lua_setmetatable (L, -2); // Stack: co, cl, st, ud
|
||||
lua_pushcclosure (L, &CFunc::CallProxyFunctor <FnType>::f, 1); // Stack: co, cl, st, function
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st, function, function
|
||||
rawsetfield (L, -4, name); // Stack: co, cl, st, function
|
||||
rawsetfield (L, -4, name); // Stack: co, cl, st
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a member function.
|
||||
*/
|
||||
template <class ReturnType, class... Params>
|
||||
Class <T>& addFunction (char const* name, ReturnType (T::* mf) (Params...))
|
||||
{
|
||||
using MemFn = ReturnType (T::*) (Params...);
|
||||
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
static const std::string GC = "__gc";
|
||||
if (name == GC)
|
||||
{
|
||||
throw std::logic_error (GC + " metamethod registration is forbidden");
|
||||
}
|
||||
CFunc::CallMemberFunctionHelper <MemFn, false>::add (L, name, mf);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class ReturnType, class... Params>
|
||||
Class <T>& addFunction (char const* name, ReturnType (T::* mf) (Params...) const)
|
||||
{
|
||||
using MemFn = ReturnType (T::*) (Params...) const;
|
||||
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
static const std::string GC = "__gc";
|
||||
if (name == GC)
|
||||
{
|
||||
throw std::logic_error (GC + " metamethod registration is forbidden");
|
||||
}
|
||||
CFunc::CallMemberFunctionHelper <MemFn, true>::add (L, name, mf);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a proxy function.
|
||||
*/
|
||||
template <class ReturnType, class... Params>
|
||||
Class <T>& addFunction (char const* name, ReturnType (*proxyFn) (T* object, Params...))
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
static const std::string GC = "__gc";
|
||||
if (name == GC)
|
||||
{
|
||||
throw std::logic_error (GC + " metamethod registration is forbidden");
|
||||
}
|
||||
using FnType = decltype (proxyFn);
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (proxyFn)); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::CallProxyFunction <FnType>::f, 1); // Stack: co, cl, st, function
|
||||
rawsetfield (L, -3, name); // Stack: co, cl, st
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class ReturnType, class... Params>
|
||||
Class <T>& addFunction (char const* name, ReturnType (*proxyFn) (const T* object, Params...))
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
static const std::string GC = "__gc";
|
||||
if (name == GC)
|
||||
{
|
||||
throw std::logic_error (GC + " metamethod registration is forbidden");
|
||||
}
|
||||
using FnType = decltype (proxyFn);
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (proxyFn)); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::CallProxyFunction <FnType>::f, 1); // Stack: co, cl, st, function
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st, function, function
|
||||
rawsetfield (L, -4, name); // Stack: co, cl, st, function
|
||||
rawsetfield (L, -4, name); // Stack: co, cl, st
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a member lua_CFunction.
|
||||
*/
|
||||
Class <T>& addFunction (char const* name, int (T::*mfp) (lua_State*))
|
||||
{
|
||||
return addCFunction (name, mfp);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a member lua_CFunction.
|
||||
*/
|
||||
Class <T>& addCFunction (char const* name, int (T::*mfp) (lua_State*))
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
typedef int (T::*MFP) (lua_State*);
|
||||
new (lua_newuserdata (L, sizeof (mfp))) MFP (mfp); // Stack: co, cl, st, function ptr
|
||||
lua_pushcclosure (L, &CFunc::CallMemberCFunction <T>::f, 1); // Stack: co, cl, st, function
|
||||
rawsetfield (L, -3, name); // Stack: co, cl, st
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a const member lua_CFunction.
|
||||
*/
|
||||
Class <T>& addFunction (char const* name, int (T::*mfp) (lua_State*) const)
|
||||
{
|
||||
return addCFunction (name, mfp);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a const member lua_CFunction.
|
||||
*/
|
||||
Class <T>& addCFunction (char const* name, int (T::*mfp) (lua_State*) const)
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
typedef int (T::*MFP) (lua_State*) const;
|
||||
new (lua_newuserdata (L, sizeof (mfp))) MFP (mfp);
|
||||
lua_pushcclosure (L, &CFunc::CallConstMemberCFunction <T>::f, 1);
|
||||
lua_pushvalue (L, -1); // Stack: co, cl, st, function, function
|
||||
rawsetfield (L, -4, name); // Stack: co, cl, st, function
|
||||
rawsetfield (L, -4, name); // Stack: co, cl, st
|
||||
|
||||
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 ()
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
lua_pushcclosure (L, &ctorContainerProxy <typename FuncTraits <MemFn>::Params, C>, 0);
|
||||
rawsetfield (L, -2, "__call");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class MemFn>
|
||||
Class <T>& addConstructor ()
|
||||
{
|
||||
assertStackState (); // Stack: const table (co), class table (cl), static table (st)
|
||||
|
||||
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)
|
||||
: Registrar (L)
|
||||
{
|
||||
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& parent)
|
||||
: Registrar (parent)
|
||||
{
|
||||
assert (lua_istable (L, -1)); // Stack: parent namespace (pns)
|
||||
|
||||
rawgetfield (L, -1, name); // Stack: pns, namespace (ns) | nil
|
||||
|
||||
if (lua_isnil (L, -1)) // Stack: pns, nil
|
||||
{
|
||||
lua_pop (L, 1); // Stack: pns
|
||||
|
||||
lua_newtable (L); // Stack: pns, ns
|
||||
lua_pushvalue (L, -1); // Stack: pns, ns, ns
|
||||
|
||||
// na.__metatable = ns
|
||||
lua_setmetatable (L, -2); // Stack: pns, ns
|
||||
|
||||
// ns.__index = indexMetaMethod
|
||||
lua_pushcfunction (L, &CFunc::indexMetaMethod);
|
||||
rawsetfield (L, -2, "__index"); // Stack: pns, ns
|
||||
|
||||
// ns.__newindex = newindexMetaMethod
|
||||
lua_pushcfunction (L, &CFunc::newindexStaticMetaMethod);
|
||||
rawsetfield (L, -2, "__newindex"); // Stack: pns, ns
|
||||
|
||||
lua_newtable (L); // Stack: pns, ns, propget table (pg)
|
||||
lua_rawsetp (L, -2, getPropgetKey ()); // ns [propgetKey] = pg. Stack: pns, ns
|
||||
|
||||
lua_newtable (L); // Stack: pns, ns, propset table (ps)
|
||||
lua_rawsetp (L, -2, getPropsetKey ()); // ns [propsetKey] = ps. Stack: pns, ns
|
||||
|
||||
// pns [name] = ns
|
||||
lua_pushvalue (L, -1); // Stack: pns, ns, ns
|
||||
rawsetfield (L, -3, name); // Stack: pns, ns
|
||||
#if 0
|
||||
lua_pushcfunction (L, &tostringMetaMethod);
|
||||
rawsetfield (L, -2, "__tostring");
|
||||
#endif
|
||||
}
|
||||
|
||||
++m_stackSize;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Close the class and continue the namespace registrations.
|
||||
*/
|
||||
explicit Namespace (ClassBase& child)
|
||||
: Registrar (child)
|
||||
{
|
||||
}
|
||||
|
||||
using Registrar::operator=;
|
||||
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Open the global namespace.
|
||||
*/
|
||||
static Namespace getGlobalNamespace (lua_State* L)
|
||||
{
|
||||
enableExceptions (L);
|
||||
return Namespace (L);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Open a new or existing namespace for registrations.
|
||||
*/
|
||||
Namespace beginNamespace (char const* name)
|
||||
{
|
||||
assertIsActive ();
|
||||
return Namespace (name, *this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Continue namespace registration in the parent.
|
||||
|
||||
Do not use this on the global namespace.
|
||||
*/
|
||||
Namespace endNamespace ()
|
||||
{
|
||||
if (m_stackSize == 1)
|
||||
{
|
||||
throw std::logic_error ("endNamespace () called on global namespace");
|
||||
}
|
||||
|
||||
assert (m_stackSize > 1);
|
||||
--m_stackSize;
|
||||
lua_pop (L, 1);
|
||||
return Namespace (*this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a variable.
|
||||
*/
|
||||
template <class T>
|
||||
Namespace& addProperty (char const* name, T* pt, bool isWritable = true)
|
||||
{
|
||||
return addVariable (name, pt, isWritable);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a variable.
|
||||
*/
|
||||
template <class T>
|
||||
Namespace& addVariable (char const* name, T* pt, bool isWritable = true)
|
||||
{
|
||||
if (m_stackSize == 1)
|
||||
{
|
||||
throw std::logic_error ("addProperty () called on global namespace");
|
||||
}
|
||||
|
||||
assert (lua_istable (L, -1)); // Stack: namespace table (ns)
|
||||
|
||||
lua_pushlightuserdata (L, pt); // Stack: ns, pointer
|
||||
lua_pushcclosure (L, &CFunc::getVariable <T>, 1); // Stack: ns, getter
|
||||
CFunc::addGetter (L, name, -2); // Stack: ns
|
||||
|
||||
if (isWritable)
|
||||
{
|
||||
lua_pushlightuserdata (L, pt); // Stack: ns, pointer
|
||||
lua_pushcclosure (L, &CFunc::setVariable <T>, 1); // Stack: ns, setter
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushstring (L, name); // Stack: ns, ps, name
|
||||
lua_pushcclosure (L, &CFunc::readOnlyError, 1); // Stack: ns, error_fn
|
||||
}
|
||||
CFunc::addSetter (L, name, -2); // Stack: ns
|
||||
|
||||
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 = TG>
|
||||
Namespace& addProperty (char const* name, TG (*get) (), void (*set) (TS) = 0)
|
||||
{
|
||||
if (m_stackSize == 1)
|
||||
{
|
||||
throw std::logic_error ("addProperty () called on global namespace");
|
||||
}
|
||||
|
||||
assert (lua_istable (L, -1)); // Stack: namespace table (ns)
|
||||
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (get)); // Stack: ns, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <TG (*) ()>::f, 1); // Stack: ns, getter
|
||||
CFunc::addGetter (L, name, -2);
|
||||
|
||||
if (set != 0)
|
||||
{
|
||||
lua_pushlightuserdata(L, reinterpret_cast <void*> (set)); // Stack: ns, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <void (*) (TS)>::f, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushstring (L, name);
|
||||
lua_pushcclosure (L, &CFunc::readOnlyError, 1);
|
||||
}
|
||||
CFunc::addSetter (L, name, -2);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a property.
|
||||
If the set function is omitted or null, the property is read-only.
|
||||
*/
|
||||
Namespace& addProperty (char const* name, int (*get) (lua_State*), int (*set) (lua_State*) = 0)
|
||||
{
|
||||
if (m_stackSize == 1)
|
||||
{
|
||||
throw std::logic_error ("addProperty () called on global namespace");
|
||||
}
|
||||
|
||||
assert (lua_istable (L, -1)); // Stack: namespace table (ns)
|
||||
lua_pushcfunction (L, get); // Stack: ns, getter
|
||||
CFunc::addGetter (L, name, -2); // Stack: ns
|
||||
if (set != 0)
|
||||
{
|
||||
lua_pushcfunction(L, set); // Stack: ns, setter
|
||||
CFunc::addSetter(L, name, -2); // Stack: ns
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushstring(L, name); // Stack: ns, name
|
||||
lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: ns, name, readOnlyError
|
||||
CFunc::addSetter(L, name, -2); // Stack: ns
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a free function.
|
||||
*/
|
||||
template <class FP>
|
||||
Namespace& addFunction (char const* name, FP const fp)
|
||||
{
|
||||
assert (lua_istable (L, -1)); // Stack: namespace table (ns)
|
||||
|
||||
lua_pushlightuserdata (L, reinterpret_cast <void*> (fp)); // Stack: ns, function ptr
|
||||
lua_pushcclosure (L, &CFunc::Call <FP>::f, 1); // Stack: ns, function
|
||||
rawsetfield (L, -2, name); // Stack: ns
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a lua_CFunction.
|
||||
*/
|
||||
Namespace& addFunction (char const* name, int (*const fp) (lua_State*))
|
||||
{
|
||||
return addCFunction (name, fp);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Add or replace a lua_CFunction.
|
||||
*/
|
||||
Namespace& addCFunction (char const* name, int (*const fp) (lua_State*))
|
||||
{
|
||||
assert (lua_istable (L, -1)); // Stack: namespace table (ns)
|
||||
|
||||
lua_pushcfunction (L, fp); // Stack: ns, function
|
||||
rawsetfield (L, -2, name); // Stack: ns
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
Open a new or existing class for registrations.
|
||||
*/
|
||||
template <class T>
|
||||
Class <T> beginClass (char const* name)
|
||||
{
|
||||
assertIsActive ();
|
||||
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 Derived, class Base>
|
||||
Class <Derived> deriveClass (char const* name)
|
||||
{
|
||||
assertIsActive ();
|
||||
return Class <Derived> (name, *this, ClassInfo <Base>::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);
|
||||
}
|
||||
|
||||
} // namespace luabridge
|
||||
Reference in New Issue
Block a user