{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
module Generics.SOP.TH
( deriveGeneric
, deriveGenericOnly
, deriveGenericSubst
, deriveGenericOnlySubst
, deriveGenericFunctions
, deriveMetadataValue
, deriveMetadataType
) where
import Control.Monad (join, replicateM, unless)
import Data.List (foldl')
import Data.Maybe (fromMaybe)
import Data.Proxy
import Language.Haskell.TH.Datatype.TyVarBndr
import Language.Haskell.TH
import Language.Haskell.TH.Datatype as TH
import Language.Haskell.TH.Datatype.TyVarBndr
import Generics.SOP.BasicFunctors
import qualified Generics.SOP.Metadata as SOP
import qualified Generics.SOP.Type.Metadata as SOP.T
import Generics.SOP.NP
import Generics.SOP.NS
import Generics.SOP.Universe
deriveGeneric :: Name -> Q [Dec]
deriveGeneric :: Name -> Q [Dec]
deriveGeneric Name
n =
Name -> (Name -> Q Type) -> Q [Dec]
deriveGenericSubst Name
n forall (m :: * -> *). Quote m => Name -> m Type
varT
deriveGenericOnly :: Name -> Q [Dec]
deriveGenericOnly :: Name -> Q [Dec]
deriveGenericOnly Name
n =
Name -> (Name -> Q Type) -> Q [Dec]
deriveGenericOnlySubst Name
n forall (m :: * -> *). Quote m => Name -> m Type
varT
deriveGenericSubst :: Name -> (Name -> Q Type) -> Q [Dec]
deriveGenericSubst :: Name -> (Name -> Q Type) -> Q [Dec]
deriveGenericSubst Name
n Name -> Q Type
f = do
DatatypeInfo
dec <- Name -> Q DatatypeInfo
reifyDatatype Name
n
[Dec]
ds1 <- forall a.
DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q a)
-> Q a
withDataDec DatatypeInfo
dec ((Name -> Q Type)
-> DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q [Dec]
deriveGenericForDataDec Name -> Q Type
f)
[Dec]
ds2 <- forall a.
DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q a)
-> Q a
withDataDec DatatypeInfo
dec ((Name -> Q Type)
-> DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q [Dec]
deriveMetadataForDataDec Name -> Q Type
f)
forall (m :: * -> *) a. Monad m => a -> m a
return ([Dec]
ds1 forall a. [a] -> [a] -> [a]
++ [Dec]
ds2)
deriveGenericOnlySubst :: Name -> (Name -> Q Type) -> Q [Dec]
deriveGenericOnlySubst :: Name -> (Name -> Q Type) -> Q [Dec]
deriveGenericOnlySubst Name
n Name -> Q Type
f = do
DatatypeInfo
dec <- Name -> Q DatatypeInfo
reifyDatatype Name
n
forall a.
DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q a)
-> Q a
withDataDec DatatypeInfo
dec ((Name -> Q Type)
-> DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q [Dec]
deriveGenericForDataDec Name -> Q Type
f)
deriveGenericFunctions :: Name -> String -> String -> String -> Q [Dec]
deriveGenericFunctions :: Name -> String -> String -> String -> Q [Dec]
deriveGenericFunctions Name
n String
codeName String
fromName String
toName = do
let codeName' :: Name
codeName' = String -> Name
mkName String
codeName
let fromName' :: Name
fromName' = String -> Name
mkName String
fromName
let toName' :: Name
toName' = String -> Name
mkName String
toName
DatatypeInfo
dec <- Name -> Q DatatypeInfo
reifyDatatype Name
n
forall a.
DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q a)
-> Q a
withDataDec DatatypeInfo
dec forall a b. (a -> b) -> a -> b
$ \DatatypeVariant
_variant Cxt
_cxt Name
name [TyVarBndrVis]
bndrs Cxt
instTys [ConstructorInfo]
cons -> do
let codeType :: Q Type
codeType = (Name -> Q Type) -> [ConstructorInfo] -> Q Type
codeFor forall (m :: * -> *). Quote m => Name -> m Type
varT [ConstructorInfo]
cons
let origType :: Q Type
origType = (Name -> Q Type) -> Name -> Cxt -> Q Type
appTysSubst forall (m :: * -> *). Quote m => Name -> m Type
varT Name
name Cxt
instTys
let repType :: Q Type
repType = [t| SOP I $(appTyVars varT codeName' bndrs) |]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence
[ forall (m :: * -> *).
Quote m =>
Name -> [TyVarBndrVis] -> m Type -> m Dec
tySynD Name
codeName' [TyVarBndrVis]
bndrs Q Type
codeType
, forall (m :: * -> *). Quote m => Name -> m Type -> m Dec
sigD Name
fromName' [t| $origType -> $repType |]
, Name -> [ConstructorInfo] -> Q Dec
embedding Name
fromName' [ConstructorInfo]
cons
, forall (m :: * -> *). Quote m => Name -> m Type -> m Dec
sigD Name
toName' [t| $repType -> $origType |]
, Name -> [ConstructorInfo] -> Q Dec
projection Name
toName' [ConstructorInfo]
cons
]
deriveMetadataValue :: Name -> String -> String -> Q [Dec]
deriveMetadataValue :: Name -> String -> String -> Q [Dec]
deriveMetadataValue Name
n String
codeName String
datatypeInfoName = do
let codeName' :: Name
codeName' = String -> Name
mkName String
codeName
let datatypeInfoName' :: Name
datatypeInfoName' = String -> Name
mkName String
datatypeInfoName
DatatypeInfo
dec <- Name -> Q DatatypeInfo
reifyDatatype Name
n
forall a.
DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q a)
-> Q a
withDataDec DatatypeInfo
dec forall a b. (a -> b) -> a -> b
$ \DatatypeVariant
variant Cxt
_cxt Name
name [TyVarBndrVis]
bndrs Cxt
_instTys [ConstructorInfo]
cons -> do
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [ forall (m :: * -> *). Quote m => Name -> m Type -> m Dec
sigD Name
datatypeInfoName' [t| SOP.DatatypeInfo $(appTyVars varT codeName' bndrs) |]
, forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec
funD Name
datatypeInfoName' [forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [] (forall (m :: * -> *). Quote m => m Exp -> m Body
normalB forall a b. (a -> b) -> a -> b
$ DatatypeVariant -> Name -> [ConstructorInfo] -> Q Exp
metadata' DatatypeVariant
variant Name
name [ConstructorInfo]
cons) []]
]
{-# DEPRECATED deriveMetadataValue "Use 'deriveMetadataType' and 'demoteDatatypeInfo' instead." #-}
deriveMetadataType :: Name -> String -> Q [Dec]
deriveMetadataType :: Name -> String -> Q [Dec]
deriveMetadataType Name
n String
datatypeInfoName = do
let datatypeInfoName' :: Name
datatypeInfoName' = String -> Name
mkName String
datatypeInfoName
DatatypeInfo
dec <- Name -> Q DatatypeInfo
reifyDatatype Name
n
forall a.
DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q a)
-> Q a
withDataDec DatatypeInfo
dec forall a b. (a -> b) -> a -> b
$ \ DatatypeVariant
variant Cxt
_ctx Name
name [TyVarBndrVis]
_bndrs Cxt
_instTys [ConstructorInfo]
cons ->
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence
[ forall (m :: * -> *).
Quote m =>
Name -> [TyVarBndrVis] -> m Type -> m Dec
tySynD Name
datatypeInfoName' [] (DatatypeVariant -> Name -> [ConstructorInfo] -> Q Type
metadataType' DatatypeVariant
variant Name
name [ConstructorInfo]
cons) ]
deriveGenericForDataDec ::
(Name -> Q Type) -> DatatypeVariant -> Cxt -> Name -> [TyVarBndrVis] -> [Type] -> [TH.ConstructorInfo] -> Q [Dec]
deriveGenericForDataDec :: (Name -> Q Type)
-> DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q [Dec]
deriveGenericForDataDec Name -> Q Type
f DatatypeVariant
_variant Cxt
_cxt Name
name [TyVarBndrVis]
_bndrs Cxt
instTys [ConstructorInfo]
cons = do
let typ :: Q Type
typ = (Name -> Q Type) -> Name -> Cxt -> Q Type
appTysSubst Name -> Q Type
f Name
name Cxt
instTys
(Name -> Q Type) -> Q Type -> [ConstructorInfo] -> Q [Dec]
deriveGenericForDataType Name -> Q Type
f Q Type
typ [ConstructorInfo]
cons
deriveGenericForDataType :: (Name -> Q Type) -> Q Type -> [TH.ConstructorInfo] -> Q [Dec]
deriveGenericForDataType :: (Name -> Q Type) -> Q Type -> [ConstructorInfo] -> Q [Dec]
deriveGenericForDataType Name -> Q Type
f Q Type
typ [ConstructorInfo]
cons = do
let codeSyn :: Q Dec
codeSyn = Name -> Maybe [Q TyVarBndrVis] -> [Q Type] -> Q Type -> Q Dec
tySynInstDCompat ''Generics.SOP.Universe.Code forall a. Maybe a
Nothing [Q Type
typ] ((Name -> Q Type) -> [ConstructorInfo] -> Q Type
codeFor Name -> Q Type
f [ConstructorInfo]
cons)
Dec
inst <- forall (m :: * -> *).
Quote m =>
m Cxt -> m Type -> [m Dec] -> m Dec
instanceD
(forall (m :: * -> *). Quote m => [m Type] -> m Cxt
cxt [])
[t| Generic $typ |]
[Q Dec
codeSyn, Name -> [ConstructorInfo] -> Q Dec
embedding 'from [ConstructorInfo]
cons, Name -> [ConstructorInfo] -> Q Dec
projection 'to [ConstructorInfo]
cons]
forall (m :: * -> *) a. Monad m => a -> m a
return [Dec
inst]
deriveMetadataForDataDec ::
(Name -> Q Type) -> DatatypeVariant -> Cxt -> Name -> [TyVarBndrVis] -> [Type] -> [TH.ConstructorInfo] -> Q [Dec]
deriveMetadataForDataDec :: (Name -> Q Type)
-> DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q [Dec]
deriveMetadataForDataDec Name -> Q Type
f DatatypeVariant
variant Cxt
_cxt Name
name [TyVarBndrVis]
_bndrs Cxt
instTys [ConstructorInfo]
cons = do
let typ :: Q Type
typ = (Name -> Q Type) -> Name -> Cxt -> Q Type
appTysSubst Name -> Q Type
f Name
name Cxt
instTys
DatatypeVariant -> Name -> Q Type -> [ConstructorInfo] -> Q [Dec]
deriveMetadataForDataType DatatypeVariant
variant Name
name Q Type
typ [ConstructorInfo]
cons
deriveMetadataForDataType :: DatatypeVariant -> Name -> Q Type -> [TH.ConstructorInfo] -> Q [Dec]
deriveMetadataForDataType :: DatatypeVariant -> Name -> Q Type -> [ConstructorInfo] -> Q [Dec]
deriveMetadataForDataType DatatypeVariant
variant Name
name Q Type
typ [ConstructorInfo]
cons = do
Dec
md <- forall (m :: * -> *).
Quote m =>
m Cxt -> m Type -> [m Dec] -> m Dec
instanceD (forall (m :: * -> *). Quote m => [m Type] -> m Cxt
cxt [])
[t| HasDatatypeInfo $typ |]
[ Q Type -> DatatypeVariant -> Name -> [ConstructorInfo] -> Q Dec
metadataType Q Type
typ DatatypeVariant
variant Name
name [ConstructorInfo]
cons
, forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec
funD 'datatypeInfo
[ forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [forall (m :: * -> *). Quote m => m Pat
wildP]
(forall (m :: * -> *). Quote m => m Exp -> m Body
normalB [| SOP.T.demoteDatatypeInfo (Proxy :: Proxy (DatatypeInfoOf $typ)) |])
[]
]
]
forall (m :: * -> *) a. Monad m => a -> m a
return [Dec
md]
codeFor :: (Name -> Q Type) -> [TH.ConstructorInfo] -> Q Type
codeFor :: (Name -> Q Type) -> [ConstructorInfo] -> Q Type
codeFor Name -> Q Type
f = [Q Type] -> Q Type
promotedTypeList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ConstructorInfo -> Q Type
go
where
go :: TH.ConstructorInfo -> Q Type
go :: ConstructorInfo -> Q Type
go ConstructorInfo
c = do (Name
_, [Q Type]
ts) <- ConstructorInfo -> Q (Name, [Q Type])
conInfo ConstructorInfo
c
(Name -> Q Type) -> [Q Type] -> Q Type
promotedTypeListSubst Name -> Q Type
f [Q Type]
ts
embedding :: Name -> [TH.ConstructorInfo] -> Q Dec
embedding :: Name -> [ConstructorInfo] -> Q Dec
embedding Name
fromName = forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec
funD Name
fromName forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Q Exp -> Q Exp) -> [ConstructorInfo] -> [Q Clause]
go' (\Q Exp
e -> [| Z $e |])
where
go' :: (Q Exp -> Q Exp) -> [TH.ConstructorInfo] -> [Q Clause]
go' :: (Q Exp -> Q Exp) -> [ConstructorInfo] -> [Q Clause]
go' Q Exp -> Q Exp
_ [] = (forall a. a -> [a] -> [a]
:[]) forall a b. (a -> b) -> a -> b
$ do
Name
x <- forall (m :: * -> *). Quote m => String -> m Name
newName String
"x"
forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
x] (forall (m :: * -> *). Quote m => m Exp -> m Body
normalB (forall (m :: * -> *). Quote m => m Exp -> [m Match] -> m Exp
caseE (forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
x) [])) []
go' Q Exp -> Q Exp
br [ConstructorInfo]
cs = (Q Exp -> Q Exp) -> [ConstructorInfo] -> [Q Clause]
go Q Exp -> Q Exp
br [ConstructorInfo]
cs
go :: (Q Exp -> Q Exp) -> [TH.ConstructorInfo] -> [Q Clause]
go :: (Q Exp -> Q Exp) -> [ConstructorInfo] -> [Q Clause]
go Q Exp -> Q Exp
_ [] = []
go Q Exp -> Q Exp
br (ConstructorInfo
c:[ConstructorInfo]
cs) = (Q Exp -> Q Exp) -> ConstructorInfo -> Q Clause
mkClause Q Exp -> Q Exp
br ConstructorInfo
c forall a. a -> [a] -> [a]
: (Q Exp -> Q Exp) -> [ConstructorInfo] -> [Q Clause]
go (\Q Exp
e -> [| S $(br e) |]) [ConstructorInfo]
cs
mkClause :: (Q Exp -> Q Exp) -> TH.ConstructorInfo -> Q Clause
mkClause :: (Q Exp -> Q Exp) -> ConstructorInfo -> Q Clause
mkClause Q Exp -> Q Exp
br ConstructorInfo
c = do
(Name
n, [Q Type]
ts) <- ConstructorInfo -> Q (Name, [Q Type])
conInfo ConstructorInfo
c
[Name]
vars <- forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Q Type]
ts) (forall (m :: * -> *). Quote m => String -> m Name
newName String
"x")
forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP Name
n (forall a b. (a -> b) -> [a] -> [b]
map forall (m :: * -> *). Quote m => Name -> m Pat
varP [Name]
vars)]
(forall (m :: * -> *). Quote m => m Exp -> m Body
normalB [| SOP $(br . npE . map (appE (conE 'I) . varE) $ vars) |])
[]
projection :: Name -> [TH.ConstructorInfo] -> Q Dec
projection :: Name -> [ConstructorInfo] -> Q Dec
projection Name
toName = forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec
funD Name
toName forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ConstructorInfo] -> [Q Clause]
go'
where
go' :: [TH.ConstructorInfo] -> [Q Clause]
go' :: [ConstructorInfo] -> [Q Clause]
go' [] = (forall a. a -> [a] -> [a]
:[]) forall a b. (a -> b) -> a -> b
$ do
Name
x <- forall (m :: * -> *). Quote m => String -> m Name
newName String
"x"
forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
x] (forall (m :: * -> *). Quote m => m Exp -> m Body
normalB (forall (m :: * -> *). Quote m => m Exp -> [m Match] -> m Exp
caseE (forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
x) [])) []
go' [ConstructorInfo]
cs = (Q Pat -> Q Pat) -> [ConstructorInfo] -> [Q Clause]
go forall a. a -> a
id [ConstructorInfo]
cs
go :: (Q Pat -> Q Pat) -> [TH.ConstructorInfo] -> [Q Clause]
go :: (Q Pat -> Q Pat) -> [ConstructorInfo] -> [Q Clause]
go Q Pat -> Q Pat
br [] = [(Q Pat -> Q Pat) -> Q Clause
mkUnreachableClause Q Pat -> Q Pat
br]
go Q Pat -> Q Pat
br (ConstructorInfo
c:[ConstructorInfo]
cs) = (Q Pat -> Q Pat) -> ConstructorInfo -> Q Clause
mkClause Q Pat -> Q Pat
br ConstructorInfo
c forall a. a -> [a] -> [a]
: (Q Pat -> Q Pat) -> [ConstructorInfo] -> [Q Clause]
go (\Q Pat
p -> forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP 'S [Q Pat -> Q Pat
br Q Pat
p]) [ConstructorInfo]
cs
mkUnreachableClause :: (Q Pat -> Q Pat) -> Q Clause
mkUnreachableClause :: (Q Pat -> Q Pat) -> Q Clause
mkUnreachableClause Q Pat -> Q Pat
br = do
Name
var <- forall (m :: * -> *). Quote m => String -> m Name
newName String
"x"
forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP 'SOP [Q Pat -> Q Pat
br (forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
var)]]
(forall (m :: * -> *). Quote m => m Exp -> m Body
normalB [| $(varE var) `seq` error "inaccessible" |])
[]
mkClause :: (Q Pat -> Q Pat) -> TH.ConstructorInfo -> Q Clause
mkClause :: (Q Pat -> Q Pat) -> ConstructorInfo -> Q Clause
mkClause Q Pat -> Q Pat
br ConstructorInfo
c = do
(Name
n, [Q Type]
ts) <- ConstructorInfo -> Q (Name, [Q Type])
conInfo ConstructorInfo
c
[Name]
vars <- forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Q Type]
ts) (forall (m :: * -> *). Quote m => String -> m Name
newName String
"x")
forall (m :: * -> *).
Quote m =>
[m Pat] -> m Body -> [m Dec] -> m Clause
clause [forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP 'SOP [Q Pat -> Q Pat
br forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP 'Z forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. a -> [a] -> [a]
:[]) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Q Pat] -> Q Pat
npP forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (\Name
v -> forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP 'I [forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
v]) forall a b. (a -> b) -> a -> b
$ [Name]
vars]]
(forall (m :: * -> *). Quote m => m Exp -> m Body
normalB forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *). Quote m => [m Exp] -> m Exp
appsE forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). Quote m => Name -> m Exp
conE Name
n forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map forall (m :: * -> *). Quote m => Name -> m Exp
varE [Name]
vars)
[]
metadataType :: Q Type -> DatatypeVariant -> Name -> [TH.ConstructorInfo] -> Q Dec
metadataType :: Q Type -> DatatypeVariant -> Name -> [ConstructorInfo] -> Q Dec
metadataType Q Type
typ DatatypeVariant
variant Name
typeName [ConstructorInfo]
cs =
Name -> Maybe [Q TyVarBndrVis] -> [Q Type] -> Q Type -> Q Dec
tySynInstDCompat ''DatatypeInfoOf forall a. Maybe a
Nothing [Q Type
typ] (DatatypeVariant -> Name -> [ConstructorInfo] -> Q Type
metadataType' DatatypeVariant
variant Name
typeName [ConstructorInfo]
cs)
metadata' :: DatatypeVariant -> Name -> [TH.ConstructorInfo] -> Q Exp
metadata' :: DatatypeVariant -> Name -> [ConstructorInfo] -> Q Exp
metadata' DatatypeVariant
dataVariant Name
typeName [ConstructorInfo]
cs = Q Exp
md
where
md :: Q Exp
md :: Q Exp
md | DatatypeVariant -> Bool
isNewtypeVariant DatatypeVariant
dataVariant
= [| SOP.Newtype $(stringE (nameModule' typeName))
$(stringE (nameBase typeName))
$(mdCon (head cs))
|]
| Bool
otherwise
= [| SOP.ADT $(stringE (nameModule' typeName))
$(stringE (nameBase typeName))
$(npE $ map mdCon cs)
$(popE $ map mdStrictness cs)
|]
mdStrictness :: TH.ConstructorInfo -> Q [Q Exp]
mdStrictness :: ConstructorInfo -> Q [Q Exp]
mdStrictness ci :: ConstructorInfo
ci@(ConstructorInfo { constructorName :: ConstructorInfo -> Name
constructorName = Name
n
, constructorStrictness :: ConstructorInfo -> [FieldStrictness]
constructorStrictness = [FieldStrictness]
bs }) =
forall a. ConstructorInfo -> Q a -> Q a
checkForGADTs ConstructorInfo
ci forall a b. (a -> b) -> a -> b
$ Name -> [FieldStrictness] -> Q [Q Exp]
mdConStrictness Name
n [FieldStrictness]
bs
mdConStrictness :: Name -> [FieldStrictness] -> Q [Q Exp]
mdConStrictness :: Name -> [FieldStrictness] -> Q [Q Exp]
mdConStrictness Name
n [FieldStrictness]
bs = do
[DecidedStrictness]
dss <- Name -> Q [DecidedStrictness]
reifyConStrictness Name
n
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\ (FieldStrictness Unpackedness
su Strictness
ss) DecidedStrictness
ds ->
[| SOP.StrictnessInfo
$(mdTHUnpackedness su)
$(mdTHStrictness ss)
$(mdDecidedStrictness ds)
|]) [FieldStrictness]
bs [DecidedStrictness]
dss)
mdCon :: TH.ConstructorInfo -> Q Exp
mdCon :: ConstructorInfo -> Q Exp
mdCon ci :: ConstructorInfo
ci@(ConstructorInfo { constructorName :: ConstructorInfo -> Name
constructorName = Name
n
, constructorVariant :: ConstructorInfo -> ConstructorVariant
constructorVariant = ConstructorVariant
conVariant }) =
forall a. ConstructorInfo -> Q a -> Q a
checkForGADTs ConstructorInfo
ci forall a b. (a -> b) -> a -> b
$
case ConstructorVariant
conVariant of
ConstructorVariant
NormalConstructor -> [| SOP.Constructor $(stringE (nameBase n)) |]
RecordConstructor [Name]
ts -> [| SOP.Record $(stringE (nameBase n))
$(npE (map mdField ts))
|]
ConstructorVariant
InfixConstructor -> do
Maybe Fixity
fixity <- Name -> Q (Maybe Fixity)
reifyFixity Name
n
case forall a. a -> Maybe a -> a
fromMaybe Fixity
defaultFixity Maybe Fixity
fixity of
Fixity Int
f FixityDirection
a -> [| SOP.Infix $(stringE (nameBase n))
$(mdAssociativity a)
f
|]
mdField :: Name -> Q Exp
mdField :: Name -> Q Exp
mdField Name
n = [| SOP.FieldInfo $(stringE (nameBase n)) |]
mdTHUnpackedness :: TH.Unpackedness -> Q Exp
mdTHUnpackedness :: Unpackedness -> Q Exp
mdTHUnpackedness Unpackedness
UnspecifiedUnpackedness = [| SOP.NoSourceUnpackedness |]
mdTHUnpackedness Unpackedness
NoUnpack = [| SOP.SourceNoUnpack |]
mdTHUnpackedness Unpackedness
Unpack = [| SOP.SourceUnpack |]
mdTHStrictness :: TH.Strictness -> Q Exp
mdTHStrictness :: Strictness -> Q Exp
mdTHStrictness Strictness
UnspecifiedStrictness = [| SOP.NoSourceStrictness |]
mdTHStrictness Strictness
Lazy = [| SOP.SourceLazy |]
mdTHStrictness Strictness
TH.Strict = [| SOP.SourceStrict |]
mdDecidedStrictness :: DecidedStrictness -> Q Exp
mdDecidedStrictness :: DecidedStrictness -> Q Exp
mdDecidedStrictness DecidedStrictness
DecidedLazy = [| SOP.DecidedLazy |]
mdDecidedStrictness DecidedStrictness
DecidedStrict = [| SOP.DecidedStrict |]
mdDecidedStrictness DecidedStrictness
DecidedUnpack = [| SOP.DecidedUnpack |]
mdAssociativity :: FixityDirection -> Q Exp
mdAssociativity :: FixityDirection -> Q Exp
mdAssociativity FixityDirection
InfixL = [| SOP.LeftAssociative |]
mdAssociativity FixityDirection
InfixR = [| SOP.RightAssociative |]
mdAssociativity FixityDirection
InfixN = [| SOP.NotAssociative |]
metadataType' :: DatatypeVariant -> Name -> [TH.ConstructorInfo] -> Q Type
metadataType' :: DatatypeVariant -> Name -> [ConstructorInfo] -> Q Type
metadataType' DatatypeVariant
dataVariant Name
typeName [ConstructorInfo]
cs = Q Type
md
where
md :: Q Type
md :: Q Type
md | DatatypeVariant -> Bool
isNewtypeVariant DatatypeVariant
dataVariant
= [t| 'SOP.T.Newtype $(stringT (nameModule' typeName))
$(stringT (nameBase typeName))
$(mdCon (head cs))
|]
| Bool
otherwise
= [t| 'SOP.T.ADT $(stringT (nameModule' typeName))
$(stringT (nameBase typeName))
$(promotedTypeList $ map mdCon cs)
$(promotedTypeListOfList $ map mdStrictness cs)
|]
mdStrictness :: TH.ConstructorInfo -> Q [Q Type]
mdStrictness :: ConstructorInfo -> Q [Q Type]
mdStrictness ci :: ConstructorInfo
ci@(ConstructorInfo { constructorName :: ConstructorInfo -> Name
constructorName = Name
n
, constructorStrictness :: ConstructorInfo -> [FieldStrictness]
constructorStrictness = [FieldStrictness]
bs }) =
forall a. ConstructorInfo -> Q a -> Q a
checkForGADTs ConstructorInfo
ci forall a b. (a -> b) -> a -> b
$ Name -> [FieldStrictness] -> Q [Q Type]
mdConStrictness Name
n [FieldStrictness]
bs
mdConStrictness :: Name -> [FieldStrictness] -> Q [Q Type]
mdConStrictness :: Name -> [FieldStrictness] -> Q [Q Type]
mdConStrictness Name
n [FieldStrictness]
bs = do
[DecidedStrictness]
dss <- Name -> Q [DecidedStrictness]
reifyConStrictness Name
n
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\ (FieldStrictness Unpackedness
su Strictness
ss) DecidedStrictness
ds ->
[t| 'SOP.T.StrictnessInfo
$(mdTHUnpackedness su)
$(mdTHStrictness ss)
$(mdDecidedStrictness ds)
|]) [FieldStrictness]
bs [DecidedStrictness]
dss)
mdCon :: TH.ConstructorInfo -> Q Type
mdCon :: ConstructorInfo -> Q Type
mdCon ci :: ConstructorInfo
ci@(ConstructorInfo { constructorName :: ConstructorInfo -> Name
constructorName = Name
n
, constructorVariant :: ConstructorInfo -> ConstructorVariant
constructorVariant = ConstructorVariant
conVariant }) =
forall a. ConstructorInfo -> Q a -> Q a
checkForGADTs ConstructorInfo
ci forall a b. (a -> b) -> a -> b
$
case ConstructorVariant
conVariant of
ConstructorVariant
NormalConstructor -> [t| 'SOP.T.Constructor $(stringT (nameBase n)) |]
RecordConstructor [Name]
ts -> [t| 'SOP.T.Record $(stringT (nameBase n))
$(promotedTypeList (map mdField ts))
|]
ConstructorVariant
InfixConstructor -> do
Maybe Fixity
fixity <- Name -> Q (Maybe Fixity)
reifyFixity Name
n
case forall a. a -> Maybe a -> a
fromMaybe Fixity
defaultFixity Maybe Fixity
fixity of
Fixity Int
f FixityDirection
a -> [t| 'SOP.T.Infix $(stringT (nameBase n))
$(mdAssociativity a)
$(natT f)
|]
mdField :: Name -> Q Type
mdField :: Name -> Q Type
mdField Name
n = [t| 'SOP.T.FieldInfo $(stringT (nameBase n)) |]
mdTHUnpackedness :: TH.Unpackedness -> Q Type
mdTHUnpackedness :: Unpackedness -> Q Type
mdTHUnpackedness Unpackedness
UnspecifiedUnpackedness = [t| 'SOP.NoSourceUnpackedness |]
mdTHUnpackedness Unpackedness
NoUnpack = [t| 'SOP.SourceNoUnpack |]
mdTHUnpackedness Unpackedness
Unpack = [t| 'SOP.SourceUnpack |]
mdTHStrictness :: TH.Strictness -> Q Type
mdTHStrictness :: Strictness -> Q Type
mdTHStrictness Strictness
UnspecifiedStrictness = [t| 'SOP.NoSourceStrictness |]
mdTHStrictness Strictness
Lazy = [t| 'SOP.SourceLazy |]
mdTHStrictness Strictness
TH.Strict = [t| 'SOP.SourceStrict |]
mdDecidedStrictness :: DecidedStrictness -> Q Type
mdDecidedStrictness :: DecidedStrictness -> Q Type
mdDecidedStrictness DecidedStrictness
DecidedLazy = [t| 'SOP.DecidedLazy |]
mdDecidedStrictness DecidedStrictness
DecidedStrict = [t| 'SOP.DecidedStrict |]
mdDecidedStrictness DecidedStrictness
DecidedUnpack = [t| 'SOP.DecidedUnpack |]
mdAssociativity :: FixityDirection -> Q Type
mdAssociativity :: FixityDirection -> Q Type
mdAssociativity FixityDirection
InfixL = [t| 'SOP.T.LeftAssociative |]
mdAssociativity FixityDirection
InfixR = [t| 'SOP.T.RightAssociative |]
mdAssociativity FixityDirection
InfixN = [t| 'SOP.T.NotAssociative |]
nameModule' :: Name -> String
nameModule' :: Name -> String
nameModule' = forall a. a -> Maybe a -> a
fromMaybe String
"" forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Maybe String
nameModule
npE :: [Q Exp] -> Q Exp
npE :: [Q Exp] -> Q Exp
npE [] = [| Nil |]
npE (Q Exp
e:[Q Exp]
es) = [| $e :* $(npE es) |]
popE :: [Q [Q Exp]] -> Q Exp
popE :: [Q [Q Exp]] -> Q Exp
popE [Q [Q Exp]]
ess =
[| POP $(npE (map (join . fmap npE) ess)) |]
npP :: [Q Pat] -> Q Pat
npP :: [Q Pat] -> Q Pat
npP [] = forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP 'Nil []
npP (Q Pat
p:[Q Pat]
ps) = forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP '(:*) [Q Pat
p, [Q Pat] -> Q Pat
npP [Q Pat]
ps]
conInfo :: TH.ConstructorInfo -> Q (Name, [Q Type])
conInfo :: ConstructorInfo -> Q (Name, [Q Type])
conInfo ci :: ConstructorInfo
ci@(ConstructorInfo { constructorName :: ConstructorInfo -> Name
constructorName = Name
n
, constructorFields :: ConstructorInfo -> Cxt
constructorFields = Cxt
ts }) =
forall a. ConstructorInfo -> Q a -> Q a
checkForGADTs ConstructorInfo
ci forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return (Name
n, forall a b. (a -> b) -> [a] -> [b]
map forall (m :: * -> *) a. Monad m => a -> m a
return Cxt
ts)
stringT :: String -> Q Type
stringT :: String -> Q Type
stringT = forall (m :: * -> *). Quote m => m TyLit -> m Type
litT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *). Quote m => String -> m TyLit
strTyLit
natT :: Int -> Q Type
natT :: Int -> Q Type
natT = forall (m :: * -> *). Quote m => m TyLit -> m Type
litT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *). Quote m => Integer -> m TyLit
numTyLit forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral
promotedTypeList :: [Q Type] -> Q Type
promotedTypeList :: [Q Type] -> Q Type
promotedTypeList [] = forall (m :: * -> *). Quote m => m Type
promotedNilT
promotedTypeList (Q Type
t:[Q Type]
ts) = [t| $promotedConsT $t $(promotedTypeList ts) |]
promotedTypeListOfList :: [Q [Q Type]] -> Q Type
promotedTypeListOfList :: [Q [Q Type]] -> Q Type
promotedTypeListOfList =
[Q Type] -> Q Type
promotedTypeList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Q Type] -> Q Type
promotedTypeList)
promotedTypeListSubst :: (Name -> Q Type) -> [Q Type] -> Q Type
promotedTypeListSubst :: (Name -> Q Type) -> [Q Type] -> Q Type
promotedTypeListSubst Name -> Q Type
_ [] = forall (m :: * -> *). Quote m => m Type
promotedNilT
promotedTypeListSubst Name -> Q Type
f (Q Type
t:[Q Type]
ts) = [t| $promotedConsT $(t >>= substType f) $(promotedTypeListSubst f ts) |]
appsT :: Name -> [Q Type] -> Q Type
appsT :: Name -> [Q Type] -> Q Type
appsT Name
n = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall (m :: * -> *). Quote m => m Type -> m Type -> m Type
appT (forall (m :: * -> *). Quote m => Name -> m Type
conT Name
n)
appTyVars :: (Name -> Q Type) -> Name -> [TyVarBndrVis] -> Q Type
appTyVars :: (Name -> Q Type) -> Name -> [TyVarBndrVis] -> Q Type
appTyVars Name -> Q Type
f Name
n [TyVarBndrVis]
bndrs =
Name -> [Q Type] -> Q Type
appsT Name
n (forall a b. (a -> b) -> [a] -> [b]
map (Name -> Q Type
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall flag. TyVarBndr_ flag -> Name
tvName) [TyVarBndrVis]
bndrs)
appTysSubst :: (Name -> Q Type) -> Name -> [Type] -> Q Type
appTysSubst :: (Name -> Q Type) -> Name -> Cxt -> Q Type
appTysSubst Name -> Q Type
f Name
n Cxt
args =
Name -> [Q Type] -> Q Type
appsT Name
n (forall a b. (a -> b) -> [a] -> [b]
map ((Name -> Q Type) -> Type -> Q Type
substType Name -> Q Type
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. Type -> Type
unSigType) Cxt
args)
unSigType :: Type -> Type
unSigType :: Type -> Type
unSigType (SigT Type
t Type
_) = Type
t
unSigType Type
t = Type
t
substType :: (Name -> Q Type) -> Type -> Q Type
substType :: (Name -> Q Type) -> Type -> Q Type
substType Name -> Q Type
f = Type -> Q Type
go
where
go :: Type -> Q Type
go (VarT Name
n) = Name -> Q Type
f Name
n
go (AppT Type
t1 Type
t2) = Type -> Type -> Type
AppT forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Type -> Q Type
go Type
t1 forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Type -> Q Type
go Type
t2
go Type
ListT = forall (m :: * -> *) a. Monad m => a -> m a
return Type
ListT
go (ConT Name
n) = forall (m :: * -> *) a. Monad m => a -> m a
return (Name -> Type
ConT Name
n)
go Type
ArrowT = forall (m :: * -> *) a. Monad m => a -> m a
return Type
ArrowT
go (TupleT Int
i) = forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Type
TupleT Int
i)
go Type
t = forall (m :: * -> *) a. Monad m => a -> m a
return Type
t
withDataDec :: TH.DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> [Type]
-> [TH.ConstructorInfo]
-> Q a)
-> Q a
withDataDec :: forall a.
DatatypeInfo
-> (DatatypeVariant
-> Cxt
-> Name
-> [TyVarBndrVis]
-> Cxt
-> [ConstructorInfo]
-> Q a)
-> Q a
withDataDec (TH.DatatypeInfo { datatypeContext :: DatatypeInfo -> Cxt
datatypeContext = Cxt
ctxt
, datatypeName :: DatatypeInfo -> Name
datatypeName = Name
name
, datatypeVars :: DatatypeInfo -> [TyVarBndrVis]
datatypeVars = [TyVarBndrVis]
bndrs
, datatypeInstTypes :: DatatypeInfo -> Cxt
datatypeInstTypes = Cxt
instTypes
, datatypeVariant :: DatatypeInfo -> DatatypeVariant
datatypeVariant = DatatypeVariant
variant
, datatypeCons :: DatatypeInfo -> [ConstructorInfo]
datatypeCons = [ConstructorInfo]
cons }) DatatypeVariant
-> Cxt -> Name -> [TyVarBndrVis] -> Cxt -> [ConstructorInfo] -> Q a
f =
forall a. DatatypeVariant -> Q a -> Q a
checkForTypeData DatatypeVariant
variant forall a b. (a -> b) -> a -> b
$
DatatypeVariant
-> Cxt -> Name -> [TyVarBndrVis] -> Cxt -> [ConstructorInfo] -> Q a
f DatatypeVariant
variant Cxt
ctxt Name
name (forall newFlag oldFlag.
newFlag -> [TyVarBndr_ oldFlag] -> [TyVarBndr_ newFlag]
changeTVFlags BndrVis
bndrReq [TyVarBndrVis]
bndrs) Cxt
instTypes [ConstructorInfo]
cons
checkForTypeData :: DatatypeVariant -> Q a -> Q a
checkForTypeData :: forall a. DatatypeVariant -> Q a -> Q a
checkForTypeData DatatypeVariant
variant Q a
q = do
case DatatypeVariant
variant of
#if MIN_VERSION_th_abstraction(0,5,0)
DatatypeVariant
TH.TypeData -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"`type data` declarations not supported"
#endif
DatatypeVariant
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
Q a
q
checkForGADTs :: TH.ConstructorInfo -> Q a -> Q a
checkForGADTs :: forall a. ConstructorInfo -> Q a -> Q a
checkForGADTs (ConstructorInfo { constructorVars :: ConstructorInfo -> [TyVarBndrVis]
constructorVars = [TyVarBndrVis]
exVars
, constructorContext :: ConstructorInfo -> Cxt
constructorContext = Cxt
exCxt }) Q a
q = do
forall (f :: * -> *).
Applicative f =>
Bool -> f BndrVis -> f BndrVis
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [TyVarBndrVis]
exVars) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Existentials not supported"
forall (f :: * -> *).
Applicative f =>
Bool -> f BndrVis -> f BndrVis
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null Cxt
exCxt) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"GADTs not supported"
Q a
q
isNewtypeVariant :: DatatypeVariant -> Bool
isNewtypeVariant :: DatatypeVariant -> Bool
isNewtypeVariant DatatypeVariant
Datatype = Bool
False
isNewtypeVariant DatatypeVariant
DataInstance = Bool
False
isNewtypeVariant DatatypeVariant
Newtype = Bool
True
isNewtypeVariant DatatypeVariant
NewtypeInstance = Bool
True
#if MIN_VERSION_th_abstraction(0,5,0)
isNewtypeVariant DatatypeVariant
TH.TypeData = Bool
False
#endif