Interface.hs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. module Gidl.Backend.Haskell.Interface where
  2. import Data.Monoid
  3. import Data.List (intercalate, nub)
  4. import Data.Char (toUpper)
  5. import Gidl.Types hiding (typeName)
  6. import Gidl.Interface
  7. import Gidl.Schema
  8. import Gidl.Backend.Haskell.Types
  9. import Ivory.Artifact
  10. import Text.PrettyPrint.Mainland
  11. interfaceModule :: Bool -> [String] -> Interface -> Artifact
  12. interfaceModule useAeson modulepath i =
  13. artifactPath (intercalate "/" modulepath) $
  14. artifactText ((ifModuleName i) ++ ".hs") $
  15. prettyLazyText 1000 $
  16. stack $
  17. [ text "{-# LANGUAGE DeriveDataTypeable #-}"
  18. , text "{-# LANGUAGE DeriveGeneric #-}"
  19. , text "{-# OPTIONS_GHC -fno-warn-unused-imports #-}"
  20. , empty
  21. , text "module"
  22. <+> im (ifModuleName i)
  23. <+> text "where"
  24. , empty
  25. , stack $ typeimports ++ extraimports
  26. , empty
  27. , schemaDoc useAeson (ifModuleName i) (producerSchema i)
  28. , empty
  29. , schemaDoc useAeson (ifModuleName i) (consumerSchema i)
  30. , empty
  31. ]
  32. where
  33. im mname = mconcat $ punctuate dot
  34. $ map text (modulepath ++ [mname])
  35. tm mname = mconcat $ punctuate dot
  36. $ map text (typepath modulepath ++ ["Types", mname])
  37. where typepath = reverse . drop 1 . reverse
  38. typeimports = map (importDecl tm)
  39. $ nub
  40. $ map importType
  41. $ interfaceTypes i
  42. extraimports = [ text "import Data.Serialize"
  43. , text "import Data.Typeable"
  44. , text "import Data.Data"
  45. , text "import GHC.Generics (Generic)"
  46. , text "import qualified Test.QuickCheck as Q"
  47. ] ++
  48. [ text "import Data.Aeson (ToJSON,FromJSON)" | useAeson ]
  49. schemaDoc :: Bool -> String -> Schema -> Doc
  50. schemaDoc _ interfaceName (Schema schemaName []) =
  51. text "-- Cannot define" <+> text schemaName <+> text "schema for"
  52. <+> text interfaceName <+> text "interface: schema is empty"
  53. schemaDoc useAeson interfaceName (Schema schemaName schema) = stack $
  54. [ text "-- Define" <+> text schemaName <+> text "schema for"
  55. <+> text interfaceName <+> text "interface"
  56. , text "data" <+> text typeName
  57. , indent 2 $ encloseStack equals deriv (text "|")
  58. [ text (constructorName n) <+> text (typeHaskellType t)
  59. | (_, (Message n t)) <- schema
  60. ]
  61. , empty
  62. , text ("put" ++ typeName) <+> colon <> colon <+> text "Putter" <+> text typeName
  63. , stack
  64. [ text ("put" ++ typeName)
  65. <+> parens (text (constructorName n) <+> text "m")
  66. <+> equals
  67. <+> primTypePutter (sizedPrim Bits32) <+> ppr h <+> text ">>"
  68. <+> text "put" <+> text "m"
  69. | (h, Message n _) <- schema ]
  70. , empty
  71. , text ("get" ++ typeName) <+> colon <> colon <+> text "Get" <+> text typeName
  72. , text ("get" ++ typeName) <+> equals <+> text "do"
  73. , indent 2 $ stack
  74. [ text "a <-" <+> primTypeGetter (sizedPrim Bits32)
  75. , text "case a of"
  76. , indent 2 $ stack $
  77. [ ppr h <+> text "-> do" </> (indent 2 (stack
  78. [ text "m <- get"
  79. , text "return" <+> parens (text (constructorName n) <+> text "m")
  80. ]))
  81. | (h,Message n _) <- schema
  82. ] ++
  83. [ text "_ -> fail"
  84. <+> dquotes (text "encountered unknown tag in get" <> text typeName)
  85. ]
  86. ]
  87. , empty
  88. , serializeInstance typeName
  89. , empty
  90. , text ("arbitrary" ++ typeName) <+> colon <> colon <+> text "Q.Gen" <+> text typeName
  91. , text ("arbitrary" ++ typeName) <+> equals
  92. , indent 2 $ text "Q.oneof" <+> encloseStack lbracket rbracket comma
  93. [ text "do" </> (indent 4 (stack
  94. [ text "a <- Q.arbitrary"
  95. , text "return" <+> parens (text (constructorName n) <+> text "a")
  96. ]))
  97. | (_, Message n _) <- schema
  98. ]
  99. , empty
  100. , arbitraryInstance typeName
  101. , empty
  102. ] ++
  103. [ toJSONInstance typeName | useAeson ] ++
  104. [ fromJSONInstance typeName | useAeson ]
  105. where
  106. constructorName n = userTypeModuleName n ++ schemaName
  107. deriv = text "deriving (Eq, Show, Data, Typeable, Generic)"
  108. typeName = interfaceName ++ schemaName
  109. ifModuleName :: Interface -> String
  110. ifModuleName (Interface iname _ _) = aux iname
  111. where
  112. aux :: String -> String
  113. aux = first_cap . u_to_camel
  114. first_cap (s:ss) = (toUpper s) : ss
  115. first_cap [] = []
  116. u_to_camel ('_':'i':[]) = []
  117. u_to_camel ('_':[]) = []
  118. u_to_camel ('_':a:as) = (toUpper a) : u_to_camel as
  119. u_to_camel (a:as) = a : u_to_camel as
  120. u_to_camel [] = []