Adrian Hedqvist
ec131d8bda
* Implemented lua using kaguya, only for config files for now * Moved color struct to its own header * statically link glew instead of including the source in the project * Other stuff that I don't remember
295 lines
10 KiB
C++
295 lines
10 KiB
C++
// Copyright satoren
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include <ostream>
|
|
#include "kaguya/config.hpp"
|
|
#include "kaguya/error_handler.hpp"
|
|
#include "kaguya/type.hpp"
|
|
#include "kaguya/utility.hpp"
|
|
|
|
namespace kaguya {
|
|
class LuaTable;
|
|
class LuaFunction;
|
|
|
|
class FunctionResults;
|
|
|
|
/**
|
|
* status of coroutine
|
|
*/
|
|
enum coroutine_status {
|
|
COSTAT_RUNNING, //!< coroutine is running
|
|
COSTAT_SUSPENDED, //!< coroutine is suspended
|
|
COSTAT_NORMAL, //!<
|
|
COSTAT_DEAD //!< coroutine is dead
|
|
};
|
|
|
|
namespace detail {
|
|
class FunctionResultProxy {
|
|
public:
|
|
template <typename RetType>
|
|
static RetType ReturnValue(lua_State *state, int restatus, int retindex,
|
|
types::typetag<RetType> tag);
|
|
static FunctionResults ReturnValue(lua_State *state, int restatus,
|
|
int retindex,
|
|
types::typetag<FunctionResults> tag);
|
|
static void ReturnValue(lua_State *state, int restatus, int retindex,
|
|
types::typetag<void> tag);
|
|
};
|
|
|
|
template <typename Derived> class LuaFunctionImpl {
|
|
private:
|
|
lua_State *state_() const {
|
|
return static_cast<const Derived *>(this)->state();
|
|
}
|
|
int pushStackIndex_(lua_State *state) const {
|
|
return static_cast<const Derived *>(this)->pushStackIndex(state);
|
|
}
|
|
int push_(lua_State *state) const {
|
|
return static_cast<const Derived *>(this)->push(state);
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* set function environment table
|
|
*/
|
|
bool setFunctionEnv(const LuaTable &env);
|
|
/**
|
|
* set function environment to new table
|
|
*/
|
|
bool setFunctionEnv(NewTable env);
|
|
/**
|
|
* get function environment table
|
|
*/
|
|
LuaTable getFunctionEnv() const;
|
|
|
|
#if KAGUYA_USE_CPP11
|
|
template <class Result, class... Args> Result call(Args &&... args) {
|
|
lua_State *state = state_();
|
|
if (!state) {
|
|
except::typeMismatchError(state, "nil");
|
|
return Result();
|
|
}
|
|
int argstart = lua_gettop(state) + 1;
|
|
push_(state);
|
|
int argnum = util::push_args(state, std::forward<Args>(args)...);
|
|
int result = lua_pcall_wrap(state, argnum, LUA_MULTRET);
|
|
except::checkErrorAndThrow(result, state);
|
|
return detail::FunctionResultProxy::ReturnValue(state, result, argstart,
|
|
types::typetag<Result>());
|
|
}
|
|
|
|
template <class... Args> FunctionResults operator()(Args &&... args);
|
|
#else
|
|
|
|
#define KAGUYA_CALL_DEF(N) \
|
|
template <class Result KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
|
|
Result call(KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
|
|
lua_State *state = state_(); \
|
|
if (!state) { \
|
|
except::typeMismatchError(state, "attempt to call nil value"); \
|
|
return Result(); \
|
|
} \
|
|
int argstart = lua_gettop(state) + 1; \
|
|
push_(state); \
|
|
int argnum = util::push_args(state KAGUYA_PP_ARG_REPEAT_CONCAT(N)); \
|
|
int result = lua_pcall_wrap(state, argnum, LUA_MULTRET); \
|
|
except::checkErrorAndThrow(result, state); \
|
|
return detail::FunctionResultProxy::ReturnValue(state, result, argstart, \
|
|
types::typetag<Result>()); \
|
|
}
|
|
|
|
KAGUYA_CALL_DEF(0)
|
|
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_CALL_DEF)
|
|
|
|
#undef KAGUYA_RESUME_DEF
|
|
|
|
inline FunctionResults operator()();
|
|
|
|
#define KAGUYA_OP_FN_DEF(N) \
|
|
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
|
|
inline FunctionResults operator()(KAGUYA_PP_ARG_CR_DEF_REPEAT(N));
|
|
|
|
#define KAGUYA_FUNCTION_ARGS_DEF(N)
|
|
#define KAGUYA_CALL_ARGS(N) KAGUYA_PP_ARG_REPEAT(N)
|
|
|
|
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF)
|
|
#undef KAGUYA_OP_FN_DEF
|
|
|
|
#undef KAGUYA_CALL_ARGS
|
|
#undef KAGUYA_FUNCTION_ARGS_DEF
|
|
#undef KAGUYA_CALL_DEF
|
|
#endif
|
|
};
|
|
|
|
template <typename Derived> class LuaThreadImpl {
|
|
private:
|
|
lua_State *state_() const {
|
|
return static_cast<const Derived *>(this)->state();
|
|
}
|
|
int pushStackIndex_(lua_State *state) const {
|
|
return static_cast<const Derived *>(this)->pushStackIndex(state);
|
|
}
|
|
|
|
public:
|
|
#if KAGUYA_USE_CPP11
|
|
template <class Result, class... Args> Result resume(Args &&... args) {
|
|
lua_State *state = state_();
|
|
if (!state) {
|
|
except::typeMismatchError(state, "attempt to call nil value");
|
|
return Result();
|
|
}
|
|
util::ScopedSavedStack save(state);
|
|
int corStackIndex = pushStackIndex_(state);
|
|
lua_State *thread = lua_tothread(state, corStackIndex);
|
|
if (!thread) {
|
|
except::typeMismatchError(state, "not thread");
|
|
return Result();
|
|
}
|
|
int argstart = 1; // exist function in stack at first resume.
|
|
if (lua_status(thread) == LUA_YIELD) {
|
|
argstart = 0;
|
|
}
|
|
util::push_args(thread, std::forward<Args>(args)...);
|
|
int argnum = lua_gettop(thread) - argstart;
|
|
if (argnum < 0) {
|
|
argnum = 0;
|
|
}
|
|
int result = lua_resume(thread, state, argnum);
|
|
except::checkErrorAndThrow(result, thread);
|
|
return detail::FunctionResultProxy::ReturnValue(thread, result, 1,
|
|
types::typetag<Result>());
|
|
}
|
|
template <class... Args> FunctionResults operator()(Args &&... args);
|
|
#else
|
|
|
|
#define KAGUYA_RESUME_DEF(N) \
|
|
template <class Result KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
|
|
Result resume(KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
|
|
lua_State *state = state_(); \
|
|
if (!state) { \
|
|
except::typeMismatchError(state, "attempt to call nil value"); \
|
|
return Result(); \
|
|
} \
|
|
util::ScopedSavedStack save(state); \
|
|
int corStackIndex = pushStackIndex_(state); \
|
|
lua_State *thread = lua_tothread(state, corStackIndex); \
|
|
if (!thread) { \
|
|
except::typeMismatchError(state, "not thread"); \
|
|
return Result(); \
|
|
} \
|
|
int argstart = 1; \
|
|
if (lua_status(thread) == LUA_YIELD) { \
|
|
argstart = 0; \
|
|
} \
|
|
util::push_args(thread KAGUYA_PP_ARG_REPEAT_CONCAT(N)); \
|
|
int argnum = lua_gettop(thread) - argstart; \
|
|
if (argnum < 0) { \
|
|
argnum = 0; \
|
|
} \
|
|
int result = lua_resume(thread, state, argnum); \
|
|
except::checkErrorAndThrow(result, thread); \
|
|
return detail::FunctionResultProxy::ReturnValue(thread, result, 1, \
|
|
types::typetag<Result>()); \
|
|
}
|
|
|
|
KAGUYA_RESUME_DEF(0)
|
|
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_RESUME_DEF)
|
|
|
|
#undef KAGUYA_RESUME_DEF
|
|
|
|
inline FunctionResults operator()();
|
|
|
|
#define KAGUYA_OP_FN_DEF(N) \
|
|
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
|
|
inline FunctionResults operator()(KAGUYA_PP_ARG_CR_DEF_REPEAT(N));
|
|
|
|
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF)
|
|
|
|
#undef KAGUYA_OP_FN_DEF
|
|
#endif
|
|
|
|
//!
|
|
//! @return state status
|
|
//!
|
|
int threadStatus() const {
|
|
lua_State *state = state_();
|
|
if (!state) {
|
|
except::typeMismatchError(state, "attempt to call nil value");
|
|
return LUA_ERRRUN;
|
|
}
|
|
util::ScopedSavedStack save(state);
|
|
int corStackIndex = pushStackIndex_(state);
|
|
lua_State *thread = lua_tothread(state, corStackIndex);
|
|
|
|
if (!thread) {
|
|
except::typeMismatchError(state, "not thread");
|
|
return LUA_ERRRUN;
|
|
}
|
|
return lua_status(thread);
|
|
}
|
|
|
|
//! deprecate
|
|
int thread_status() const { return threadStatus(); }
|
|
|
|
//!
|
|
//! @return coroutine status
|
|
//!
|
|
coroutine_status costatus(lua_State *l = 0) const {
|
|
lua_State *state = state_();
|
|
if (!state) {
|
|
return COSTAT_DEAD;
|
|
}
|
|
util::ScopedSavedStack save(state);
|
|
int corStackIndex = pushStackIndex_(state);
|
|
lua_State *thread = lua_tothread(state, corStackIndex);
|
|
|
|
if (!thread) {
|
|
except::typeMismatchError(state, "not thread");
|
|
return COSTAT_DEAD;
|
|
} else if (thread == l) {
|
|
return COSTAT_RUNNING;
|
|
} else {
|
|
switch (lua_status(thread)) {
|
|
case LUA_YIELD:
|
|
return COSTAT_SUSPENDED;
|
|
case 0: // LUA_OK
|
|
{
|
|
if (lua_gettop(thread) == 0) {
|
|
return COSTAT_DEAD;
|
|
} else {
|
|
return COSTAT_SUSPENDED;
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return COSTAT_DEAD;
|
|
}
|
|
|
|
//!
|
|
//! @return if coroutine status is dead, return true. Otherwise return false
|
|
//!
|
|
bool isThreadDead() const { return costatus() == COSTAT_DEAD; }
|
|
|
|
/// @brief set function for thread running.
|
|
void setFunction(const LuaFunction &f);
|
|
|
|
/// @brief get lua thread
|
|
lua_State *getthread() {
|
|
lua_State *state = state_();
|
|
util::ScopedSavedStack save(state);
|
|
int corStackIndex = pushStackIndex_(state);
|
|
return lua_tothread(state, corStackIndex);
|
|
}
|
|
};
|
|
}
|
|
}
|