{-# OPTIONS_GHC -Wall #-} {-# LANGUAGE FlexibleContexts #-} -------------------------------------------------------------------------------- -- | -- Module : HarmTrace.Base.Parse.General -- Copyright : (c) 2012--2016, Chordify BV -- License : LGPL-3 -- -- Maintainer : haskelldevelopers@chordify.net -- Stability : experimental -- Portability : non-portable -- -- Summary: Some general parsing utilities used for parsing textual chord -- representations. -------------------------------------------------------------------------------- module HarmTrace.Base.Parse.General ( -- * Top level parsers parseData , parseDataWithErrors , parseDataSafe -- * Some general parsers , pString , pLineEnd , pManyTill -- Re-exporting the uu-parsinglib , module Text.ParserCombinators.UU , module Text.ParserCombinators.UU.Utils , module Text.ParserCombinators.UU.BasicInstances -- , module Data.ListLike.Base ) where import Text.ParserCombinators.UU import Text.ParserCombinators.UU.Utils hiding ( pSpaces ) import Text.ParserCombinators.UU.BasicInstances hiding ( IsLocationUpdatedBy ) import Data.ListLike.Base ( ListLike ) import Data.List ( intersperse ) -------------------------------------------------------------------------------- -- A collection of parsing functions used by parsers throughout the project -------------------------------------------------------------------------------- -- | This is identical to 'parseData' however it will throw an 'error' when -- the the list with parsing errors is not empty. No, this will not make your -- program more \safe\. However, in certain cases you really want to be sure -- that parsing has finished without errors. In those cases you should use -- 'parseDataSafe'. parseDataSafe :: (ListLike s a, Show a, Show s) => P (Str a s LineColPos) b -> s -> b parseDataSafe p inp = case parseDataWithErrors p inp of (dat, [] ) -> dat (_ , err) -> error ("HarmTrace.Base.Parsing: a parsing" ++ " function did not finish without errors. While" ++ " parsing the data starting with:\n" ++ (take 80 $ show inp) ++ "\nThe following errors were encountered:\n" ++ (concat . intersperse "\n" . take 50 . map show $ err)) -- | Top-level parser that ignores error-reporting, regardless of there were -- error in the parse parseData :: (ListLike s a, Show a) => P (Str a s LineColPos) b -> s -> b parseData p inp = fst ( parseDataWithErrors p inp ) -- | Top-level parser that returns both the result as well as a (possibly empty) -- list of error-corrections. parseDataWithErrors :: (ListLike s a, Show a) => P (Str a s LineColPos) b -> s -> (b, [Error LineColPos]) parseDataWithErrors p inp = (parse ( (,) <$> p <*> pEnd) (createStr (LineColPos 0 0 0) inp)) -- | Parses a specific string pString :: (ListLike state a, IsLocationUpdatedBy loc a, Show a, Eq a) => [a] -> P (Str a state loc) [a] {-# INLINABLE pString #-} pString s = foldr (\a b -> (:) <$> a <*> b) (pure []) (map pSym s) -- | Parses UNIX and DOS/WINDOWS line endings including trailing whitespace pLineEnd :: Parser String pLineEnd = pString "\n" <|> pString "\r\n" <|> pString " " <|> pString "\t" -- | Parses an arbitrary times the first parsing combinator until the parsing -- second parsing combinator is encountered. The result of the second parsing -- combinator is ignored. pManyTill :: P st a -> P st b -> P st [a] pManyTill p end = [] <$ end <<|> (:) <$> p <*> pManyTill p end