Schema.hs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. module Gidl.Backend.Tower.Schema where
  2. import Data.Monoid
  3. import Data.List (intercalate, nub)
  4. import Gidl.Interface
  5. import Gidl.Schema
  6. import Gidl.Backend.Ivory.Types
  7. import Gidl.Backend.Ivory.Schema (ifModuleName, parserName, senderName)
  8. import Ivory.Artifact
  9. import Text.PrettyPrint.Mainland
  10. schemaModule :: [String] -> Interface -> Schema -> Artifact
  11. schemaModule modulepath ir schema =
  12. artifactPath (intercalate "/" (modulepath ++ [ifModuleName ir])) $
  13. artifactText (schemaName ++ ".hs") $
  14. prettyLazyText 1000 $
  15. stack
  16. [ text "{-# LANGUAGE DataKinds #-}"
  17. , text "{-# LANGUAGE RankNTypes #-}"
  18. , text "{-# LANGUAGE ScopedTypeVariables #-}"
  19. , text "{-# OPTIONS_GHC -fno-warn-unused-imports #-}"
  20. , empty
  21. , text "module"
  22. <+> im (ifModuleName ir) <> dot <> text schemaName
  23. <+> text "where"
  24. , empty
  25. , stack $ typeimports ++ extraimports
  26. , empty
  27. , schemaDoc (ifModuleName ir) schema
  28. ]
  29. where
  30. (Schema schemaName _) = schema
  31. rootpath = reverse . drop 2 . reverse
  32. modAt path = mconcat (punctuate dot (map text path))
  33. im mname = modAt (modulepath ++ [mname])
  34. tm mname = modAt (rootpath modulepath ++ ["Ivory","Types", mname])
  35. ivoryIFMod = modAt (rootpath modulepath
  36. ++ ["Ivory","Interface", ifModuleName ir, schemaName])
  37. typeimports = map (importDecl tm)
  38. $ nub
  39. $ map importType
  40. $ interfaceTypes ir
  41. extraimports = [ text "import" <+> modAt (rootpath modulepath ++ ["Ivory", "Types"])
  42. , text "import qualified" <+> ivoryIFMod <+> text "as I"
  43. , text "import Ivory.Language"
  44. , text "import Ivory.Stdlib"
  45. , text "import Ivory.Tower"
  46. , text "import Ivory.Serialize"
  47. ]
  48. schemaDoc :: String -> Schema -> Doc
  49. schemaDoc interfaceName (Schema schemaName []) =
  50. text "-- Cannot define" <+> text schemaName <+> text "schema for"
  51. <+> text interfaceName <+> text "interface: schema is empty"
  52. schemaDoc interfaceName (Schema schemaName schema) = stack
  53. [ text "-- Define" <+> text schemaName <+> text "schema for"
  54. <+> text interfaceName <+> text "interface"
  55. , empty
  56. , text "data" <+> constructor<+> equals <+> constructor
  57. , indent 2 $ encloseStack lbrace rbrace comma
  58. [ accessorName n <+> colon <> colon
  59. <+> text "ChanOutput" <+> typeIvoryArea t
  60. | (_, (Message n t)) <- schema
  61. ]
  62. , empty
  63. , text (inputFuncName typeName) <+> align
  64. (stack [ text ":: (ANat n)"
  65. , text "=> ChanOutput (Array n (Stored Uint8))"
  66. , text "-> Tower e" <+> constructor
  67. ])
  68. , text (inputFuncName typeName) <+> text "frame_ch" <+> equals <+> text "do"
  69. , indent 2 $ stack
  70. [ towerMonadDependencies
  71. , stack [ chanName n <+> text "<- channel"
  72. | (_, Message n _) <- schema ]
  73. , empty
  74. , text "monitor" <+> dquotes (text (outputFuncName typeName))
  75. <+> text "$ do"
  76. , indent 2 $ stack
  77. [ text "handler frame_ch \"parse_frame\" $ do"
  78. , indent 2 $ stack
  79. [ stack [ emitterName n <+> text "<- emitter"
  80. <+> parens (text "fst" <+> chanName n)
  81. <+> text "1"
  82. | (_, Message n _) <- schema
  83. ]
  84. , text "callback $ \\f -> do"
  85. , indent 2 $ stack
  86. [ text "offs <- local izero"
  87. , text "_ <- I." <> text (parserName typeName)
  88. <+> text "f offs $ I." <> constructor
  89. , indent 2 $ encloseStack lbrace rbrace comma
  90. [ text "I." <> accessorName n <+> equals
  91. <+> text "\\v -> emit" <+> emitterName n
  92. <+> text "v >> return true"
  93. | (_, Message n _) <- schema
  94. ]
  95. , text "return ()"
  96. ]
  97. ]
  98. ]
  99. , empty
  100. , text "return" <+> constructor <+> encloseStack lbrace rbrace comma
  101. [ accessorName n <+> equals
  102. <+> parens (text "snd" <+> chanName n)
  103. | (_, Message n _) <- schema
  104. ]
  105. ]
  106. , empty
  107. , text (outputFuncName typeName) <> align
  108. (stack [ text ":: (ANat n)"
  109. , text "=>" <+> constructor
  110. , text "-> Tower e (ChanOutput (Array n (Stored Uint8)))"
  111. ])
  112. , text (outputFuncName typeName) <+> text "a" <+> equals <+> text "do"
  113. , indent 2 $ stack
  114. [ towerMonadDependencies
  115. , text "frame_ch <- channel"
  116. , text "monitor" <+> dquotes (text (inputFuncName typeName))
  117. <+> text "$ do"
  118. , indent 2 $ stack
  119. [ text "handler" <+> parens (accessorName n <+> text "a")
  120. <+> dquotes (accessorName n) <+> text "$ do"
  121. </> indent 2 (parseEmitBody n)
  122. </> empty
  123. | (_, Message n _) <- schema
  124. ]
  125. , text "return (snd frame_ch)"
  126. ]
  127. ]
  128. where
  129. constructor = text typeName
  130. accessorName n = text (userEnumValueName n ++ schemaName)
  131. typeName = interfaceName ++ schemaName
  132. chanName s = text "ch_" <> text s
  133. emitterName s = text "emitter_" <> text s
  134. parseEmitBody n = stack
  135. [ text "e <- emitter (fst frame_ch) 1"
  136. , text "callback $ \\w -> do"
  137. , indent 2 $ stack
  138. [ text "f <- local izero"
  139. , text "o <- local izero"
  140. , text "ok <-" <+> text "I." <> accessorName n
  141. <+> parens (text "I." <> text (senderName typeName)
  142. <+> text "f o")
  143. <+> text "w"
  144. , text "ifte_ ok (emit e (constRef f)) (return ())"
  145. ]
  146. ]
  147. towerMonadDependencies = stack
  148. [ text "towerModule serializeModule"
  149. , text "mapM_ towerArtifact serializeArtifacts"
  150. , text "mapM_ towerModule typeModules"
  151. , text "mapM_ towerDepends typeModules"
  152. , empty
  153. ]
  154. inputFuncName :: String -> String
  155. inputFuncName tn = userEnumValueName tn ++ "Input"
  156. outputFuncName :: String -> String
  157. outputFuncName tn = userEnumValueName tn ++ "Output"