{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -cpp #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}
{-# OPTIONS_GHC -Wno-unused-pattern-binds #-}
module Generics.MRSOP.TH
( deriveFamilyWith
, deriveFamilyWithTy
, deriveFamily
, genFamilyDebug
) where
import Data.Function (on)
import Data.Char (isAlphaNum)
import Data.List (sortBy)
import qualified Data.SOP.NS as SOP (NS(..))
import Control.Monad
import Control.Monad.State
import Control.Monad.Writer (WriterT, tell, runWriterT)
import Control.Monad.Identity (runIdentity)
import Language.Haskell.TH hiding (match)
import Language.Haskell.TH.Syntax (liftString)
import Generics.MRSOP.Util
import Generics.MRSOP.Base.Class
import Generics.MRSOP.Base.NP
import Generics.MRSOP.Base.Universe hiding (match)
import qualified Generics.MRSOP.Base.Metadata as Meta
import qualified Data.Map as M
data OpaqueData = OpaqueData
{ opaqueName :: Name
, opaqueTable :: M.Map Name Name
, opaqueCons :: M.Map Name Name
} deriving (Eq , Show)
deriveFamilyWith :: Name -> Q Type -> Q [Dec]
deriveFamilyWith opqName t
= do sty <- t >>= convertType
opqData <- reifyOpaqueType opqName
(_ , (Idxs _ m _)) <- runIdxsM (reifySTy opqData sty)
m' <- mapM extractDTI (M.toList m)
let final = sortBy (compare `on` second) m'
res <- genFamily opqData sty final
return res
where
second (_ , x , _) = x
extractDTI (sty , (_ix , Nothing))
= fail $ "Type " ++ show sty ++ " has no datatype information."
extractDTI (sty , (ix , Just dti))
= return (sty , ix , dti)
deriveFamilyWithTy :: Q Type -> Q Type -> Q [Dec]
deriveFamilyWithTy opq ty
= do opqTy <- opq
case opqTy of
ConT opqName -> deriveFamilyWith opqName ty
_ -> fail $ "Type " ++ show opqTy ++ " must be a name!"
deriveFamily :: Q Type -> Q [Dec]
deriveFamily = deriveFamilyWith (mkName "Singl")
type DataName = Name
type ConName = Name
type FieldName = Name
type Args = [Name]
data DTI ty
= ADT DataName Args [ CI ty ]
| New DataName Args (CI ty)
deriving (Eq , Show , Functor)
data CI ty
= Normal ConName [ty]
| Infix ConName Fixity ty ty
| Record ConName [ (FieldName , ty) ]
deriving (Eq , Show , Functor)
ciMapM :: (Monad m) => (ty -> m tw) -> CI ty -> m (CI tw)
ciMapM f (Normal name tys) = Normal name <$> mapM f tys
ciMapM f (Infix name x l r) = Infix name x <$> f l <*> f r
ciMapM f (Record name tys) = Record name <$> mapM (rstr . (id *** f)) tys
where
rstr (a , b) = b >>= return . (a,)
dtiMapM :: (Monad m) => (ty -> m tw) -> DTI ty -> m (DTI tw)
dtiMapM f (ADT name args ci) = ADT name args <$> mapM (ciMapM f) ci
dtiMapM f (New name args ci) = New name args <$> ciMapM f ci
dti2ci :: DTI ty -> [CI ty]
dti2ci (ADT _ _ cis) = cis
dti2ci (New _ _ ci) = [ ci ]
ci2ty :: CI ty -> [ty]
ci2ty (Normal _ tys) = tys
ci2ty (Infix _ _ a b) = [a , b]
ci2ty (Record _ tys) = map snd tys
ciName :: CI ty -> Name
ciName (Normal n _) = n
ciName (Infix n _ _ _) = n
ciName (Record n _) = n
ci2Pat :: CI ty -> Q ([Name] , Pat)
ci2Pat ci
= do ns <- mapM (const (newName "x")) (ci2ty ci)
return (ns , (ConP (ciName ci) (map VarP ns)))
ci2Exp :: CI ty -> Q ([Name], Exp)
ci2Exp ci
= do ns <- mapM (const (newName "y")) (ci2ty ci)
return (ns , foldl (\e n -> AppE e (VarE n)) (ConE (ciName ci)) ns)
data STy
= AppST STy STy
| VarST Name
| ConST Name
deriving (Eq , Show, Ord)
styFold :: (a -> a -> a) -> (Name -> a) -> (Name -> a) -> STy -> a
styFold app var con (AppST a b) = app (styFold app var con a) (styFold app var con b)
styFold _ var _ (VarST n) = var n
styFold _ _ con (ConST n) = con n
isClosed :: STy -> Bool
isClosed = styFold (&&) (const False) (const True)
convertType :: (Monad m) => Type -> m STy
convertType (AppT a b) = AppST <$> convertType a <*> convertType b
convertType (SigT t _) = convertType t
convertType (VarT n) = return (VarST n)
convertType (ConT n) = return (ConST n)
convertType (ParensT t) = convertType t
convertType ListT = return (ConST (mkName "[]"))
convertType (TupleT n) = return (ConST (mkName $ '(':replicate (n-1) ',' ++ ")"))
convertType t = fail ("convertType: Unsupported Type: " ++ show t)
trevnocType :: STy -> Type
trevnocType (AppST a b) = AppT (trevnocType a) (trevnocType b)
trevnocType (VarST n) = VarT n
trevnocType (ConST n)
| n == mkName "[]" = ListT
| isTupleN n = TupleT $ length (show n) - 1
| otherwise = ConT n
where isTupleN n0 = take 2 (show n0) == "(,"
stySubst :: STy -> Name -> STy -> STy
stySubst (AppST a b) m n = AppST (stySubst a m n) (stySubst b m n)
stySubst (ConST a) _ _ = ConST a
stySubst (VarST x) m n
| x == m = n
| otherwise = VarST x
styReduce :: [(Name , STy)] -> STy -> STy
styReduce parms t = foldr (\(n , m) ty -> stySubst ty n m) t parms
styFlatten :: STy -> (STy , [STy])
styFlatten (AppST a b) = id *** (++ [b]) $ styFlatten a
styFlatten sty = (sty , [])
reifyDec :: Name -> Q Dec
reifyDec name =
do info <- reify name
case info of TyConI dec -> return dec
_ -> fail $ show name ++ " is not a declaration"
argInfo :: TyVarBndr -> Name
argInfo (PlainTV n) = n
argInfo (KindedTV n _) = n
decInfo :: Dec -> Q (DTI STy)
decInfo (TySynD _name _args _ty) = fail "Type Synonyms not supported"
decInfo (DataD _ name args _ cons _) = ADT name (map argInfo args) <$> mapM conInfo cons
decInfo (NewtypeD _ name args _ con _) = New name (map argInfo args) <$> conInfo con
decInfo _ = fail "Only type declarations are supported"
conInfo :: Con -> Q (CI STy)
conInfo (NormalC name ty) = Normal name <$> mapM (convertType . snd) ty
conInfo (RecC name ty) = Record name <$> mapM (\(s , _ , t) -> (s,) <$> convertType t) ty
conInfo (InfixC l name r)
= do info <- reifyFixity name
let fixity = maybe defaultFixity id $ info
Infix name fixity <$> convertType (snd l) <*> convertType (snd r)
conInfo (ForallC _ _ _) = fail "Existentials not supported"
#if MIN_VERSION_template_haskell(2,11,0)
conInfo (GadtC _ _ _) = fail "GADTs not supported"
conInfo (RecGadtC _ _ _) = fail "GADTs not supported"
#endif
dtiReduce :: DTI STy -> [STy] -> DTI STy
dtiReduce (ADT name args cons) parms
= ADT name [] (map (ciReduce (zip args parms)) cons)
dtiReduce (New name args con) parms
= New name [] (ciReduce (zip args parms) con)
ciReduce :: [(Name , STy)] -> CI STy -> CI STy
ciReduce parms ci = runIdentity (ciMapM (return . styReduce parms) ci)
data IK
= AtomI Int
| AtomK Name
deriving (Eq , Show)
data Idxs
= Idxs { idxsNext :: Int
, idxsMap :: M.Map STy (Int , Maybe (DTI IK))
, idxsSyns :: M.Map STy STy
}
deriving (Show)
onMap :: (M.Map STy (Int , Maybe (DTI IK)) -> M.Map STy (Int , Maybe (DTI IK)))
-> Idxs -> Idxs
onMap f (Idxs n m eqs) = Idxs n (f m) eqs
type IdxsM = StateT Idxs
runIdxsM :: (Monad m) => IdxsM m a -> m (a , Idxs)
runIdxsM = flip runStateT (Idxs 0 M.empty M.empty)
type M = IdxsM Q
indexOf :: (Monad m) => STy -> IdxsM m Int
indexOf name
= do st <- get
case M.lookup name (idxsSyns st) of
Just orig -> indexOf orig
Nothing ->
case M.lookup name (idxsMap st) of
Just i -> return (fst i)
Nothing -> let i = idxsNext st
in put (Idxs (i + 1)
(M.insert name (i , Nothing) (idxsMap st))
(idxsSyns st))
>> return i
register :: (Monad m) => STy -> DTI IK -> IdxsM m ()
register ty info = indexOf ty
>> modify (onMap $ M.adjust (id *** const (Just info)) ty)
lkup :: (Monad m) => STy -> IdxsM m (Maybe (Int , Maybe (DTI IK)))
lkup ty = M.lookup ty . idxsMap <$> get
addTySynEquiv :: (Monad m) => STy -> STy -> IdxsM m ()
addTySynEquiv orig new =
modify (\st -> st { idxsSyns = M.insert new orig (idxsSyns st) })
lkupData :: (Monad m) => STy -> IdxsM m (Maybe (DTI IK))
lkupData ty = join . fmap snd <$> lkup ty
hasData :: (Monad m) => STy -> IdxsM m Bool
hasData ty = maybe False (const True) <$> lkupData ty
reifyOpaqueType :: Name -> Q OpaqueData
reifyOpaqueType opq
= do triples <- (extract <.> reifyDec) opq
let (hsTyMap , consMap) = genMaps triples
return $ OpaqueData opq hsTyMap consMap
where
genMaps :: [(Name , Name , Name)] -> (M.Map Name Name , M.Map Name Name)
genMaps xys = (M.fromList (map (\(x , y , _) -> (x , y)) xys)
,M.fromList (map (\(_ , x , y) -> (x , y)) xys))
extract :: Dec -> Q [(Name , Name , Name)]
extract (DataD _ _ _ _ cs _) = mapM extractCon cs
extract _
= failMsg
extractCon :: Con -> Q (Name , Name , Name)
extractCon (GadtC [opqC] [(_ , ConT hsTy)] (AppT _ (PromotedT ty)))
= return (hsTy , ty , opqC)
extractCon _
= failMsg
failMsg = fail $ "The opaque-type universe you provided is of the wrong form;"
++ "Check documentation for Generics.MRSOP.TH.reifyOpaqueType"
reifySTy :: OpaqueData -> STy -> M ()
reifySTy opq sty0
= do _ <- indexOf sty0
(dec , args) <- preprocess sty0
go dec args
where
preprocess :: STy -> M (DTI STy , [STy])
preprocess ty =
let (head , args) = styFlatten ty
in case head of
ConST name -> do
dec <- lift (reifyDec name)
resolveTySyn (addTySynEquiv ty) dec args
_ -> fail "I can't convert appST or varST in reifySTy"
resolveTySyn :: (STy -> M ()) -> Dec -> [STy] -> M (DTI STy , [STy])
resolveTySyn upd8 (TySynD _ defargs def) localargs = do
sdef <- convertType def
let dict = zip (map argInfo defargs) localargs
let res = styReduce dict sdef
upd8 res
preprocess res
resolveTySyn _ def localargs = (,localargs) <$> lift (decInfo def)
go :: DTI STy -> [STy] -> M ()
go dec args
= do
let res = dtiReduce dec args
(final , todo) <- runWriterT $ dtiMapM (convertSTy (opaqueTable opq)) res
register sty0 final
mapM_ (reifySTy opq) todo
convertSTy :: M.Map Name Name -> STy -> WriterT [STy] M IK
convertSTy opqTable ty
| ty == sty0 = AtomI <$> lift (indexOf ty)
| isClosed ty
= case makeCons opqTable ty of
Just k -> return (AtomK k)
Nothing -> do ix <- lift (indexOf ty)
hasDti <- lift (hasData ty)
when (not hasDti) (tell [ty])
return (AtomI ix)
| otherwise
= fail $ "I can't convert type variable " ++ show ty
++ " when converting " ++ show sty0
makeCons :: M.Map Name Name -> STy -> Maybe Name
makeCons opqTable (ConST n) = M.lookup n opqTable
makeCons _ _ = Nothing
type Input = [(STy , Int , DTI IK)]
tlListOf :: (a -> Type) -> [a] -> Type
tlListOf f = foldr (\h r -> AppT (AppT PromotedConsT (f h)) r) PromotedNilT
int2Type :: Int -> Type
int2Type 0 = tyZ
int2Type n = AppT tyS (int2Type (n - 1))
int2SNatPat :: Int -> Pat
int2SNatPat 0 = ConP (mkName "SZ") []
int2SNatPat n = ConP (mkName "SS") [int2SNatPat $ n-1]
tyS , tyZ , tyI , tyK :: Type
tyS = PromotedT (mkName "S")
tyZ = PromotedT (mkName "Z")
tyI = PromotedT (mkName "I")
tyK = PromotedT (mkName "K")
inputToCodes :: Input -> Q Type
inputToCodes = return . tlListOf dti2Codes . map third
where
third (_ , _ , x) = x
dti2Codes :: DTI IK -> Type
dti2Codes = tlListOf ci2Codes . dti2ci
ci2Codes :: CI IK -> Type
ci2Codes = tlListOf ik2Codes . ci2ty
ik2Codes :: IK -> Type
ik2Codes (AtomI n) = AppT tyI $ int2Type n
ik2Codes (AtomK k) = AppT tyK $ PromotedT k
inputToFam :: Input -> Q Type
inputToFam = return . tlListOf trevnocType . map first
where
first (x , _ , _) = x
styToName :: STy -> Name
styToName = mkName . styFold (++) nameBase (fixList . nameBase)
where
fixList :: String -> String
fixList n
| n == "[]" = "List"
| take 2 n == "(," = "Tup" ++ show (length n - 2)
| otherwise = n
onBaseName :: (String -> String) -> Name -> Name
onBaseName f = mkName . f . nameBase
codesName :: STy -> Q Name
codesName = return . onBaseName ("Codes" ++) . styToName
familyName :: STy -> Q Name
familyName = return . onBaseName ("Fam" ++) . styToName
genPiece1 :: STy -> Input -> Q [Dec]
genPiece1 first ls
= do codes <- TySynD <$> codesName first
<*> return []
<*> inputToCodes ls
fam <- TySynD <$> familyName first
<*> return []
<*> inputToFam ls
return [fam , codes]
idxPatSynName :: STy -> Name
idxPatSynName = styToName . (AppST (ConST (mkName "Idx")))
idxPatSyn :: STy -> Pat
idxPatSyn = flip ConP [] . idxPatSynName
genIdxPatSyn :: STy -> Int -> Q Dec
genIdxPatSyn sty ix
= return (PatSynD (idxPatSynName sty) (PrefixPatSyn []) ImplBidir (int2SNatPat ix))
genPiece2 :: OpaqueData -> STy -> Input -> Q [Dec]
genPiece2 opq first ls
= do p21 <- mapM (\(sty , ix , _dti) -> genIdxPatSyn sty ix) ls
p22 <- genPiece2_2 opq first ls
return $ p21 ++ p22
genPiece2_2 :: OpaqueData -> STy -> Input -> Q [Dec]
genPiece2_2 _opq first ls
= concat <$> mapM (\(sty , ix , dti) -> genTagPatSyns sty ix dti) ls
where
genTagPatSyns :: STy -> Int -> DTI IK -> Q [Dec]
genTagPatSyns sty ix dti
= concat <$> mapM (uncurry $ genTagPatSynFor ix sty)
(zip [0..] $ dti2ci dti)
genTagPatSynFor :: Int -> STy -> Int -> CI IK -> Q [Dec]
genTagPatSynFor ix sty cidx ci
= let fields = ci2ty ci
in do vars <- mapM (const (newName "p")) fields
let namedFields = zip fields vars
name <- patSynName sty cidx ci
pat <- [p| Tag $(int2Constr cidx) $(tagPatSynProd namedFields) |]
let pDef = PatSynD name (PrefixPatSyn vars) ImplBidir pat
phiN <- newName "phi"
konN <- newName "kon"
patTy <- genTagPatType ix phiN konN fields
let pTy = PatSynSigD name patTy
return [pTy , pDef]
genTagPatType :: Int -> Name -> Name -> [IK] -> Q Type
genTagPatType tyIx phi kon (AtomK konst : rest)
= [t| $(return $ VarT kon) $(return (ConT konst))
-> $(genTagPatType tyIx phi kon rest) |]
genTagPatType tyIx phi kon (AtomI ni : rest)
= [t| $(return (VarT phi)) $(return $ int2Type ni)
-> $(genTagPatType tyIx phi kon rest) |]
genTagPatType tyIx phi kon []
= [t| View $(return $ VarT kon)
$(return $ VarT phi)
(Lkup $(return $ int2Type tyIx)
$(ConT <$> codesName first))
|]
patSynName :: STy -> Int -> CI IK -> Q Name
patSynName sty cidx ci
| ciHasIllegalName ci
= let styname = nameBase $ styToName sty
in return . mkName $ styname ++ "_Ifx" ++ show cidx
| ConST _ <- sty
= return . mkName $ nameBase (ciName ci) ++ "_"
| otherwise
= let styname = nameBase $ styToName sty
in return . mkName $ styname ++ nameBase (ciName ci) ++ "_"
ciHasIllegalName :: CI ty -> Bool
ciHasIllegalName (Infix _ _ _ _) = True
ciHasIllegalName ci = any (not . isAlphaNum) $ nameBase (ciName ci)
tagPatSynProd :: [(IK , Name)] -> Q Pat
tagPatSynProd [] = [p| Nil |]
tagPatSynProd (h:hs) = [p| $(tagPatSynProdHead h) :* ( $(tagPatSynProd hs) ) |]
int2Constr :: Int -> Q Pat
int2Constr 0 = [p| CZ |]
int2Constr n = [p| CS $(int2Constr (n-1)) |]
tagPatSynProdHead :: (IK , Name) -> Q Pat
tagPatSynProdHead (AtomI _ , name) = [p| NA_I $(return . VarP $ name) |]
tagPatSynProdHead (AtomK _ , name) = [p| NA_K $(return . VarP $ name) |]
genPiece3 :: OpaqueData -> STy -> Input -> Q Dec
genPiece3 opq first ls
= head <$> [d| instance Family $(return $ ConT $ opaqueName opq)
$(ConT <$> familyName first)
$(ConT <$> codesName first)
where sfrom' = $(genPiece3_1 opq ls)
sto' = $(genPiece3_2 opq ls) |]
ci2PatExp :: OpaqueData -> Int -> Int -> CI IK -> Q (Pat , Exp)
ci2PatExp opq _dtiIx cIdx ci
= do (vars , pat) <- ci2Pat ci
bdy <- [e| Rep $(mkInj cIdx $ genBdy (zip vars (ci2ty ci))) |]
return (ConP (mkName "El") [pat] , bdy)
where
mkInj :: Int -> Q Exp -> Q Exp
mkInj 0 e = [e| SOP.Z $e |]
mkInj n e = [e| SOP.S $(mkInj (n-1) e) |]
genBdy :: [(Name , IK)] -> Q Exp
genBdy [] = [e| Nil |]
genBdy (x : xs) = [e| $(mkHead x) :* ( $(genBdy xs) ) |]
mkHead (x , AtomI _) = [e| NA_I (El $(return (VarE x))) |]
mkHead (x , AtomK k) = [e| NA_K $(makeK opq k (\r -> AppE (ConE r) (VarE x))) |]
ci2ExpPat :: OpaqueData -> Int -> Int -> CI IK -> Q (Pat , Exp)
ci2ExpPat opq _dtiIx cIdx ci
= do (vars , myexp) <- ci2Exp ci
pat <- [p| Rep $(mkInj cIdx $ genBdy (zip vars (ci2ty ci))) |]
return (pat , AppE (ConE $ mkName "El") myexp)
where
mkInj :: Int -> Q Pat -> Q Pat
mkInj 0 e = [p| SOP.Z $e |]
mkInj n e = [p| SOP.S $(mkInj (n-1) e) |]
genBdy :: [(Name , IK)] -> Q Pat
genBdy [] = [p| Nil |]
genBdy (x : xs) = [p| $(mkHead x) :* ( $(genBdy xs) ) |]
mkHead (x , AtomI _) = [p| NA_I (El $(return (VarP x))) |]
mkHead (x , AtomK k) = [p| NA_K $(makeK opq k (flip ConP [VarP x])) |]
makeK :: OpaqueData -> Name -> (Name -> a) -> Q a
makeK opq n cont
= case M.lookup n (opaqueCons opq) of
Nothing -> fail $ "makeK: Can't find constructor for " ++ show n ++ " in opaque def"
Just c -> return $ cont c
match :: Pat -> Exp -> Match
match pat bdy = Match pat (NormalB bdy) []
genPiece3_1 :: OpaqueData -> Input -> Q Exp
genPiece3_1 opq input
= LamCaseE <$> mapM (\(sty , ix , dti) -> clauseForIx sty ix dti) input
where
clauseForIx :: STy -> Int -> DTI IK -> Q Match
clauseForIx sty ix dti = match (idxPatSyn sty)
<$> (LamCaseE <$> genMatchFor ix dti)
genMatchFor :: Int -> DTI IK -> Q [Match]
genMatchFor ix dti = map (uncurry match) <$> mapM (uncurry $ ci2PatExp opq ix)
(zip [0..] $ dti2ci dti)
genPiece3_2 :: OpaqueData -> Input -> Q Exp
genPiece3_2 opq input
= LamCaseE <$> mapM (\(sty , ix , dti) -> clauseForIx sty ix dti) input
where
clauseForIx :: STy -> Int -> DTI IK -> Q Match
clauseForIx sty ix dti = match (idxPatSyn sty)
<$> (LamCaseE <$> genMatchFor ix dti)
genMatchFor :: Int -> DTI IK -> Q [Match]
genMatchFor ix dti = map (uncurry match) <$> mapM (uncurry $ ci2ExpPat opq ix)
(zip [0..] $ dti2ci dti)
genPiece4 :: OpaqueData -> STy -> Input -> Q [Dec]
genPiece4 opq first ls
= [d| instance Meta.HasDatatypeInfo $opqName
$(ConT <$> familyName first)
$(ConT <$> codesName first)
where datatypeInfo _ = $(genDatatypeInfoClauses ls) |]
where
opqName = return (ConT $ opaqueName opq)
genDatatypeInfoClauses :: Input -> Q Exp
genDatatypeInfoClauses input
= LamCaseE <$> mapM genDatatypeInfoMatch input
genDatatypeInfoMatch :: (STy , Int , DTI IK) -> Q Match
genDatatypeInfoMatch (sty , idx , dti)
= match (int2SNatPat idx) <$> genInfo sty dti
genMod :: Name -> Q Exp
genMod = strlit . maybe "" id . nameModule
strlit :: String -> Q Exp
strlit = return . LitE . StringL
genDatatypeName :: STy -> Q Exp
genDatatypeName = styFold (\e1 e2 -> [e| ( $e1 Meta.:@: $e2 ) |])
(\n -> [e| Meta.Name $(strlit (nameBase n)) |] )
(\n -> [e| Meta.Name $(strlit (nameBase n)) |] )
genInfo :: STy -> DTI IK -> Q Exp
genInfo sty (ADT name _ cis)
= [e| Meta.ADT $(genMod name) $(genDatatypeName sty) $(genConInfoNP cis) |]
genInfo sty (New name _ ci)
= [e| Meta.New $(genMod name) $(genDatatypeName sty) $(genConInfo ci) |]
genConInfo :: CI IK -> Q Exp
genConInfo (Record conname fields)
= [e| Meta.Record $(strlit $ nameBase conname) $(genFieldInfo $ map fst fields) |]
genConInfo (Normal conname _)
= [e| Meta.Constructor $(strlit $ nameBase conname) |]
genConInfo (Infix conname fix _ _)
= [e| Meta.Infix $(strlit $ nameBase conname) $(genAssoc fix) $(genFix fix) |]
where
genAssoc (Fixity _ InfixL) = [e| Meta.LeftAssociative |]
genAssoc (Fixity _ InfixR) = [e| Meta.RightAssociative |]
genAssoc (Fixity _ InfixN) = [e| Meta.NotAssociative |]
genFix (Fixity i _) = return . LitE . IntegerL . fromIntegral $ i
genFieldInfo :: [ FieldName ] -> Q Exp
genFieldInfo [] = [e| Nil |]
genFieldInfo (f:fs) = [e| Meta.FieldInfo $(strlit . nameBase $ f) :* ( $(genFieldInfo fs) ) |]
genConInfoNP :: [ CI IK ] -> Q Exp
genConInfoNP [] = [e| Nil |]
genConInfoNP (ci:cis) = [e| $(genConInfo ci) :* ( $(genConInfoNP cis) ) |]
genFamily :: OpaqueData -> STy -> Input -> Q [Dec]
genFamily opq first ls
= do p1 <- genPiece1 first ls
p2 <- genPiece2 opq first ls
p3 <- genPiece3 opq first ls
p4 <- genPiece4 opq first ls
return $ p1 ++ p2 ++ [p3] ++ p4
genFamilyDebug :: STy -> [(STy , Int , DTI IK)] -> Q [Dec]
genFamilyDebug _ ms = concat <$> mapM genDec ms
where
genDec :: (STy , Int , DTI IK) -> Q [Dec]
genDec (_sty , ix , dti)
= [d| $( genPat ix ) = $(mkBody dti) |]
mkBody :: DTI IK -> Q Exp
mkBody dti = [e| $(liftString $ show dti) |]
genPat :: Int -> Q Pat
genPat n = genName n >>= \name -> return (VarP name)
genName :: Int -> Q Name
genName n = return (mkName $ "tyInfo_" ++ show n)