{-# LANGUAGE DeriveDataTypeable #-} module Main where import qualified CheckPVP import Paths_check_pvp (version, ) import qualified Distribution.HaskellSuite.Compiler as Compiler import Distribution.HaskellSuite.Packages (StandardDB, IsDBName, getDBName, ) import qualified Distribution.PackageDescription.Configuration as Config import qualified Distribution.PackageDescription as P import Distribution.PackageDescription.Parse (readPackageDescription, ) import Distribution.Simple.Utils (defaultPackageDesc) import qualified Language.Haskell.Exts.Annotated.CPP as CPP import qualified Language.Haskell.Exts.Annotated.Simplify as Simp import qualified Language.Haskell.Exts.Annotated.Syntax as Syntax import qualified Language.Haskell.Exts.Annotated as HSE import qualified Language.Haskell.Exts as UnAnn import Language.Haskell.Exts.Annotated.CPP (CpphsOptions, defines, ) import Language.Haskell.Exts.SrcLoc (SrcLoc(SrcLoc), ) import Language.Haskell.Exts.Extension (Language(Haskell98), Extension, knownExtensions, knownLanguages, ) import Control.Exception (Exception, throwIO, ) import Data.Typeable (Typeable, ) import Data.Tagged (Tagged(Tagged), ) import Data.Foldable (forM_, ) import Data.Maybe (fromMaybe, ) import Text.Printf (printf, ) data PVPException = ParseError HSE.SrcLoc String deriving Typeable instance Show PVPException where show (ParseError (SrcLoc file line col) msg) = printf "%s:%d:%d:\n %s" file line col msg instance Exception PVPException fromParseResult :: HSE.ParseResult a -> IO a fromParseResult (HSE.ParseOk x) = return x fromParseResult (HSE.ParseFailed loc msg) = throwIO $ ParseError loc msg main :: IO () main = Compiler.main theTool data CheckPVPName = CheckPVPName instance IsDBName CheckPVPName where getDBName = Tagged "check-pvp" theTool :: Compiler.Simple (StandardDB CheckPVPName) theTool = Compiler.simple "check-pvp" version knownLanguages knownExtensions compile [] fixCppOpts :: CpphsOptions -> CpphsOptions fixCppOpts opts = opts { defines = ("__GLASGOW_HASKELL__", "763") : defines opts } parse :: Language -> [Extension] -> CpphsOptions -> FilePath -> IO (HSE.Module HSE.SrcSpan) parse lang exts cppOpts file = return . fmap HSE.srcInfoSpan . fst =<< fromParseResult =<< CPP.parseFileWithCommentsAndCPP (fixCppOpts cppOpts) (mode lang exts file) file mode :: Language -> [Extension] -> String -> UnAnn.ParseMode mode lang exts file = UnAnn.defaultParseMode { UnAnn.parseFilename = file, UnAnn.baseLanguage = lang, UnAnn.extensions = exts, UnAnn.ignoreLanguagePragmas = False, UnAnn.ignoreLinePragmas = False } compile :: Compiler.CompileFn compile _buildDir mbLang exts cppOpts _pkgName _pkgdbs _deps files = do let lang = fromMaybe Haskell98 mbLang flags = CheckPVP.defaultFlags let verbosity = CheckPVP.flagVerbosity flags desc <- fmap Config.flattenPackageDescription . readPackageDescription verbosity =<< defaultPackageDesc verbosity let classified = CheckPVP.classifyDependencies $ P.buildDepends desc mapM_ (CheckPVP.printUpperBoundDiagnostics flags) classified checkFlags <- CheckPVP.makeCheckFlags flags classified moduleSet <- mapM (parse lang exts cppOpts) files forM_ moduleSet $ \(Syntax.Module _loc _head _pragma imports _decls) -> CheckPVP.checkImports checkFlags (map Simp.sImportDecl imports)