Types.hs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. module Gidl.Backend.Ivory.Types where
  2. import Data.Monoid
  3. import Data.List (intercalate, nub)
  4. import Data.Char (toUpper, toLower)
  5. import Gidl.Types
  6. import Ivory.Artifact
  7. import Text.PrettyPrint.Mainland
  8. -- invariant: only make a typeModule from a StructType, Newtype, or EnumType
  9. -- i.e. when isUserDefined is true.
  10. typeModule :: [String] -> Type -> Artifact
  11. typeModule modulepath t =
  12. artifactPath (intercalate "/" modulepath) $
  13. artifactText ((typeModuleName t) ++ ".hs") $
  14. prettyLazyText 80 $
  15. stack
  16. [ text "{-# LANGUAGE DataKinds #-}"
  17. , text "{-# LANGUAGE TypeOperators #-}"
  18. , text "{-# LANGUAGE QuasiQuotes #-}"
  19. , text "{-# LANGUAGE GeneralizedNewtypeDeriving #-}"
  20. , text "{-# LANGUAGE FlexibleInstances #-}"
  21. , text "{-# OPTIONS_GHC -fno-warn-orphans #-}"
  22. , empty
  23. , text "module"
  24. <+> tm (typeModuleName t)
  25. <+> text "where"
  26. , empty
  27. , stack (imports ++
  28. [ text "import Ivory.Language"
  29. , text "import Ivory.Serialize"
  30. ])
  31. , empty
  32. , typeDecl t
  33. ]
  34. where
  35. imports = map (importDecl tm)
  36. $ nub
  37. $ map (importType . PrimType)
  38. $ typeLeaves t
  39. tm mname = mconcat $ punctuate dot
  40. $ map text (modulepath ++ [mname])
  41. typeImportedIvoryType :: Type -> String
  42. typeImportedIvoryType t@(PrimType (Newtype tn _)) =
  43. userTypeModuleName tn ++ "." ++ typeIvoryType t
  44. typeImportedIvoryType t@(PrimType (EnumType tn _ _)) =
  45. userTypeModuleName tn ++ "." ++ typeIvoryType t
  46. typeImportedIvoryType t = typeIvoryType t
  47. typeIvoryType :: Type -> String
  48. typeIvoryType (StructType tn _) = "Struct \"" ++ userTypeStructName tn ++ "\""
  49. typeIvoryType (PrimType (Newtype tn _)) = userTypeModuleName tn
  50. typeIvoryType (PrimType (EnumType tn _ _)) = userTypeModuleName tn
  51. typeIvoryType (PrimType (AtomType a)) = case a of
  52. AtomInt Bits8 -> "Sint8"
  53. AtomInt Bits16 -> "Sint16"
  54. AtomInt Bits32 -> "Sint32"
  55. AtomInt Bits64 -> "Sint64"
  56. AtomWord Bits8 -> "Uint8"
  57. AtomWord Bits16 -> "Uint16"
  58. AtomWord Bits32 -> "Uint32"
  59. AtomWord Bits64 -> "Uint64"
  60. AtomFloat -> "IFloat"
  61. AtomDouble -> "IDouble"
  62. typeIvoryType (PrimType VoidType) = "()"
  63. typeModuleName :: Type -> String
  64. typeModuleName (StructType tn _) = userTypeModuleName tn
  65. typeModuleName (PrimType (Newtype tn _)) = userTypeModuleName tn
  66. typeModuleName (PrimType (EnumType tn _ _)) = userTypeModuleName tn
  67. typeModuleName (PrimType (AtomType _)) = error "do not take typeModuleName of an AtomType"
  68. typeModuleName (PrimType VoidType) = error "do not take typeModuleName of a VoidType"
  69. userTypeModuleName :: String -> String
  70. userTypeModuleName = first_cap . userEnumValueName
  71. where
  72. first_cap (s:ss) = (toUpper s) : ss
  73. first_cap [] = []
  74. userEnumValueName :: String -> String
  75. userEnumValueName = first_lower . u_to_camel
  76. where
  77. first_lower (s:ss) = (toLower s) : ss
  78. first_lower [] = []
  79. u_to_camel ('_':'t':[]) = []
  80. u_to_camel ('_':[]) = []
  81. u_to_camel ('_':a:as) = (toUpper a) : u_to_camel as
  82. u_to_camel (a:as) = a : u_to_camel as
  83. u_to_camel [] = []
  84. userTypeStructName :: String -> String
  85. userTypeStructName = first_lower . drop_t_suffix
  86. where
  87. first_lower (s:ss) = (toLower s) : ss
  88. first_lower [] = []
  89. drop_t_suffix [] = []
  90. drop_t_suffix ('_':'t':[]) = []
  91. drop_t_suffix (a:as) = a : drop_t_suffix as
  92. typeDecl :: Type -> Doc
  93. typeDecl (StructType tname ss) = stack
  94. [ text "[ivory|"
  95. , text "struct" <+> structname
  96. , indent 2 $ encloseStack lbrace rbrace semi
  97. [ text i <+> colon <> colon
  98. <+> text "Stored" <+> text (typeImportedIvoryType (PrimType t))
  99. | (i,t) <- ss ]
  100. , text "|]"
  101. , empty
  102. , packRep <+> colon <> colon <+> text "WrappedPackRep" <+> storedType
  103. , packRep <+> equals <+> text "wrapPackRep" <+> dquotes structname <+> text "$"
  104. , indent 2 $ text "packStruct" <+> encloseStack lbracket rbracket comma
  105. [ text "packLabel" <+> text i
  106. | (i,_) <- ss]
  107. , empty
  108. , text "instance Packable" <+> storedType <+> text "where"
  109. , indent 2 $ text "packRep" <+> equals <+> text "wrappedPackRep" <+> packRep
  110. , empty
  111. , text (userEnumValueName tname) <> text "TypesModule :: Module"
  112. , text (userEnumValueName tname) <> text "TypesModule" <+> equals
  113. <+> text "package" <+> dquotes (structname <> text "_types") <+> text "$ do"
  114. , indent 2 $ stack
  115. [ text "defStruct"
  116. <+> parens (text "Proxy :: Proxy" <+> dquotes structname)
  117. , text "depend serializeModule"
  118. , text "wrappedPackMod" <+> packRep
  119. ]
  120. ]
  121. where
  122. storedType = parens (text "Struct" <+> dquotes structname)
  123. structname = text (userTypeStructName tname)
  124. packRep = text "pack" <> text (userTypeModuleName tname)
  125. typeDecl (PrimType (Newtype tname n)) = stack
  126. [ text "newtype" <+> text typename <+> equals
  127. , indent 2 $ text typename <+> align
  128. (lbrace <+> text ("un" ++ typename ) <+> text "::"
  129. <+> text (typeImportedIvoryType (PrimType n))
  130. </> rbrace <+> typeDeriving (words ("IvoryType IvoryVar IvoryExpr " ++
  131. "IvoryEq IvoryStore IvoryInit IvoryZeroVal Num")))
  132. , empty
  133. , packRep <+> colon <> colon <+> text "WrappedPackRep" <+> storedType
  134. , packRep <+> equals <+> text "wrapPackRep" <+> dquotes (text typename) <+> text "$"
  135. , indent 2 $ text "repackV" <+> text typename <+> text ("un" ++ typename) <+> text "packRep"
  136. , empty
  137. , text "instance Packable" <+> storedType <+> text "where"
  138. , indent 2 $ text "packRep" <+> equals <+> text "wrappedPackRep" <+> packRep
  139. , empty
  140. , text (userEnumValueName tname) <> text "TypesModule :: Module"
  141. , text (userEnumValueName tname) <> text "TypesModule" <+> equals
  142. <+> text "package"
  143. <+> dquotes (text (userTypeStructName tname) <> text "_types")
  144. <+> text "$ do"
  145. , indent 2 $ stack
  146. [ text "depend serializeModule"
  147. , text "wrappedPackMod" <+> packRep
  148. ]
  149. ]
  150. where
  151. typename = userTypeModuleName tname
  152. storedType = parens (text "Stored" <+> text typename)
  153. packRep = text "pack" <> text typename
  154. typeDecl (PrimType (EnumType tname s es)) = stack
  155. [ text "newtype" <+> text typename <+> equals
  156. , indent 2 $ text typename <+> align
  157. (lbrace <+> text ("un" ++ typename) <+> text "::" <+>
  158. text bt </>
  159. rbrace <+> typeDeriving (words ("IvoryType IvoryVar IvoryExpr IvoryEq "
  160. ++ "IvoryStore IvoryInit IvoryZeroVal")))
  161. , empty
  162. , stack
  163. [ stack
  164. [ empty
  165. , text (userEnumValueName i) <+> colon <> colon <+> text typename
  166. , text (userEnumValueName i) <+> equals <+> text typename <+> ppr e
  167. ]
  168. | (i,e) <- es ]
  169. , empty
  170. , packRep <+> colon <> colon <+> text "WrappedPackRep" <+> storedType
  171. , packRep <+> equals <+> text "wrapPackRep" <+> dquotes (text typename) <+> text "$"
  172. , indent 2 $ text "repackV" <+> text typename <+> text ("un" ++ typename) <+> text "packRep"
  173. , empty
  174. , text "instance Packable" <+> storedType <+> text "where"
  175. , indent 2 $ text "packRep" <+> equals <+> text "wrappedPackRep" <+> packRep
  176. , empty
  177. , text (userEnumValueName tname) <> text "TypesModule :: Module"
  178. , text (userEnumValueName tname) <> text "TypesModule" <+> equals
  179. <+> text "package"
  180. <+> dquotes (text (userTypeStructName tname) <> text "_types")
  181. <+> text "$ do"
  182. , indent 2 $ stack
  183. [ text "depend serializeModule"
  184. , text "wrappedPackMod" <+> packRep
  185. ]
  186. ]
  187. where
  188. typename = userTypeModuleName tname
  189. packRep = text "pack" <> text typename
  190. storedType = parens (text "Stored" <+> text typename)
  191. bt = case s of
  192. Bits8 -> "Uint8"
  193. Bits16 -> "Uint16"
  194. Bits32 -> "Uint32"
  195. Bits64 -> "Uint64"
  196. typeDecl a = error ("typeDecl: broken invariant, cannot create type for " ++ show a)
  197. typeDeriving :: [String] -> Doc
  198. typeDeriving cs = text "deriving" <+> parens (commasep (map text cs))
  199. data ImportType = LibraryType String
  200. | UserType String
  201. | NoImport
  202. deriving (Eq, Show)
  203. importType :: Type -> ImportType
  204. importType (StructType n _) = UserType n
  205. importType (PrimType (EnumType n _ _)) = UserType n
  206. importType (PrimType (Newtype n _)) = UserType n
  207. importType (PrimType (AtomType _)) = NoImport
  208. importType (PrimType VoidType) = NoImport
  209. isUserDefined :: Type -> Bool
  210. isUserDefined t = case importType t of
  211. UserType _ -> True
  212. _ -> False
  213. importDecl :: (String -> Doc) -> ImportType -> Doc
  214. importDecl _ (LibraryType p) =
  215. text "import" <+> text p
  216. importDecl mkpath (UserType t) =
  217. text "import qualified" <+> mkpath (userTypeModuleName t)
  218. <+> text "as" <+> text (userTypeModuleName t)
  219. importDecl _ NoImport = empty
  220. encloseStack :: Doc -> Doc -> Doc -> [Doc] -> Doc
  221. encloseStack l r p ds = case ds of
  222. [] -> empty -- l </> r
  223. [d] -> l <+> d </> r
  224. _ -> align (l <+> (folddoc (\a b -> a </> p <+> b) ds) </> r)