merge total remake

This commit is contained in:
Eduardo Bart
2011-08-13 23:09:11 -03:00
parent 0af7856475
commit 55862b07ad
253 changed files with 6777 additions and 8463 deletions

View File

@@ -0,0 +1,207 @@
#ifndef LUABINDER_H
#define LUABINDER_H
// this file is and must be included only from luainterface.h
#include "luainterface.h"
#include "luaexception.h"
/// This namespace contains some dirty metaprogamming with C++0x features
/// The purpose here is to create templates that can bind any function from C++
/// and expose in lua environment. This is done combining variadic templates,
/// lambdas, tuples and some type traits features from the new C++0x standard to create
/// templates that can detect functions arguments to generate a lambdas. These lambdas
/// pops arguments from lua stack, call the bound C++ function and then
/// pushes the result to lua.
namespace luabinder
{
/// Removes const references, transforming 'const T&' into 'T'
template<typename T>
struct remove_const_ref {
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
};
/// Pack arguments from lua stack into a tuple recursively
template<int N>
struct pack_values_into_tuple {
template<typename Tuple>
static void call(Tuple& tuple, LuaInterface* lua) {
typedef typename std::tuple_element<N-1, Tuple>::type ValueType;
std::get<N-1>(tuple) = lua->polymorphicPop<ValueType>();
pack_values_into_tuple<N-1>::call(tuple, lua);
}
};
template<>
struct pack_values_into_tuple<0> {
template<typename Tuple>
static void call(Tuple &tuple, LuaInterface* lua) { }
};
/// C++ function caller that can push results to lua
template<typename Ret, typename F, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, int>::type
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
Ret ret = f(args...);
lua->polymorphicPush(ret);
return 1;
}
/// C++ void function caller
template<typename Ret, typename F, typename... Args>
typename std::enable_if<std::is_void<Ret>::value, int>::type
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
f(args...);
return 0;
}
/// Expand arguments from tuple for later calling the C++ function
template<int N, typename Ret>
struct expand_fun_arguments {
template<typename Tuple, typename F, typename... Args>
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::cref(std::get<N-1>(tuple)), args...);
}
};
template<typename Ret>
struct expand_fun_arguments<0,Ret> {
template<typename Tuple, typename F, typename... Args>
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
return call_fun_and_push_result<Ret>(f, lua, args...);
}
};
/// Bind different types of functions generating a lambda
template<typename Ret, typename F, typename Tuple>
LuaCppFunction bind_fun_specializer(const F& f) {
enum { N = std::tuple_size<Tuple>::value };
return [=](LuaInterface* lua) {
if(lua->stackSize() != N)
throw LuaBadNumberOfArgumentsException(N, lua->stackSize());
Tuple tuple;
pack_values_into_tuple<N>::call(tuple, lua);
return expand_fun_arguments<N,Ret>::call(tuple, f, lua);
};
}
/// Bind a std::function
template<typename Ret, typename... Args>
LuaCppFunction bind_fun(const std::function<Ret(Args...)>& f) {
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
}
/// Bind a customized functions
template<>
inline
LuaCppFunction bind_fun(const std::function<int(LuaInterface*)>& f) {
return f;
}
/// Convert to C++ functions pointers to std::function then bind
template<typename Ret, typename... Args>
LuaCppFunction bind_fun(Ret (*f)(Args...)) {
return bind_fun(std::function<Ret(Args...)>(f));
}
// a tuple_element that works with the next algorithm
template<std::size_t __i, typename _Tp>
struct tuple_element;
template<std::size_t __i, typename _Head, typename... _Tail>
struct tuple_element<__i, std::tuple<_Head, _Tail...> >
: tuple_element<__i - 1, std::tuple<_Tail...> > { };
template<typename _Head, typename... _Tail>
struct tuple_element<0, std::tuple<_Head, _Tail...> > { typedef _Head type; };
template<typename _Head>
struct tuple_element<-1,std::tuple<_Head>> { typedef void type; };
template<std::size_t __i>
struct tuple_element<__i,std::tuple<>> { typedef void type; };
template<typename Enable, int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple;
// some dirty stuff to extract arguments from std::bind holders
template<int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple<
typename std::enable_if<
(N > 0 && std::is_placeholder<
typename tuple_element<N-1, HoldersTuple>::type
>::value > 0), void
>::type, N, ArgsTuple, HoldersTuple, Args...> {
typedef typename std::tuple_element<N-1, HoldersTuple>::type holder_type;
typedef typename tuple_element<std::is_placeholder<holder_type>::value-1, ArgsTuple>::type _arg_type;
typedef typename remove_const_ref<_arg_type>::type arg_type;
typedef typename get_holded_tuple<void, N-1, ArgsTuple, HoldersTuple, arg_type, Args...>::type type;
};
template<int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple<typename std::enable_if<(N > 0 && std::is_placeholder<typename tuple_element<N-1, HoldersTuple>::type>::value == 0), void>::type, N, ArgsTuple, HoldersTuple, Args...> {
typedef typename get_holded_tuple<void, N-1, ArgsTuple, HoldersTuple, Args...>::type type;
};
template<typename ArgsTuple, typename HoldersTuple, typename... Args>
struct get_holded_tuple<void, 0, ArgsTuple, HoldersTuple, Args...> {
typedef typename std::tuple<Args...> type;
};
/// Rebind functions already bound by std::bind handling it's placeholders
template<typename Ret, typename... Args, typename... Holders>
LuaCppFunction bind_fun(const std::_Bind<Ret (*(Holders...))(Args...)>& f) {
typedef typename std::tuple<Args...> ArgsTuple;
typedef typename std::tuple<Holders...> HoldersTuple;
typedef typename get_holded_tuple<void, sizeof...(Holders), ArgsTuple, HoldersTuple>::type Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
}
/// Rebind member functions already bound by std::bind handling it's placeholders
template<typename Obj, typename Ret, typename... Args, typename... Holders>
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<Ret (Obj::*)(Args...)>(Obj*, Holders...)>& f) {
typedef typename std::tuple<Args...> ArgsTuple;
typedef typename std::tuple<Holders...> HoldersTuple;
typedef typename get_holded_tuple<void, sizeof...(Holders), ArgsTuple, HoldersTuple>::type Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
}
/// Bind customized functions already bound by std::bind
template<typename Obj>
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<int (Obj::*)(LuaInterface*)>(Obj*, std::_Placeholder<1>)>& f) {
return f;
}
inline
LuaCppFunction bind_fun(const std::_Bind<int (*(std::_Placeholder<1>))(LuaInterface*)>& f) {
return f;
}
/// Bind member functions
template<typename Ret, typename Obj, typename... Args>
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) {
auto mf = std::mem_fn(f);
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(mf),
Tuple>(mf);
}
template<typename Ret, typename Obj, typename... Args>
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...) const) {
auto mf = std::mem_fn(f);
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(mf),
Tuple>(mf);
}
/// Bind customized member functions
template<typename Obj>
LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaInterface*)) {
auto mf = std::mem_fn(f);
return [=](LuaInterface* lua) {
auto obj = lua->castValue<Obj*>(1);
lua->remove(1);
return mf(obj, lua);
};
}
}
#endif

