    {-# LANGUAGE PatternGuards #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Distribution.Lex
    -- Copyright   :  Ben Gamari 2015-2019
    --
    -- Maintainer  :  cabal-devel@haskell.org
    -- Portability :  portable
    --
    -- This module contains a simple lexer supporting quoted strings

    module Distribution.Lex (
            tokenizeQuotedWords
     ) where

    import Data.Char (isSpace)
    import Distribution.Compat.Semigroup as Semi

    newtype DList a = DList ([a] -> [a])

    runDList :: DList a -> [a]
    runDList (DList run) = run []

    singleton :: a -> DList a
    singleton a = DList (a:)

    instance Monoid (DList a) where
      mempty = DList id
      mappend = (Semi.<>)

    instance Semigroup (DList a) where
      DList a <> DList b = DList (a . b)

    tokenizeQuotedWords :: String -> [String]
    tokenizeQuotedWords = filter (not . null) . go False mempty
      where
        go :: Bool        -- ^ in quoted region
           -> DList Char  -- ^ accumulator
           -> String      -- ^ string to be parsed
           -> [String]    -- ^ parse result
        go _ accum []
          | [] <- accum' = []
          | otherwise    = [accum']
          where accum' = runDList accum

        go False  accum (c:cs)
          | isSpace c = runDList accum : go False mempty cs
          | c == '"'  = go True accum cs

        go True   accum (c:cs)
          | c == '"'  = go False accum cs

        go quoted accum (c:cs)
                      = go quoted (accum `mappend` singleton c) cs