Gidl.hs 4.6 KB

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