module TypeStructure.TH.Template where
import TypeStructure.Prelude.Basic
import TypeStructure.Prelude.Transformers
import TypeStructure.Prelude.Data
import TypeStructure.TH.Model
import qualified TypeStructure.Prelude.TH as T
import qualified TypeStructure.Model as M
import qualified TypeStructure.Class as C
renderType :: Type -> T.Exp
renderType = \case
App l r -> T.purify [e| M.Type_App $(return $ renderType $ l) $(return $ renderType $ r) |]
Var n -> T.purify [e| M.Type_Var $(T.stringE $ n) |]
Con tcs -> T.purify [e| M.Type_Con $(return $ renderTypeCon tcs) |]
renderTypeCon :: TypeCon -> T.Exp
renderTypeCon (ns, n) = T.purify [e| ($(T.stringE ns), $(T.stringE n)) |]
renderDeclaration :: Declaration -> T.Exp
renderDeclaration = \case
Primitive _ -> T.purify [e| M.Declaration_Primitive |]
ADT vars constructors -> T.purify [e| M.Declaration_ADT $varsE $consE |] where
varsE = T.listE $ map T.stringE vars
consE = T.listE $ map renderCons constructors
where
renderCons (n, tss) = [e| ($nameE, $typesE) |] where
nameE = T.stringE $ n
typesE = T.listE $ map (return . renderType) tss
Synonym vars t -> T.purify [e| M.Declaration_Synonym $varsE $typeE |] where
varsE = T.listE $ map T.stringE vars
typeE = return $ renderType t
renderInstance
:: T.Name
-> [TypeVar]
-> TypeCon
-> [(TypeCon, Declaration)]
-> [T.Type]
-> T.Dec
renderInstance name vars tcs dictionaryRecords inheritedDictionaries =
T.InstanceD
context
(T.ConT ''C.TypeStructure `T.AppT` headType)
[graphDec]
where
context = flip map varTypes $ (T.ClassP ''C.TypeStructure . pure)
varTypes = map (T.VarT . T.mkName) vars
headType = foldl T.AppT (T.ConT name) varTypes
graphDec = T.FunD 'C.graph [T.Clause [] (T.NormalB exp) [finalTypeDec, dictionaryDec, typeConDec]]
where
exp = T.purify $ [e| const ($(T.varE $ T.mkName "finalType"), $(T.varE $ T.mkName "dictionary")) |]
finalTypeDec = T.FunD (T.mkName "finalType") [clause] where
clause = T.Clause [] (T.NormalB exp) [] where
exp =
T.purify $
foldM
(\l r -> [e| M.Type_App $(return l) $(return r) |])
(T.purify [e| M.Type_Con $(T.varE $ T.mkName "typeCon") |])
(map varExp varTypes)
where
varExp t = T.purify [e| ((fst . C.graph) (undefined :: $(return t))) |]
dictionaryDec = T.FunD (T.mkName "dictionary") [T.Clause [] (T.NormalB exp) []] where
exp = T.purify
[e|
let
newRecords = $(
return $ T.ListE $ flip map dictionaryRecords $ \(tcs, ds) ->
T.purify
[e|
let
typeCon = $(return $ renderTypeCon tcs)
declaration = $(return $ renderDeclaration ds)
in (typeCon, declaration)
|]
)
inheritedDictionary =
mconcat $ dicsOfTypeVars ++ dicsOfReferredTypes
where
dicsOfTypeVars = $(return $ T.ListE $ map dictionaryExp varTypes)
dicsOfReferredTypes = $(return $ T.ListE $ map dictionaryExp inheritedDictionaries)
in foldr (\p -> (p:) . delete p) inheritedDictionary newRecords
|]
where
dictionaryExp t = T.purify [e| ((snd . C.graph) (undefined :: $(return t))) |]
typeConDec = T.FunD (T.mkName "typeCon") [T.Clause [] (T.NormalB exp) []] where
exp = renderTypeCon tcs