View File

@@ -0,0 +1,12 @@
#ifndef LUADECLARATIONS_H
#define LUADECLARATIONS_H
#include <global.h>
class LuaInterface;
class LuaObject;
typedef std::function<int(LuaInterface*)> LuaCppFunction;
typedef std::unique_ptr<LuaCppFunction> LuaCppFunctionPtr;
typedef std::shared_ptr<LuaObject> LuaObjectPtr;
#endif

View File

@@ -0,0 +1,31 @@
#include "luaexception.h"
#include "luainterface.h"
LuaException::LuaException(const std::string& error, int traceLevel)
{
g_lua.clearStack(); // on every exception, clear lua stack
generateLuaErrorMessage(error, traceLevel);
}
void LuaException::generateLuaErrorMessage(const std::string& error, int traceLevel)
{
// append trace level to error message
if(traceLevel >= 0)
m_what = aux::make_string("LUA ERROR: ", g_lua.traceback(error, traceLevel));
else
m_what = aux::make_string("LUA ERROR: ", error);
}
LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(int expected, int got)
{
std::string error = "attempt to call a function with wrong number of arguments";
if(expected >= 0 && got >= 0)
error = aux::make_string(error, " (expected ", expected, ", but got ", got, ")");
generateLuaErrorMessage(error, 1);
}
LuaBadValueCastException::LuaBadValueCastException(const std::string& luaTypeName, const std::string& cppTypeName)
{
std::string error = aux::make_string("attempt to cast a '", luaTypeName, "' lua value to '", cppTypeName, "'");
generateLuaErrorMessage(error, 0);
}

