{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE ViewPatterns #-}
module Data.Class.Closed.TH where
import Data.Class.Closed (Closed)
import Data.Maybe (fromMaybe)
import Data.Proxy (Proxy (..))
import Language.Haskell.TH (Dec (..), Name, Q, TyVarBndr (..), Type (..),
appT, classD, clause, conT, defaultSigD,
funD, instanceWithOverlapD, nameBase,
newName, normalB, sigD, varT)
import Language.Haskell.TH.Syntax (getQ, putQ)
close ∷ Q [Dec] -> Q [Dec]
close :: Q [Dec] -> Q [Dec]
close = (Q [Dec] -> ([Dec] -> Q [Dec]) -> Q [Dec]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Dec -> Q Dec) -> [Dec] -> Q [Dec]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Dec -> Q Dec
modify) where
modify ∷ Dec → Q Dec
modify :: Dec -> Q Dec
modify (ClassD Cxt
context Name
name [TyVarBndr]
tvs [FunDep]
deps [Dec]
decs) = do
let con :: TypeQ
con = Name -> TypeQ
conT Name
name
ty :: TypeQ
ty = (TypeQ -> TyVarBndr -> TypeQ) -> TypeQ -> [TyVarBndr] -> TypeQ
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\TypeQ
t TyVarBndr
b → TypeQ -> TypeQ -> TypeQ
appT TypeQ
t (TyVarBndr -> TypeQ
binderT TyVarBndr
b)) TypeQ
con [TyVarBndr]
tvs
Name
private ← Name -> Q Name
getPrivateName Name
name
CxtQ -> Name -> [TyVarBndr] -> [FunDep] -> [Q Dec] -> Q Dec
classD (Cxt -> CxtQ
forall (f :: * -> *) a. Applicative f => a -> f a
pure Cxt
context) Name
name [TyVarBndr]
tvs [FunDep]
deps
([Q Dec] -> Q Dec) -> [Q Dec] -> Q Dec
forall a b. (a -> b) -> a -> b
$ Name -> TypeQ -> Q Dec
defaultSigD Name
private [t|Closed $con ⇒ Proxy $ty|]
Q Dec -> [Q Dec] -> [Q Dec]
forall a. a -> [a] -> [a]
: Name -> TypeQ -> Q Dec
sigD Name
private [t|Proxy $ty|]
Q Dec -> [Q Dec] -> [Q Dec]
forall a. a -> [a] -> [a]
: Name -> [ClauseQ] -> Q Dec
funD Name
private [[PatQ] -> BodyQ -> [Q Dec] -> ClauseQ
clause [] (ExpQ -> BodyQ
normalB [|Proxy|]) []]
Q Dec -> [Q Dec] -> [Q Dec]
forall a. a -> [a] -> [a]
: (Dec -> Q Dec) -> [Dec] -> [Q Dec]
forall a b. (a -> b) -> [a] -> [b]
map Dec -> Q Dec
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Dec]
decs
modify (InstanceD Maybe Overlap
overlap Cxt
context ty :: Type
ty@(Type -> Maybe Name
conName → Just Name
name) [Dec]
decs) = do
Name
private ← Name -> Q Name
getPrivateName Name
name
Maybe Overlap -> CxtQ -> TypeQ -> [Q Dec] -> Q Dec
instanceWithOverlapD Maybe Overlap
overlap (Cxt -> CxtQ
forall (f :: * -> *) a. Applicative f => a -> f a
pure Cxt
context) (Type -> TypeQ
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type
ty)
([Q Dec] -> Q Dec) -> [Q Dec] -> Q Dec
forall a b. (a -> b) -> a -> b
$ Name -> [ClauseQ] -> Q Dec
funD Name
private [[PatQ] -> BodyQ -> [Q Dec] -> ClauseQ
clause [] (ExpQ -> BodyQ
normalB [|Proxy|]) []]
Q Dec -> [Q Dec] -> [Q Dec]
forall a. a -> [a] -> [a]
: (Dec -> Q Dec) -> [Dec] -> [Q Dec]
forall a b. (a -> b) -> [a] -> [b]
map Dec -> Q Dec
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Dec]
decs
modify Dec
dec = Dec -> Q Dec
forall (f :: * -> *) a. Applicative f => a -> f a
pure Dec
dec
#if MIN_VERSION_template_haskell(2, 17, 0)
binderT ∷ TyVarBndr flag → Q Type
binderT (PlainTV name _) = varT name
binderT (KindedTV name _ _) = varT name
#else
binderT ∷ TyVarBndr → Q Type
binderT :: TyVarBndr -> TypeQ
binderT (PlainTV Name
name) = Name -> TypeQ
varT Name
name
binderT (KindedTV Name
name Type
_) = Name -> TypeQ
varT Name
name
#endif
getPrivateName ∷ Name → Q Name
getPrivateName :: Name -> Q Name
getPrivateName Name
name = do
[(Name, Name)]
cache ← [(Name, Name)] -> Maybe [(Name, Name)] -> [(Name, Name)]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [(Name, Name)] -> [(Name, Name)])
-> Q (Maybe [(Name, Name)]) -> Q [(Name, Name)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Q (Maybe [(Name, Name)])
forall a. Typeable a => Q (Maybe a)
getQ
case Name -> [(Name, Name)] -> Maybe Name
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Name
name [(Name, Name)]
cache of
Just Name
private → Name -> Q Name
forall (m :: * -> *) a. Monad m => a -> m a
return Name
private
Maybe Name
Nothing → do
Name
temp ← String -> Q Name
newName (String
"_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Name -> String
nameBase Name
name)
Name
private ← String -> Q Name
newName (Name -> String
forall a. Show a => a -> String
show Name
temp)
[(Name, Name)] -> Q ()
forall a. Typeable a => a -> Q ()
putQ ((Name
name, Name
private)(Name, Name) -> [(Name, Name)] -> [(Name, Name)]
forall a. a -> [a] -> [a]
:[(Name, Name)]
cache)
Name -> Q Name
forall (m :: * -> *) a. Monad m => a -> m a
return Name
private
conName ∷ Type → Maybe Name
conName :: Type -> Maybe Name
conName (ConT Name
n) = Name -> Maybe Name
forall a. a -> Maybe a
Just Name
n
conName (AppT Type
x Type
_) = Type -> Maybe Name
conName Type
x
conName (AppKindT Type
x Type
_) = Type -> Maybe Name
conName Type
x
conName (SigT Type
x Type
_) = Type -> Maybe Name
conName Type
x
conName (InfixT Type
_ Name
n Type
_) = Name -> Maybe Name
forall a. a -> Maybe a
Just Name
n
conName (UInfixT Type
_ Name
n Type
_) = Name -> Maybe Name
forall a. a -> Maybe a
Just Name
n
conName (ParensT Type
x) = Type -> Maybe Name
conName Type
x
conName Type
_ = Maybe Name
forall a. Maybe a
Nothing