packages feed

hslua-examples-2.0.0: low-level-factorial/low-level-factorial.hs

-- 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 ()