compiler-warnings (empty) → 0.1.0
raw patch · 4 files changed
+375/−0 lines, 4 filesdep +basedep +binarydep +compiler-warningssetup-changed
Dependencies added: base, binary, compiler-warnings, parsec, tasty, tasty-hunit, tasty-quickcheck, tasty-th, text
Files
- Setup.hs +4/−0
- compiler-warnings.cabal +52/−0
- src/Text/Warning.hs +146/−0
- test/Main.hs +173/−0
+ Setup.hs view
@@ -0,0 +1,4 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+main :: IO ()+main = defaultMain
+ compiler-warnings.cabal view
@@ -0,0 +1,52 @@+-- This file has been generated from package.yaml by hpack version 0.14.0.+--+-- see: https://github.com/sol/hpack++name: compiler-warnings+version: 0.1.0+synopsis: Parser for common compiler warning formats+category: Development+homepage: https://github.com/yi-editor/compiler-warnings#readme+bug-reports: https://github.com/yi-editor/compiler-warnings/issues+maintainer: Yi developers <yi-devel@googlegroups.com>+license: BSD2+build-type: Simple+cabal-version: >= 1.10++source-repository head+ type: git+ location: https://github.com/yi-editor/compiler-warnings++library+ hs-source-dirs:+ src+ ghc-options: -Wall -ferror-spans+ build-depends:+ base >= 4.8 && < 5+ , binary >= 0.7.5+ , text >= 1.2+ , parsec >= 3.1+ exposed-modules:+ Text.Warning+ other-modules:+ Paths_compiler_warnings+ default-language: Haskell2010++test-suite tasty+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs:+ test+ ghc-options: -Wall -ferror-spans+ build-depends:+ base >= 4.8 && < 5+ , binary >= 0.7.5+ , text >= 1.2+ , parsec >= 3.1+ , tasty+ , tasty-th+ , tasty-hunit+ , tasty-quickcheck+ , text+ , compiler-warnings+ default-language: Haskell2010
+ src/Text/Warning.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++module Text.Warning+ ( Warning (..)+ , parseWarnings+ ) where++import Data.Binary+import Data.Char+import Data.Monoid+import GHC.Generics+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE++import qualified Text.ParserCombinators.Parsec as P++type Parser a = P.GenParser Char () a++data Line+ = StarterLine Warning+ | WarningTextLine T.Text+ | GarbageLine T.Text+ | EmptyLine+ deriving Show++data Warning = Warning+ { cmFilePath :: !FilePath+ , cmStartLine :: !Int+ , cmStartColumn :: !Int+ , cmEndLine :: !Int+ , cmEndColumn :: !Int+ , cmMessage :: !T.Text+ } deriving (Eq, Generic, Show)++parseWarnings :: String -> [Warning]+parseWarnings input =+ go Nothing [] classifiedLines+ where+ go Nothing ws [] = reverse ws+ go (Just w) ws [] = reverse (w : ws)+ go (Just w) ws (WarningTextLine t : rest) =+ go (Just (appendMsg t w)) ws rest+ go (Just w) ws rest = go Nothing (w : ws) rest+ go Nothing ws (StarterLine w : rest) = go (Just w) ws rest+ go _ ws (_ : rest) = go Nothing ws rest+ classifiedLines = map parseLine (lines input)+ parseLine "" = EmptyLine+ parseLine s@(c : _) | isSpace c = WarningTextLine (T.pack s)+ parseLine s = either+ (const (GarbageLine (T.pack s)))+ StarterLine+ (P.parse (P.choice errorParsers) "" s)+ errorParsers =+ [ P.try multilineSpan+ , P.try onelineSpan+ , P.try point+ , P.try pointTypeScript+ , line+ ]+ appendMsg :: T.Text -> Warning -> Warning+ appendMsg msg2 (Warning fn l1 c1 l2 c2 msg) =+ Warning fn l1 c1 l2 c2 (msg <> "\n" <> msg2)++point :: P.GenParser Char () Warning+point = do+ fn <- filename+ _ <- P.char ':'+ l <- number+ _ <- P.char ':'+ c <- number+ _ <- P.char ':'+ msg <- message+ return (Warning fn l c l (c + 1) msg)++pointTypeScript :: P.GenParser Char () Warning+pointTypeScript = do+ fn <- filename+ _ <- P.char '('+ l <- number+ _ <- P.char ','+ c <- number+ _ <- P.string "):"+ msg <- message+ return (Warning fn l c l (c + 1) msg)++line :: P.GenParser Char () Warning+line = do+ fn <- filename+ _ <- P.char ':'+ l <- number+ _ <- P.char ':'+ msg <- message+ return (Warning fn l 1 l (-1) msg)++onelineSpan :: P.GenParser Char () Warning+onelineSpan = do+ fn <- filename+ _ <- P.char ':'+ l <- number+ _ <- P.char ':'+ c1 <- number+ _ <- P.char '-'+ c2 <- number+ _ <- P.char ':'+ msg <- message+ return (Warning fn l c1 l c2 msg)++multilineSpan :: P.GenParser Char () Warning+multilineSpan = do+ fn <- filename+ _ <- P.char ':'+ (l1, c1) <- lineCol+ _ <- P.char '-'+ (l2, c2) <- lineCol+ _ <- P.char ':'+ msg <- message+ return (Warning fn l1 c1 l2 c2 msg)++filename :: P.GenParser Char () FilePath+filename = (:) <$> P.noneOf " ():\t" <*> P.many1 (P.noneOf "():\t")++message :: Parser T.Text+message = fmap T.pack (P.many P.anyChar)++number :: P.GenParser Char () Int+number = fmap read (P.many1 P.digit)++lineCol :: P.GenParser Char () (Int, Int)+lineCol = do+ _ <- P.char '('+ l <- number+ _ <- P.char ','+ c <- number+ _ <- P.char ')'+ return (l, c)++instance Binary Warning where+ put (Warning fn l1 c1 l2 c2 msg) = do+ put (TE.encodeUtf8 msg)+ put fn+ put l1 >> put c1+ put l2 >> put c2+ get = do+ msg <- fmap TE.decodeUtf8 get+ Warning <$> get <*> get <*> get <*> get <*> get <*> pure msg
+ test/Main.hs view
@@ -0,0 +1,173 @@+#!/usr/bin/env runhaskell+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE OverloadedStrings #-}++import qualified Data.Text as T+import Data.Binary (encode, decode)+import Test.Tasty.TH+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck+import Text.Warning++main :: IO ()+main = $defaultMainGenerator++case_0 :: Assertion+case_0 =+ let input = unlines+ [ "foo:3:5: Fail"+ ]+ warnings =+ [ Warning "foo" 3 5 3 6 " Fail"+ ]+ in do parseWarnings input @?= warnings++case_ghc_1 :: Assertion+case_ghc_1 =+ let input = unlines+ [ "modules/Warning.hs:29:5: Not in scope: ‘eit'"+ ]+ warnings =+ [ Warning "modules/Warning.hs" 29 5 29 6 " Not in scope: ‘eit'"+ ]+ in do parseWarnings input @?= warnings++case_ghc_1_with_newlines :: Assertion+case_ghc_1_with_newlines =+ let input = unlines+ [ ""+ , "modules/Warning.hs:29:5: Not in scope: ‘eit'"+ , ""+ ]+ warnings =+ [ Warning "modules/Warning.hs" 29 5 29 6 " Not in scope: ‘eit'"+ ]+ in do parseWarnings input @?= warnings++case_ghc_2 :: Assertion+case_ghc_2 =+ let input = unlines+ [ "modules/Warning.hs:29:5: Not in scope: ‘eit'"+ -- , ""+ , "modules/Warning.hs:29:9: Not in scope: ‘her'"+ ]+ warnings =+ [ Warning "modules/Warning.hs" 29 5 29 6 " Not in scope: ‘eit'"+ , Warning "modules/Warning.hs" 29 9 29 10 " Not in scope: ‘her'"+ ]+ in do parseWarnings input @?= warnings++case_ghc_2_with_newlines :: Assertion+case_ghc_2_with_newlines =+ let input = unlines+ [ "modules/Warning.hs:29:5: Not in scope: ‘eit'"+ , ""+ , "modules/Warning.hs:29:9: Not in scope: ‘her'"+ ]+ warnings =+ [ Warning "modules/Warning.hs" 29 5 29 6 " Not in scope: ‘eit'"+ , Warning "modules/Warning.hs" 29 9 29 10 " Not in scope: ‘her'"+ ]+ in do parseWarnings input @?= warnings++case_ghc_2_perhaps_you_meant :: Assertion+case_ghc_2_perhaps_you_meant =+ let input = unlines+ [ "modules/Warning.hs:30:5:"+ , " Not in scope: ‘eit'"+ , " Perhaps you meant ‘pi’ (imported from Prelude)"+ , ""+ , "modules/Warning.hs:29:9: Not in scope: ‘her'"+ ]+ warnings =+ [ Warning "modules/Warning.hs" 30 5 30 6+ (T.intercalate "\n"+ [ ""+ , " Not in scope: ‘eit'"+ , " Perhaps you meant ‘pi’ (imported from Prelude)"+ ])+ , Warning "modules/Warning.hs" 29 9 29 10 " Not in scope: ‘her'"+ ]+ in do parseWarnings input @?= warnings++case_make :: Assertion+case_make =+ let input = unlines+ [ "ghc -imodules -ferror-spans -Wall -Werror -c modules/Warning.hs"+ , "modules/Warning.hs:30:5-6:"+ , " Not in scope: 'ei'"+ , " Perhaps you meant 'pi' (imported from Prelude)"+ , " modules/Warning.hs:30:8-11: Not in scope: 'ther'"+ , "Makefile:6: recipe for target 'modules/Warning.o' failed"+ , "make: *** [modules/Warning.o] Error 1"+ ]+ warnings =+ [ Warning "modules/Warning.hs" 30 5 30 6+ (T.intercalate "\n"+ [ ""+ , " Not in scope: 'ei'"+ , " Perhaps you meant 'pi' (imported from Prelude)"+ , " modules/Warning.hs:30:8-11: Not in scope: 'ther'"+ ])+ , Warning "Makefile" 6 1 6 (-1) " recipe for target 'modules/Warning.o' failed"+ ]+ in do parseWarnings input @?= warnings++case_ghc_multiline :: Assertion+case_ghc_multiline =+ let input = unlines+ [ "[1 of 1] Compiling Main ( test/Main.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.0.0/build/tasty/tasty-tmp/Main.o )"+ , ""+ , "test/Main.hs:(148,1)-(149,120): warning: [-Worphans]"+ , " Orphan instance: instance Arbitrary Warning"+ , " To avoid this"+ , " move the instance declaration to the module of the class or of the type, or"+ , " wrap the type with a newtype and declare the instance on the new type."+ , "Linking .stack-work/dist/x86_64-osx/Cabal-1.24.0.0/build/tasty/tasty .."+ ]+ warnings =+ [ Warning "test/Main.hs" 148 1 149 120+ (T.intercalate "\n"+ [ " warning: [-Worphans]"+ , " Orphan instance: instance Arbitrary Warning"+ , " To avoid this"+ , " move the instance declaration to the module of the class or of the type, or"+ , " wrap the type with a newtype and declare the instance on the new type."+ ])+ ]+ in do parseWarnings input @?= warnings++case_typescript :: Assertion+case_typescript =+ let input = "lol.ts(13,9): error TS2304: Cannot find name 'lol'."+ warnings = [Warning "lol.ts" 13 9 13 10 " error TS2304: Cannot find name 'lol'."]+ in do parseWarnings input @?= warnings++case_colons_in_error_message :: Assertion+case_colons_in_error_message =+ let input = unlines+ [ "modules/Snippet.hs:75:34-37:"+ , " Couldn't match expected type ‘WriterT"+ , "\t\t\t\t\tR.YiString"+ , " transformers-0.3.0.0:Data.Functor.Identity.Identity"+ , " a’"+ , " with actual type ‘a’"+ ]+ warnings =+ [ Warning "modules/Snippet.hs" 75 34 75 37+ (T.intercalate "\n"+ [ ""+ , " Couldn't match expected type ‘WriterT"+ , "\t\t\t\t\tR.YiString"+ , " transformers-0.3.0.0:Data.Functor.Identity.Identity"+ , " a’"+ , " with actual type ‘a’"+ ])+ ]+ in do parseWarnings input @?= warnings++prop_binary_roundtrip :: Warning -> Bool+prop_binary_roundtrip w = decode (encode w) == w++instance Arbitrary Warning where+ arbitrary = Warning <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> (T.pack <$> arbitrary)