-- File created: 2009-01-30 14:54:14

module System.FilePath.Glob.Simplify (simplify) where

import System.FilePath.Glob.Base (Pattern(..), Token(..), liftP)

-- |Simplifies a 'Pattern' object: removes redundant @\"./\"@, for instance.
-- The resulting 'Pattern' matches the exact same input as the original one,
-- with some differences:
--
-- * The output of 'globDir' will differ: for example, globbing for @\"./\*\"@
--   gives @\"./foo\"@, but after simplification this'll be only @\"foo\"@.
--
-- * Decompiling the simplified 'Pattern' will obviously not give the original.
--
-- * The simplified 'Pattern' is a bit faster to match with and uses less
--   memory, since some redundant data is removed.
--
-- For the last of the above reasons, if you're performance-conscious and not
-- using 'globDir', you should always 'simplify' after calling 'compile'.
simplify :: Pattern -> Pattern
simplify :: Pattern -> Pattern
simplify = ([Token] -> [Token]) -> Pattern -> Pattern
liftP ([Token] -> [Token]
go ([Token] -> [Token]) -> ([Token] -> [Token]) -> [Token] -> [Token]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Token] -> [Token]
pre)
 where
   -- ./ at beginning -> nothing (any number of /'s)
   pre :: [Token] -> [Token]
pre (ExtSeparator:PathSeparator:xs :: [Token]
xs) = [Token] -> [Token]
pre ((Token -> Bool) -> [Token] -> [Token]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Token -> Bool
isSlash [Token]
xs)
   pre                             xs :: [Token]
xs  = [Token]
xs

   go :: [Token] -> [Token]
go [] = []

   -- /./ -> /
   go (PathSeparator:ExtSeparator:xs :: [Token]
xs@(PathSeparator:_)) = [Token] -> [Token]
go [Token]
xs

   go (x :: Token
x:xs :: [Token]
xs) =
      if Token -> Bool
isSlash Token
x
         then let (compressed :: [Token]
compressed,ys :: [Token]
ys) = (Token -> Bool) -> [Token] -> ([Token], [Token])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Token -> Bool
isSlash [Token]
xs
               in if [Token] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Token]
compressed
                     then Token
x Token -> [Token] -> [Token]
forall a. a -> [a] -> [a]
: [Token] -> [Token]
go [Token]
ys
                     else [Token] -> [Token]
go (Token
x Token -> [Token] -> [Token]
forall a. a -> [a] -> [a]
: [Token]
ys)
         else Token
x Token -> [Token] -> [Token]
forall a. a -> [a] -> [a]
: [Token] -> [Token]
go [Token]
xs

   isSlash :: Token -> Bool
isSlash PathSeparator = Bool
True
   isSlash _             = Bool
False