    {-# LANGUAGE ExistentialQuantification, Rank2Types #-}

    module Util(
        forceList,
        gzip, universeParentBi,
        exitMessage, exitMessageImpure,
        getContentsUTF8, wildcardMatch
        ) where

    import System.Exit
    import System.IO
    import System.IO.Unsafe
    import Unsafe.Coerce
    import Data.Data
    import Data.Generics.Uniplate.DataOnly
    import System.FilePattern
    import Data.List.Extra

    ---------------------------------------------------------------------
    -- CONTROL.DEEPSEQ

    forceList :: [a] -> [a]
    forceList :: forall a. [a] -> [a]
    forceList [a]
    xs = [a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [a]
    xs Int -> [a] -> [a]
    forall a b. a -> b -> b
    `seq` [a]
    xs

    ---------------------------------------------------------------------
    -- SYSTEM.IO

    exitMessage :: String -> IO a
    exitMessage :: forall a. String -> IO a
    exitMessage String
    msg = do
        Handle -> String -> IO ()
    hPutStrLn Handle
    stderr String
    msg
        ExitCode -> IO a
    forall a. ExitCode -> IO a
    exitWith (ExitCode -> IO a) -> ExitCode -> IO a
    forall a b. (a -> b) -> a -> b
    $ Int -> ExitCode
    ExitFailure Int
    1

    exitMessageImpure :: String -> a
    exitMessageImpure :: forall a. String -> a
    exitMessageImpure = IO a -> a
    forall a. IO a -> a
    unsafePerformIO (IO a -> a) -> (String -> IO a) -> String -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> IO a
    forall a. String -> IO a
    exitMessage

    getContentsUTF8 :: IO String
    getContentsUTF8 :: IO String
    getContentsUTF8 = do
        Handle -> TextEncoding -> IO ()
    hSetEncoding Handle
    stdin TextEncoding
    utf8
        IO String
    getContents

    ---------------------------------------------------------------------
    -- DATA.GENERICS

    data Box = forall a . Data a => Box a

    gzip :: Data a => (forall b . Data b => b -> b -> c) -> a -> a -> Maybe [c]
    gzip :: forall a c.
    Data a =>
    (forall b. Data b => b -> b -> c) -> a -> a -> Maybe [c]
    gzip forall b. Data b => b -> b -> c
    f a
    x a
    y | a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    x Constr -> Constr -> Bool
    forall a. Eq a => a -> a -> Bool
    /= a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    y = Maybe [c]
    forall a. Maybe a
    Nothing
               | Bool
    otherwise = [c] -> Maybe [c]
    forall a. a -> Maybe a
    Just ([c] -> Maybe [c]) -> [c] -> Maybe [c]
    forall a b. (a -> b) -> a -> b
    $ (Box -> Box -> c) -> [Box] -> [Box] -> [c]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Box -> Box -> c
    op ((forall d. Data d => d -> Box) -> a -> [Box]
    forall a u. Data a => (forall d. Data d => d -> u) -> a -> [u]
    forall u. (forall d. Data d => d -> u) -> a -> [u]
    gmapQ d -> Box
    forall d. Data d => d -> Box
    Box a
    x) ((forall d. Data d => d -> Box) -> a -> [Box]
    forall a u. Data a => (forall d. Data d => d -> u) -> a -> [u]
    forall u. (forall d. Data d => d -> u) -> a -> [u]
    gmapQ d -> Box
    forall d. Data d => d -> Box
    Box a
    y)
             -- unsafeCoerce is safe because gmapQ on the same constr gives the same fields
             -- in the same order
        where op :: Box -> Box -> c
    op (Box a
    x) (Box a
    y) = a -> a -> c
    forall b. Data b => b -> b -> c
    f a
    x (a -> a
    forall a b. a -> b
    unsafeCoerce a
    y)

    ---------------------------------------------------------------------
    -- DATA.GENERICS.UNIPLATE.OPERATIONS

    universeParent :: Data a => a -> [(Maybe a, a)]
    universeParent :: forall a. Data a => a -> [(Maybe a, a)]
    universeParent a
    x = (Maybe a
    forall a. Maybe a
    Nothing,a
    x) (Maybe a, a) -> [(Maybe a, a)] -> [(Maybe a, a)]
    forall a. a -> [a] -> [a]
    : a -> [(Maybe a, a)]
    forall a. Data a => a -> [(Maybe a, a)]
    f a
    x
        where
            f :: Data a => a -> [(Maybe a, a)]
            f :: forall a. Data a => a -> [(Maybe a, a)]
    f a
    x = [[(Maybe a, a)]] -> [(Maybe a, a)]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat [(a -> Maybe a
    forall a. a -> Maybe a
    Just a
    x, a
    y) (Maybe a, a) -> [(Maybe a, a)] -> [(Maybe a, a)]
    forall a. a -> [a] -> [a]
    : a -> [(Maybe a, a)]
    forall a. Data a => a -> [(Maybe a, a)]
    f a
    y | a
    y <- a -> [a]
    forall on. Uniplate on => on -> [on]
    children a
    x]

    universeParentBi :: (Data a, Data b) => a -> [(Maybe b, b)]
    universeParentBi :: forall a b. (Data a, Data b) => a -> [(Maybe b, b)]
    universeParentBi = (b -> [(Maybe b, b)]) -> [b] -> [(Maybe b, b)]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap b -> [(Maybe b, b)]
    forall a. Data a => a -> [(Maybe a, a)]
    universeParent ([b] -> [(Maybe b, b)]) -> (a -> [b]) -> a -> [(Maybe b, b)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> [b]
    forall from to. Biplate from to => from -> [to]
    childrenBi

    ---------------------------------------------------------------------
    -- SYSTEM.FILEPATTERN

    -- | Returns true if the pattern matches the string. For example:
    --
    -- >>> let isSpec = wildcardMatch "**.*Spec"
    -- >>> isSpec "Example"
    -- False
    -- >>> isSpec "ExampleSpec"
    -- True
    -- >>> isSpec "Namespaced.ExampleSpec"
    -- True
    -- >>> isSpec "Deeply.Nested.ExampleSpec"
    -- True
    --
    -- See this issue for details: <https://github.com/ndmitchell/hlint/issues/402>.
    wildcardMatch :: FilePattern -> String -> Bool
    wildcardMatch :: String -> String -> Bool
    wildcardMatch String
    p String
    m = let f :: String -> String
    f = String -> String -> String -> String
    forall a. Eq a => [a] -> [a] -> [a] -> [a]
    replace String
    "." String
    "/" in String -> String
    f String
    p String -> String -> Bool
    ?== String -> String
    f String
    m