diff --git a/Cabal/src/Distribution/Lex.hs b/Cabal/src/Distribution/Lex.hs index 4c8eb8f6734..753d6ce4d36 100644 --- a/Cabal/src/Distribution/Lex.hs +++ b/Cabal/src/Distribution/Lex.hs @@ -1,5 +1,3 @@ ------------------------------------------------------------------------------ - -- | -- Module : Distribution.Lex -- Copyright : Ben Gamari 2015-2019 @@ -12,39 +10,38 @@ module Distribution.Lex ( tokenizeQuotedWords ) where -import Distribution.Compat.DList import Distribution.Compat.Prelude import Prelude () -- | A simple parser supporting quoted strings. -- -- Please be aware that this will only split strings when seeing whitespace --- outside of quotation marks, i.e, @"foo\"bar baz\"qux quux"@ will be --- converted to @["foobar bazqux", "quux"]@. +-- outside of quotation marks; +-- +-- > foo"bar baz"qux quux +-- +-- >>> tokenizeQuotedWords "foo\"bar baz\"qux quux" +-- ["foobar bazqux","quux"] -- --- This behavior can be useful when parsing text like --- @"ghc-options: -Wl,\"some option with spaces\""@, for instance. +-- This behavior can be useful when parsing text like; +-- +-- > ghc-options: -Wl,"some option with spaces" +-- +-- >>> tokenizeQuotedWords "ghc-options: -Wl,\"some option with spaces\"" +-- ["ghc-options:","-Wl,some option with spaces"] tokenizeQuotedWords :: String -> [String] -tokenizeQuotedWords = filter (not . null) . go False mempty +tokenizeQuotedWords xs = repack $ foldr alg (const ([] :| [])) xs False 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 <> singleton c) cs + repack :: NonEmpty String -> [String] + repack (zs :| acc) = if null zs then acc else zs : acc + + alg + :: Char -- current character + -> (Bool -> NonEmpty String) -- continuation, depending on whether we are in a quoted region or not + -> Bool -- are we in a quoted region? + -> NonEmpty String + alg '"' rest mode = rest (not mode) + alg c rest False + | isSpace c = [] :| repack (rest False) + alg c rest mode = case rest mode of + w :| ws -> (c : w) :| ws