HsLua

2012-03-09 21:06 UTC
  • Xyne

About

This page contains notes, references and examples for working with HsLua. I may expand on this eventually but I’ve just started working with HsLua a few hours ago at the time of writing. I was frustrated by the lack of (working) examples so I decided to post what I had figured out in the hopes that it would save others a few “wtf?” moments.

References

Here are some useful references. The C API examples translate directly to Haskell.

Section 3.14 of the Lua reference manual provides a good example of how the stack is used when working with Lua from C. Study it and the examples below until you understand each step. It should provide the necessary insight for working with HsLua.

Example

Save the following in the same directory and run lua.hs.

test.lua

username = os.getenv("USER") or "<user>"


luaVersion = function(name)
  s = string.format("This is %s.\n", _VERSION)
  s = s .. string.format("It was invoked by %s.\n\n", name)
  io.write(s)
end


haskellVersion = function()
  io.write( "Invoking the Haskell function from Lua...\n" )
  io.write( hsVersion(_VERSION) )
  io.write( "\n\n" )
end

return "Lua: finished loading"

lua.hs

import qualified Scripting.Lua as Lua
import System.Info
import Data.Version

luaScript = "test.lua"

version :: String -> IO String
version name =
  return $
  "This is " ++
  compilerName ++
  " " ++
  (showVersion compilerVersion) ++
  "\nIt was invoked by " ++
  name


main =
  -- Create a new Lua state and open the standard libraries.
  Lua.newstate >>= \ l ->
  Lua.openlibs l >>

  -- Load the test script.
  Lua.loadfile l luaScript >>

  -- Register the 'version' function as 'hsVersion' so that it can be called
  -- from within Lua.
  Lua.registerhsfunction l "hsVersion" version >>

  -- Run the script and get error code.
  Lua.pcall l 0 Lua.multret 0 >>= \ errorCode ->
  if errorCode > 0
    -- A non-zero error code indicates an error. There should be an error
    -- message on the stack. Check if there is and print it if so.
    then
      Lua.isstring l (-1) >>= \ isStr ->
      if isStr
        -- If it is a string, print it along with the error code.
        then
          Lua.tostring l (-1) >>= \ msg ->
          Lua.close l >>
          putStrLn ("error: " ++ msg ++ "(" ++ (show errorCode) ++ ")")
        -- Otherwise print "unknown" along with the error code.
        else
          Lua.close l >>
          putStrLn ("error: unknown (" ++ (show errorCode) ++ ")")

    -- If the pcall was successful, the stack should contain the return value.
    else
      Lua.tostring l (-1) >>= \ rval ->
      putStrLn (luaScript ++ " returned \"" ++ rval ++ "\"\n") >>

      -- Now let's invoke the "luaVersion" function in the script.
      -- We need to invoke it with an argument, so we push it onto the stack.
      Lua.getglobal l "luaVersion" >>
      Lua.pushstring l compilerName >>
      Lua.pcall l 1 0 0 >>
      Lua.pop l 1 >>


      -- Now the "haskellVersion" function in the script, which wraps the
      -- "version" function above.
      Lua.getglobal l "haskellVersion" >>
      Lua.pcall l 0 0 0 >>


      Lua.close l >>

      -- Print something at the very end to make sure that the script hasn't
      -- aborted.
      putStrLn "done"

Contact
echo xyne.archlinux.org | sed 's/\./@/'
Validation
XHTML 1.0 Strict CSS level 3 Atom 1.0