content: -- lua_setglobal is unsafe in general and causes a compiler warning.
  {-# OPTIONS_GHC -Wno-warnings-deprecations #-}
  {-| Expose factorial function to Lua, using the low-level API. -}
  module Main where
  import Prelude
  import Control.Monad (void)
  import Foreign.C (withCString, withCStringLen)
  import Foreign.Ptr (nullPtr)
  import Lua
  
  luaScript :: String
  luaScript = unlines
    [ "print(' 5! =', factorial(5), type(factorial(5)))"
    , "print('30! =', factorial(30), type(factorial(30)))"
    ]
  
  factorial :: PreCFunction
  factorial l = do
    -- Get the first function argument as an integer.
    n <- lua_tointegerx l (nthBottom 1) nullPtr
    let result = product [1..fromIntegral n] :: Prelude.Integer
    -- push as integer if the result is small enough,
    -- and as string otherwise.
    if result <= fromIntegral (maxBound :: Lua.Integer)
      then lua_pushinteger l (fromIntegral result)
      else withCString (show result) (void . lua_pushstring l)
    -- Signal that one result value is on the top of the stack.
    return (NumResults 1)
  
  main :: IO ()
  main = void . withNewState $ \l -> do
    luaL_openlibs l
    -- expose Haskell function `factorial` as a Lua function of the same name.
    hslua_pushhsfunction l factorial
    _ <- withCString "factorial" (lua_setglobal l)
    -- Load the script.
    LUA_OK <- withCStringLen luaScript $ \(sPtr, sLen) ->
      withCString "script" $ luaL_loadbuffer l sPtr (fromIntegral sLen)
    -- Call the loaded script.
    LUA_OK <- lua_pcall l (NumArgs 0) LUA_MULTRET (StackIndex 0)
    return ()
  