Gidl.hs 4.4 KB

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