View File

@@ -0,0 +1,34 @@
#ifndef LUAEXCEPTION_H
#define LUAEXCEPTION_H
#include "luadeclarations.h"
class LuaException : public std::exception
{
public:
LuaException(const std::string& error, int traceLevel = -1);
virtual ~LuaException() throw() { }
void generateLuaErrorMessage(const std::string& error, int traceLevel);
virtual const char* what() const throw() { return m_what.c_str(); }
protected:
LuaException() { }
std::string m_what;
};
class LuaBadNumberOfArgumentsException : public LuaException
{
public:
LuaBadNumberOfArgumentsException(int expected = -1, int got = -1);
};
class LuaBadValueCastException : public LuaException
{
public:
LuaBadValueCastException(const std::string& luaTypeName, const std::string& cppTypeName);
};
#endif

View File

@@ -0,0 +1,63 @@
#include "luainterface.h"
#include <graphics/fontmanager.h>
#include <ui/ui.h>
#include <net/protocol.h>
void LuaInterface::registerFunctions()
{
// easy typing _1, _2, ...
using namespace std::placeholders;
// UIWidget
g_lua.registerClass<UIWidget>();
g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create);
g_lua.bindClassMemberFunction("destroy", &UIWidget::destroy);
g_lua.bindClassMemberFunction("addChild", &UIWidget::addChild);
g_lua.bindClassMemberField<UIWidget>("id", &UIWidget::getId, &UIWidget::setId);
g_lua.bindClassMemberField<UIWidget>("enabled", &UIWidget::isEnabled, &UIWidget::setEnabled);
g_lua.bindClassMemberField<UIWidget>("visible", &UIWidget::isVisible, &UIWidget::setVisible);
g_lua.bindClassMemberField<UIWidget>("width", &UIWidget::getWidth, &UIWidget::setWidth);
g_lua.bindClassMemberField<UIWidget>("height", &UIWidget::getHeight, &UIWidget::setHeight);
g_lua.bindClassMemberField<UIWidget>("parent", &UIWidget::getParent, &UIWidget::setParent);
g_lua.bindClassMemberField<UIWidget>("marginTop", &UIWidget::getMarginTop, &UIWidget::setMarginTop);
g_lua.bindClassMemberField<UIWidget>("marginBottom", &UIWidget::getMarginBottom, &UIWidget::setMarginBottom);
g_lua.bindClassMemberField<UIWidget>("marginLeft", &UIWidget::getMarginLeft, &UIWidget::setMarginLeft);
g_lua.bindClassMemberField<UIWidget>("marginRight", &UIWidget::getMarginRight, &UIWidget::setMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("centerIn", &UIWidget::centerIn);
g_lua.bindClassMemberFunction<UIWidget>("addAnchor", &UIWidget::addAnchor);
g_lua.bindClassMemberFunction<UIWidget>("getChild", &UIWidget::getChildById);
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);
// UILabel
g_lua.registerClass<UILabel, UIWidget>();
g_lua.bindClassStaticFunction<UILabel>("create", &UILabel::create);
g_lua.bindClassMemberField("text", &UILabel::getText, &UILabel::setText);
g_lua.bindClassMemberFunction("resizeToText", &UILabel::resizeToText);
// UIButton
g_lua.registerClass<UIButton, UIWidget>();
g_lua.bindClassStaticFunction<UIButton>("create", &UIButton::create);
g_lua.bindClassMemberField("text", &UIButton::getText, &UIButton::setText);
// UILineEdit
g_lua.registerClass<UILineEdit, UIWidget>();
g_lua.bindClassStaticFunction<UILineEdit>("create", &UILineEdit::create);
g_lua.bindClassMemberField("text", &UILineEdit::getText, &UILineEdit::setText);
// UIWindow
g_lua.registerClass<UIWindow, UIWidget>();
g_lua.bindClassStaticFunction<UIWindow>("create", &UIWindow::create);
g_lua.bindClassMemberField("title", &UIWindow::getTitle, &UIWindow::setTitle);
// Protocol
g_lua.registerClass<Protocol>();
// global functions
g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1));
g_lua.bindGlobalFunction("setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _1));
g_lua.bindGlobalFunction("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1));
g_lua.bindGlobalFunction("loadUI", std::bind(&UIManager::loadUI, &g_ui, _1));
g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui));
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,329 @@
#ifndef LUAINTERFACE_H
#define LUAINTERFACE_H
#include "luadeclarations.h"
struct lua_State;
typedef int (*LuaCFunction) (lua_State *L);
/// Class that manages LUA stuff
class LuaInterface
{
public:
LuaInterface();
~LuaInterface();
void init();
void terminate();
/// Register core script functions
void registerFunctions();
// functions that will register all script stuff in lua global environment
void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
void registerClassStaticFunction(const std::string& className,
const std::string& functionName,
const LuaCppFunction& function);
void registerClassMemberFunction(const std::string& className,
const std::string& functionName,
const LuaCppFunction& function);
void registerClassMemberField(const std::string& className,
const std::string& field,
const LuaCppFunction& getFunction,
const LuaCppFunction& setFunction);
void registerGlobalFunction(const std::string& functionName,
const LuaCppFunction& function);
// register shortcuts using templates
template<class C, class B = LuaObject>
void registerClass() {
registerClass(aux::demangle_type<C>(), aux::demangle_type<B>());
}
template<class C>
void registerClassStaticFunction(const std::string& functionName, const LuaCppFunction& function) {
registerClassStaticFunction(aux::demangle_type<C>(), functionName, function);
}
template<class C>
void registerClassMemberFunction(const std::string& functionName, const LuaCppFunction& function) {
registerClassMemberFunction(aux::demangle_type<C>(), functionName, function);
}
template<class C>
void registerClassMemberField(const std::string& field,
const LuaCppFunction& getFunction,
const LuaCppFunction& setFunction) {
registerClassMemberField(aux::demangle_type<C>(), field, getFunction, setFunction);
}
// methods for binding functions
template<class C, typename F>
void bindClassStaticFunction(const std::string& functionName, const F& function);
template<class C, typename F>
void bindClassMemberFunction(const std::string& functionName, F C::*function);
template<class C, typename F1, typename F2>
void bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction);
template<class C, typename F>
void bindClassMemberGetField(const std::string& fieldName, F C::*getFunction);
template<class C, typename F>
void bindClassMemberSetField(const std::string& fieldName, F C::*setFunction);
template<typename F>
void bindGlobalFunction(const std::string& functionName, const F& function);
private:
/// Metamethod that will retrieve fields values (that include functions) from the object when using '.' or ':'
static int luaObjectGetEvent(LuaInterface* lua);
/// Metamethod that is called when setting a field of the object by using the keyword '='
static int luaObjectSetEvent(LuaInterface* lua);
/// Metamethod that will check equality of objects by using the keyword '=='
static int luaObjectEqualEvent(LuaInterface* lua);
/// Metamethod that is called every two lua garbage collections
/// for any LuaObject that have no references left in lua environment
/// anymore, thus this creates the possibility of holding an object
/// existence by lua until it got no references left
static int luaObjectCollectEvent(LuaInterface* lua);
public:
/// Loads and runs a script
/// @exception LuaException is thrown on any lua error
void runScript(const std::string& fileName);
/// Loads and runs the script from buffer
/// @exception LuaException is thrown on any lua error
void runBuffer(const std::string& buffer, const std::string& source);
/// Loads a script file and pushes it's main function onto stack,
/// @exception LuaException is thrown on any lua error
void loadScript(const std::string& fileName);
/// Loads a function from buffer and pushes it onto stack,
/// @exception LuaException is thrown on any lua error
void loadFunction(const std::string& buffer, const std::string& source = "lua function buffer");
/// Evaluates a lua expression and pushes the result value onto the stack
/// @exception LuaException is thrown on any lua error
void evaluateExpression(const std::string& expression, const std::string& source = "lua expression");
/// Generates a traceback message for the current call stack
/// @param errorMessage is an additional error message
/// @param level is the level of the traceback, 0 means trace from calling function
/// @return the generated traceback message
std::string traceback(const std::string& errorMessage = "", int level = 0);
/// Searches for the source of the current running function
std::string currentSourcePath();
/// @brief Calls a function
/// The function and arguments must be on top of the stack in order,
/// results are pushed onto the stack.
/// @exception LuaException is thrown on any lua error
/// @return number of results
int safeCall(int numArgs = 0);
/// Same as safeCall but catches exceptions and can also calls a table of functions,
/// if any error occurs it will be reported to stdout and returns 0 results
/// @param requestedResults is the number of results requested to pushes onto the stack,
/// if supplied, the call will always pushes that number of results, even if it fails
int protectedCall(int numArgs = 0, int requestedResults = -1);
/// @brief Creates a new environment table
/// The new environment table is redirected to the global environment (aka _G),
/// this allows to access global variables from _G in the new environment and
/// prevents new variables in this new environment to be set on the global environment
void newEnvironment();
private:
/// Load scripts requested by lua 'require'
static int luaScriptLoader(lua_State* L);
/// Handle lua errors from safeCall
static int luaErrorHandler(lua_State* L);
/// Handle bound cpp functions callbacks
static int luaCppFunctionCallback(lua_State* L);
/// Collect bound cpp function pointers
static int luaCollectCppFunction(lua_State* L);
public:
void createLuaState();
void closeLuaState();
void collectGarbage();
void loadBuffer(const std::string& buffer, const std::string& source);
int pcall(int numArgs = 0, int numRets = 0, int errorFuncIndex = 0);
void call(int numArgs = 0, int numRets = 0);
void throwError();
int ref();
int weakRef();
void unref(int ref);
void useValue() { pushValue(); ref(); }
const char* typeName(int index = -1);
std::string functionSourcePath();
void insert(int index);
void remove(int index);
bool next(int index = -2);
void copy(int index = -1);
void getStackFunction(int level = 0);
void getRef(int ref);
void getWeakRef(int weakRef);
void getGlobalEnvironment();
void setGlobalEnvironment();
void setMetatable(int index = -2);
void getMetatable(int index = -1);
void getField(const char* key, int index = -1);
void getField(const std::string& key, int index = -1) { return getField(key.c_str(), index); }
void setField(const char* key, int index = -2);
void setField(const std::string& key, int index = -2) { return setField(key.c_str(), index); }
void getTable(int index = -2);
void setTable(int index = -3);
void getEnv(int index = -1);
void setEnv(int index = -2);
void getGlobal(const std::string& key);
void setGlobal(const std::string& key);
void rawGet(int index = -1);
void rawGeti(int n, int index = -1);
void rawSet(int index = -3);
void rawSeti(int n, int index = -2);
void newTable();
void* newUserdata(int size);
void pop(int n = 1);
int popInteger();
double popNumber();
bool popBoolean();
std::string popString();
void* popUserdata();
void* popUpvalueUserdata();
LuaObjectPtr popObject();
void pushNil();
void pushInteger(int v);
void pushNumber(double v);
void pushBoolean(bool v);
void pushCString(const char* v);
void pushString(const std::string& v) { pushCString(v.c_str()); }
void pushLightUserdata(void* p);
void pushThread();
void pushValue(int index = -1);
void pushObject(const LuaObjectPtr& obj);
void pushCFunction(LuaCFunction func, int n = 0);
void pushCppFunction(const LuaCppFunction& func);
bool isNil(int index = -1);
bool isBoolean(int index = -1);
bool isNumber(int index = -1);
bool isString(int index = -1);
bool isTable(int index = -1);
bool isFunction(int index = -1);
bool isCFunction(int index = -1);
bool isLuaFunction(int index = -1) { return (isFunction() && !isCFunction()); }
bool isUserdata(int index = -1);
bool toBoolean(int index = -1);
int toInteger(int index = -1);
double toNumber(int index = -1);
const char* toCString(int index = -1);
std::string toString(int index = -1);
void* toUserdata(int index = -1);
LuaObjectPtr toObject(int index = -1);
int getTop();
int stackSize() { return getTop(); }
void clearStack() { pop(stackSize()); }
bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); }
/// Pushes any type onto the stack
template<typename T, typename... Args>
void polymorphicPush(T v, Args... args) { push_luavalue(v); polymorphicPush(args...); }
void polymorphicPush() { }
/// Casts a value from stack to any type
/// @exception LuaBadValueCastException thrown if the cast fails
template<class T>
T castValue(int index = -1);
/// Same as castValue but also pops
template<class T>
T polymorphicPop() { T v = castValue<T>(); pop(1); return v; }
private:
lua_State* L;
int m_weakTableRef;
};
extern LuaInterface g_lua;
// must be included after, because they need LuaInterface fully declared
#include "luaexception.h"
#include "luabinder.h"
#include "luavaluecasts.h"
// next templates must be defined after above includes
template<class C, typename F>
void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) {
registerClassStaticFunction<C>(functionName, luabinder::bind_fun(function));
}
template<class C, typename F>
void LuaInterface::bindClassMemberFunction(const std::string& functionName, F C::*function) {
registerClassMemberFunction<C>(functionName, luabinder::bind_mem_fun(function));
}
template<class C, typename F1, typename F2>
void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
registerClassMemberField<C>(fieldName,
luabinder::bind_mem_fun(getFunction),
luabinder::bind_mem_fun(setFunction));
}
template<class C, typename F>
void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F C::*getFunction) {
registerClassMemberField<C>(fieldName,
luabinder::bind_mem_fun(getFunction),
LuaCppFunction());
}
template<class C, typename F>
void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F C::*setFunction) {
registerClassMemberField<C>(fieldName,
LuaCppFunction(),
luabinder::bind_mem_fun(setFunction));
}
template<typename F>
void LuaInterface::bindGlobalFunction(const std::string& functionName, const F& function) {
registerGlobalFunction(functionName, luabinder::bind_fun(function));
}
template<class T>
T LuaInterface::castValue(int index) {
T o;
if(!luavalue_cast(index, o))
throw LuaBadValueCastException(typeName(index), aux::demangle_type<T>());
return o;
}
#endif

