Schema.hs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. module Gidl.Backend.Ivory.Schema 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.Ivory.Types
  9. import Ivory.Artifact
  10. import Text.PrettyPrint.Mainland
  11. schemaModule :: [String] -> Interface -> Schema -> Artifact
  12. schemaModule modulepath ir schema =
  13. artifactPath (intercalate "/" (modulepath ++ [ifModuleName ir])) $
  14. artifactText (schemaName ++ ".hs") $
  15. prettyLazyText 80 $
  16. stack
  17. [ text "{-# LANGUAGE DataKinds #-}"
  18. , text "{-# LANGUAGE RankNTypes #-}"
  19. , text "{-# LANGUAGE ScopedTypeVariables #-}"
  20. , text "{-# OPTIONS_GHC -fno-warn-unused-imports #-}"
  21. , empty
  22. , text "module"
  23. <+> im (ifModuleName ir) <> dot <> text schemaName
  24. <+> text "where"
  25. , empty
  26. , stack $ typeimports ++ extraimports
  27. , empty
  28. , schemaDoc (ifModuleName ir) schema
  29. ]
  30. where
  31. (Schema schemaName _) = schema
  32. rootpath = reverse . drop 1 . reverse
  33. modAt path = mconcat (punctuate dot (map text path))
  34. im mname = modAt (modulepath ++ [mname])
  35. tm mname = modAt (rootpath modulepath ++ ["Types", mname])
  36. unpackMod = modAt (rootpath modulepath ++ ["Unpack"])
  37. typeimports = map (importDecl tm)
  38. $ nub
  39. $ map importType
  40. $ interfaceTypes ir
  41. extraimports = [ text "import" <+> unpackMod
  42. , text "import Ivory.Language"
  43. , text "import Ivory.Serialize"
  44. , text "import Ivory.Stdlib"
  45. ]
  46. schemaDoc :: String -> Schema -> Doc
  47. schemaDoc interfaceName (Schema schemaName []) =
  48. text "-- Cannot define" <+> text schemaName <+> text "schema for"
  49. <+> text interfaceName <+> text "interface: schema is empty"
  50. schemaDoc interfaceName (Schema schemaName schema) = stack
  51. [ text "-- Define" <+> text schemaName <+> text "schema for"
  52. <+> text interfaceName <+> text "interface"
  53. , empty
  54. , text "data" <+> constructor <+> equals <+> constructor
  55. , indent 2 $ encloseStack lbrace rbrace comma
  56. [ case t of
  57. PrimType VoidType -> text (accessorName n) <+> colon <> colon
  58. <+> text "(forall s r b . Ivory ('Effects r b (Scope s)) IBool)"
  59. _ -> text (accessorName n) <+> colon <> colon
  60. <+> parens (text "forall s r b s' . ConstRef s'"
  61. <+> typeIvoryArea t
  62. <+> text "-> Ivory ('Effects r b (Scope s)) IBool")
  63. | (_, (Message n t)) <- schema
  64. ]
  65. , empty
  66. , text (parserName typeName) <+> align
  67. (stack [ text ":: forall s0 r b s2 s3 n"
  68. , text " . (ANat n)"
  69. , text "=> ConstRef s2 (Array n (Stored Uint8))"
  70. , text "-> Ref s3 (Stored Uint32)"
  71. , text "->" <+> text typeName
  72. , text "-> Ivory ('Effects r b (Scope s0)) IBool"
  73. ])
  74. , text (parserName typeName) <+> text "arr offs iface = do"
  75. , indent 2 $ stack
  76. [ text "unpackWithCallback arr offs $ \\tag_ref -> do"
  77. , indent 2 $ text "(tag :: Uint32) <- deref tag_ref"
  78. , indent 2 $ text "cond" <+> encloseStack lbracket rbracket comma
  79. [ parens (text "tag ==?" <+> ppr h) <+> text "==>" <+> unpackK
  80. | (h, Message n t) <- schema
  81. , let k = text (accessorName n) <+> text "iface"
  82. , let unpackK = case t of
  83. PrimType VoidType -> k
  84. _ -> text "unpackWithCallback arr offs" <+> parens k
  85. ]
  86. ]
  87. , empty
  88. , text (senderName typeName) <+> align
  89. (stack [ text ":: forall n s1 s2"
  90. , text " . (ANat n)"
  91. , text "=> Ref s1 (Array n (Stored Uint8))"
  92. , text "-> Ref s2 (Stored Uint32)"
  93. , text "->" <+> constructor
  94. ])
  95. , text (senderName typeName) <+> text "arr offs" <+> equals
  96. <+> constructor
  97. , indent 2 $ encloseStack lbrace rbrace comma
  98. [ case t of
  99. PrimType VoidType -> text (accessorName n) <+> equals <+> text "do" </> indent 4
  100. (stack [ text "o <- deref offs"
  101. , text "let required_size = fromInteger (packSize (packRep :: PackRep (Stored Uint32)))"
  102. , text " sufficient_space = (o + required_size) <? arrayLen arr"
  103. , text "when sufficient_space $ do"
  104. , indent 2 $ stack
  105. [ text "ident <- local (ival (" <+> ppr h <+> text ":: Uint32))"
  106. , text "packInto arr o (constRef ident)"
  107. , text "offs += required_size"
  108. ]
  109. , text "return sufficient_space"
  110. ])
  111. _ -> text (accessorName n) <+> equals <+> text "\\m -> do" </> indent 4
  112. (stack [ text "o <- deref offs"
  113. , text "let required_size = fromInteger (packSize (packRep :: PackRep"
  114. <+> typeIvoryArea t <+> text ")"
  115. <+> text "+ packSize (packRep :: PackRep (Stored Uint32)))"
  116. , text " sufficient_space = (o + required_size) <? arrayLen arr"
  117. , text "when sufficient_space $ do"
  118. , indent 2 $ stack
  119. [ text "ident <- local (ival (" <+> ppr h <+> text ":: Uint32))"
  120. , text "packInto arr o (constRef ident)"
  121. , text "packInto arr (o + fromInteger (packSize (packRep :: PackRep (Stored Uint32)))) m"
  122. , text "offs += required_size"
  123. ]
  124. , text "return sufficient_space"
  125. ])
  126. | (h, (Message n t)) <- schema
  127. ]
  128. ]
  129. where
  130. constructor = text typeName
  131. accessorName n = userEnumValueName n ++ schemaName
  132. typeName = interfaceName ++ schemaName
  133. parserName :: String -> String
  134. parserName tn = userEnumValueName tn ++ "Parser"
  135. senderName :: String -> String
  136. senderName tn = userEnumValueName tn ++ "Sender"
  137. ifModuleName :: Interface -> String
  138. ifModuleName (Interface iname _ _) = aux iname
  139. where
  140. aux :: String -> String
  141. aux = first_cap . u_to_camel
  142. first_cap (s:ss) = (toUpper s) : ss
  143. first_cap [] = []
  144. u_to_camel ('_':'i':[]) = []
  145. u_to_camel ('_':[]) = []
  146. u_to_camel ('_':a:as) = (toUpper a) : u_to_camel as
  147. u_to_camel (a:as) = a : u_to_camel as
  148. u_to_camel [] = []