packages feed

protobuf-simple-0.1.0.0: app/Parser.hs

-- |
-- Module:      Main
-- Copyright:   (c) 2015-2016 Martijn Rijkeboer <mrr@sru-systems.com>
-- License:     MIT
-- Maintainer:  Martijn Rijkeboer <mrr@sru-systems.com>
--
-- Main module for the protoc executable.

module Main where


import Data.Either (lefts, rights)
import Parser.FileDesc (FileDesc)
import Parser.FileWriter (write)
import Parser.Generator (generate)
import Parser.ProtoParser (parseProto)
import System.Console.GetOpt (OptDescr(..), ArgDescr(..), ArgOrder(..), getOpt, usageInfo)
import System.Environment (getArgs)


data Options = Options
    { optHelp    :: Bool
    , optVersion :: Bool
    } deriving Show


data ProtoInfo = ProtoInfo
    { filePath :: FilePath
    , content  :: String
    } deriving Show


defaultOptions :: Options
defaultOptions = Options
    { optHelp    = False
    , optVersion = False
    }


options :: [OptDescr (Options -> Options)]
options =
    [ Option ['h'] ["help"]
        (NoArg (\opts -> opts{optHelp = True}))
        "show usage"
    , Option ['v'] ["version"]
        (NoArg (\opts -> opts{optVersion = True}))
        "show version number"
    ]


parserOpts :: [String] -> Either String (Options, [String])
parserOpts argv =
    case getOpt Permute options argv of
      (o,n,[]  ) -> Right (foldl (flip id) defaultOptions o, n)
      (_,_,errs) -> Left  (concat errs ++ usage)



main :: IO ()
main = do
    args <- getArgs
    case parserOpts args of
      Right opts -> handleOpts opts
      Left  errs -> putStrLn errs


handleOpts :: (Options, [String]) -> IO ()
handleOpts (Options {optHelp=True}, _)    = putStrLn  usage
handleOpts (Options {optVersion=True}, _) = putStrLn  version
handleOpts (Options {}, [])               = putStrLn  noFiles
handleOpts (Options {}, fs)               = printFiles $ getProtoInfos fs


getProtoInfos :: [FilePath] -> IO [ProtoInfo]
getProtoInfos = mapM getProtoInfo


getProtoInfo :: FilePath -> IO ProtoInfo
getProtoInfo fPath = do
    fData <- readFile fPath
    return $ ProtoInfo fPath fData


printFiles :: IO [ProtoInfo] -> IO ()
printFiles infos = do
    is <- infos
    let parsed = parseFiles is
    putStr $ unlines $ lefts parsed
    write $ generate $ rights parsed


parseFiles :: [ProtoInfo] -> [Either String FileDesc]
parseFiles = map parseFile


parseFile :: ProtoInfo -> Either String FileDesc
parseFile info = parseProto (filePath info) (content info)


noFiles :: String
noFiles = "protoc: no file given\n" ++ usage


usage :: String
usage = usageInfo "Usage: protoc [OPTION]... FILES" options


version :: String
version = "protoc 0.0.1"