module Language.Core.Utils (everywhereExcept, everywhereExceptM, noNames, notNull, expectJust, fixedPointBy, applyPasses, varsIn, dupsBy, everywhere'Except, everywhere'But, wordsBy) where import Data.Generics import Data.List import Data.Maybe import qualified Data.Set as S everywhereExcept :: Data a => GenericT -> a -> a everywhereExcept = everywhereBut (mkQ False (\ (_::String) -> True)) everywhere'Except :: Data a => GenericT -> a -> a everywhere'Except = everywhere'But (mkQ False (\ (_::String) -> True)) everywhereExceptM :: (Data a, Monad m) => GenericM m -> a -> m a everywhereExceptM = everywhereButM (mkQ False (\ (_::String) -> True)) noNames :: Data a => r -> (r -> r -> r) -> GenericQ r -> a -> r noNames e c = everythingBut e c (mkQ False (\ (_::String) -> True)) everythingBut :: r -> (r -> r -> r) -> GenericQ Bool -> GenericQ r -> GenericQ r everythingBut empty combine q q1 x | q x = empty | otherwise = q1 x `combine` (foldl' combine empty (gmapQ (everythingBut empty combine q q1) x)) everywhere'But :: GenericQ Bool -> GenericT -> GenericT -- Guarded to let traversal cease if predicate q holds for x everywhere'But q f x | q x = x | otherwise = let top = f x in top `seq` (gmapT (everywhere'But q f) top) everywhereButM :: Monad m => GenericQ Bool -> GenericM m -> GenericM m everywhereButM q f x | q x = return x | otherwise = (gmapM (everywhereButM q f) x) >>= f notNull :: [a] -> Bool notNull = not . null expectJust :: String -> Maybe a -> a expectJust s = fromMaybe (error s) fixedPointBy :: (a -> a -> Bool) -> (a -> a) -> a -> a fixedPointBy done trans start = go start where go v = let next = trans v in if done v next then next else go next applyPasses :: [a -> a] -> a -> a applyPasses passes p = -- trace ("p = " ++ show p) $ foldl' (\ p' nextF -> nextF p') p passes varsIn :: (Ord b, Typeable b, Data a) => a -> S.Set b varsIn = noNames S.empty S.union (mkQ S.empty (\ v -> S.singleton v)) dupsBy :: (a -> a -> Bool) -> [a] -> [a] dupsBy (~=) xs = filter (\ x -> length (filter (~= x) xs) > 1) xs wordsBy :: Eq a => a -> [a] -> [[a]] wordsBy _ [] = [[]] wordsBy y (x:xs) | y == x = [x]:(wordsBy y xs) wordsBy y (x:xs) = case wordsBy y xs of (z:zs) -> (x:z):zs [] -> [[y]]