{-# LANGUAGE OverloadedStrings #-} {-| Santa's wishlist processor. The program expexts the path to a filter file as its only argument. See the blog-post for more details: https://hslua.org/santas-little-lua-scripts.html -} module Main where import Control.Monad (filterM) import Data.Text (Text, pack) import HsLua.Core ( Lua, NumResults (..), NumArgs (..) , call, dofile, newtable, nth, pop, pushvalue, run , setfield, top, toboolean) import HsLua.Marshalling (pushBool, pushText) import System.Environment (getArgs) data Toy = Bricks | TrainSet | Doll deriving Show data Behavior = Nice | Naughty deriving (Eq, Show) data Wish = Wish { wishingChild :: Child , wishedToy :: Toy } deriving Show data Child = Child { childName :: Text , childBehavior :: Behavior } deriving Show pushToy :: Toy -> Lua () pushToy = pushText . pack . show pushChild :: Child -> Lua () pushChild (Child name behavior) = do -- create new Lua table on the stack newtable -- push boolean to stack pushText name -- table now in position 2; assign string to field in table setfield (nth 2) "name" -- push boolean to stack pushBool (behavior == Nice) setfield (nth 2) "nice" pushWish :: Wish -> Lua () pushWish (Wish child toy) = do newtable pushChild child setfield (nth 2) "child" pushToy toy setfield (nth 2) "toy" wishes :: [Wish] wishes = [ Wish (Child "Theodor" Nice) Bricks , Wish (Child "Philine" Nice) TrainSet , Wish (Child "Steve" Naughty) Doll ] hasPredicate :: Wish -> Lua Bool hasPredicate wish = do -- Assume filter function is at the top of the stack; -- create a copy so we can re-use it. pushvalue top pushWish wish -- Call the function. There is one argument on the stack, -- and we expect one result to be returned. call (NumArgs 1) (NumResults 1) toboolean top <* pop 1 main :: IO () main = do filterFile <- fmap (!! 0) getArgs -- get first argument result <- run $ do _status <- dofile (Just filterFile) filterM hasPredicate wishes print result