GLFW-b-1.0.0: Graphics/UI/GLFW/Internal/C/TH.hs
{-# LANGUAGE TemplateHaskell #-}
-- deriveC creates an instance of C c h from [(c, h)].
--
-- Example:
--
-- > pairs :: [(CInt, Bool)]
-- > pairs = [(0, False), (1, True)]
-- >
-- > deriveC ''CInt ''Bool pairs
--
-- would derive
--
-- > instance C CInt Bool where
-- > fromC 0 = False
-- > fromC 1 = True
-- > fromC _ = error ...
-- >
-- > toC False = 0
-- > toC True = 1
module Graphics.UI.GLFW.Internal.C.TH
( deriveC
) where
--------------------------------------------------------------------------------
import Data.Data (Data)
import Data.Tuple (swap)
import Language.Haskell.TH (Dec, Name, Q, appT, clause, conT, cxt, funD, global, instanceD, mkName, nameBase, normalB, varP)
import Language.Haskell.TH.Quote (dataToPatQ)
import Language.Haskell.TH.Syntax (Lift(..))
--------------------------------------------------------------------------------
deriveC :: (Data c, Data h, Lift c, Lift h) => Name -> Name -> [(c, h)] -> Q [Dec]
deriveC ctype htype pairs =
(:[]) `fmap` deriveC1 ctype htype pairs
--------------------------------------------------------------------------------
deriveC1 :: (Data c, Data h, Lift c, Lift h) => Name -> Name -> [(c, h)] -> Q Dec
deriveC1 _ _ [] =
error "deriveC: no pairs!"
deriveC1 ctype htype pairs =
instanceD
(cxt [])
(appT
(appT (conT cname) (conT ctype))
(conT htype)
)
[ funD frname frClauses
, funD toname toClauses
]
where
cname = mkName "C"
frname = mkName "fromC"
toname = mkName "toC"
vname = mkName "v"
frClauses = map genPairClause pairs ++ [genErrorClause]
toClauses = map (genPairClause . swap) pairs
genPairClause (v0, v1) =
clause [pat] body []
where
pat = dataToPatQ (const Nothing) v0
body = normalB [|v1|]
genErrorClause =
clause [pat] body []
where
pat = varP vname
body = normalB [| error $ msg ++ show $(global vname) |]
-- e.g., "C CInt Bool fromC: "
msg = unwords (map nameBase [cname, ctype, htype, frname]) ++ ": "