{-# 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 = [Name] -> [Dec] -> [(Name, Dec)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((Int -> Name) -> [Int] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Name
mkName (String -> Name) -> (Int -> String) -> Int -> Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String
"x" String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String) -> (Int -> String) -> Int -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show) [(Int
0::Int)..]) [Dec]
decs
[StmtQ] -> ExpQ
doE ([StmtQ] -> ExpQ) -> [StmtQ] -> ExpQ
forall a b. (a -> b) -> a -> b
$
((Name, Dec) -> StmtQ) -> [(Name, Dec)] -> [StmtQ]
forall a b. (a -> b) -> [a] -> [b]
map (Name, Dec) -> StmtQ
toStmt [(Name, Dec)]
labeledDecs [StmtQ] -> [StmtQ] -> [StmtQ]
forall a. [a] -> [a] -> [a]
++
[ ExpQ -> StmtQ
noBindS [e| return $ concat $(listE (map (varE . fst) labeledDecs)) |] ]
where
toStmt :: (Name, Dec) -> StmtQ
toStmt (Name
varName, Dec
dec) = case Dec -> Maybe (Cxt, Type, [Dec])
fromPlainInstanceD Dec
dec of
Just (Cxt
preds, AppT (ConT ((Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== ''Deriving) -> Bool
True)) Type
cls, []) ->
PatQ -> ExpQ -> StmtQ
bindS (Name -> PatQ
varP Name
varName)
[e| runDeriver $(proxyE (return (tyVarsToAny cls)))
preds
cls |]
Just (Cxt
preds, Type
ty, [Dec]
decs) ->
PatQ -> ExpQ -> StmtQ
bindS (Name -> PatQ
varP Name
varName)
[e| runInstantiator $(proxyE (return (tyVarsToAny ty)))
preds
ty
decs |]
Maybe (Cxt, Type, [Dec])
_ -> String -> StmtQ
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> StmtQ) -> String -> StmtQ
forall a b. (a -> b) -> a -> b
$
String
"Expected deriver or instantiator, instead got:\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++
Dec -> String
forall a. Show a => a -> String
show Dec
dec
tyVarsToAny :: Data a => a -> a
tyVarsToAny :: a -> a
tyVarsToAny = (forall a. Data a => a -> a) -> forall a. Data a => a -> a
everywhere (a -> a
forall a. a -> a
id (a -> a) -> (Type -> Type) -> a -> a
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 :: 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]
_ ->
a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Name] -> a -> a
forall b. Data b => [Name] -> b -> b
go [Name
n | SigD Name
n Type
_ <- [Dec]
decls] a
x)
Info
_ -> String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Q a) -> String -> Q a
forall a b. (a -> b) -> a -> b
$ String
"dequalifyMethods expected class, but got:\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Info -> String
forall a. Ppr a => a -> String
pprint Info
info
where
go :: Data b => [Name] -> b -> b
go :: [Name] -> b -> b
go [Name]
names = (forall a. Data a => a -> a) -> b -> b
forall a. Data a => (forall a. Data a => a -> a) -> a -> a
gmapT ([Name] -> b -> b
forall b. Data b => [Name] -> b -> b
go [Name]
names) (b -> b) -> (String -> String) -> b -> b
forall a b.
(Typeable a, Typeable b) =>
(a -> a) -> (b -> b) -> a -> a
`extT` (String -> String
forall a. a -> a
id :: String -> String) (b -> b) -> (Name -> Name) -> b -> b
forall a b.
(Typeable a, Typeable b) =>
(a -> a) -> (b -> b) -> a -> a
`extT`
(\Name
n -> if Name
n Name -> [Name] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Name]
names then Name -> Name
dequalify Name
n else Name
n)