Gidl.hs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. module Gidl
  2. ( run
  3. ) where
  4. import Data.Char
  5. import Data.Monoid
  6. import Data.Maybe (catMaybes)
  7. import Control.Monad
  8. import System.Console.GetOpt
  9. import System.Environment
  10. import System.Exit
  11. import Text.Show.Pretty
  12. import Ivory.Artifact
  13. import Gidl.Parse
  14. import Gidl.Backend.Haskell
  15. import Gidl.Backend.Ivory
  16. import Gidl.Backend.Rpc (rpcBackend)
  17. import Gidl.Backend.Tower
  18. data OptParser opt = OptParser [String] (opt -> opt)
  19. instance Monoid (OptParser opt) where
  20. mempty = OptParser [] id
  21. OptParser as f `mappend` OptParser bs g = OptParser (as ++ bs) (f . g)
  22. success :: (opt -> opt) -> OptParser opt
  23. success = OptParser []
  24. invalid :: String -> OptParser opt
  25. invalid e = OptParser [e] id
  26. parseOptions :: [OptDescr (OptParser opt)] -> [String]
  27. -> Either [String] (opt -> opt)
  28. parseOptions opts args = case getOpt Permute opts args of
  29. (fs,[],[]) -> case mconcat fs of
  30. OptParser [] f -> Right f
  31. OptParser es _ -> Left es
  32. (_,_,es) -> Left es
  33. data Backend
  34. = HaskellBackend
  35. | IvoryBackend
  36. | TowerBackend
  37. | RpcBackend
  38. deriving (Eq, Show)
  39. data Opts = Opts
  40. { backend :: Backend
  41. , idlpath :: FilePath
  42. , outpath :: FilePath
  43. , packagename :: String
  44. , namespace :: String
  45. , debug :: Bool
  46. , help :: Bool
  47. }
  48. initialOpts :: Opts
  49. initialOpts = Opts
  50. { backend = error (usage ["must specify a backend"])
  51. , idlpath = error (usage ["must specify an idl file"])
  52. , outpath = error (usage ["must specify an output path"])
  53. , packagename = error (usage ["must specify a package name"])
  54. , namespace = ""
  55. , debug = False
  56. , help = False
  57. }
  58. setBackend :: String -> OptParser Opts
  59. setBackend b = case map toUpper b of
  60. "HASKELL" -> success (\o -> o { backend = HaskellBackend })
  61. "IVORY" -> success (\o -> o { backend = IvoryBackend })
  62. "TOWER" -> success (\o -> o { backend = TowerBackend })
  63. "RPC" -> success (\o -> o { backend = RpcBackend })
  64. _ -> invalid ("\"" ++ b ++ "\" is not a valid backend.\n"
  65. ++ "Supported backends: haskell, ivory, tower")
  66. setIdlPath :: String -> OptParser Opts
  67. setIdlPath p = success (\o -> o { idlpath = p })
  68. setOutPath :: String -> OptParser Opts
  69. setOutPath p = success (\o -> o { outpath = p })
  70. setPackageName :: String -> OptParser Opts
  71. setPackageName p = success (\o -> o { packagename = p })
  72. setNamespace :: String -> OptParser Opts
  73. setNamespace p = success (\o -> o { namespace = p })
  74. setDebug :: OptParser Opts
  75. setDebug = success (\o -> o { debug = True })
  76. setHelp :: OptParser Opts
  77. setHelp = success (\o -> o { help = True })
  78. options :: [OptDescr (OptParser Opts)]
  79. options =
  80. [ Option "b" ["backend"] (ReqArg setBackend "BACKEND")
  81. "code generator backend"
  82. , Option "i" ["idl"] (ReqArg setIdlPath "FILE")
  83. "IDL file"
  84. , Option "o" ["out"] (ReqArg setOutPath "DIR")
  85. "root directory for output"
  86. , Option "p" ["package"] (ReqArg setPackageName "NAME")
  87. "package name for output"
  88. , Option "n" ["namespace"] (ReqArg setNamespace "NAME")
  89. "namespace for output"
  90. , Option "" ["debug"] (NoArg setDebug)
  91. "enable debugging output"
  92. , Option "h" ["help"] (NoArg setHelp)
  93. "display this message and exit"
  94. ]
  95. parseOpts :: [String] -> IO Opts
  96. parseOpts args = case parseOptions options args of
  97. Right f -> let opts = f initialOpts in
  98. if help opts then putStrLn (usage []) >> exitSuccess
  99. else return opts
  100. Left errs -> putStrLn (usage errs) >> exitFailure
  101. usage :: [String] -> String
  102. usage errs = usageInfo banner options
  103. where
  104. banner = unlines (errs ++ ["", "Usage: gidl OPTIONS"])
  105. run :: IO ()
  106. run = do
  107. args <- getArgs
  108. opts <- parseOpts args
  109. idl <- readFile (idlpath opts)
  110. case parseDecls idl of
  111. Left e -> print e >> exitFailure
  112. Right (te, ie) -> do
  113. when (debug opts) $ do
  114. putStrLn (ppShow te)
  115. putStrLn (ppShow ie)
  116. case backend opts of
  117. HaskellBackend -> artifactBackend opts $
  118. haskellBackend te ie (packagename opts) (namespace opts)
  119. IvoryBackend -> artifactBackend opts $
  120. ivoryBackend te ie (packagename opts) (namespace opts)
  121. TowerBackend -> artifactBackend opts $
  122. towerBackend te ie (packagename opts) (namespace opts)
  123. RpcBackend -> artifactBackend opts $
  124. rpcBackend te ie (packagename opts) (namespace opts)
  125. where
  126. artifactBackend :: Opts -> [Artifact] -> IO ()
  127. artifactBackend opts as = do
  128. when (debug opts) $ mapM_ printArtifact as
  129. es <- mapM (putArtifact (outpath opts)) as
  130. case catMaybes es of
  131. [] -> exitSuccess
  132. ees -> putStrLn (unlines ees) >> exitFailure