module GHC.Utils.Misc (
ghciSupported, debugIsOn,
isWindowsHost, isDarwinHost,
applyWhen, nTimes,
zipEqual, zipWithEqual, zipWith3Equal, zipWith4Equal,
zipLazy, stretchZipWith, zipWithAndUnzip, zipAndUnzip,
zipWithLazy, zipWith3Lazy,
filterByList, filterByLists, partitionByList,
unzipWith,
mapFst, mapSnd, chkAppend,
mapAndUnzip, mapAndUnzip3,
filterOut, partitionWith,
dropWhileEndLE, spanEnd, last2, lastMaybe,
List.foldl1', foldl2, count, countWhile, all2,
lengthExceeds, lengthIs, lengthIsNot,
lengthAtLeast, lengthAtMost, lengthLessThan,
listLengthCmp, atLength,
equalLength, compareLength, leLength, ltLength,
isSingleton, only, GHC.Utils.Misc.singleton,
notNull, snocView,
isIn, isn'tIn,
chunkList,
changeLast,
mapLastM,
whenNonEmpty,
mergeListsBy,
isSortedBy,
fstOf3, sndOf3, thdOf3,
firstM, first3M, secondM,
fst3, snd3, third3,
uncurry3,
liftFst, liftSnd,
takeList, dropList, splitAtList, split,
dropTail, capitalise,
sortWith, minWith, nubSort, ordNub,
isEqual, eqListBy, eqMaybeBy,
thenCmp, cmpList,
removeSpaces,
(<&&>), (<||>),
fuzzyMatch, fuzzyLookup,
transitiveClosure,
seqList, strictMap,
looksLikeModuleName,
looksLikePackageName,
getCmd, toCmdArgs, toArgs,
exactLog2,
readRational,
readSignificandExponentPair,
readHexRational,
readHexSignificandExponentPair,
doesDirNameExist,
getModificationUTCTime,
modificationTimeIfExists,
withAtomicRename,
Suffix,
splitLongestPrefix,
escapeSpaces,
Direction(..), reslash,
makeRelativeTo,
abstractConstr, abstractDataType, mkNoRepType,
charToC,
hashString,
HasCallStack,
HasDebugCallStack,
OverridingBool(..),
overrideWith,
) where
#include "HsVersions.h"
import GHC.Prelude
import GHC.Utils.Exception
import GHC.Utils.Panic.Plain
import Data.Data
import qualified Data.List as List
import Data.List.NonEmpty ( NonEmpty(..) )
import GHC.Exts
import GHC.Stack (HasCallStack)
import Control.Applicative ( liftA2 )
import Control.Monad ( liftM, guard )
import Control.Monad.IO.Class ( MonadIO, liftIO )
import System.IO.Error as IO ( isDoesNotExistError )
import System.Directory ( doesDirectoryExist, getModificationTime, renameFile )
import System.FilePath
import Data.Char ( isUpper, isAlphaNum, isSpace, chr, ord, isDigit, toUpper
, isHexDigit, digitToInt )
import Data.Int
import Data.Ratio ( (%) )
import Data.Ord ( comparing )
import Data.Bits
import Data.Word
import qualified Data.IntMap as IM
import qualified Data.Set as Set
import Data.Time
#if defined(DEBUG)
import GHC.Utils.Outputable ( text )
import GHC.Driver.Ppr ( warnPprTrace )
#endif
infixr 9 `thenCmp`
ghciSupported :: Bool
#if defined(HAVE_INTERNAL_INTERPRETER)
ghciSupported = True
#else
ghciSupported = False
#endif
debugIsOn :: Bool
#if defined(DEBUG)
debugIsOn = True
#else
debugIsOn = False
#endif
isWindowsHost :: Bool
#if defined(mingw32_HOST_OS)
isWindowsHost = True
#else
isWindowsHost = False
#endif
isDarwinHost :: Bool
#if defined(darwin_HOST_OS)
isDarwinHost = True
#else
isDarwinHost = False
#endif
applyWhen :: Bool -> (a -> a) -> a -> a
applyWhen True f x = f x
applyWhen _ _ x = x
nTimes :: Int -> (a -> a) -> (a -> a)
nTimes 0 _ = id
nTimes 1 f = f
nTimes n f = f . nTimes (n1) f
fstOf3 :: (a,b,c) -> a
sndOf3 :: (a,b,c) -> b
thdOf3 :: (a,b,c) -> c
fstOf3 (a,_,_) = a
sndOf3 (_,b,_) = b
thdOf3 (_,_,c) = c
fst3 :: (a -> d) -> (a, b, c) -> (d, b, c)
fst3 f (a, b, c) = (f a, b, c)
snd3 :: (b -> d) -> (a, b, c) -> (a, d, c)
snd3 f (a, b, c) = (a, f b, c)
third3 :: (c -> d) -> (a, b, c) -> (a, b, d)
third3 f (a, b, c) = (a, b, f c)
uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
uncurry3 f (a, b, c) = f a b c
liftFst :: (a -> b) -> (a, c) -> (b, c)
liftFst f (a,c) = (f a, c)
liftSnd :: (a -> b) -> (c, a) -> (c, b)
liftSnd f (c,a) = (c, f a)
firstM :: Monad m => (a -> m c) -> (a, b) -> m (c, b)
firstM f (x, y) = liftM (\x' -> (x', y)) (f x)
first3M :: Monad m => (a -> m d) -> (a, b, c) -> m (d, b, c)
first3M f (x, y, z) = liftM (\x' -> (x', y, z)) (f x)
secondM :: Monad m => (b -> m c) -> (a, b) -> m (a, c)
secondM f (x, y) = (x,) <$> f y
filterOut :: (a->Bool) -> [a] -> [a]
filterOut _ [] = []
filterOut p (x:xs) | p x = filterOut p xs
| otherwise = x : filterOut p xs
partitionWith :: (a -> Either b c) -> [a] -> ([b], [c])
partitionWith _ [] = ([],[])
partitionWith f (x:xs) = case f x of
Left b -> (b:bs, cs)
Right c -> (bs, c:cs)
where (bs,cs) = partitionWith f xs
chkAppend :: [a] -> [a] -> [a]
chkAppend xs ys
| null ys = xs
| otherwise = xs ++ ys
zipEqual :: String -> [a] -> [b] -> [(a,b)]
zipWithEqual :: String -> (a->b->c) -> [a]->[b]->[c]
zipWith3Equal :: String -> (a->b->c->d) -> [a]->[b]->[c]->[d]
zipWith4Equal :: String -> (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]
#if !defined(DEBUG)
zipEqual _ = zip
zipWithEqual _ = zipWith
zipWith3Equal _ = zipWith3
zipWith4Equal _ = List.zipWith4
#else
zipEqual _ [] [] = []
zipEqual msg (a:as) (b:bs) = (a,b) : zipEqual msg as bs
zipEqual msg _ _ = panic ("zipEqual: unequal lists: "++msg)
zipWithEqual msg z (a:as) (b:bs)= z a b : zipWithEqual msg z as bs
zipWithEqual _ _ [] [] = []
zipWithEqual msg _ _ _ = panic ("zipWithEqual: unequal lists: "++msg)
zipWith3Equal msg z (a:as) (b:bs) (c:cs)
= z a b c : zipWith3Equal msg z as bs cs
zipWith3Equal _ _ [] [] [] = []
zipWith3Equal msg _ _ _ _ = panic ("zipWith3Equal: unequal lists: "++msg)
zipWith4Equal msg z (a:as) (b:bs) (c:cs) (d:ds)
= z a b c d : zipWith4Equal msg z as bs cs ds
zipWith4Equal _ _ [] [] [] [] = []
zipWith4Equal msg _ _ _ _ _ = panic ("zipWith4Equal: unequal lists: "++msg)
#endif
zipLazy :: [a] -> [b] -> [(a,b)]
zipLazy [] _ = []
zipLazy (x:xs) ~(y:ys) = (x,y) : zipLazy xs ys
zipWithLazy :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWithLazy _ [] _ = []
zipWithLazy f (a:as) ~(b:bs) = f a b : zipWithLazy f as bs
zipWith3Lazy :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
zipWith3Lazy _ [] _ _ = []
zipWith3Lazy f (a:as) ~(b:bs) ~(c:cs) = f a b c : zipWith3Lazy f as bs cs
filterByList :: [Bool] -> [a] -> [a]
filterByList (True:bs) (x:xs) = x : filterByList bs xs
filterByList (False:bs) (_:xs) = filterByList bs xs
filterByList _ _ = []
filterByLists :: [Bool] -> [a] -> [a] -> [a]
filterByLists (True:bs) (x:xs) (_:ys) = x : filterByLists bs xs ys
filterByLists (False:bs) (_:xs) (y:ys) = y : filterByLists bs xs ys
filterByLists _ _ _ = []
partitionByList :: [Bool] -> [a] -> ([a], [a])
partitionByList = go [] []
where
go trues falses (True : bs) (x : xs) = go (x:trues) falses bs xs
go trues falses (False : bs) (x : xs) = go trues (x:falses) bs xs
go trues falses _ _ = (reverse trues, reverse falses)
stretchZipWith :: (a -> Bool) -> b -> (a->b->c) -> [a] -> [b] -> [c]
stretchZipWith _ _ _ [] _ = []
stretchZipWith p z f (x:xs) ys
| p x = f x z : stretchZipWith p z f xs ys
| otherwise = case ys of
[] -> []
(y:ys) -> f x y : stretchZipWith p z f xs ys
mapFst :: (a->c) -> [(a,b)] -> [(c,b)]
mapSnd :: (b->c) -> [(a,b)] -> [(a,c)]
mapFst f xys = [(f x, y) | (x,y) <- xys]
mapSnd f xys = [(x, f y) | (x,y) <- xys]
mapAndUnzip :: (a -> (b, c)) -> [a] -> ([b], [c])
mapAndUnzip _ [] = ([], [])
mapAndUnzip f (x:xs)
= let (r1, r2) = f x
(rs1, rs2) = mapAndUnzip f xs
in
(r1:rs1, r2:rs2)
mapAndUnzip3 :: (a -> (b, c, d)) -> [a] -> ([b], [c], [d])
mapAndUnzip3 _ [] = ([], [], [])
mapAndUnzip3 f (x:xs)
= let (r1, r2, r3) = f x
(rs1, rs2, rs3) = mapAndUnzip3 f xs
in
(r1:rs1, r2:rs2, r3:rs3)
zipWithAndUnzip :: (a -> b -> (c,d)) -> [a] -> [b] -> ([c],[d])
zipWithAndUnzip f (a:as) (b:bs)
= let (r1, r2) = f a b
(rs1, rs2) = zipWithAndUnzip f as bs
in
(r1:rs1, r2:rs2)
zipWithAndUnzip _ _ _ = ([],[])
zipAndUnzip :: [a] -> [b] -> ([a],[b])
zipAndUnzip (a:as) (b:bs)
= let (rs1, rs2) = zipAndUnzip as bs
in
(a:rs1, b:rs2)
zipAndUnzip _ _ = ([],[])
atLength :: ([a] -> b)
-> b
-> [a]
-> Int
-> b
atLength atLenPred atEnd ls0 n0
| n0 < 0 = atLenPred ls0
| otherwise = go n0 ls0
where
go 0 ls = atLenPred ls
go _ [] = atEnd
go n (_:xs) = go (n1) xs
lengthExceeds :: [a] -> Int -> Bool
lengthExceeds lst n
| n < 0
= True
| otherwise
= atLength notNull False lst n
lengthAtLeast :: [a] -> Int -> Bool
lengthAtLeast = atLength (const True) False
lengthIs :: [a] -> Int -> Bool
lengthIs lst n
| n < 0
= False
| otherwise
= atLength null False lst n
lengthIsNot :: [a] -> Int -> Bool
lengthIsNot lst n
| n < 0 = True
| otherwise = atLength notNull True lst n
lengthAtMost :: [a] -> Int -> Bool
lengthAtMost lst n
| n < 0
= False
| otherwise
= atLength null True lst n
lengthLessThan :: [a] -> Int -> Bool
lengthLessThan = atLength (const False) True
listLengthCmp :: [a] -> Int -> Ordering
listLengthCmp = atLength atLen atEnd
where
atEnd = LT
atLen [] = EQ
atLen _ = GT
equalLength :: [a] -> [b] -> Bool
equalLength [] [] = True
equalLength (_:xs) (_:ys) = equalLength xs ys
equalLength _ _ = False
compareLength :: [a] -> [b] -> Ordering
compareLength [] [] = EQ
compareLength (_:xs) (_:ys) = compareLength xs ys
compareLength [] _ = LT
compareLength _ [] = GT
leLength :: [a] -> [b] -> Bool
leLength xs ys = case compareLength xs ys of
LT -> True
EQ -> True
GT -> False
ltLength :: [a] -> [b] -> Bool
ltLength xs ys = case compareLength xs ys of
LT -> True
EQ -> False
GT -> False
singleton :: a -> [a]
singleton x = [x]
isSingleton :: [a] -> Bool
isSingleton [_] = True
isSingleton _ = False
notNull :: Foldable f => f a -> Bool
notNull = not . null
only :: [a] -> a
#if defined(DEBUG)
only [a] = a
#else
only (a:_) = a
#endif
only _ = panic "Util: only"
# if !defined(DEBUG)
isIn, isn'tIn :: Eq a => String -> a -> [a] -> Bool
isIn _msg x ys = x `elem` ys
isn'tIn _msg x ys = x `notElem` ys
# else /* DEBUG */
isIn, isn'tIn :: (HasDebugCallStack, Eq a) => String -> a -> [a] -> Bool
isIn msg x ys
= elem100 0 x ys
where
elem100 :: Eq a => Int -> a -> [a] -> Bool
elem100 _ _ [] = False
elem100 i x (y:ys)
| i > 100 = WARN(True, text ("Over-long elem in " ++ msg)) (x `elem` (y:ys))
| otherwise = x == y || elem100 (i + 1) x ys
isn'tIn msg x ys
= notElem100 0 x ys
where
notElem100 :: Eq a => Int -> a -> [a] -> Bool
notElem100 _ _ [] = True
notElem100 i x (y:ys)
| i > 100 = WARN(True, text ("Over-long notElem in " ++ msg)) (x `notElem` (y:ys))
| otherwise = x /= y && notElem100 (i + 1) x ys
# endif /* DEBUG */
chunkList :: Int -> [a] -> [[a]]
chunkList _ [] = []
chunkList n xs = as : chunkList n bs where (as,bs) = splitAt n xs
changeLast :: [a] -> a -> [a]
changeLast [] _ = panic "changeLast"
changeLast [_] x = [x]
changeLast (x:xs) x' = x : changeLast xs x'
mapLastM :: Functor f => (a -> f a) -> [a] -> f [a]
mapLastM _ [] = panic "mapLastM: empty list"
mapLastM f [x] = (\x' -> [x']) <$> f x
mapLastM f (x:xs) = (x:) <$> mapLastM f xs
whenNonEmpty :: Applicative m => [a] -> (NonEmpty a -> m ()) -> m ()
whenNonEmpty [] _ = pure ()
whenNonEmpty (x:xs) f = f (x :| xs)
mergeListsBy :: forall a. (a -> a -> Ordering) -> [[a]] -> [a]
mergeListsBy cmp lists | debugIsOn, not (all sorted lists) =
panic "mergeListsBy: input lists must be sorted"
where sorted = isSortedBy cmp
mergeListsBy cmp all_lists = merge_lists all_lists
where
merge2 :: [a] -> [a] -> [a]
merge2 [] ys = ys
merge2 xs [] = xs
merge2 (x:xs) (y:ys) =
case cmp x y of
GT -> y : merge2 (x:xs) ys
_ -> x : merge2 xs (y:ys)
merge_neighbours :: [[a]] -> [[a]]
merge_neighbours [] = []
merge_neighbours [xs] = [xs]
merge_neighbours (xs : ys : lists) =
merge2 xs ys : merge_neighbours lists
merge_lists :: [[a]] -> [a]
merge_lists lists =
case merge_neighbours lists of
[] -> []
[xs] -> xs
lists' -> merge_lists lists'
isSortedBy :: (a -> a -> Ordering) -> [a] -> Bool
isSortedBy cmp = sorted
where
sorted [] = True
sorted [_] = True
sorted (x:y:xs) = cmp x y /= GT && sorted (y:xs)
minWith :: Ord b => (a -> b) -> [a] -> a
minWith get_key xs = ASSERT( not (null xs) )
head (sortWith get_key xs)
nubSort :: Ord a => [a] -> [a]
nubSort = Set.toAscList . Set.fromList
ordNub :: Ord a => [a] -> [a]
ordNub xs
= go Set.empty xs
where
go _ [] = []
go s (x:xs)
| Set.member x s = go s xs
| otherwise = x : go (Set.insert x s) xs
transitiveClosure :: (a -> [a])
-> (a -> a -> Bool)
-> [a]
-> [a]
transitiveClosure succ eq xs
= go [] xs
where
go done [] = done
go done (x:xs) | x `is_in` done = go done xs
| otherwise = go (x:done) (succ x ++ xs)
_ `is_in` [] = False
x `is_in` (y:ys) | eq x y = True
| otherwise = x `is_in` ys
foldl2 :: (acc -> a -> b -> acc) -> acc -> [a] -> [b] -> acc
foldl2 _ z [] [] = z
foldl2 k z (a:as) (b:bs) = foldl2 k (k z a b) as bs
foldl2 _ _ _ _ = panic "Util: foldl2"
all2 :: (a -> b -> Bool) -> [a] -> [b] -> Bool
all2 _ [] [] = True
all2 p (x:xs) (y:ys) = p x y && all2 p xs ys
all2 _ _ _ = False
count :: (a -> Bool) -> [a] -> Int
count p = go 0
where go !n [] = n
go !n (x:xs) | p x = go (n+1) xs
| otherwise = go n xs
countWhile :: (a -> Bool) -> [a] -> Int
countWhile p = go 0
where go !n (x:xs) | p x = go (n+1) xs
go !n _ = n
takeList :: [b] -> [a] -> [a]
takeList [] _ = []
takeList (_:xs) ls =
case ls of
[] -> []
(y:ys) -> y : takeList xs ys
dropList :: [b] -> [a] -> [a]
dropList [] xs = xs
dropList _ xs@[] = xs
dropList (_:xs) (_:ys) = dropList xs ys
splitAtList :: [b] -> [a] -> ([a], [a])
splitAtList xs ys = go 0# xs ys
where
go _ !_ [] = (ys, [])
go n [] bs = (take (I# n) ys, bs)
go n (_:as) (_:bs) = go (n +# 1#) as bs
dropTail :: Int -> [a] -> [a]
dropTail n xs
= go (drop n xs) xs
where
go (_:ys) (x:xs) = x : go ys xs
go _ _ = []
dropWhileEndLE :: (a -> Bool) -> [a] -> [a]
dropWhileEndLE p = foldr (\x r -> if null r && p x then [] else x:r) []
spanEnd :: (a -> Bool) -> [a] -> ([a], [a])
spanEnd p l = go l [] [] l
where go yes _rev_yes rev_no [] = (yes, reverse rev_no)
go yes rev_yes rev_no (x:xs)
| p x = go yes (x : rev_yes) rev_no xs
| otherwise = go xs [] (x : rev_yes ++ rev_no) xs
last2 :: [a] -> (a,a)
last2 = List.foldl' (\(_,x2) x -> (x2,x)) (partialError,partialError)
where
partialError = panic "last2 - list length less than two"
lastMaybe :: [a] -> Maybe a
lastMaybe [] = Nothing
lastMaybe xs = Just $ last xs
snocView :: [a] -> Maybe ([a],a)
snocView [] = Nothing
snocView xs
| (xs,x) <- go xs
= Just (xs,x)
where
go :: [a] -> ([a],a)
go [x] = ([],x)
go (x:xs)
| !(xs',x') <- go xs
= (x:xs', x')
go [] = error "impossible"
split :: Char -> String -> [String]
split c s = case rest of
[] -> [chunk]
_:rest -> chunk : split c rest
where (chunk, rest) = break (==c) s
capitalise :: String -> String
capitalise [] = []
capitalise (c:cs) = toUpper c : cs
isEqual :: Ordering -> Bool
isEqual GT = False
isEqual EQ = True
isEqual LT = False
thenCmp :: Ordering -> Ordering -> Ordering
thenCmp EQ ordering = ordering
thenCmp ordering _ = ordering
eqListBy :: (a->a->Bool) -> [a] -> [a] -> Bool
eqListBy _ [] [] = True
eqListBy eq (x:xs) (y:ys) = eq x y && eqListBy eq xs ys
eqListBy _ _ _ = False
eqMaybeBy :: (a ->a->Bool) -> Maybe a -> Maybe a -> Bool
eqMaybeBy _ Nothing Nothing = True
eqMaybeBy eq (Just x) (Just y) = eq x y
eqMaybeBy _ _ _ = False
cmpList :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering
cmpList _ [] [] = EQ
cmpList _ [] _ = LT
cmpList _ _ [] = GT
cmpList cmp (a:as) (b:bs)
= case cmp a b of { EQ -> cmpList cmp as bs; xxx -> xxx }
removeSpaces :: String -> String
removeSpaces = dropWhileEndLE isSpace . dropWhile isSpace
(<&&>) :: Applicative f => f Bool -> f Bool -> f Bool
(<&&>) = liftA2 (&&)
infixr 3 <&&>
(<||>) :: Applicative f => f Bool -> f Bool -> f Bool
(<||>) = liftA2 (||)
infixr 2 <||>
restrictedDamerauLevenshteinDistance :: String -> String -> Int
restrictedDamerauLevenshteinDistance str1 str2
= restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2
where
m = length str1
n = length str2
restrictedDamerauLevenshteinDistanceWithLengths
:: Int -> Int -> String -> String -> Int
restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2
| m <= n
= if n <= 32
then restrictedDamerauLevenshteinDistance' (undefined :: Word32) m n str1 str2
else restrictedDamerauLevenshteinDistance' (undefined :: Integer) m n str1 str2
| otherwise
= if m <= 32
then restrictedDamerauLevenshteinDistance' (undefined :: Word32) n m str2 str1
else restrictedDamerauLevenshteinDistance' (undefined :: Integer) n m str2 str1
restrictedDamerauLevenshteinDistance'
:: (Bits bv, Num bv) => bv -> Int -> Int -> String -> String -> Int
restrictedDamerauLevenshteinDistance' _bv_dummy m n str1 str2
| [] <- str1 = n
| otherwise = extractAnswer $
List.foldl' (restrictedDamerauLevenshteinDistanceWorker
(matchVectors str1) top_bit_mask vector_mask)
(0, 0, m_ones, 0, m) str2
where
m_ones@vector_mask = (2 ^ m) 1
top_bit_mask = (1 `shiftL` (m 1)) `asTypeOf` _bv_dummy
extractAnswer (_, _, _, _, distance) = distance
restrictedDamerauLevenshteinDistanceWorker
:: (Bits bv, Num bv) => IM.IntMap bv -> bv -> bv
-> (bv, bv, bv, bv, Int) -> Char -> (bv, bv, bv, bv, Int)
restrictedDamerauLevenshteinDistanceWorker str1_mvs top_bit_mask vector_mask
(pm, d0, vp, vn, distance) char2
= seq str1_mvs $ seq top_bit_mask $ seq vector_mask $
seq pm' $ seq d0' $ seq vp' $ seq vn' $
seq distance'' $ seq char2 $
(pm', d0', vp', vn', distance'')
where
pm' = IM.findWithDefault 0 (ord char2) str1_mvs
d0' = ((((sizedComplement vector_mask d0) .&. pm') `shiftL` 1) .&. pm)
.|. ((((pm' .&. vp) + vp) .&. vector_mask) `xor` vp) .|. pm' .|. vn
hp' = vn .|. sizedComplement vector_mask (d0' .|. vp)
hn' = d0' .&. vp
hp'_shift = ((hp' `shiftL` 1) .|. 1) .&. vector_mask
hn'_shift = (hn' `shiftL` 1) .&. vector_mask
vp' = hn'_shift .|. sizedComplement vector_mask (d0' .|. hp'_shift)
vn' = d0' .&. hp'_shift
distance' = if hp' .&. top_bit_mask /= 0 then distance + 1 else distance
distance'' = if hn' .&. top_bit_mask /= 0 then distance' 1 else distance'
sizedComplement :: Bits bv => bv -> bv -> bv
sizedComplement vector_mask vect = vector_mask `xor` vect
matchVectors :: (Bits bv, Num bv) => String -> IM.IntMap bv
matchVectors = snd . List.foldl' go (0 :: Int, IM.empty)
where
go (ix, im) char = let ix' = ix + 1
im' = IM.insertWith (.|.) (ord char) (2 ^ ix) im
in seq ix' $ seq im' $ (ix', im')
fuzzyMatch :: String -> [String] -> [String]
fuzzyMatch key vals = fuzzyLookup key [(v,v) | v <- vals]
fuzzyLookup :: String -> [(String,a)] -> [a]
fuzzyLookup user_entered possibilites
= map fst $ take mAX_RESULTS $ List.sortBy (comparing snd)
[ (poss_val, distance) | (poss_str, poss_val) <- possibilites
, let distance = restrictedDamerauLevenshteinDistance
poss_str user_entered
, distance <= fuzzy_threshold ]
where
fuzzy_threshold = truncate $ fromIntegral (length user_entered + 2) / (4 :: Rational)
mAX_RESULTS = 3
unzipWith :: (a -> b -> c) -> [(a, b)] -> [c]
unzipWith f pairs = map ( \ (a, b) -> f a b ) pairs
seqList :: [a] -> b -> b
seqList [] b = b
seqList (x:xs) b = x `seq` seqList xs b
strictMap :: (a -> b) -> [a] -> [b]
strictMap _ [] = []
strictMap f (x : xs) =
let
!x' = f x
!xs' = strictMap f xs
in
x' : xs'
looksLikeModuleName :: String -> Bool
looksLikeModuleName [] = False
looksLikeModuleName (c:cs) = isUpper c && go cs
where go [] = True
go ('.':cs) = looksLikeModuleName cs
go (c:cs) = (isAlphaNum c || c == '_' || c == '\'') && go cs
looksLikePackageName :: String -> Bool
looksLikePackageName = all (all isAlphaNum <&&> not . (all isDigit)) . split '-'
getCmd :: String -> Either String
(String, String)
getCmd s = case break isSpace $ dropWhile isSpace s of
([], _) -> Left ("Couldn't find command in " ++ show s)
res -> Right res
toCmdArgs :: String -> Either String
(String, [String])
toCmdArgs s = case getCmd s of
Left err -> Left err
Right (cmd, s') -> case toArgs s' of
Left err -> Left err
Right args -> Right (cmd, args)
toArgs :: String -> Either String
[String]
toArgs str
= case dropWhile isSpace str of
s@('[':_) -> case reads s of
[(args, spaces)]
| all isSpace spaces ->
Right args
_ ->
Left ("Couldn't read " ++ show str ++ " as [String]")
s -> toArgs' s
where
toArgs' :: String -> Either String [String]
toArgs' s = case dropWhile isSpace s of
[] -> Right []
('"' : _) -> do
(arg, rest) <- readAsString s
(arg:) `fmap` toArgs' rest
s' -> case break (isSpace <||> (== '"')) s' of
(argPart1, s''@('"':_)) -> do
(argPart2, rest) <- readAsString s''
((argPart1 ++ show argPart2):) `fmap` toArgs' rest
(arg, s'') -> (arg:) `fmap` toArgs' s''
readAsString :: String -> Either String (String, String)
readAsString s = case reads s of
[(arg, rest)]
| all isSpace (take 1 rest) ->
Right (arg, rest)
_ ->
Left ("Couldn't read " ++ show s ++ " as String")
exactLog2 :: Integer -> Maybe Integer
exactLog2 x
| x <= 0 = Nothing
| x > fromIntegral (maxBound :: Int32) = Nothing
| x' .&. (x') /= x' = Nothing
| otherwise = Just (fromIntegral c)
where
x' = fromIntegral x :: Int32
c = countTrailingZeros x'
readRational__ :: ReadS Rational
readRational__ r = do
((i, e), t) <- readSignificandExponentPair__ r
return ((i%1)*10^^e, t)
readRational :: String -> Rational
readRational top_s
= case top_s of
'-' : xs -> (read_me xs)
xs -> read_me xs
where
read_me s
= case (do { (x,"") <- readRational__ s ; return x }) of
[x] -> x
[] -> error ("readRational: no parse:" ++ top_s)
_ -> error ("readRational: ambiguous parse:" ++ top_s)
readSignificandExponentPair__ :: ReadS (Integer, Integer)
readSignificandExponentPair__ r = do
(n,d,s) <- readFix r
(k,t) <- readExp s
let pair = (n, toInteger (k d))
return (pair, t)
where
readFix r = do
(ds,s) <- lexDecDigits r
(ds',t) <- lexDotDigits s
return (read (ds++ds'), length ds', t)
readExp (e:s) | e `elem` "eE" = readExp' s
readExp s = return (0,s)
readExp' ('+':s) = readDec s
readExp' ('-':s) = do (k,t) <- readDec s
return (k,t)
readExp' s = readDec s
readDec s = do
(ds,r) <- nonnull isDigit s
return (foldl1 (\n d -> n * 10 + d) [ ord d ord '0' | d <- ds ],
r)
lexDecDigits = nonnull isDigit
lexDotDigits ('.':s) = return (span' isDigit s)
lexDotDigits s = return ("",s)
nonnull p s = do (cs@(_:_),t) <- return (span' p s)
return (cs,t)
span' _ xs@[] = (xs, xs)
span' p xs@(x:xs')
| x == '_' = span' p xs'
| p x = let (ys,zs) = span' p xs' in (x:ys,zs)
| otherwise = ([],xs)
readSignificandExponentPair :: String -> (Integer, Integer)
readSignificandExponentPair top_s
= case top_s of
'-' : xs -> let (i, e) = read_me xs in (i, e)
xs -> read_me xs
where
read_me s
= case (do { (x,"") <- readSignificandExponentPair__ s ; return x }) of
[x] -> x
[] -> error ("readSignificandExponentPair: no parse:" ++ top_s)
_ -> error ("readSignificandExponentPair: ambiguous parse:" ++ top_s)
readHexRational :: String -> Rational
readHexRational str =
case str of
'-' : xs -> (readMe xs)
xs -> readMe xs
where
readMe as =
case readHexRational__ as of
Just n -> n
_ -> error ("readHexRational: no parse:" ++ str)
readHexRational__ :: String -> Maybe Rational
readHexRational__ ('0' : x : rest)
| x == 'X' || x == 'x' =
do let (front,rest2) = span' isHexDigit rest
guard (not (null front))
let frontNum = steps 16 0 front
case rest2 of
'.' : rest3 ->
do let (back,rest4) = span' isHexDigit rest3
guard (not (null back))
let backNum = steps 16 frontNum back
exp1 = 4 * length back
case rest4 of
p : ps | isExp p -> fmap (mk backNum . (+ exp1)) (getExp ps)
_ -> return (mk backNum exp1)
p : ps | isExp p -> fmap (mk frontNum) (getExp ps)
_ -> Nothing
where
isExp p = p == 'p' || p == 'P'
getExp ('+' : ds) = dec ds
getExp ('-' : ds) = fmap negate (dec ds)
getExp ds = dec ds
mk :: Integer -> Int -> Rational
mk n e = fromInteger n * 2^^e
dec cs = case span' isDigit cs of
(ds,"") | not (null ds) -> Just (steps 10 0 ds)
_ -> Nothing
steps base n ds = List.foldl' (step base) n ds
step base n d = base * n + fromIntegral (digitToInt d)
span' _ xs@[] = (xs, xs)
span' p xs@(x:xs')
| x == '_' = span' p xs'
| p x = let (ys,zs) = span' p xs' in (x:ys,zs)
| otherwise = ([],xs)
readHexRational__ _ = Nothing
readHexSignificandExponentPair :: String -> (Integer, Integer)
readHexSignificandExponentPair str =
case str of
'-' : xs -> let (i, e) = readMe xs in (i, e)
xs -> readMe xs
where
readMe as =
case readHexSignificandExponentPair__ as of
Just n -> n
_ -> error ("readHexSignificandExponentPair: no parse:" ++ str)
readHexSignificandExponentPair__ :: String -> Maybe (Integer, Integer)
readHexSignificandExponentPair__ ('0' : x : rest)
| x == 'X' || x == 'x' =
do let (front,rest2) = span' isHexDigit rest
guard (not (null front))
let frontNum = steps 16 0 front
case rest2 of
'.' : rest3 ->
do let (back,rest4) = span' isHexDigit rest3
guard (not (null back))
let backNum = steps 16 frontNum back
exp1 = 4 * length back
case rest4 of
p : ps | isExp p -> fmap (mk backNum . (+ exp1)) (getExp ps)
_ -> return (mk backNum exp1)
p : ps | isExp p -> fmap (mk frontNum) (getExp ps)
_ -> Nothing
where
isExp p = p == 'p' || p == 'P'
getExp ('+' : ds) = dec ds
getExp ('-' : ds) = fmap negate (dec ds)
getExp ds = dec ds
mk :: Integer -> Int -> (Integer, Integer)
mk n e = (n, fromIntegral e)
dec cs = case span' isDigit cs of
(ds,"") | not (null ds) -> Just (steps 10 0 ds)
_ -> Nothing
steps base n ds = foldl' (step base) n ds
step base n d = base * n + fromIntegral (digitToInt d)
span' _ xs@[] = (xs, xs)
span' p xs@(x:xs')
| x == '_' = span' p xs'
| p x = let (ys,zs) = span' p xs' in (x:ys,zs)
| otherwise = ([],xs)
readHexSignificandExponentPair__ _ = Nothing
doesDirNameExist :: FilePath -> IO Bool
doesDirNameExist fpath = doesDirectoryExist (takeDirectory fpath)
getModificationUTCTime :: FilePath -> IO UTCTime
getModificationUTCTime = getModificationTime
modificationTimeIfExists :: FilePath -> IO (Maybe UTCTime)
modificationTimeIfExists f =
(do t <- getModificationUTCTime f; return (Just t))
`catchIO` \e -> if isDoesNotExistError e
then return Nothing
else ioError e
withAtomicRename :: (MonadIO m) => FilePath -> (FilePath -> m a) -> m a
withAtomicRename targetFile f = do
let temp = targetFile <.> "tmp"
res <- f temp
liftIO $ renameFile temp targetFile
return res
splitLongestPrefix :: String -> (Char -> Bool) -> (String,String)
splitLongestPrefix str pred
| null r_pre = (str, [])
| otherwise = (reverse (tail r_pre), reverse r_suf)
where (r_suf, r_pre) = break pred (reverse str)
escapeSpaces :: String -> String
escapeSpaces = foldr (\c s -> if isSpace c then '\\':c:s else c:s) ""
type Suffix = String
data Direction = Forwards | Backwards
reslash :: Direction -> FilePath -> FilePath
reslash d = f
where f ('/' : xs) = slash : f xs
f ('\\' : xs) = slash : f xs
f (x : xs) = x : f xs
f "" = ""
slash = case d of
Forwards -> '/'
Backwards -> '\\'
makeRelativeTo :: FilePath -> FilePath -> FilePath
this `makeRelativeTo` that = directory </> thisFilename
where (thisDirectory, thisFilename) = splitFileName this
thatDirectory = dropFileName that
directory = joinPath $ f (splitPath thisDirectory)
(splitPath thatDirectory)
f (x : xs) (y : ys)
| x == y = f xs ys
f xs ys = replicate (length ys) ".." ++ xs
abstractConstr :: String -> Constr
abstractConstr n = mkConstr (abstractDataType n) ("{abstract:"++n++"}") [] Prefix
abstractDataType :: String -> DataType
abstractDataType n = mkDataType n [abstractConstr n]
charToC :: Word8 -> String
charToC w =
case chr (fromIntegral w) of
'\"' -> "\\\""
'\'' -> "\\\'"
'\\' -> "\\\\"
c | c >= ' ' && c <= '~' -> [c]
| otherwise -> ['\\',
chr (ord '0' + ord c `div` 64),
chr (ord '0' + ord c `div` 8 `mod` 8),
chr (ord '0' + ord c `mod` 8)]
hashString :: String -> Int32
hashString = foldl' f golden
where f m c = fromIntegral (ord c) * magic + hashInt32 m
magic = fromIntegral (0xdeadbeef :: Word32)
golden :: Int32
golden = 1013904242
hashInt32 :: Int32 -> Int32
hashInt32 x = mulHi x golden + x
mulHi :: Int32 -> Int32 -> Int32
mulHi a b = fromIntegral (r `shiftR` 32)
where r :: Int64
r = fromIntegral a * fromIntegral b
#if defined(DEBUG)
type HasDebugCallStack = HasCallStack
#else
type HasDebugCallStack = (() :: Constraint)
#endif
data OverridingBool
= Auto
| Always
| Never
deriving Show
overrideWith :: Bool -> OverridingBool -> Bool
overrideWith b Auto = b
overrideWith _ Always = True
overrideWith _ Never = False