    {-# LANGUAGE CPP #-}
    {-|
    Module      : Lua.Primary
    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

    Haskell bindings to Lua C API functions.

    The exposed functions correspond closely to the respective C Lua API
    functions. However, C API functions which can throw Lua errors are not
    exported directly, as any errors would crash the program. Non-error
    throwing @hslua_@ versions are provided instead. The @hslua@ ersatz
    functions have worse performance than the original.

    Some of the Lua functions may, directly or indirectly, call a Haskell
    function, and trigger garbage collection, rescheduling etc. These
    functions are always imported safely (i.e., with the @safe@ keyword).

    However, all function can trigger garbage collection. If that can lead
    to problems, then the package should be configured without flag
    @allow-unsafe-gc@.
    -}
    module Lua.Primary
      ( lua_absindex
      , lua_arith
      , lua_checkstack
      , lua_close
      , lua_close_ptr
      , lua_concat
      , lua_copy
      , lua_createtable
      , lua_gc
      , lua_getglobal
      , lua_getmetatable
      , lua_gettable
      , lua_gettop
      , lua_getiuservalue
      , lua_insert
      , lua_isboolean
      , lua_iscfunction
      , lua_isfunction
      , lua_isinteger
      , lua_islightuserdata
      , lua_isnil
      , lua_isnone
      , lua_isnoneornil
      , lua_isnumber
      , lua_isstring
      , lua_istable
      , lua_isthread
      , lua_isuserdata
      , lua_load
      , lua_newthread
      , lua_newuserdatauv
      , lua_next
      , lua_pcall
      , lua_pop
      , lua_pushboolean
      , lua_pushcclosure
      , lua_pushcfunction
      , lua_pushglobaltable
      , lua_pushinteger
      , lua_pushlightuserdata
      , lua_pushlstring
      , lua_pushnil
      , lua_pushnumber
      , lua_pushstring
      , lua_pushthread
      , lua_pushvalue
      , lua_rawequal
      , lua_rawget
      , lua_rawgeti
      , lua_rawlen
      , lua_rawset
      , lua_rawseti
      , lua_remove
      , lua_replace
      , lua_rotate
      , lua_setglobal
      , lua_setmetatable
      , lua_settable
      , lua_settop
      , lua_setiuservalue
      , lua_setwarnf
      , lua_status
      , lua_stringtonumber
      , lua_toboolean
      , lua_tocfunction
      , lua_tointegerx
      , lua_tolstring
      , lua_tonumberx
      , lua_topointer
      , lua_tothread
      , lua_touserdata
      , lua_type
      , lua_typename
      , lua_version
      , lua_warning
      , module Lua.Ersatz.Functions
      , module Lua.Ersatz.Auxiliary
      )
    where

    import Foreign.C
    import Lua.Ersatz.Auxiliary
    import Lua.Ersatz.Functions
    import Lua.Types as Lua
    import Foreign.Ptr

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

    -- | Converts the acceptable index @idx@ into an equivalent absolute
    -- index (that is, one that does not depend on the stack top).
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_absindex>
    foreign import capi unsafe "lua.h lua_absindex"
      lua_absindex :: Lua.State
                   -> StackIndex     -- ^ idx
                   -> IO StackIndex

    -- | 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 (@>>@)
    --
    -- __WARNING__: @lua_arith@ is unsafe in Haskell: if the call to a
    -- metamethod triggers an error, then that error cannot be handled and
    -- will lead to an unrecoverable program crash. Consider using the
    -- @'Lua.hslua_arith'@ ersatz function instead. Likewise, the metamethod
    -- may not call a Haskell function unless the library was compiled
    -- without @allow-unsafe-gc@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_arith>.
    foreign import capi SAFTY "lua.h lua_arith"
      lua_arith :: State -> ArithOPCode {- ^ op -} -> IO ()
    {-# WARNING lua_arith
          [ "This is an unsafe function, errors will lead to a program crash;"
          , "consider using hslua_arith instead."
          ] #-}

    -- | Ensures that the stack has space for at least @n@ extra slots (that
    -- is, that you can safely push up to @n@ values into it). It returns
    -- false if it cannot fulfill the request, either because it would cause
    -- the stack to be larger than a fixed maximum size (typically at least
    -- several thousand elements) or because it cannot allocate memory for
    -- the extra space. This function never shrinks the stack; if the stack
    -- already has space for the extra slots, it is left unchanged.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_checkstack>
    foreign import capi unsafe "lua.h lua_checkstack"
      lua_checkstack :: Lua.State -> CInt {- ^ n -} -> IO LuaBool

    -- | Destroys all objects in the given Lua state (calling the
    -- corresponding garbage-collection metamethods, if any) and frees all
    -- dynamic memory used by this state. In several platforms, you may not
    -- need to call this function, because all resources are naturally
    -- released when the host program ends. On the other hand, long-running
    -- programs that create multiple states, such as daemons or web servers,
    -- will probably need to close states as soon as they are not needed.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_close>
    foreign import capi safe "lua.h lua_close"
      lua_close :: Lua.State -> IO ()

    -- | Function pointer to function 'lua_close'; intended to be used with
    -- 'Foreign.ForeignPtr.newForeignPtr'.
    foreign import ccall safe "lua.h &lua_close"
      lua_close_ptr :: FunPtr (Ptr () -> IO ())

    -- | Concatenates the @n@ values at the top of the stack, pops them, and
    -- leaves the result at the top. If @n@ is 1, the result is the single
    -- value on the stack (that is, the function does nothing); if @n@ is 0,
    -- the result is the empty string. Concatenation is performed following
    -- the usual semantics of Lua (see
    -- <https://www.lua.org/manual/5.4/manual.html#3.4.6 §3.4.6> of the Lua
    -- manual).
    --
    -- __WARNING__: @lua_concat@ is unsafe in Haskell: This function will
    -- cause an unrecoverable crash an error if any of the concatenated
    -- values causes an error when executing a metamethod. Consider using
    -- the @'Lua.hslua_concat'@ ersatz function instead.
    foreign import capi SAFTY "lua.h lua_concat"
      lua_concat :: State -> CInt {- ^ n -} -> IO ()
    {-# WARNING lua_concat
          [ "This is an unsafe function, it will cause a program crash if"
          , "a metamethod throws an error."
          , "Consider using hslua_concat instead."
          ] #-}

    -- | Copies the element at index @fromidx@ into the valid index @toidx@,
    -- replacing the value at that position. Values at other positions are
    -- not affected.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_copy>
    foreign import capi unsafe "lua.h lua_copy"
      lua_copy :: Lua.State
               -> StackIndex  -- ^ fromidx
               -> StackIndex  -- ^ toidx
               -> IO ()

    -- | Creates a new empty table and pushes it onto the stack. Parameter
    -- @narr@ is a hint for how many elements the table will have as a
    -- sequence; parameter @nrec@ is a hint for how many other elements the
    -- table will have. Lua may use these hints to preallocate memory for
    -- the new table. This preallocation is useful for performance when you
    -- know in advance how many elements the table will have. Otherwise you
    -- can use the function @lua_newtable@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_createtable>.
    foreign import capi SAFTY "lua.h lua_createtable"
      lua_createtable :: Lua.State
                      -> CInt -- ^ narr
                      -> CInt -- ^ nrec
                      -> IO ()

    -- | Controls the garbage collector.
    --
    -- See the Lua docs at
    -- <https://www.lua.org/manual/5.4/manual.html#lua_gc>.
    -- Unused dataN values should be set to 0, but can be anything.
    foreign import capi safe "lua.h lua_gc"
      lua_gc :: Lua.State
             -> GCCode    -- ^ what
             -> CInt      -- ^ data1
             -> CInt      -- ^ data2
             -> CInt      -- ^ data3
             -> IO CInt

    -- | Pushes onto the stack the value of the global name. Returns the
    -- type of that value.
    --
    -- __WARNING__: @lua_getglobal@ is unsafe in Haskell: if the call to a
    -- metamethod triggers an error, then that error cannot be handled and
    -- will lead to an unrecoverable program crash. Consider using the
    -- @'Lua.hslua_getglobal'@ ersatz function instead. Likewise, the
    -- metamethod may not call a Haskell function unless the library was
    -- compiled without @allow-unsafe-gc@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_getglobal>.
    foreign import capi SAFTY "lua.h lua_getglobal"
      lua_getglobal :: State -> CString {- ^ name -} -> IO TypeCode
    {-# WARNING lua_getglobal
          [ "This is an unsafe function, errors will lead to a program crash;"
          , "consider using hslua_getglobal instead."
          ] #-}

    -- | If the value at the given index has a metatable, the function
    -- pushes that metatable onto the stack and returns @1@. Otherwise, the
    -- function returns @0@ and pushes nothing on the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_getmetatable>.
    foreign import capi unsafe "lua.h lua_getmetatable"
      lua_getmetatable :: Lua.State -> StackIndex -> IO LuaBool

    -- | Pushes onto the stack the value @t[k]@, where @t@ is the value at
    -- the given index and @k@ is the value at the top of the stack.
    --
    -- This function pops the key from the stack, pushing the resulting
    -- value in its place. As in Lua, this function may trigger a metamethod
    -- for the \"index\" event (see
    -- <https://www.lua.org/manual/5.4/manual.html#2.4 §2.4>).
    --
    -- Returns the type of the pushed value.
    --
    -- __WARNING__: @lua_gettable@ is unsafe in Haskell: if the call to a
    -- metamethod triggers an error, then that error cannot be handled and
    -- will lead to an unrecoverable program crash. Consider using the
    -- @'Lua.hslua_gettable'@ ersatz function instead. Likewise, the
    -- metamethod may not call a Haskell function unless the library was
    -- compiled without @allow-unsafe-gc@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_gettable>.
    foreign import capi SAFTY "lua.h lua_gettable"
      lua_gettable :: Lua.State -> StackIndex {- ^ index -} -> IO TypeCode
    {-# WARNING lua_gettable
          [ "This is an unsafe function, errors will lead to a program crash;"
          , "consider using hslua_gettable instead."
          ] #-}

    -- | Returns the index of the top element in the stack. Because indices
    -- start at 1, this result is equal to the number of elements in the
    -- stack (and so 0 means an empty stack).
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_gettop>
    foreign import capi unsafe "lua.h lua_gettop"
      lua_gettop :: Lua.State -> IO StackIndex

    -- | Pushes onto the stack the @n@-th user value associated with the
    -- full userdata at the given index and returns the type of the pushed
    -- value.
    --
    -- If the userdata does not have that value, pushes __nil__ and returns
    -- 'LUA_TNONE'.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_getiuservalue>
    foreign import capi unsafe "lua.h lua_getiuservalue"
      lua_getiuservalue :: Lua.State
                        -> StackIndex   -- ^ index
                        -> CInt         -- ^ n
                        -> IO TypeCode

    -- | Moves the top element into the given valid index, shifting up the
    -- elements above this index to open space. This function cannot be
    -- called with a pseudo-index, because a pseudo-index is not an actual
    -- stack position.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_insert>
    foreign import capi unsafe "lua.h lua_insert"
      lua_insert :: Lua.State -> StackIndex -> IO ()

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- boolean, and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isboolean>
    foreign import capi unsafe "lua.h lua_isboolean"
      lua_isboolean :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a C
    -- function, and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_iscfunction>
    foreign import capi unsafe "lua.h lua_iscfunction"
      lua_iscfunction :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- function (either C or Lua), and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isfunction>
    foreign import capi unsafe "lua.h lua_isfunction"
      lua_isfunction :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is an
    -- integer (that is, the value is a number and is represented as an
    -- integer), and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isinteger>
    foreign import capi unsafe "lua.h lua_isinteger"
      lua_isinteger :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- light userdata, and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_islightuserdata>
    foreign import capi unsafe "lua.h lua_islightuserdata"
      lua_islightuserdata :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is
    -- __nil__, and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isnil>
    foreign import capi unsafe "lua.h lua_isnil"
      lua_isnil :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the given index is not valid, and
    -- @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isnone>
    foreign import capi unsafe "lua.h lua_isnone"
      lua_isnone :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the given index is not valid or if
    -- the value at the given index is __nil__, and @'Lua.FALSE'@
    -- otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isnoneornil>
    foreign import capi unsafe "lua.h lua_isnoneornil"
      lua_isnoneornil :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- number or a string convertible to a number, and @'Lua.FALSE'@
    -- otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isnumber>
    foreign import capi unsafe "lua.h lua_isnumber"
      lua_isnumber :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- string or a number (which is always convertible to a string), and
    -- @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isstring>
    foreign import capi unsafe "lua.h lua_isstring"
      lua_isstring :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- table, and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_istable>
    foreign import capi unsafe "lua.h lua_istable"
      lua_istable :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- thread, and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isthread>
    foreign import capi unsafe "lua.h lua_isthread"
      lua_isthread :: Lua.State -> StackIndex -> IO LuaBool

    -- | Returns @'Lua.TRUE'@ if the value at the given index is a
    -- userdata (either full or light), and @'Lua.FALSE'@ otherwise.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_isuserdata>
    foreign import capi unsafe "lua.h lua_isuserdata"
      lua_isuserdata :: Lua.State -> StackIndex -> IO LuaBool

    -- | Loads a Lua chunk (without running it). If there are no errors,
    -- @lua_load@ pushes the compiled chunk as a Lua function on top of the
    -- stack. Otherwise, it pushes an error message.
    --
    -- The return values of @lua_load@ are:
    --
    -- - @'Lua.LUA_OK'@: no errors;
    -- - @'Lua.LUA_ERRSYNTAX'@: syntax error during pre-compilation;
    -- - @'Lua.LUA_ERRMEM'@: memory allocation error;
    -- - @'Lua.LUA_ERRGCMM'@: error while running a @__gc@
    --   metamethod. (This error has no relation with the chunk being
    --   loaded. It is generated by the garbage collector.)
    --
    -- This function only loads a chunk; it does not run it.
    --
    -- @lua_load@ automatically detects whether the chunk is text or binary,
    -- and loads it accordingly (see program luac).
    --
    -- The @lua_load@ function uses a user-supplied reader function to
    -- read the chunk (see @'Lua.Reader'@). The data argument is an opaque
    -- value passed to the reader function.
    --
    -- The @chunkname@ argument gives a name to the chunk, which is used for
    -- error messages and in debug information (see
    -- <https://www.lua.org/manual/5.4/manual.html#4.7 §4.7>).
    --
    -- @lua_load@ automatically detects whether the chunk is text or binary
    -- and loads it accordingly (see program @luac@). The string mode works
    -- as in function @load@, with the addition that a @NULL@ value is
    -- equivalent to the string "bt".
    --
    -- @lua_load@ uses the stack internally, so the reader function must
    -- always leave the stack unmodified when returning.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_load>.
    foreign import capi safe "lua.h lua_load"
      lua_load :: Lua.State
               -> Lua.Reader     -- ^ reader
               -> Ptr ()         -- ^ data
               -> CString        -- ^ chunkname
               -> CString        -- ^ mode
               -> IO StatusCode

    -- | Creates a new thread, pushes it on the stack, and returns a
    -- 'Lua.State' that represents this new thread. The new thread returned
    -- by this function shares with the original thread its global
    -- environment, but has an independent execution stack.
    --
    -- There is no explicit function to close or to destroy a thread.
    -- Threads are subject to garbage collection, like any Lua object.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_newthread>
    foreign import capi SAFTY "lua.h lua_newthread"
      lua_newthread :: Lua.State -> IO Lua.State

    -- | This function creates and pushes on the stack a new full userdata,
    -- with @nuvalue@ associated Lua values, called @user values@, plus an
    -- associated block of raw memory with @size@ bytes. (The user values
    -- can be set and read with the functions 'lua_setiuservalue' and
    -- 'lua_getiuservalue'.)
    --
    -- The function returns the address of the block of memory. Lua ensures
    -- that this address is valid as long as the corresponding userdata is
    -- alive (see <https://www.lua.org/manual/5.4/manual.html#2.5 §2.5>).
    -- Moreover, if the userdata is marked for finalization (see
    -- <https://www.lua.org/manual/5.4/manual.html#2.5.3 §2.5.3>), its
    -- address is valid at least until the call to its finalizer.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_newuserdatauv>.
    foreign import capi SAFTY "lua.h lua_newuserdatauv"
      lua_newuserdatauv :: Lua.State
                        -> CSize       -- ^ size
                        -> CInt        -- ^ nuvalue
                        -> IO (Ptr ())

    -- | Pops a key from the stack, and pushes a key–value pair from the
    -- table at the given index (the \"next\" pair after the given key). If
    -- there are no more elements in the table, then
    -- <https://www.lua.org/manual/5.4/manual.html#lua_next lua_next>
    -- returns 'Lua.FALSE' (and pushes nothing).
    --
    -- A typical traversal looks like this:
    --
    -- > -- table is in the stack at index 't'
    -- > lua_pushnil l    -- first key
    -- > let loop = lua_next l t >>= \case
    -- >       FALSE -> return ()
    -- >       _ -> do
    -- >         lua_type l (-2) >>= lua_typename l >>= peekCString >>= putStrLn
    -- >         lua_type l (-1) >>= lua_typename l >>= peekCString >>= putStrLn
    -- >         -- removes 'value'; keeps 'key' for next iteration
    -- >         lua_pop l 1
    -- >         loop
    -- > loop
    --
    -- While traversing a table, do not call 'lua_tolstring' directly on a
    -- key, unless you know that the key is actually a string. Recall that
    -- 'lua_tolstring' may change the value at the given index; this
    -- confuses the next call to
    -- <https://www.lua.org/manual/5.4/manual.html#lua_next lua_next>.
    --
    -- See function
    -- <https://www.lua.org/manual/5.4/manual.html#pdf-next next> for the
    -- caveats of modifying the table during its traversal.
    --
    -- __WARNING__: @lua_next@ is unsafe in Haskell: This function will
    -- cause an unrecoverable crash an error if the given key is neither
    -- @nil@ nor present in the table. Consider using the @'Lua.hslua_next'@
    -- ersatz function instead.
    foreign import capi SAFTY "lua.h lua_next"
      lua_next :: State -> StackIndex {- ^ index -} -> IO LuaBool
    {-# WARNING lua_next
          [ "This is an unsafe function, it will cause a program crash if"
          , "the given key is neither nil nor present in the table."
          , "Consider using hslua_next instead."
          ] #-}

    -- | Calls a function in protected mode.
    --
    -- To call a function you must use the following protocol: first, the
    -- function to be called is pushed onto the stack; then, the arguments
    -- to the function are pushed in direct order; that is, the first
    -- argument is pushed first. Finally you call @lua_pcall@; @nargs@ is
    -- the number of arguments that you pushed onto the stack. All arguments
    -- and the function value are popped from the stack when the function is
    -- called. The function results are pushed onto the stack when the
    -- function returns. The number of results is adjusted to @nresults@,
    -- unless @nresults@ is @'Lua.LUA_MULTRET'@. In this case, all
    -- results from the function are pushed. Lua takes care that the
    -- returned values fit into the stack space. The function results are
    -- pushed onto the stack in direct order (the first result is pushed
    -- first), so that after the call the last result is on the top of the
    -- stack.
    --
    -- If there is any error, @lua_pcall@ catches it, pushes a single value
    -- on the stack (the error message), and returns the error code.
    -- @lua_pcall@ always removes the function and its arguments from the
    -- stack.
    --
    -- If @msgh@ is @0@, then the error object returned on the stack is
    -- exactly the original error object. Otherwise, @msgh@ is the location
    -- of a message handler. (This index cannot be a pseudo-index.) In case
    -- of runtime errors, this function will be called with the error object
    -- and its return value will be the object returned on the stack by
    -- @'lua_pcall'@.
    --
    -- Typically, the message handler is used to add more debug information
    -- to the error object, such as a stack traceback. Such information
    -- cannot be gathered after the return of @'lua_pcall'@, since by then
    -- the stack has unwound.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pcall>.
    foreign import capi safe "lua.h lua_pcall"
      lua_pcall :: Lua.State
                -> NumArgs        -- ^ nargs
                -> NumResults     -- ^ nresults
                -> StackIndex     -- ^ msgh
                -> IO StatusCode

    -- | Pops @n@ elements from the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pop>
    foreign import capi unsafe "lua.h lua_pop"
      lua_pop :: Lua.State -> CInt {- ^ n -} -> IO ()

    -- | Pushes a boolean value with the given value onto the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushboolean>.
    foreign import capi unsafe "lua.h lua_pushboolean"
      lua_pushboolean :: Lua.State -> LuaBool -> IO ()

    -- | Pushes a new C closure onto the stack.
    --
    -- When a C function is created, it is possible to associate some values
    -- with it, thus creating a C closure (see
    -- <https://www.lua.org/manual/5.1/manual.html#3.4 §3.4>); these values
    -- are then accessible to the function whenever it is called. To
    -- associate values with a C function, first these values should be
    -- pushed onto the stack (when there are multiple values, the first
    -- value is pushed first). Then lua_pushcclosure is called to create and
    -- push the C function onto the stack, with the argument @n@ telling how
    -- many values should be associated with the function. lua_pushcclosure
    -- also pops these values from the stack.
    --
    -- The maximum value for @n@ is 255.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushcclosure>.
    foreign import capi SAFTY "lua.h lua_pushcclosure"
      lua_pushcclosure :: Lua.State
                       -> CFunction   -- ^ fn
                       -> NumArgs     -- ^ n
                       -> IO ()

    -- | Pushes a C function onto the stack. This function receives a
    -- pointer to a C function and pushes onto the stack a Lua value of type
    -- @function@ that, when called, invokes the corresponding C function.
    --
    -- Any function to be callable by Lua must follow the correct protocol
    -- to receive its parameters and return its results (see 'CFunction').
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushcfunction>.
    foreign import capi unsafe "lua.h lua_pushcfunction"
      lua_pushcfunction :: Lua.State
                        -> CFunction   -- ^ fn
                        -> IO ()

    -- | Pushes the global environment onto the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushglobaltable>
    foreign import capi unsafe "lua.h lua_pushglobaltable"
      lua_pushglobaltable :: Lua.State -> IO ()

    -- | Pushes an integer with with the given value onto the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushinteger>.
    foreign import capi unsafe "lua.h lua_pushinteger"
      lua_pushinteger :: Lua.State -> Lua.Integer -> IO ()

    -- | Pushes a light userdata onto the stack.
    --
    -- Userdata represent C values in Lua. A light userdata represents a
    -- pointer, a @Ptr ()@ (i.e., @void*@ in C lingo). It is a value (like a
    -- number): you do not create it, it has no individual metatable, and it
    -- is not collected (as it was never created). A light userdata is equal
    -- to "any" light userdata with the same C address.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushlightuserdata>.
    foreign import capi unsafe "lua.h lua_pushlightuserdata"
      lua_pushlightuserdata :: Lua.State -> Ptr a -> IO ()

    -- | Pushes the string pointed to by @s@ with size @len@ onto the stack.
    -- Lua makes (or reuses) an internal copy of the given string, so the
    -- memory at s can be freed or reused immediately after the function
    -- returns. The string can contain any binary data, including embedded
    -- zeros.
    --
    -- Returns a pointer to the internal copy of the string.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushlstring>.
    foreign import capi SAFTY "lua.h lua_pushlstring"
      lua_pushlstring :: Lua.State
                      -> Ptr CChar    -- ^ s
                      -> CSize        -- ^ len
                      -> IO ()

    -- | Pushes a nil value onto the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushnil>.
    foreign import capi unsafe "lua.h lua_pushnil"
      lua_pushnil :: Lua.State -> IO ()

    -- | Pushes a float with the given value onto the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushnumber>.
    foreign import capi unsafe "lua.h lua_pushnumber"
      lua_pushnumber :: Lua.State -> Lua.Number -> IO ()

    -- | Pushes the zero-terminated string pointed to by @s@ onto the stack.
    -- Lua makes (or reuses) an internal copy of the given string, so the
    -- memory at @s@ can be freed or reused immediately after the function
    -- returns.
    --
    -- Returns a pointer to the internal copy of the string.
    --
    -- If s is NULL, pushes nil and returns NULL.
    foreign import ccall unsafe "lua.h lua_pushstring"
      lua_pushstring :: Lua.State -> CString {- ^ s -} -> IO CString

    -- | Pushes the current thread onto the stack. Returns @1@ iff this
    -- thread is the main thread of its state.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushthread>.
    foreign import capi unsafe "lua.h lua_pushthread"
      lua_pushthread :: Lua.State -> IO CInt

    -- | Pushes a copy of the element at the given index onto the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_pushvalue>
    foreign import capi unsafe "lua.h lua_pushvalue"
      lua_pushvalue :: Lua.State -> StackIndex -> IO ()

    -- | Returns @True@ if the two values in indices @idx1@ and @idx2@ are
    -- primitively equal (that is, without calling the @__eq@ metamethod).
    -- Otherwise returns @False@. Also returns @False@ if any of the indices
    -- are not valid.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_rawequal>
    foreign import capi unsafe "lua.h lua_rawequal"
      lua_rawequal :: Lua.State
                   -> StackIndex  -- ^ idx1
                   -> StackIndex  -- ^ idx2
                   -> IO LuaBool

    -- | Similar to @'lua_gettable'@, but does a raw access (i.e., without
    -- metamethods).
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_rawget>.
    foreign import capi unsafe "lua.h lua_rawget"
      lua_rawget :: Lua.State -> StackIndex -> IO TypeCode

    -- | Pushes onto the stack the value @t[n]@, where @t@ is the table at
    -- the given index. The access is raw, that is, it does not invoke the
    -- @__index@ metamethod.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_rawgeti>.
    foreign import capi unsafe "lua.h lua_rawgeti"
      lua_rawgeti :: Lua.State -> StackIndex -> Lua.Integer {- ^ n -}
                  -> IO TypeCode

    -- | Returns the raw "length" of the value at the given index: for
    -- strings, this is the string length; for tables, this is the result of
    -- the length operator (@#@) with no metamethods; for userdata, this is
    -- the size of the block of memory allocated for the userdata; for other
    -- values, it is 0.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_rawlen>.
    foreign import capi unsafe "lua.h lua_rawlen"
      lua_rawlen :: Lua.State -> StackIndex -> IO CSize

    -- | Similar to @'lua_settable'@, but does a raw assignment (i.e.,
    -- without metamethods).
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_rawset>.
    foreign import capi SAFTY "lua.h lua_rawset"
      lua_rawset :: Lua.State -> StackIndex -> IO ()

    -- | Does the equivalent of @t[i] = v@, where @t@ is the table at the
    -- given index and @v@ is the value at the top of the stack.
    --
    -- This function pops the value from the stack. The assignment is raw,
    -- that is, it does not invoke the @__newindex@ metamethod.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_rawseti>.
    foreign import capi SAFTY "lua.h lua_rawseti"
      lua_rawseti :: Lua.State -> StackIndex -> Lua.Integer -> IO ()

    -- | Removes the element at the given valid index, shifting down the
    -- elements above this index to fill the gap. This function cannot be
    -- called with a pseudo-index, because a pseudo-index is not an actual
    -- stack position.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_remove>
    foreign import capi unsafe "lua.h lua_remove"
      lua_remove :: Lua.State -> StackIndex -> IO ()

    -- | Moves the top element into the given valid index without shifting
    -- any element (therefore replacing the value at that given index), and
    -- then pops the top element.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_replace>
    foreign import capi unsafe "lua.h lua_replace"
      lua_replace :: Lua.State -> StackIndex -> IO ()

    -- | Rotates the stack elements between the valid index @idx@ and the
    -- top of the stack. The elements are rotated @n@ positions in the
    -- direction of the top, for a positive @n@, or @-n@ positions in the
    -- direction of the bottom, for a negative @n@. The absolute value of
    -- @n@ must not be greater than the size of the slice being rotated.
    -- This function cannot be called with a pseudo-index, because a
    -- pseudo-index is not an actual stack position.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_rotate>
    foreign import capi unsafe "lua.h lua_rotate"
      lua_rotate :: Lua.State
                 -> StackIndex  -- ^ idx
                 -> CInt        -- ^ n
                 -> IO ()

    -- | Pops a value from the stack and sets it as the new value of global
    -- @name@.
    --
    -- __WARNING__: @lua_setglobal@ is unsafe in Haskell: if the call to a
    -- metamethod triggers an error, then that error cannot be handled and
    -- will lead to an unrecoverable program crash. Consider using the
    -- @'Lua.hslua_setglobal'@ ersatz function instead. Likewise,
    -- the global metamethod may not call a Haskell function unless the
    -- library was compiled without @allow-unsafe-gc@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_setglobal>.
    foreign import capi SAFTY "lua.h lua_setglobal"
      lua_setglobal :: State -> CString {- ^ name -} -> IO ()
    {-# WARNING lua_setglobal
          [ "This is an unsafe function, errors will lead to a program crash;"
          , "consider using hslua_getglobal instead."
          ] #-}

    -- | Pops a table from the stack and sets it as the new metatable for
    -- the value at the given index.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_setmetatable>.
    foreign import capi unsafe "lua.h lua_setmetatable"
      lua_setmetatable :: Lua.State -> StackIndex -> IO ()

    -- | Does the equivalent to @t[k] = v@, where @t@ is the value at the
    -- given index, @v@ is the value at the top of the stack, and @k@ is the
    -- value just below the top.
    --
    -- This function pops both the key and the value from the stack. As in
    -- Lua, this function may trigger a metamethod for the \"newindex\"
    -- event (see <https://www.lua.org/manual/5.4/manual.html#2.4 §2.4>).
    --
    -- __WARNING__: @lua_settable@ is unsafe in Haskell: if the call to a
    -- metamethod triggers an error, then that error cannot be handled and
    -- will lead to an unrecoverable program crash. Consider using the
    -- @'Lua.hslua_settable'@ ersatz function instead. Likewise, the
    -- metamethod may not call a Haskell function unless the library was
    -- compiled without @allow-unsafe-gc@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_settable>
    foreign import capi SAFTY "lua.h lua_settable"
      lua_settable :: Lua.State -> StackIndex {- ^ index -} -> IO ()
    {-# WARNING lua_settable
          [ "This is an unsafe function, errors will lead to a program crash;"
          , "consider using hslua_settable instead."
          ] #-}

    -- | Accepts any index, or 0, and sets the stack top to this index. If
    -- the new top is larger than the old one, then the new elements are
    -- filled with *nil*. If @index@ is 0, then all stack elements are
    -- removed.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_settop>
    foreign import capi unsafe "lua.h lua_settop"
      lua_settop :: Lua.State -> StackIndex {- ^ index -} -> IO ()

    -- | Pops a value from the stack and sets it as the new @n@-th user
    -- value associated to the full userdata at the given index. Returns 0
    -- if the userdata does not have that value.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_setiuservalue>
    foreign import capi unsafe "lua.h lua_setiuservalue"
      lua_setiuservalue :: Lua.State
                        -> StackIndex  -- ^ index
                        -> CInt        -- ^ n
                        -> IO LuaBool

    -- | Sets the warning function to be used by Lua to emit warnings (see
    -- 'WarnFunction'). The @ud@ parameter sets the value @ud@ passed to the
    -- warning function.
    foreign import capi unsafe "lua.h lua_setwarnf"
      lua_setwarnf :: Lua.State
                   -> Lua.WarnFunction -- ^ f
                   -> Ptr ()           -- ^ ud
                   -> IO ()

    -- |  Returns the status of this Lua thread.
    --
    -- The status can be @'Lua.LUA_OK'@ for a normal thread, an
    -- error value if the thread finished the execution of a @lua_resume@
    -- with an error, or @'Lua.LUA_YIELD'@ if the thread is
    -- suspended.
    --
    -- You can only call functions in threads with status
    -- @'Lua.LUA_OK'@. You can resume threads with status
    -- @'Lua.LUA_OK'@ (to start a new coroutine) or
    -- @'Lua.LUA_YIELD'@ (to resume a coroutine).
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_status>.
    foreign import capi unsafe "lua.h lua_status"
      lua_status :: Lua.State -> IO StatusCode

    -- | Converts the zero-terminated string @s@ to a number, pushes that
    -- number into the stack, and returns the total size of the string, that
    -- is, its length plus one. The conversion can result in an integer or a
    -- float, according to the lexical conventions of Lua (see
    -- <https://www.lua.org/manual/5.4/manual.html#3.1 §3.1>). The string
    -- may have leading and trailing spaces and a sign. If the string is not
    -- a valid numeral, returns 0 and pushes nothing. (Note that the result
    -- can be used as a boolean, true if the conversion succeeds.)
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_stringtonumber>.
    foreign import capi unsafe "lua.h lua_stringtonumber"
      lua_stringtonumber :: Lua.State -> CString -> IO CSize

    -- | Converts the Lua value at the given index to a haskell boolean
    -- value. Like all tests in Lua, @toboolean@ returns @True@ for any Lua
    -- value different from *false* and *nil*; otherwise it returns @False@.
    -- (If you want to accept only actual boolean values, use
    -- @'lua_isboolean'@ to test the value's type.)
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_toboolean>
    foreign import capi unsafe "lua.h lua_toboolean"
      lua_toboolean :: Lua.State -> StackIndex -> IO LuaBool

    -- | Converts a value at the given index to a C function. That value
    -- must be a C function; otherwise, returns @Nothing@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_tocfunction>
    foreign import capi unsafe "lua.h lua_tocfunction"
      lua_tocfunction :: Lua.State -> StackIndex -> IO CFunction

    -- | Converts the Lua value at the given acceptable index to the signed
    -- integral type 'Lua.Integer'. The Lua value must be an integer, a
    -- number, or a string convertible to an integer (see
    -- <https://www.lua.org/manual/5.4/manual.html#3.4.3 §3.4.3> of the Lua
    -- 5.4 Reference Manual); otherwise, @lua_tointegerx@ returns @0@.
    --
    -- If the number is not an integer, it is truncated in some
    -- non-specified way.
    --
    -- If @isnum@ is not @NULL@, its referent is assigned a boolean value
    -- that indicates whether the operation succeeded.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_tointegerx>
    foreign import capi unsafe "lua.h lua_tointegerx"
      lua_tointegerx :: Lua.State
                     -> StackIndex       -- ^ index
                     -> Ptr LuaBool      -- ^ isnum
                     -> IO Lua.Integer

    -- | Converts the Lua value at the given index to a C string. If @len@
    -- is not @NULL@, it sets the referent with the string length. The Lua
    -- value must be a string or a number; otherwise, the function returns
    -- @NULL@. If the value is a number, then @lua_tolstring@ also changes
    -- the actual value in the stack to a string. (This change confuses
    -- @lua_next@ when @lua_tolstring@ is applied to keys during a table
    -- traversal.)
    --
    -- @lua_tolstring@ returns a pointer to a string inside the Lua state.
    -- This string always has a zero ('\0') after its last character (as in
    -- C), but can contain other zeros in its body.
    --
    -- Because Lua has garbage collection, there is no guarantee that the
    -- pointer returned by @lua_tolstring@ will be valid after the
    -- corresponding Lua value is removed from the stack.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_tolstring>
    foreign import ccall SAFTY "lua.h lua_tolstring"
      lua_tolstring :: Lua.State
                    -> StackIndex        -- ^ index
                    -> Ptr CSize         -- ^ len
                    -> IO (Ptr CChar)

    -- | Converts the Lua value at the given index to the C type lua_Number
    -- (see lua_Number). The Lua value must be a number or a string
    -- convertible to a number (see §3.4.3); otherwise, lua_tonumberx
    -- returns 0.
    --
    -- If @isnum@ is not @NULL@, its referent is assigned a boolean value
    -- that indicates whether the operation succeeded.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_tonumberx>
    foreign import ccall unsafe "lua.h lua_tonumberx"
      lua_tonumberx :: Lua.State
                    -> StackIndex        -- ^ index
                    -> Ptr LuaBool       -- ^ isnum
                    -> IO Lua.Number

    -- | Converts the value at the given index to a generic C pointer
    -- (@void*@). The value can be a userdata, a table, a thread, or a
    -- function; otherwise, @lua_topointer@ returns @'nullPtr'@. Different
    -- objects will give different pointers. There is no way to convert the
    -- pointer back to its original value.
    --
    -- Typically this function is used only for hashing and debug
    -- information.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_topointer>
    foreign import ccall unsafe "lua.h lua_topointer"
      lua_topointer :: Lua.State -> StackIndex -> IO (Ptr ())

    -- | Converts the value at the given index to a Lua thread (represented
    -- as @'Lua.State'@). This value must be a thread; otherwise, the
    -- function returns @'nullPtr'@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_tothread>
    foreign import capi unsafe "lua.h lua_tothread"
      lua_tothread :: Lua.State -> StackIndex -> IO Lua.State

    -- | If the value at the given index is a full userdata, returns its
    -- block address. If the value is a light userdata, returns its pointer.
    -- Otherwise, returns @'nullPtr'@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_touserdata>
    foreign import capi unsafe "lua.h lua_touserdata"
      lua_touserdata :: Lua.State -> StackIndex -> IO (Ptr a)

    -- | Returns the type of the value in the given valid index, or
    -- @'Lua.LUA_TNONE'@ for a non-valid (but acceptable) index.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_type>
    foreign import capi unsafe "lua.h lua_type"
      lua_type :: Lua.State -> StackIndex -> IO TypeCode

    -- | Returns the name of the type encoded by the value @tp@, which must
    -- be one the values returned by @'lua_type'@.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_typename>
    foreign import ccall unsafe "lua.h lua_typename"
      lua_typename :: Lua.State -> TypeCode {- ^ tp -} -> IO CString

    -- | Returns the address of the version number (a C static variable)
    -- stored in the Lua core. When called with a valid 'Lua.State', returns
    -- the address of the version used to create that state. When called
    -- with @NULL@, returns the address of the version running the call.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_version>
    foreign import ccall unsafe "lua.h lua_version"
      lua_version :: Lua.State -> IO (Ptr Lua.Number)

    -- | Emits a warning with the given message. A message in a call with
    -- @tocont@ true should be continued in another call to this function.
    --
    -- See <https://www.lua.org/manual/5.4/manual.html#pdf-warn warn> for
    -- more details about warnings.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#lua_warning>
    foreign import capi safe "lua.h lua_warning"
      lua_warning :: Lua.State
                  -> CString   -- ^ message
                  -> LuaBool   -- ^ tocont
                  -> IO ()