1 {-# LANGUAGE TemplateHaskell #-}
4 import Language.Haskell.TH.Syntax
5 import Language.Haskell.TH
9 className :: Name -> Name
10 className = mkName . (++"'") . stringName
11 constructorName :: Name -> Name
12 constructorName = mkName . map toLower . stringName
13 selectorName :: Name -> Name
14 selectorName = mkName . map toLower . (++"'") . stringName
15 stringName :: Name -> String
16 stringName (Name occ _) = occString occ
18 numberedArgs :: [a] -> [String]
19 numberedArgs = zipWith (\i _->"f" ++ show i) [0 :: Int ..]
21 mkConsClass :: Name -> DecsQ
22 mkConsClass typename = reify typename >>= \info->case info of
25 DataD _ _ tyvars _ constructors _
28 , mkConstructorClasses tyvars constructors
29 , mkPrinterInstances tyvars constructors
30 , mkCompilerInstances tyvars constructors
33 -> fail "mkConsClass only supports data types"
35 -> fail "mkConsClass only supports types"
37 mkDerivation :: [TyVarBndr] -> DecQ
38 mkDerivation tyvars = let names = (map (VarT . getNameTyVarBndr) tyvars) in pure $
40 [ConT (mkName "Serialise") `AppT` t | t <- names]
41 (ConT (mkName "Serialise") `AppT` foldl AppT (ConT typename) names)
44 mkConstructorClasses :: [TyVarBndr] -> [Con] -> DecQ
45 mkConstructorClasses tyvars constructors = do
46 cclasses <- mapM mkConstructorClassMember constructors
47 sclasses <- concat <$> mapM mkSelectorClassMember constructors
48 pure $ ClassD [] (className typename) [PlainTV view] [] (cclasses ++ sclasses)
52 mkConstructorClassMember :: Con -> DecQ
53 mkConstructorClassMember (NormalC consname fs)
54 = mkConstructorClassMemberForName consname [t | (_, t)<-fs]
55 mkConstructorClassMember (RecC consname fs)
56 = mkConstructorClassMemberForName consname [t | (_, _, t)<-fs]
57 mkConstructorClassMember t
58 = fail $ "mkConsClass not supported for types such as: " ++ show t
60 mkConstructorClassMemberForName :: Name -> [Type] -> DecQ
61 mkConstructorClassMemberForName consname fs
62 = pure $ SigD (constructorName consname)
63 $ foldr (AppT . AppT ArrowT) resultT
64 $ map (AppT $ VarT view) fs
66 mkSelectorClassMember :: Con -> DecsQ
67 mkSelectorClassMember (NormalC _ fs)
68 = mapM (uncurry mkSelectorClassMemberForField)
69 $ zipWith (\(_, t) i->(mkName $ map toLower (stringName typename) ++ "f" ++ show i, t)) fs [0 :: Int ..]
70 mkSelectorClassMember (RecC _ fs)
71 = mapM (uncurry mkSelectorClassMemberForField) [(n, t)|(n, _, t)<-fs]
72 mkSelectorClassMember t
73 = fail $ "mkConsClass not supported for types such as: " ++ show t
75 mkSelectorClassMemberForField :: Name -> Type -> DecQ
76 mkSelectorClassMemberForField n t = pure
78 $ ForallT [] [ConT (mkName "Serialise") `AppT` VarT (getNameTyVarBndr ty) | ty <- tyvars]
79 $ ArrowT `AppT` resultT `AppT` (VarT view `AppT` t)
81 resultT = VarT view `AppT` (foldl AppT (ConT typename) $ map (VarT . getNameTyVarBndr) $ tyvars)
83 mkPrinterInstances :: [TyVarBndr] -> [Con] -> DecQ
84 mkPrinterInstances _ constructors
85 = InstanceD Nothing [] (AppT (ConT $ className typename) (ConT $ mkName "Printer")) . concat
86 <$> mapM mkPrinterInstance constructors
88 mkPrinterInstance :: Con -> DecsQ
89 mkPrinterInstance (NormalC name fs)
90 | null fs = pure [FunD (constructorName name)
91 [Clause [] (NormalB $ VarE (mkName "printLit") `AppE` LitE (StringL $ stringName name)) [] ]]
93 let args = map mkName $ numberedArgs fs
94 in (:) <$> pure (FunD (constructorName name)
98 (AppE (VarE (mkName "printCons") `AppE` LitE (StringL $ stringName name))
99 (foldl (\x y->x `pc` pl " " `pc` y) (pl "") $ map VarE args)
104 <*> mapM mkPrinterSelector
105 (zipWith (\_ i->map toLower (stringName typename) ++ "f" ++ show i) fs [0 :: Int ..])
106 mkPrinterInstance (RecC name fs)
107 = let args = map mkName $ numberedArgs fs
108 in (:) <$> pure (FunD (constructorName name)
112 (AppE (VarE (mkName "printRec") `AppE` LitE (StringL $ stringName typename))
113 (foldl1 (\x y->x `pc` pl ", " `pc` y)
114 $ zipWith (\x ((Name occ'' _), _, _)->pl (occString occ'') `pc` pl "=" `pc` VarE x) args fs)
119 <*> mapM mkPrinterSelector [occString occ | (Name occ _, _, _)<-fs]
120 mkPrinterInstance t = fail $ "mkConsClass not supported for types such as: " ++ show t
122 mkPrinterSelector :: String -> Q Dec
123 mkPrinterSelector n' = do
124 body <- [|\d->d >> printLit $(pure $ LitE $ StringL ('.':n'))|]
125 pure $ FunD (selectorName $ mkName n') [Clause [] (NormalB body) []]
127 mkCompilerInstances :: [TyVarBndr] -> [Con] -> DecQ
128 mkCompilerInstances _ constructors
129 = InstanceD Nothing [] (AppT (ConT $ className typename) (ConT $ mkName "Compiler")) . concat
130 <$> mapM (uncurry mkCompilerInstance) (zip constructors [0..])
132 mkCompilerInstance :: Con -> Int -> DecsQ
133 mkCompilerInstance (NormalC name fs) consnum = (:)
134 <$> mkCompilerInstanceForName name consnum (numberedArgs fs)
135 <*> mapM (uncurry mkCompilerSelector) (zip [0..] [map toLower (stringName typename) ++ f | f<-numberedArgs fs])
136 mkCompilerInstance (RecC name fs) consnum = (:)
137 <$> mkCompilerInstanceForName name consnum [occString occ | (Name occ _, _, _) <- fs]
138 <*> mapM (uncurry mkCompilerSelector) (zip [0..] [occString occ | (Name occ _, _, _) <- fs])
139 mkCompilerInstance t _ = fail $ "mkConsClass not supported for types such as: " ++ show t
141 mkCompilerInstanceForName :: Name -> Int -> [String] -> DecQ
142 mkCompilerInstanceForName name consnum fs =
143 let args = map mkName $ numberedArgs fs
145 body <- [|instr [Push $(pure $ LitE $ IntegerL $ toInteger $ consnum)] *> $(mkBody $ map VarE args) <* instr [Sth $ $(pure $ LitE $ IntegerL $ toInteger $ length fs) + 1] |]
146 pure $ FunD (constructorName name)
147 [Clause (map VarP args) (NormalB body) [] ]
149 mkBody :: [Exp] -> Q Exp
150 mkBody [] = pure $ VarE (mkName "pure") `AppE` ConE name
151 mkBody (a:as) = foldM (\x y->pure $ ifx "<*>" x y) (ifx "<$>" (ConE name) a) as
153 mkCompilerSelector :: Int -> String -> DecQ
154 mkCompilerSelector idx n' = do
155 body <- [|\d->d >> instr [Ldh $(pure $ LitE (IntegerL (toInteger idx)))] |]
156 pure $ FunD (selectorName $ mkName n')
157 [Clause [] (NormalB body) [] ]
160 instrE e = VarE (mkName "instr") `AppE` ListE [e]
162 ifx :: String -> Exp -> Exp -> Exp
163 ifx op a b = InfixE (Just a) (VarE $ mkName op) (Just b)
165 pc :: Exp -> Exp -> Exp
166 pc l r = VarE (mkName ">>>") `AppE` l `AppE` r
169 pl s = VarE (mkName "printLit") `AppE` LitE (StringL s)
171 getNameTyVarBndr :: TyVarBndr -> Name
172 getNameTyVarBndr (PlainTV name) = name
173 getNameTyVarBndr (KindedTV name _) = name