packages feed

cspmchecker-0.1: src/Checker/Main.hs

{-# LANGUAGE DoAndIfThenElse #-}
module Main where

import Control.Monad
import Control.Monad.Trans
import Data.List
import System.Console.GetOpt
import System.Directory
import System.Environment
import System.FilePath
import System.Exit
import System.IO

import CSPM
import CSPM.PrettyPrinter
import Monad
import Util.Annotated
import Util.Exception
import Util.PrettyPrint

countSuccesses :: [Sfdr Bool] -> Sfdr ()
countSuccesses tasks = do
    results <- sequence tasks
    let 
        failed = length $ filter id results
        succeeded = length $ filter id results
        total = length tasks
    if failed+succeeded > 1 then do
        liftIO $ putStrLn $ show succeeded++" files succeeded out of "++show total
    else return ()

getFilesFromDir :: FilePath -> IO [FilePath]
getFilesFromDir path = do
    all <- getDirectoryContents path
    let all' = [path++"/"++f | f <- all]
    files <- filterM doesFileExist all'
    dirs <- filterM doesDirectoryExist all'
    let 
        dirs' = filter (\f -> not $ (isSuffixOf "." f) 
                                    || (isSuffixOf ".." f)) dirs
        files' = filter (isSuffixOf ".csp") files
    fss <- mapM getFilesFromDir [dir | dir <- dirs']
    return $ files'++concat fss

doFile :: FilePath -> Sfdr Bool
doFile fp = do
    liftIO $ putStr $ "Checking "++fp++"....."
    res <- tryM $ do
        ms <- parseFile fp
        typeCheckFile ms
        return ()
    ws <- getState lastWarnings
    resetCSPM
    case res of
        Left e -> do
            printError ("\n"++show e)
            return False
        Right _ -> do
            liftIO $ putStrLn $ "Ok"
            if ws /= [] then printError (show (prettyPrint ws))
            else return ()
            return True

printError :: String -> Sfdr ()
printError s = liftIO $ putStrLn $ "\ESC[1;31m\STX"++s++"\ESC[0m\STX"

data Options = Options {
        recursive :: Bool,
        help :: Bool
    }
defaultOptions = Options { 
        recursive = False, 
        help = False 
    }

options :: [OptDescr (Options -> Options)]
options = [
    Option ['r'] ["recursive"] 
        (NoArg (\o -> o { recursive = True })) 
        "If the input file is a directory, check all files contained in all subdirectories",
    Option ['h'] ["help"] 
        (NoArg (\o -> o { help = True })) 
        "Display usage message"
    ]

header :: String
header = "Usage: cspmchecker [OPTION...] files..."

main :: IO ()
main = do
    args <- getArgs
    st <- initSfdrState
    runSfdr st $ 
        case getOpt RequireOrder options args of
            (_,_,e:es) -> liftIO $ putStr $ concat (e:es) ++ usageInfo header options
            (o,files, []) -> do
                let opts = foldl (flip id) defaultOptions o
                case (opts, files) of
                    (_, []) -> 
                        liftIO $ putStr $ usageInfo header options
                    (Options { help = True }, files) -> 
                        liftIO $ putStr $ usageInfo header options
                    (Options { recursive = True }, dirs) -> do
                        tasks <- mapM (liftIO . getFilesFromDir) dirs
                        countSuccesses (map doFile (concat tasks))
                    (_, files) -> 
                        countSuccesses (map doFile files)