    {-# LANGUAGE CPP #-}
    {-|
    Module      : Lua.Ersatz.Functions
    Copyright   : © 2007–2012 Gracjan Polak;
                  © 2012–2016 Ömer Sinan Ağacan;
                  © 2017-2024 Albert Krewinkel
    License     : MIT
    Maintainer  : Albert Krewinkel <tarleb@hslua.org>
    Stability   : beta
    Portability : ForeignFunctionInterface, CPP

    Ersatz functions for Lua API items which may, directly or indirectly,
    throw a Lua error.
    -}
    module Lua.Ersatz.Functions
      ( hslua_arith
      , hslua_compare
        -- * Get functions (Lua -> stack)
      , hslua_gettable
      , hslua_getglobal
        -- * Set functions (stack -> Lua)
      , hslua_settable
      , hslua_setglobal
        -- * Misc
      , hslua_error
      , hslua_next
      , hslua_concat
      )where

    import Foreign.C
    import Lua.Types as Lua
    import Foreign.Ptr

    #ifdef ALLOW_UNSAFE_GC
    #define SAFTY unsafe
    #else
    #define SAFTY safe
    #endif

    -- | Performs an arithmetic or bitwise operation over the two values (or
    -- one, in the case of negations) at the top of the stack, with the
    -- value at the top being the second operand, pops these values, and
    -- pushes the result of the operation. The function follows the
    -- semantics of the corresponding Lua operator (that is, it may call
    -- metamethods).
    --
    -- The value of @op@ must be one of the following constants:
    --
    -- -   __@LUA_OPADD@:__ performs addition (@+@)
    -- -   __@LUA_OPSUB@:__ performs subtraction (@-@)
    -- -   __@LUA_OPMUL@:__ performs multiplication (@*@)
    -- -   __@LUA_OPDIV@:__ performs float division (@\/@)
    -- -   __@LUA_OPIDIV@:__ performs floor division (@\/\/@)
    -- -   __@LUA_OPMOD@:__ performs modulo (@%@)
    -- -   __@LUA_OPPOW@:__ performs exponentiation (@^@)
    -- -   __@LUA_OPUNM@:__ performs mathematical negation (unary @-@)
    -- -   __@LUA_OPBNOT@:__ performs bitwise NOT (@~@)
    -- -   __@LUA_OPBAND@:__ performs bitwise AND (@&@)
    -- -   __@LUA_OPBOR@:__ performs bitwise OR (@|@)
    -- -   __@LUA_OPBXOR@:__ performs bitwise exclusive OR (@~@)
    -- -   __@LUA_OPSHL@:__ performs left shift (@\<\<@)
    -- -   __@LUA_OPSHR@:__ performs right shift (@>>@)
    --
    -- This function wraps @lua_arith@ and takes an additional parameter
    -- @status@; if it is not @NULL@, then the return value is set to the
    -- status after calling @lua_arith@.
    foreign import ccall SAFTY "hslua.h hslua_arith"
      hslua_arith :: State
                  -> ArithOPCode     -- ^ op
                  -> Ptr StatusCode
                  -> IO ()

    -- | Compares two Lua values. Returns @1@ if the value at index @index1@
    -- satisfies op when compared with the value at index @index2@,
    -- following the semantics of the corresponding Lua operator (that is,
    -- it may call metamethods). Otherwise returns @0@. Also returns @0@ if
    -- any of the indices is not valid.
    --
    -- The value of op must be one of the following constants:
    --
    --  - 'Lua.Constants.LUA_OPEQ': compares for equality (==)
    --  - 'Lua.Constants.LUA_OPLT': compares for less than (<)
    --  - 'Lua.Constants.LUA_OPLE': compares for less or equal (<=)
    --
    -- This function wraps @lua_compare@ and takes an additional parameter
    -- @status@; if it is not @NULL@, then the return value is set to the
    -- status after calling @lua_compare@.
    foreign import capi safe "hslua.h hslua_compare"
      hslua_compare :: Lua.State
                    -> StackIndex     -- ^ index 1
                    -> StackIndex     -- ^ index 2
                    -> OPCode         -- ^ operator
                    -> Ptr StatusCode -- ^ status
                    -> IO LuaBool

    --
    -- Get functions (Lua -> stack)
    --

    -- | Behaves like @'Lua.Primary.lua_gettable'@, but prevents
    -- unrecoverable program crashes by calling that function through
    -- @'Lua.lua_pcall'@. Takes an additional status code pointer
    -- that is set to the status returned by @lua_pcall@.
    foreign import ccall safe "hslua.h hslua_gettable"
      hslua_gettable :: Lua.State -> StackIndex -> Ptr StatusCode -> IO TypeCode

    -- | Behaves like @'Lua.Primary.lua_getglobal'@, but prevents
    -- unrecoverable program crashes by calling that function through
    -- @'Lua.lua_pcall'@. Takes an additional status code pointer
    -- that is set to the status returned by @lua_pcall@.
    foreign import ccall safe "hslua.h hslua_getglobal"
      hslua_getglobal :: Lua.State
                      -> CString
                      -> CSize
                      -> Ptr StatusCode
                      -> IO TypeCode

    --
    -- Set functions (stack -> Lua)
    --

    -- | Behaves like @'Lua.Primary.lua_settable'@, but prevents
    -- unrecoverable program crashes by calling that function through
    -- @'Lua.lua_pcall'@. Takes an additional status code pointer
    -- that is set to the status returned by @lua_pcall@.
    foreign import ccall safe "hslua.h hslua_settable"
      hslua_settable :: Lua.State -> StackIndex -> Ptr StatusCode -> IO ()

    -- | Behaves like @'Lua.Primary.lua_setglobal'@, but prevents
    -- unrecoverable program crashes by calling that function through
    -- @'Lua.lua_pcall'@. Takes an additional status code pointer
    -- that is set to the status returned by @lua_pcall@.
    foreign import ccall safe "hslua.h hslua_setglobal"
      hslua_setglobal :: Lua.State -> CString -> CSize -> Ptr StatusCode -> IO ()

    --
    -- Miscellaneous functions
    --

    -- | Replacement for
    -- <https://lua.org/manual/5.4/manual.html#lua_error lua_error>; it uses
    -- the HsLua error signaling convention instead of raw Lua errors.
    foreign import ccall SAFTY "hslua.h hslua_error"
      hslua_error :: Lua.State -> IO NumResults

    -- | Wrapper around
    -- <https://lua.org/manual/5.4/manual.html#lua_next lua_next> which
    -- catches any Lua errors.
    foreign import ccall safe "hslua.h hslua_next"
      hslua_next :: Lua.State -> StackIndex -> Ptr StatusCode -> IO LuaBool

    -- | Wrapper around
    -- <https://lua.org/manual/5.4/manual.html#lua_concat lua_concat>
    -- which catches any Lua errors.
    foreign import ccall safe "hslua.h hslua_concat"
      hslua_concat :: Lua.State -> NumArgs -> Ptr StatusCode -> IO ()