dungeon/libs/kaguya-1.3.2/include/kaguya/error_handler.hpp
Adrian Hedqvist ec131d8bda Too much stuff
* 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
2017-10-18 12:25:25 +02:00

174 lines
4.9 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 <string>
#include "kaguya/config.hpp"
#include "kaguya/type.hpp"
namespace kaguya {
inline const char *get_error_message(lua_State *state) {
if (lua_type(state, -1) == LUA_TSTRING) {
const char *message = lua_tostring(state, -1);
return message ? message : "unknown error";
} else {
return "unknown error";
}
}
inline int lua_pcall_wrap(lua_State *state, int argnum, int retnum) {
int result = lua_pcall(state, argnum, retnum, 0);
return result;
}
struct ErrorHandler {
typedef standard::function<void(int, const char *)> function_type;
static bool handle(const char *message, lua_State *state) {
function_type handler = getHandler(state);
if (handler) {
handler(0, message);
return true;
}
return false;
}
static bool handle(int status_code, const char *message, lua_State *state) {
function_type handler = getHandler(state);
if (handler) {
handler(status_code, message);
return true;
}
return false;
}
static bool handle(int status_code, lua_State *state) {
function_type handler = getHandler(state);
if (handler) {
handler(status_code, get_error_message(state));
return true;
}
return false;
}
static function_type getHandler(lua_State *state) {
function_type *funptr = getFunctionPointer(state);
if (funptr) {
return *funptr;
}
return function_type();
}
static void unregisterHandler(lua_State *state) {
if (state) {
function_type *funptr = getFunctionPointer(state);
if (funptr) {
*funptr = function_type();
}
}
}
static void registerHandler(lua_State *state, function_type f) {
if (state) {
function_type *funptr = getFunctionPointer(state);
if (!funptr) {
util::ScopedSavedStack save(state);
lua_pushlightuserdata(state, handlerRegistryKey());
void *ptr = lua_newuserdata(
state, sizeof(function_type)); // dummy data for gc call
funptr = new (ptr) function_type();
// create function_type metatable
lua_newtable(state);
lua_pushcclosure(state, &error_handler_cleanner, 0);
lua_setfield(state, -2, "__gc");
lua_pushvalue(state, -1);
lua_setfield(state, -1, "__index");
lua_setmetatable(state, -2);
lua_rawset(state, LUA_REGISTRYINDEX);
}
*funptr = f;
}
}
static void throwDefaultError(int status, const char *message = 0) {
switch (status) {
case LUA_ERRSYNTAX:
throw LuaSyntaxError(status, message ? std::string(message)
: "unknown syntax error");
case LUA_ERRRUN:
throw LuaRuntimeError(status, message ? std::string(message)
: "unknown runtime error");
case LUA_ERRMEM:
throw LuaMemoryError(status, message ? std::string(message)
: "lua memory allocation error");
case LUA_ERRERR:
throw LuaErrorRunningError(status, message
? std::string(message)
: "unknown error running error");
#if LUA_VERSION_NUM >= 502
case LUA_ERRGCMM:
throw LuaGCError(status,
message ? std::string(message) : "unknown gc error");
#endif
default:
throw LuaUnknownError(status, message ? std::string(message)
: "lua unknown error");
}
}
private:
static void *handlerRegistryKey() {
static void *key;
return key;
}
static function_type *getFunctionPointer(lua_State *state) {
if (state) {
util::ScopedSavedStack save(state);
lua_pushlightuserdata(state, handlerRegistryKey());
lua_rawget(state, LUA_REGISTRYINDEX);
function_type *ptr = (function_type *)lua_touserdata(state, -1);
return ptr;
}
return 0;
}
ErrorHandler() {}
ErrorHandler(const ErrorHandler &);
ErrorHandler &operator=(const ErrorHandler &);
static int error_handler_cleanner(lua_State *state) {
function_type *ptr = (function_type *)lua_touserdata(state, 1);
ptr->~function_type();
return 0;
}
};
namespace except {
inline void OtherError(lua_State *state, const std::string &message) {
if (ErrorHandler::handle(message.c_str(), state)) {
return;
}
}
inline void typeMismatchError(lua_State *state, const std::string &message) {
if (ErrorHandler::handle(message.c_str(), state)) {
return;
}
}
inline void memoryError(lua_State *state, const char *message) {
if (ErrorHandler::handle(message, state)) {
return;
}
}
inline bool checkErrorAndThrow(int status, lua_State *state) {
if (status != 0 && status != LUA_YIELD) {
ErrorHandler::handle(status, state);
return false;
}
return true;
}
}
}