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.
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.
Save the following in the same directory and run lua.hs.
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"
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"