{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module TH.Utilities where
import Data.Data
import Data.Generics
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
tyVarBndrName :: TyVarBndr -> Name
tyVarBndrName (PlainTV n) = n
tyVarBndrName (KindedTV n _) = n
appsT :: Type -> [Type] -> Type
appsT x [] = x
appsT x (y:xs) = appsT (AppT x y) xs
unAppsT :: Type -> [Type]
unAppsT = go []
where
go xs (AppT l x) = go (x : xs) l
go xs ty = ty : xs
typeToNamedCon :: Type -> Maybe (Name, [Type])
#if MIN_VERSION_template_haskell(2,11,0)
typeToNamedCon (InfixT l n r) = Just (n, [l, r])
typeToNamedCon (UInfixT l n r) = Just (n, [l, r])
#endif
typeToNamedCon (unAppsT -> (ConT n : args)) = Just (n, args)
typeToNamedCon _ = Nothing
expectTyCon1 :: Name -> Type -> Q Type
expectTyCon1 expected (AppT (ConT n) x) | expected == n = return x
expectTyCon1 expected (AppT (PromotedT n) x) | expected == n = return x
expectTyCon1 expected x = fail $
"Expected " ++ pprint expected ++
", applied to one argument, but instead got " ++ pprint x ++ "."
expectTyCon2 :: Name -> Type -> Q (Type, Type)
expectTyCon2 expected (AppT (AppT (ConT n) x) y) | expected == n = return (x, y)
expectTyCon2 expected (AppT (AppT (PromotedT n) x) y) | expected == n = return (x, y)
#if MIN_VERSION_template_haskell(2,11,0)
expectTyCon2 expected (InfixT x n y) | expected == n = return (x, y)
expectTyCon2 expected (UInfixT x n y) | expected == n = return (x, y)
#endif
expectTyCon2 expected x = fail $
"Expected " ++ pprint expected ++
", applied to two arguments, but instead got " ++ pprint x ++ "."
proxyE :: TypeQ -> ExpQ
proxyE ty = [| Proxy :: Proxy $(ty) |]
everywhereButStrings :: Data a => (forall b. Data b => b -> b) -> a -> a
everywhereButStrings f =
(f . gmapT (everywhereButStrings f)) `extT` (id :: String -> String)
everywhereButStringsM :: forall a m. (Data a, Monad m) => GenericM m -> a -> m a
everywhereButStringsM f x = do
x' <- gmapM (everywhereButStringsM f) x
(f `extM` (return :: String -> m String)) x'
toSimpleName :: Name -> Name
toSimpleName = mkName . pprint
dequalify :: Name -> Name
dequalify = mkName . nameBase
dequalifyTyVars :: Data a => a -> a
dequalifyTyVars = everywhere (id `extT` modifyType)
where
modifyType (VarT n) = VarT (dequalify n)
modifyType ty = ty
freeVarsT :: Type -> [Name]
freeVarsT (ForallT tvs _ ty) = filter (`notElem` (map tyVarBndrName tvs)) (freeVarsT ty)
freeVarsT (VarT n) = [n]
freeVarsT ty = concat $ gmapQ (const [] `extQ` freeVarsT) ty
plainInstanceD :: Cxt -> Type -> [Dec] -> Dec
plainInstanceD =
#if MIN_VERSION_template_haskell(2,11,0)
InstanceD Nothing
#else
InstanceD
#endif
fromPlainInstanceD :: Dec -> Maybe (Cxt, Type, [Dec])
#if MIN_VERSION_template_haskell(2,11,0)
fromPlainInstanceD (InstanceD _ a b c) = Just (a, b, c)
#else
fromPlainInstanceD (InstanceD a b c) = Just (a, b, c)
#endif
fromPlainInstanceD _ = Nothing
typeRepToType :: TypeRep -> Q Type
typeRepToType tr = do
let (con, args) = splitTyConApp tr
name = Name (OccName (tyConName con)) (NameG TcClsName (PkgName (tyConPackage con)) (ModName (tyConModule con)))
resultArgs <- mapM typeRepToType args
return (appsT (ConT name) resultArgs)
data ExpLifter = ExpLifter ExpQ deriving (Typeable)
instance Lift ExpLifter where
lift (ExpLifter e) = e
dumpSplices :: DecsQ -> DecsQ
dumpSplices x = do
ds <- x
let code = lines (pprint ds)
reportWarning ("\n" ++ unlines (map (" " ++) code))
return ds