View File

@@ -0,0 +1,47 @@
#include "luaobject.h"
#include "luainterface.h"
LuaObject::LuaObject() : m_fieldsTableRef(-1)
{
}
LuaObject::~LuaObject()
{
luaReleaseFieldsTable();
}
void LuaObject::luaReleaseFieldsTable()
{
if(m_fieldsTableRef != -1)
g_lua.unref(m_fieldsTableRef);
}
void LuaObject::luaSetField(const std::string& key)
{
// create fields table on the fly
if(m_fieldsTableRef == -1) {
g_lua.newTable(); // create fields table
m_fieldsTableRef = g_lua.ref(); // save a reference for it
}
g_lua.getRef(m_fieldsTableRef); // push the table
g_lua.insert(-2); // move the value to the top
g_lua.setField(key); // set the field
g_lua.pop(); // pop the fields table
}
void LuaObject::luaGetField(const std::string& key)
{
if(m_fieldsTableRef != -1) {
g_lua.getRef(m_fieldsTableRef); // push the obj's fields table
g_lua.getField(key); // push the field value
g_lua.remove(-2); // remove the table
} else {
g_lua.pushNil();
}
}
int LuaObject::getUseCount()
{
return shared_from_this().use_count() - 1;
}

View File

@@ -0,0 +1,81 @@
#ifndef LUAOBJECT_H
#define LUAOBJECT_H
#include "luadeclarations.h"
/// LuaObject, all script-able classes have it as base
class LuaObject : public std::enable_shared_from_this<LuaObject>
{
public:
LuaObject();
virtual ~LuaObject() ;
/// Calls a function or table of functions stored in a lua field, results are pushed onto the stack,
/// if any lua error occurs, it will be reported to stdout and return 0 results
/// @return the number of results
template<typename... T>
int callLuaField(const std::string& field, const T&... args);
/// Sets a field in this lua object
template<typename T>
void setLuaField(const std::string& key, const T& value);
/// Gets a field from this lua object
template<typename T>
T getLuaField(const std::string& key);
/// Release fields table reference
void luaReleaseFieldsTable();
/// Sets a field from this lua object, the value must be on the stack
void luaSetField(const std::string& key);
/// Gets a field from this lua object, the result is pushed onto the stack
void luaGetField(const std::string& key);
/// Returns the number of references of this object
/// @note each userdata of this object on lua counts as a reference
int getUseCount();
/// Returns the class name used in Lua
virtual std::string getLuaObjectName() const {
// this could later be cached for more performance
return aux::demangle_name(typeid(*this).name());
}
LuaObjectPtr asLuaObject() { return shared_from_this(); }
private:
int m_fieldsTableRef;
};
#include "luainterface.h"
template<typename... T>
int LuaObject::callLuaField(const std::string& field, const T&... args) {
// note that the field must be retrieved from this object lua value
// to force using the __index metamethod of it's metatable
// so cannot use LuaObject::getField here
// push field
g_lua.pushObject(asLuaObject());
g_lua.getField(field);
// the first argument is always this object (self)
g_lua.insert(-2);
g_lua.polymorphicPush(args...);
return g_lua.protectedCall(1 + sizeof...(args));
}
template<typename T>
void LuaObject::setLuaField(const std::string& key, const T& value) {
g_lua.polymorphicPush(value);
luaSetField(key);
}
template<typename T>
T LuaObject::getLuaField(const std::string& key) {
luaGetField(key);
return g_lua.polymorphicPop<T>();
}
#endif

