{-# LANGUAGE OverloadedStrings #-} module Main where import Data.Aeson (encode) import Options.Applicative import qualified Data.Text.IO as TIO import System.Exit (exitFailure) import Text.Show.Pretty (ppShow) import AsciiDoc.Parse (parseDocument) import qualified Data.ByteString.Lazy as B import System.IO (hPutStrLn, stderr) data OutputFormat = AST -- ^ Show the parsed AST in Haskell notation | JSON -- ^ Show the parsed AST in JSON serialization deriving (Show, Eq) -- | Command line options data Options = Options { optInputFiles :: [FilePath] , optOutputFormat :: OutputFormat } deriving (Show) -- | Parser for output format outputFormatParser :: ReadM OutputFormat outputFormatParser = eitherReader $ \s -> case s of "ast" -> Right AST "json" -> Right JSON _ -> Left $ "Invalid output format: " ++ s ++ ". Use 'ast' or 'json'." -- | Command line options parser optionsParser :: Parser Options optionsParser = Options <$> many (argument str ( metavar "FILE" <> help "Input files (omit to read from stdin)" )) <*> option outputFormatParser ( long "to" <> metavar "FORMAT" <> value AST <> help "Output format (ast*|json)" ) -- | Program description opts :: ParserInfo Options opts = info (optionsParser <**> helper) ( fullDesc <> progDesc "Parse AsciiDoc and output an AST" <> header "hasciidoc - AsciiDoc parser in Haskell" ) main :: IO () main = do options <- execParser opts let raiseError fp pos msg = do hPutStrLn stderr $ "Parse error at " <> show fp <> " position " <> show pos <> ": " <> msg exitFailure -- Parse the document doc <- case optInputFiles options of [] -> TIO.getContents >>= parseDocument TIO.readFile raiseError "stdin" fs -> mconcat <$> mapM (\fp -> TIO.readFile fp >>= parseDocument TIO.readFile raiseError fp) fs case optOutputFormat options of AST -> putStrLn $ ppShow doc JSON -> do B.putStr $ encode doc B.putStr "\n"