module Main where import Control.Monad (when) import Control.Monad.State (evalState) import qualified Data.Map as Map import Data.Maybe (fromMaybe) import Micro.Compiler import Micro.Error (showErrorList, showParserError) import Micro.Lexer (scan) import Micro.Parser (parse, parseFromFile) import System.Console.GetOpt import System.Environment (getProgName) import System.Environment.Blank (getArgs) import System.Exit (exitFailure, exitSuccess) import System.IO (hPutStr, hPutStrLn, stderr, stdout) data Options = Options { optParse :: Bool, optHelp :: Bool, optVersion :: Bool } defOptions = Options { optParse = False, optHelp = False, optVersion = False } options :: [OptDescr (Options -> Options)] options = [ Option ['p'] ["parse"] (NoArg (\opts -> opts {optParse = True})) "only parse, reporting any errors", Option ['h'] ["help"] (NoArg (\opts -> opts {optHelp = True})) "show help", Option ['v'] ["version"] (NoArg (\opts -> opts {optVersion = True})) "output version and exit" ] usage :: String -> [String] -> IO () usage progName errs | null errs = do putStrLn helpText exitSuccess | otherwise = do hPutStrLn stderr ("error: " ++ concat errs ++ "Try " ++ progName ++ " -h for more information.") exitFailure where header = "Usage: " ++ progName ++ " [OPTION...] file" helpText = usageInfo header options compileFile :: String -> Bool -> IO () compileFile filename onlyParse = do res <- parseFromFile (scan parse) filename case res of Left err -> hPutStrLn stderr (showParserError err) >> exitFailure Right ast -> do res <- return $ evalState (compileAll ast) startState case crExit res of Right out -> if onlyParse then exitSuccess else hPutStrLn stdout out Left errs -> hPutStr stderr (showErrorList errs) >> exitFailure main :: IO () main = do progName <- getProgName argv <- getArgs case getOpt Permute options argv of (o, n, []) -> do when (optHelp opts) $ usage progName [] when (optVersion opts) $ putStrLn (progName ++ " " ++ version) >> exitSuccess case n of [filename] -> compileFile filename $ optParse opts _ -> usage progName [] where opts = foldl (flip id) defOptions o (_, _, errs) -> usage progName errs