HarmTrace-Base-1.1.0.2: src/HarmTrace/Base/Parsing.hs
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE FlexibleContexts #-}
--------------------------------------------------------------------------------
-- |
-- Module : HarmTrace.Base.Parsing
-- Copyright : (c) 2012--2013 W. Bas de Haas and Jose Pedro Magalhaes
-- License : LGPL-3
--
-- Maintainer : bas@chordify.net, dreixel@chordify.net
-- Stability : experimental
-- Portability : non-portable
--
-- Summary: Some general parsing utilities used for parsing textual chord
-- representations.
--------------------------------------------------------------------------------
module HarmTrace.Base.Parsing ( -- * Top level parsers
parseData
, parseDataWithErrors
, parseDataSafe
-- * Some general parsers
, pString
, pLineEnd
, pManyTill
-- Re-exporting the uu-parsinglib
, module Data.ListLike.Base
, module Text.ParserCombinators.UU
, module Text.ParserCombinators.UU.Utils
, module Text.ParserCombinators.UU.BasicInstances
) 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))
-- | Toplevel 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 )
-- | Toplevel 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