/*
 * MACROS_AND_UTILS.H
 */
#ifndef MACROS_AND_UTILS_H
#define MACROS_AND_UTILS_H

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

 // M$ compiler doesn't support 'inline' keyword in C files...
#if defined( _MSC_VER)
#define inline __inline
#endif

#define USE_DEBUG_SPEW() 0
#if USE_DEBUG_SPEW()
extern char const* debugspew_indent;
#define INDENT_BEGIN "%.*s "
#define INDENT_END , (U ? U->debugspew_indent_depth : 0), debugspew_indent
#define DEBUGSPEW_CODE(_code) _code
#define DEBUGSPEW_PARAM_COMMA( param_) param_,
#define DEBUGSPEW_COMMA_PARAM( param_) , param_
#else // USE_DEBUG_SPEW()
#define DEBUGSPEW_CODE(_code)
#define DEBUGSPEW_PARAM_COMMA( param_)
#define DEBUGSPEW_COMMA_PARAM( param_)
#endif // USE_DEBUG_SPEW()

#ifdef NDEBUG

#define _ASSERT_L(lua,c)     //nothing
#define STACK_CHECK(L,o)     //nothing
#define STACK_CHECK_ABS(L,o) //nothing
#define STACK_MID(L,c)       //nothing
#define STACK_END(L,c)       //nothing
#define STACK_DUMP(L)        //nothing

#else // NDEBUG

#define _ASSERT_L( L, cond_) if( (cond_) == 0) { (void) luaL_error( L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);}

#define STACK_CHECK( L, offset_) \
    { \
        int const L##_delta = offset_; \
        if( (L##_delta < 0) || (lua_gettop( L) < L##_delta)) \
        { \
            assert( FALSE); \
            (void) luaL_error( L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop( L), L##_delta, __FILE__, __LINE__); \
        } \
        int const L##_oldtop = lua_gettop( L) - L##_delta

#define STACK_CHECK_ABS( L, offset_) \
    { \
        int const L##_pos = offset_; \
        if( lua_gettop( L) < L##_pos) \
        { \
            assert( FALSE); \
            (void) luaL_error( L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop( L), L##_pos, __FILE__, __LINE__); \
        } \
        int const L##_oldtop = 0

#define STACK_MID( L, change) \
        do if( change != LUA_MULTRET) \
        { \
            int stack_check_a = lua_gettop( L) - L##_oldtop; \
            int stack_check_b = (change); \
            if( stack_check_a != stack_check_b) \
            { \
                assert( FALSE); \
                luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", stack_check_a, stack_check_b, __FILE__, __LINE__); \
            } \
        } while( 0)

#define STACK_END( L, change) \
        STACK_MID( L, change); \
    }

#define STACK_DUMP( L)    luaG_dump( L)

#endif // NDEBUG

#define ASSERT_L(c) _ASSERT_L(L,c)

inline void STACK_GROW(lua_State * L, int n_)
{
    if (!lua_checkstack(L, n_))
        luaL_error(L, "Cannot grow stack!");
}

// non-string keyed registry access
#define REGISTRY_SET( L, key_, value_) \
{ \
    push_unique_key( L, key_); \
    value_; \
    lua_rawset( L, LUA_REGISTRYINDEX); \
}

#define REGISTRY_GET( L, key_) \
{ \
    push_unique_key( L, key_); \
    lua_rawget( L, LUA_REGISTRYINDEX); \
}

#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L)

#endif // MACROS_AND_UTILS_H
