Types.hs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. module Gidl.Backend.Haskell.Types where
  2. import Data.Monoid
  3. import Data.List (intercalate, nub)
  4. import Data.Char (toUpper)
  5. import Gidl.Types
  6. import Ivory.Artifact
  7. import Text.PrettyPrint.Mainland
  8. -- invariant: only make a typeModule from a StructType, NewtypeType, or EnumType
  9. -- i.e. when isUserDefined is true.
  10. typeModule :: [String] -> TypeRepr -> Artifact
  11. typeModule modulepath tr@(TypeRepr _ td) =
  12. artifactPath (intercalate "/" modulepath) $
  13. artifactText ((typeModuleName tr) ++ ".hs") $
  14. prettyLazyText 80 $
  15. stack
  16. [ text "module"
  17. <+> tm (typeModuleName tr)
  18. <+> text "where"
  19. , empty
  20. , stack $ map (importDecl tm)
  21. $ nub
  22. $ map importType
  23. $ typeLeaves td
  24. , empty
  25. , typeDecl typename td
  26. ]
  27. where
  28. typename = typeModuleName tr
  29. tm mname = mconcat $ punctuate dot
  30. $ map text (modulepath ++ [mname])
  31. typeHaskellType :: TypeRepr -> String
  32. typeHaskellType (TypeRepr tn (StructType _)) = userTypeModuleName tn
  33. typeHaskellType (TypeRepr tn (NewtypeType _)) = userTypeModuleName tn
  34. typeHaskellType (TypeRepr tn (EnumType _)) = userTypeModuleName tn
  35. typeHaskellType (TypeRepr _ (AtomType a)) = case a of
  36. AtomInt Bits8 -> "Int8"
  37. AtomInt Bits16 -> "Int16"
  38. AtomInt Bits32 -> "Int32"
  39. AtomInt Bits64 -> "Int64"
  40. AtomWord Bits8 -> "Word8"
  41. AtomWord Bits16 -> "Word16"
  42. AtomWord Bits32 -> "Word32"
  43. AtomWord Bits64 -> "Word64"
  44. AtomFloat -> "Float"
  45. AtomDouble -> "Double"
  46. typeHaskellType (TypeRepr _ VoidType) = "()"
  47. typeModuleName :: TypeRepr -> String
  48. typeModuleName (TypeRepr tn (StructType _)) = userTypeModuleName tn
  49. typeModuleName (TypeRepr tn (NewtypeType _)) = userTypeModuleName tn
  50. typeModuleName (TypeRepr tn (EnumType _)) = userTypeModuleName tn
  51. typeModuleName (TypeRepr _ (AtomType _)) = error "do not take typeModuleName of an AtomType"
  52. typeModuleName (TypeRepr _ VoidType) = error "do not take typeModuleName of a VoidType"
  53. userTypeModuleName :: String -> String
  54. userTypeModuleName = first_cap . u_to_camel
  55. where
  56. first_cap (s:ss) = (toUpper s) : ss
  57. first_cap [] = []
  58. u_to_camel ('_':'t':[]) = []
  59. u_to_camel ('_':[]) = []
  60. u_to_camel ('_':a:as) = (toUpper a) : u_to_camel as
  61. u_to_camel (a:as) = a : u_to_camel as
  62. u_to_camel [] = []
  63. typeDecl :: TypeName -> Type TypeRepr -> Doc
  64. typeDecl tname (StructType (Struct ss)) = stack
  65. [ text "data" <+> text tname <+> equals
  66. , indent 2 $ text tname
  67. , indent 4 $ encloseStack lbrace (rbrace <+> deriv) comma
  68. [ text i <+> colon <> colon <+> text (typeHaskellType t)
  69. | (i,t) <- ss ]
  70. ]
  71. where deriv = typeDeriving ["Eq", "Show"]
  72. typeDecl tname (NewtypeType (Newtype n)) = stack
  73. [ text "newtype" <+> text tname <+> equals
  74. , indent 2 $ text tname <+> align
  75. (lbrace <+> text ("un" ++ tname) <+> text "::" <+>
  76. text (typeHaskellType n) </>
  77. rbrace <+> typeDeriving ["Eq", "Show"])
  78. ]
  79. typeDecl tname (EnumType (EnumT _ es)) = stack
  80. [ text "data" <+> text tname
  81. , indent 2 $ encloseStack equals deriv (text "|")
  82. [ text (userTypeModuleName i)
  83. | (i, _) <- es ]
  84. , empty
  85. , text "instance Enum" <+> text tname <+> text "where"
  86. , indent 2 $ stack $
  87. [ text "toEnum" <+> ppr e <+> equals <+> text (userTypeModuleName i)
  88. | (i,e) <- es ] ++
  89. [ text ("toEnum _ = error \"toEnum: invalid value for " ++ tname ++ "\"") ] ++
  90. [ text "fromEnum" <+> text (userTypeModuleName i) <+> equals <+> ppr e
  91. | (i,e) <- es ]
  92. ]
  93. where deriv = typeDeriving ["Eq", "Show", "Ord"]
  94. typeDecl tn _ = error ("typeDecl: cannot create decl for built in type " ++ tn)
  95. typeDeriving :: [String] -> Doc
  96. typeDeriving cs = text "deriving" <+> parens (commasep (map text cs))
  97. data ImportType = LibraryType String
  98. | UserType String
  99. | NoImport
  100. deriving (Eq, Show)
  101. importType :: TypeRepr -> ImportType
  102. importType (TypeRepr _ (AtomType a)) =
  103. case a of
  104. AtomWord _ -> LibraryType "Data.Word"
  105. AtomInt _ -> LibraryType "Data.Int"
  106. _ -> NoImport
  107. importType (TypeRepr _ VoidType) = NoImport
  108. importType (TypeRepr n _) = UserType n
  109. isUserDefined :: TypeRepr -> Bool
  110. isUserDefined tr = case importType tr of
  111. UserType _ -> True
  112. _ -> False
  113. importDecl :: (String -> Doc) -> ImportType -> Doc
  114. importDecl _ (LibraryType p) =
  115. text "import" <+> text p
  116. importDecl mkpath (UserType t) =
  117. text "import" <+> mkpath (userTypeModuleName t)
  118. importDecl _ NoImport = empty
  119. encloseStack :: Doc -> Doc -> Doc -> [Doc] -> Doc
  120. encloseStack l r p ds = case ds of
  121. [] -> l </> r
  122. [d] -> l <+> d </> r
  123. _ -> align (l <+> (folddoc (\a b -> a </> p <+> b) ds) </> r)