module Control.Monad.SFML.Types.TH
( lift
, lift'
, liftWithDestroy
) where
import Language.Haskell.TH
import Data.Char
import Control.Monad.State.Strict hiding (lift)
import Control.Monad.SFML.Types.Internal
import qualified SFML.Graphics as G
lift :: Name -> Q [Dec]
lift adapteeName = do
argsNum <- extractArgNum adapteeName
lift' adapteeName argsNum
lift' :: Name -> Int -> Q [Dec]
lift' adapteeName argNum = do
let args = mkArgs argNum
adapteeFn <- varE adapteeName
let wrapper = mkApply adapteeFn (map VarE args)
fnBody <- [| SFML $ liftIO $ $(return wrapper) |]
generateWrapper adapteeName args fnBody
generateWrapper :: Name -> [Name] -> Exp -> Q [Dec]
generateWrapper adapteeName args fnBody = do
adapterName <- newName $ nameBase adapteeName
adapteeFn <- varE adapteeName
let wrapper = mkApply adapteeFn (map VarE args)
return [FunD adapterName [Clause (map VarP args) (NormalB fnBody) []]]
liftWithDestroy :: Name -> Name -> Q [Dec]
liftWithDestroy modifier adapteeName = do
argsNum <- extractArgNum adapteeName
let args = mkArgs argsNum
adapteeFn <- varE adapteeName
let wrapper = mkApply adapteeFn (map VarE args)
fnBody <- [| SFML $ do
res <- liftIO $ $(varE modifier) $ $(return wrapper)
modify $ \s -> G.destroy res : s
return res |]
generateWrapper adapteeName args fnBody
mkArgs :: Int -> [Name]
mkArgs n = map (mkName . (:[])) . take n $ ['a' .. 'z']
extractArgNum :: Name -> Q Int
extractArgNum fname = do
info <- reify fname
case info of
(VarI _ (ForallT _ _ t) _ _) -> return . countArgs $ t
(VarI _ t _ _) -> return . countArgs $ t
(ClassOpI _ (ForallT _ _ t) _ _) -> return . countArgs $ t
e -> error $ show e ++ " is not a function."
where
countArgs (AppT (AppT ArrowT _) ts) = 1 + countArgs ts
countArgs _ = 0
mkApply :: Exp -> [Exp] -> Exp
mkApply fn [] = fn
mkApply fn (x:xs) = foldl AppE (AppE fn x) xs
capitalize [] = []
capitalize (x:xs) = toUpper x : xs