{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-}
module TH.Derive
( derive
, Deriving
, Deriver(..)
, Instantiator(..)
, dequalifyMethods
) where
import Data.Data
import Data.Generics
import Language.Haskell.TH
import Language.Haskell.TH.Instances ()
import TH.Utilities
import TH.Derive.Internal
import TH.Derive.Storable ()
import GHC.Exts (Any)
derive :: DecsQ -> ExpQ
derive :: DecsQ -> ExpQ
derive DecsQ
decsq = do
[Dec]
decs <- DecsQ
decsq
let labeledDecs :: [(Name, Dec)]
labeledDecs = forall a b. [a] -> [b] -> [(a, b)]
zip (forall a b. (a -> b) -> [a] -> [b]
map (String -> Name
mkName forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String
"x" forall a. [a] -> [a] -> [a]
++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show) [(Int
0::Int)..]) [Dec]
decs
forall (m :: * -> *). Quote m => [m Stmt] -> m Exp
doE forall a b. (a -> b) -> a -> b
$
forall a b. (a -> b) -> [a] -> [b]
map (Name, Dec) -> Q Stmt
toStmt [(Name, Dec)]
labeledDecs forall a. [a] -> [a] -> [a]
++
[ forall (m :: * -> *). Quote m => m Exp -> m Stmt
noBindS [e| return $ concat $(listE (map (varE . fst) labeledDecs)) |] ]
where
toStmt :: (Name, Dec) -> Q Stmt
toStmt (Name
varName, Dec
dec) = case Dec -> Maybe (Cxt, Type, [Dec])
fromPlainInstanceD Dec
dec of
Just (Cxt
preds, AppT (ConT ((forall a. Eq a => a -> a -> Bool
== ''Deriving) -> Bool
True)) Type
cls, []) ->
forall (m :: * -> *). Quote m => m Pat -> m Exp -> m Stmt
bindS (forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
varName)
[e| runDeriver $(proxyE (return (tyVarsToAny cls)))
preds
cls |]
Just (Cxt
preds, Type
ty, [Dec]
decs) ->
forall (m :: * -> *). Quote m => m Pat -> m Exp -> m Stmt
bindS (forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
varName)
[e| runInstantiator $(proxyE (return (tyVarsToAny ty)))
preds
ty
decs |]
Maybe (Cxt, Type, [Dec])
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$
String
"Expected deriver or instantiator, instead got:\n" forall a. [a] -> [a] -> [a]
++
forall a. Show a => a -> String
show Dec
dec
tyVarsToAny :: Data a => a -> a
tyVarsToAny :: forall a. Data a => a -> a
tyVarsToAny = (forall a. Data a => a -> a) -> forall a. Data a => a -> a
everywhere (forall a. a -> a
id forall a b.
(Typeable a, Typeable b) =>
(a -> a) -> (b -> b) -> a -> a
`extT` Type -> Type
modifyType)
where
modifyType :: Type -> Type
modifyType (VarT Name
_) = Name -> Type
ConT ''Any
modifyType Type
ty = Type
ty
dequalifyMethods :: Data a => Name -> a -> Q a
dequalifyMethods :: forall a. Data a => Name -> a -> Q a
dequalifyMethods Name
className a
x = do
Info
info <- Name -> Q Info
reify Name
className
case Info
info of
ClassI (ClassD Cxt
_ Name
_ [TyVarBndr ()]
_ [FunDep]
_ [Dec]
decls) [Dec]
_ ->
forall (m :: * -> *) a. Monad m => a -> m a
return (forall b. Data b => [Name] -> b -> b
go [Name
n | SigD Name
n Type
_ <- [Dec]
decls] a
x)
Info
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"dequalifyMethods expected class, but got:\n" forall a. [a] -> [a] -> [a]
++ forall a. Ppr a => a -> String
pprint Info
info
where
go :: Data b => [Name] -> b -> b
go :: forall b. Data b => [Name] -> b -> b
go [Name]
names = forall a. Data a => (forall a. Data a => a -> a) -> a -> a
gmapT (forall b. Data b => [Name] -> b -> b
go [Name]
names) forall a b.
(Typeable a, Typeable b) =>
(a -> a) -> (b -> b) -> a -> a
`extT` (forall a. a -> a
id :: String -> String) forall a b.
(Typeable a, Typeable b) =>
(a -> a) -> (b -> b) -> a -> a
`extT`
(\Name
n -> if Name
n forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Name]
names then Name -> Name
dequalify Name
n else Name
n)