#pragma once #include "lanesconf.h" #include "luaerrors.h" // ################################################################################################# #if HAVE_LUA_ASSERT() inline void LUA_ASSERT_IMPL(lua_State* L_, bool cond_, char const* file_, int const line_, char const* txt_) { if (!cond_) { raise_luaL_error(L_, "LUA_ASSERT %s:%d '%s'", file_, line_, txt_); } } #define LUA_ASSERT(L_, cond_) LUA_ASSERT_IMPL(L_, cond_, __FILE__, __LINE__, #cond_) #define LUA_ASSERT_CODE(code_) code_ class StackChecker { private: lua_State* const L; int oldtop; public: struct Relative { int const offset; operator int() const { return offset; } }; struct Absolute { int const offset; operator int() const { return offset; } }; StackChecker(lua_State* const L_, Relative offset_, char const* file_, size_t const line_) : L{ L_ } , oldtop{ lua_gettop(L_) - offset_ } { if ((offset_ < 0) || (oldtop < 0)) { assert(false); raise_luaL_error(L, "STACK INIT ASSERT failed (%d not %d): %s:%llu", lua_gettop(L), offset_, file_, line_); } } StackChecker(lua_State* const L_, Absolute pos_, char const* file_, size_t const line_) : L{ L_ } , oldtop{ 0 } { if (lua_gettop(L) != pos_) { assert(false); raise_luaL_error(L, "STACK INIT ASSERT failed (%d not %d): %s:%llu", lua_gettop(L), pos_, file_, line_); } } StackChecker& operator=(StackChecker const& rhs_) { assert(L == rhs_.L); oldtop = rhs_.oldtop; return *this; } // verify if the distance between the current top and the initial one is what we expect void check(int expected_, char const* file_, size_t const line_) { if (expected_ != LUA_MULTRET) { int const actual{ lua_gettop(L) - oldtop }; if (actual != expected_) { assert(false); raise_luaL_error(L, "STACK ASSERT failed (%d not %d): %s:%llu", actual, expected_, file_, line_); } } } }; #define STACK_CHECK_START_REL(L, offset_) \ StackChecker _stackChecker_##L \ { \ L, StackChecker::Relative{ offset_ }, __FILE__, __LINE__ \ } #define STACK_CHECK_START_ABS(L, offset_) \ StackChecker _stackChecker_##L \ { \ L, StackChecker::Absolute{ offset_ }, __FILE__, __LINE__ \ } #define STACK_CHECK_RESET_REL(L, offset_) \ _stackChecker_##L = StackChecker \ { \ L, StackChecker::Relative{ offset_ }, __FILE__, __LINE__ \ } #define STACK_CHECK_RESET_ABS(L, offset_) \ _stackChecker_##L = StackChecker \ { \ L, StackChecker::Absolute{ offset_ }, __FILE__, __LINE__ \ } #define STACK_CHECK(L, offset_) _stackChecker_##L.check(offset_, __FILE__, __LINE__) #else // HAVE_LUA_ASSERT() #define LUA_ASSERT(L_, c) nullptr // nothing #define LUA_ASSERT_CODE(code_) nullptr #define STACK_CHECK_START_REL(L_, offset_) #define STACK_CHECK_START_ABS(L_, offset_) #define STACK_CHECK_RESET_REL(L_, offset_) #define STACK_CHECK_RESET_ABS(L_, offset_) #define STACK_CHECK(L_, offset_) #endif // HAVE_LUA_ASSERT()