From 7ae66425ab8f771463303c708f0dff3d69974800 Mon Sep 17 00:00:00 2001 From: Maxim Koltsov Date: Thu, 4 Jun 2020 23:05:16 +0300 Subject: [PATCH] Improve list parser Current parser for lists, like `packages:` in `cabal.project.local`, fails to process some input, for example: packages: foo/foo.cabal , bar/bar.cabal , baz/baz.cabal This commit simplifies the parser by using `sepBy` directly and by handling indented fields more uniformly. --- src/Hie/Cabal/Parser.hs | 26 ++++++++++++++++---------- test/Spec.hs | 4 ++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Hie/Cabal/Parser.hs b/src/Hie/Cabal/Parser.hs index 92633f0..488d1b5 100644 --- a/src/Hie/Cabal/Parser.hs +++ b/src/Hie/Cabal/Parser.hs @@ -6,6 +6,7 @@ import Control.Applicative import Control.Monad import Data.Attoparsec.Text import Data.Char +import Data.Functor import Data.Maybe import Data.Text (Text) import qualified Data.Text as T @@ -92,19 +93,24 @@ parseString = parseQuoted <|> unqualName unqualName :: Parser Text unqualName = takeWhile1 (not . (\c -> isSpace c || c == ',')) +-- | Skip spaces and if enf of line is reached, skip it as well and require that +-- next one starts with indent. +-- +-- Used for parsing fields. +optSkipToNextLine :: Indent -> Parser () +optSkipToNextLine i = do + skipMany $ satisfy (\c -> isSpace c && not (isEndOfLine c)) + mChar <- peekChar + case mChar of + Just c | isEndOfLine c -> + char c *> indent i $> () + _ -> pure () + +-- | Comma or space separated list, with optional new lines. parseList :: Indent -> Parser [Text] parseList i = items <|> (emptyOrComLine >> indent i >> items) where - items = do - skipMany tabOrSpace - h <- parseString - skipMany tabOrSpace - skipMany (char ',') - t <- - items - <|> (skipToNextLine >> indent i >> parseList i) - <|> pure [] - pure $ h : t + items = sepBy parseString (optSkipToNextLine i *> skipMany (char ',') *> optSkipToNextLine i) pathMain :: Indent -> [Text] -> Text -> [Text] -> [Text] -> Parser [Text] pathMain i p m o a = diff --git a/test/Spec.hs b/test/Spec.hs index ed378ee..917412e 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -86,6 +86,10 @@ spec = do $ it "quoted list" $ ("\"one\"\n two\n three3" :: Text) ~> parseList 1 `shouldParse` ["one", "two", "three3"] + describe "Should Succeed" + $ it "list with leading commas" + $ ("one\n , two\n , three3" :: Text) ~> parseList 1 + `shouldParse` ["one", "two", "three3"] exeSection :: Text exeSection =