module Ceilometer.Types.TH
( declarePF
) where
import Control.Applicative
import Data.Char
import Data.Maybe
import Language.Haskell.TH
declarePF :: String
-> (String, Name)
-> [(String, Integer)]
-> [Name]
-> Q [Dec]
declarePF = declareWith "pf"
declareWith :: String -> String -> (String, Name) -> [(String, Integer)] -> [Name] -> Q [Dec]
declareWith prefix field (tyconStr, mappedType) ds derives = do
pfunc <- lookupPrismFunc
pty <- lookupPrismTyCon
just <- lookupJust
nothing <- lookupNothing
let tycon = mkName $ map toUpper prefix ++ field ++ tyconStr
dacons = map (mkName . (field ++) . fst) ds
dec = DataD [] tycon [] (map (flip NormalC []) dacons) derives
p = mkName (prefix ++ field ++ tyconStr)
vals = map (IntegerL . snd) ds
pretties = zipWith mkClause
(map ((:[]) . flip ConP []) dacons)
(map (NormalB . LitE) vals)
pretty = mkName "pretty"
parses = zipWith mkClause
(map ((:[]) . LitP) vals)
(map (NormalB . AppE (ConE just) . ConE) dacons)
++ [Clause [WildP] (NormalB (ConE nothing)) []]
parse = mkName "parse"
cases = Clause []
(NormalB $ AppE (AppE (VarE pfunc) (VarE pretty)) (VarE parse))
[FunD pretty pretties, FunD parse parses]
sig = SigD p (AppT (AppT (ConT pty) (ConT mappedType)) (ConT tycon))
def = FunD p [cases]
return [dec, sig, def]
mkClause :: [Pat] -> Body -> Clause
mkClause x y = Clause x y []
lookupPrismFunc, lookupPrismTyCon :: Q Name
lookupJust, lookupNothing :: Q Name
lookupPrismFunc = lookupV "prism'"
lookupPrismTyCon = lookupT "Prism'"
lookupJust = lookupV "Just"
lookupNothing = lookupV "Nothing"
lookupT :: String -> Q Name
lookupT x = fromMaybe (error $ "TH: not in scope " ++ x) <$> lookupTypeName x
lookupV :: String -> Q Name
lookupV x = fromMaybe (error $ "TH: not in scope " ++ x) <$> lookupValueName x