{-# LANGUAGE CPP #-}
{-|
Module      : Lua.Primary
Copyright   : © 2007–2012 Gracjan Polak;
              © 2012–2016 Ömer Sinan Ağacan;
              © 2017-2023 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 ()
