Gidl.hs 4.0 KB

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