View File

@@ -0,0 +1,195 @@
#ifndef LUAVALUECASTS_H
#define LUAVALUECASTS_H
// this file is and must be included only from luainterface.h
#include "luainterface.h"
#include "luaexception.h"
/// Pushes bool
inline void push_luavalue(bool v) {
g_lua.pushBoolean(v);
}
/// Pushes int
inline void push_luavalue(int v) {
g_lua.pushInteger(v);
}
/// Pushes double
inline void push_luavalue(double v) {
g_lua.pushNumber(v);
}
/// Pushes std::string
inline void push_luavalue(const std::string& v) {
g_lua.pushString(v);
}
/// Pushes const char*
inline void push_luavalue(const char* v) {
g_lua.pushCString(v);
}
/// Pushes LuaCppFunction
inline void push_luavalue(const LuaCppFunction& v) {
g_lua.pushCppFunction(v);
}
/// Pushes LuaObjectPtr
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type
push_luavalue(const T& v) {
if(v)
return g_lua.pushObject(v);
return g_lua.pushNil();
}
/// Push std::function types
template<typename Ret, typename... Args>
void push_luavalue(const std::function<Ret(Args...)>& v) {
if(v) {
LuaCppFunction f = luabinder::bind_fun(v);
g_lua.pushCppFunction(f);
} else
g_lua.pushNil();
}
/// Casts lua value to bool
inline bool luavalue_cast(int index, bool& o) {
o = g_lua.toBoolean(index);
return true;
}
/// Casts lua value to int
inline bool luavalue_cast(int index, int& o) {
o = g_lua.toInteger(index);
if(o == 0 && !g_lua.isNumber(index))
return false;
return true;
}
/// Casts lua value to double
inline bool luavalue_cast(int index, double& o) {
o = g_lua.toNumber(index);
if(o == 0 && !g_lua.isNumber(index))
return false;
return true;
}
/// Casts lua value to std::string
inline bool luavalue_cast(int index, std::string& o) {
o = g_lua.toString(index);
if(o.empty() && !g_lua.isString(index))
return false;
return true;
}
/// Casts lua value to LuaObjectPtr
inline bool luavalue_cast(int index, LuaObjectPtr& o) {
if(g_lua.isUserdata(index)) {
o = g_lua.toObject(index);
return true;
} else if(g_lua.isNil(index)) {
o = nullptr;
return true;
}
return false;
}
/// Casts lua value to enum
template<class T>
typename std::enable_if<std::is_enum<T>::value, bool>::type
luavalue_cast(int index, T& o) {
return luavalue_cast(index, (int&)o);
}
/// Cast lua userdata to a class pointer
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
luavalue_cast(int index, T*& o) {
LuaObjectPtr obj;
if(!luavalue_cast(index, obj))
return false;
o = std::dynamic_pointer_cast<T>(obj).get();
return !!o;
}
/// Cast lua userdata to a class shared pointer
template<class T>
bool luavalue_cast(int index, std::shared_ptr<T>& o) {
LuaObjectPtr obj;
if(!luavalue_cast(index, obj))
return false;
o = std::dynamic_pointer_cast<T>(obj);
return !!o;
}
/// Cast a lua function to a std::function
template<typename... Args>
bool luavalue_cast(int index, std::function<void(Args...)>& o) {
if(g_lua.isFunction(index)) {
g_lua.pushValue(index);
// weak references are used here, this means that the script must hold another reference
// to this function, otherwise it will expire
int funcWeakRef = g_lua.weakRef();
o = [=](Args... args...) {
// note that we must catch exceptions, because this lambda can be called from anywhere
// and most of them won't catch exceptions (e.g. dispatcher)
g_lua.getWeakRef(funcWeakRef);
try {
if(g_lua.isFunction()) {
g_lua.polymorphicPush(args...);
assert(g_lua.safeCall(sizeof...(Args)) == 0);
} else {
throw LuaException("attempt to call an expired lua function from C++,"
"did you forget to hold a reference for that function?", 0);
}
} catch(std::exception& e) {
logError(e.what());
}
};
return true;
} else if(g_lua.isNil(index)) {
o = std::function<void(Args...)>();
return true;
}
return false;
}
/// Cast a lua function to a std::function that can return
template<typename Ret, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, bool>::type
luavalue_cast(int index, std::function<Ret(Args...)>& o) {
if(g_lua.isFunction(index)) {
g_lua.pushValue(index);
// weak references are used here, this means that the script must hold another reference
// to this function, otherwise it will expire
int funcWeakRef = g_lua.weakRef();
o = [=](Args... args...) -> Ret {
// note that we must catch exceptions, because this lambda can be called from anywhere
// and most of them won't catch exceptions (e.g. dispatcher)
try {
g_lua.getWeakRef(funcWeakRef);
if(g_lua.isFunction()) {
g_lua.polymorphicPush(args...);
if(g_lua.safeCall(sizeof...(Args)) != 1)
throw LuaException("a function from lua didn't retrieve the expected number of results", 0);
return g_lua.polymorphicPop<Ret>();
} else {
throw LuaException("attempt to call an expired lua function from C++,"
"did you forget to hold a reference for that function?", 0);
}
} catch(std::exception& e) {
logError(e.what());
}
return Ret();
};
return true;
} else if(g_lua.isNil(index)) {
o = std::function<Ret(Args...)>();
return true;
}
return false;
}
#endif