|
@@ -0,0 +1,62 @@
|
|
|
+{-# LANGUAGE NamedFieldPuns #-}
|
|
|
+
|
|
|
+module Main where
|
|
|
+
|
|
|
+import qualified Control.Exception as Exn
|
|
|
+import qualified Foreign.Lua as Lua
|
|
|
+
|
|
|
+data Config = Config
|
|
|
+ { cfgHost :: String,
|
|
|
+ cfgPort :: Int,
|
|
|
+ cfgFiles :: [String]
|
|
|
+ }
|
|
|
+ deriving (Show)
|
|
|
+
|
|
|
+readConfig :: FilePath -> IO Config
|
|
|
+readConfig configPath =
|
|
|
+ -- set up a new Lua state, and make sure we close it at the end
|
|
|
+ Exn.bracket Lua.newstate Lua.close $ \st ->
|
|
|
+ -- we should set up a mechanism to convert Lua/Haskell errors into
|
|
|
+ -- one another, but that seems like a lot of work here, so this
|
|
|
+ -- just panics whenever any errors happen, hence `unsafeRunWith`
|
|
|
+ Lua.unsafeRunWith st $ do
|
|
|
+ -- this loads the stdlib into Lua, but you probably don't
|
|
|
+ -- actually want this in a config file! (it allows e.g. file IO
|
|
|
+ -- and stuff)
|
|
|
+ Lua.openlibs
|
|
|
+ -- load the actual config path. this should check error
|
|
|
+ -- conditions, but eh.
|
|
|
+ _ <- Lua.loadfile configPath
|
|
|
+ -- that simply loads the code as a zero-argument function: now
|
|
|
+ -- call it
|
|
|
+ Lua.call 0 0
|
|
|
+
|
|
|
+ -- use the `readGlobal` helper to extract the globals defined by
|
|
|
+ -- the config file...
|
|
|
+ cfgHost <- readGlobal "host"
|
|
|
+ cfgPort <- readGlobal "port"
|
|
|
+ cfgFiles <- readGlobal "files"
|
|
|
+
|
|
|
+ -- and return the values
|
|
|
+ return Config {cfgHost, cfgPort, cfgFiles}
|
|
|
+
|
|
|
+-- | Read the global variable @name@ into a Haskell value
|
|
|
+readGlobal :: Lua.Peekable t => String -> Lua.Lua t
|
|
|
+readGlobal name = do
|
|
|
+ -- this pushes the global named `name` onto the top of the stack
|
|
|
+ Lua.getglobal name
|
|
|
+ -- this finds out what index is at the top of the stack
|
|
|
+ idx <- Lua.gettop
|
|
|
+ -- this uses the `peek` functionality, already parameterized by a
|
|
|
+ -- typeclass, to convert the value at the given index into the
|
|
|
+ -- appropriate Haskell type
|
|
|
+ value <- Lua.peek idx
|
|
|
+ -- pop the global, now that we've already got it in Haskell-land
|
|
|
+ Lua.pop 1
|
|
|
+ -- ...and return it
|
|
|
+ return value
|
|
|
+
|
|
|
+main :: IO ()
|
|
|
+main = do
|
|
|
+ cfg <- readConfig "sample.lua"
|
|
|
+ print cfg
|