{-# LANGUAGE TemplateHaskellQuotes #-}
module Test.Mutagen.TH.Lazy
( deriveLazy
)
where
import Language.Haskell.TH
( Lit (..)
, Name
, Q
, newName
)
import Language.Haskell.TH.Desugar
( DClause (..)
, DCon (..)
, DDec (..)
, DExp (..)
, DLetDec (..)
, DPat (..)
, DType (..)
)
import Test.Mutagen
( Lazy
, lazyNode
, __evaluated__
)
import Test.Mutagen.TH.Util
( applyTyVars
, createDPat
, dConName
, dTyVarBndrName
, mkConDExp
, reifyTypeDef
)
deriveLazy :: Name -> [Name] -> Q [DDec]
deriveLazy :: Name -> [Name] -> Q [DDec]
deriveLazy Name
typeName [Name]
ignoredCons = do
(dtvbs, dcons) <- Name -> Q ([DTyVarBndrVis], [DCon])
reifyTypeDef Name
typeName
let targetType = Name -> [DTyVarBndrVis] -> DType
applyTyVars Name
typeName [DTyVarBndrVis]
dtvbs
let wantedCons = (DCon -> Bool) -> [DCon] -> [DCon]
forall a. (a -> Bool) -> [a] -> [a]
filter (\DCon
con -> DCon -> Name
dConName DCon
con Name -> [Name] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Name]
ignoredCons) [DCon]
dcons
insClauses <- mapM deriveLazyNode wantedCons
let insCxt = [Name -> DType
DConT ''Lazy DType -> DType -> DType
`DAppT` Name -> DType
DVarT (DTyVarBndrVis -> Name
dTyVarBndrName DTyVarBndrVis
tvb) | DTyVarBndrVis
tvb <- [DTyVarBndrVis]
dtvbs]
let insTy = Name -> DType
DConT ''Lazy DType -> DType -> DType
`DAppT` DType
targetType
let insBody = [DLetDec -> DDec
DLetDec (Name -> [DClause] -> DLetDec
DFunD 'lazyNode [DClause]
insClauses)]
return [DInstanceD Nothing Nothing insCxt insTy insBody]
deriveLazyNode :: DCon -> Q DClause
deriveLazyNode :: DCon -> Q DClause
deriveLazyNode DCon
con = do
acc_ <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"acc"
(vars, pat) <- createDPat con
let lazyNodeExprs =
[ Name -> DExp
DVarE 'lazyNode
DExp -> DExp -> DExp
`DAppE` (Name -> DExp
DConE '(:) DExp -> DExp -> DExp
`DAppE` Lit -> DExp
DLitE (Integer -> Lit
IntegerL Integer
idx) DExp -> DExp -> DExp
`DAppE` Name -> DExp
DVarE Name
acc_)
DExp -> DExp -> DExp
`DAppE` Name -> DExp
DVarE Name
var
| (Integer
idx, Name
var) <- [Integer] -> [Name] -> [(Integer, Name)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Integer
0 ..] [Name]
vars
]
let clauseBody =
Name -> DExp
DVarE '__evaluated__
DExp -> DExp -> DExp
`DAppE` Name -> DExp
DVarE Name
acc_
DExp -> DExp -> DExp
`DAppE` Name -> [DExp] -> DExp
mkConDExp (DCon -> Name
dConName DCon
con) [DExp]
lazyNodeExprs
return (DClause [DVarP acc_, pat] clauseBody)