{-# LANGUAGE TemplateHaskellQuotes #-}
module AST.TH.Nodes
( makeKNodes
) where
import AST.Class.Nodes
import AST.TH.Internal.Utils
import Control.Lens.Operators
import qualified Data.Set as Set
import Language.Haskell.TH
import qualified Language.Haskell.TH.Datatype as D
import Prelude.Compat
makeKNodes :: Name -> DecsQ
makeKNodes typeName = makeTypeInfo typeName >>= makeKNodesForType
makeKNodesForType :: TypeInfo -> DecsQ
makeKNodesForType info =
instanceD (simplifyContext (makeContext info)) (appT (conT ''KNodes) (pure (tiInstance info)))
[ tySynInstD ''KNodesConstraint
(simplifyContext nodesConstraint <&> toTuple <&> TySynEqn [tiInstance info, VarT constraintVar])
, dataInstD (pure []) ''KWitness
[pure (tiInstance info), pure (VarT (mkName "node"))]
Nothing (nodeOfCons <&> pure) []
, InlineP 'kLiftConstraint Inline FunLike AllPhases & PragmaD & pure
, funD 'kLiftConstraint (makeKLiftConstraints wit <&> pure)
]
<&> (:[])
where
(nodeOfCons, wit) = makeNodeOf info
constraintVar :: Name
constraintVar = mkName "constraint"
contents = tiContents info
nodesConstraint =
(Set.toList (tcChildren contents) <&> (VarT constraintVar `AppT`))
<> (Set.toList (tcEmbeds contents) <&>
\x -> ConT ''KNodesConstraint `AppT` x `AppT` VarT constraintVar)
<> Set.toList (tcOthers contents)
makeContext :: TypeInfo -> [Pred]
makeContext info =
tiCons info
>>= D.constructorFields
<&> matchType (tiVar info)
>>= ctxForPat
where
ctxForPat (Tof _ pat) = ctxForPat pat
ctxForPat (XofF t) = [ConT ''KNodes `AppT` t]
ctxForPat _ = []
makeKLiftConstraints :: NodeWitnesses -> [Clause]
makeKLiftConstraints wit
| null clauses = [Clause [] (NormalB (LamCaseE [])) []]
| otherwise = clauses
where
clauses = (nodeWitCtrs wit <&> liftNode) <> (embedWitCtrs wit <&> liftEmbed)
liftNode x =
Clause [ConP x []]
(NormalB (VarE 'const `AppE` VarE 'id)) []
liftEmbed x =
Clause [ConP x [VarP witVar]]
(NormalB (VarE 'kLiftConstraint `AppE` VarE witVar)) []
witVar :: Name
witVar = mkName "witness"