headed-megaparsec 0.2.0.2 → 0.2.1
raw patch · 5 files changed
+192/−223 lines, 5 filesdep ~megaparsecdep ~parser-combinatorssetup-changedPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: megaparsec, parser-combinators
API changes (from Hackage documentation)
+ HeadedMegaparsec: hidden :: (Ord err, Stream strm) => HeadedParsec err strm a -> HeadedParsec err strm a
Files
- Setup.hs +0/−2
- headed-megaparsec.cabal +3/−3
- library/HeadedMegaparsec.hs +165/−182
- library/HeadedMegaparsec/Megaparsec.hs +6/−9
- library/HeadedMegaparsec/Prelude.hs +18/−27
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
headed-megaparsec.cabal view
@@ -1,5 +1,5 @@ name: headed-megaparsec-version: 0.2.0.2+version: 0.2.1 category: Parsers, Parsing, Megaparsec synopsis: More informative parser homepage: https://github.com/nikita-volkov/headed-megaparsec@@ -28,6 +28,6 @@ build-depends: base >=4.12 && <5, case-insensitive >=1.2 && <2,- megaparsec >=9 && <10,- parser-combinators >=1.1 && <1.4,+ megaparsec >=9.2 && <10,+ parser-combinators >=1.3 && <1.4, selective >=0.5 && <0.6
library/HeadedMegaparsec.hs view
@@ -1,115 +1,108 @@ module HeadedMegaparsec-(- -- * Types- HeadedParsec,- -- * Execution- toParsec,- -- * Transformation- wrapToHead,- label,- dbg,- filter,- -- * Construction- parse,- endHead,-)+ ( -- * Types+ HeadedParsec,++ -- * Execution+ toParsec,++ -- * Transformation+ wrapToHead,+ label,+ hidden,+ dbg,+ filter,++ -- * Construction+ parse,+ endHead,+ ) where -import HeadedMegaparsec.Prelude hiding (try, head, tail, filter) import Control.Applicative.Combinators-import Text.Megaparsec (Parsec, Stream) import qualified HeadedMegaparsec.Megaparsec as Megaparsec+import HeadedMegaparsec.Prelude hiding (filter, head, tail, try)+import Text.Megaparsec (Parsec, Stream) import qualified Text.Megaparsec as Megaparsec-import qualified Text.Megaparsec.Debug as Megaparsec import qualified Text.Megaparsec.Char as MegaparsecChar import qualified Text.Megaparsec.Char.Lexer as MegaparsecLexer--{- $setup-->>> :set -XApplicativeDo+import qualified Text.Megaparsec.Debug as Megaparsec --}+-- $setup+--+-- >>> :set -XApplicativeDo -- * Types-------------------------- -{-|-Headed parser.--Abstracts over explicit composition between consecutive megaparsec `try` blocks,-providing for better error messages.--With headed parser you don't need to use `try` at all.--==__Examples__-->>> import Prelude->>> import Control.Applicative->>> import Data.Void->>> import qualified Text.Megaparsec as M->>> import qualified Text.Megaparsec.Char as M->>> import qualified Text.Megaparsec.Char.Lexer as ML->>> :{- let- select :: HeadedParsec Void String (Maybe [Either Char Int], Maybe Int)- select = do- string' "select"- endHead- _targets <- optional (space1 *> targets)- _limit <- optional (space1 *> limit)- return (_targets, _limit)- where- -- Lifted versions of basic parsers:- char = parse . M.char- space = parse M.space- space1 = parse M.space1- decimal = parse ML.decimal- string' = parse . M.string'- -- Syntax parsers:- targets = M.sepBy1 target commaSeparator- target = Left <$> char '*' <|> Right <$> decimal- commaSeparator = space *> char ',' *> endHead *> space- limit = string' "limit" *> endHead *> space1 *> decimal- test :: String -> IO ()- test = M.parseTest (toParsec select <* M.eof)-:}-->>> test "select 1, "-1:11:- |-1 | select 1, - | ^-unexpected end of input-expecting '*', integer, or white space-->>> test "select limit "-...-unexpected end of input-expecting integer or white space-->>> test "select 1, 2 limit 2"-(Just [Right 1,Right 2],Just 2)---}+-- |+-- Headed parser.+--+-- Abstracts over explicit composition between consecutive megaparsec `try` blocks,+-- providing for better error messages.+--+-- With headed parser you don't need to use `try` at all.+--+-- ==__Examples__+--+-- >>> import Prelude+-- >>> import Control.Applicative+-- >>> import Data.Void+-- >>> import qualified Text.Megaparsec as M+-- >>> import qualified Text.Megaparsec.Char as M+-- >>> import qualified Text.Megaparsec.Char.Lexer as ML+-- >>> :{+-- let+-- select :: HeadedParsec Void String (Maybe [Either Char Int], Maybe Int)+-- select = do+-- string' "select"+-- endHead+-- _targets <- optional (space1 *> targets)+-- _limit <- optional (space1 *> limit)+-- return (_targets, _limit)+-- where+-- -- Lifted versions of basic parsers:+-- char = parse . M.char+-- space = parse M.space+-- space1 = parse M.space1+-- decimal = parse ML.decimal+-- string' = parse . M.string'+-- -- Syntax parsers:+-- targets = M.sepBy1 target commaSeparator+-- target = Left <$> char '*' <|> Right <$> decimal+-- commaSeparator = space *> char ',' *> endHead *> space+-- limit = string' "limit" *> endHead *> space1 *> decimal+-- test :: String -> IO ()+-- test = M.parseTest (toParsec select <* M.eof)+-- :}+--+-- >>> test "select 1, "+-- 1:11:+-- |+-- 1 | select 1,+-- | ^+-- unexpected end of input+-- expecting '*', integer, or white space+--+-- >>> test "select limit "+-- ...+-- unexpected end of input+-- expecting integer or white space+--+-- >>> test "select 1, 2 limit 2"+-- (Just [Right 1,Right 2],Just 2) newtype HeadedParsec err strm a = HeadedParsec (Parsec err strm (Either a (Parsec err strm a))) -{-|-A helper required for hacking `dbg`.--}+-- |+-- A helper required for hacking `dbg`. data Showable a = Showable String a - -- * Instances-------------------------- -- ** Showable-------------------------- instance Show (Showable a) where show (Showable msg _) = msg -- ** HeadedParsec-------------------------- instance Functor (HeadedParsec err strm) where fmap fn (HeadedParsec p) = HeadedParsec (fmap (bimap fn (fmap fn)) p)@@ -123,17 +116,19 @@ junction2 <- p2 case junction2 of Left a -> return (Left (aToB a))- Right tailP2 -> return $ Right $ do- a <- tailP2- return (aToB a)- Right tailP1 -> return $ Right $ do- aToB <- tailP1- junction2 <- p2- case junction2 of- Left a -> return (aToB a)- Right tailP2 -> do- a <- tailP2- return (aToB a)+ Right tailP2 -> return $+ Right $ do+ a <- tailP2+ return (aToB a)+ Right tailP1 -> return $+ Right $ do+ aToB <- tailP1+ junction2 <- p2+ case junction2 of+ Left a -> return (aToB a)+ Right tailP2 -> do+ a <- tailP2+ return (aToB a) instance (Ord err, Stream strm) => Selective (HeadedParsec err strm) where select (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec $ do@@ -146,15 +141,16 @@ case junction2 of Left aToB -> return (Left (aToB a)) Right tailP2 -> return (Right (fmap ($ a) tailP2))- Right tailP1 -> return $ Right $ do- eitherAOrB <- tailP1- case eitherAOrB of- Right b -> return b- Left a -> do- junction2 <- p2- case junction2 of- Left aToB -> return (aToB a)- Right tailP2 -> fmap ($ a) tailP2+ Right tailP1 -> return $+ Right $ do+ eitherAOrB <- tailP1+ case eitherAOrB of+ Right b -> return b+ Left a -> do+ junction2 <- p2+ case junction2 of+ Left aToB -> return (aToB a)+ Right tailP2 -> fmap ($ a) tailP2 instance (Ord err, Stream strm) => Monad (HeadedParsec err strm) where return = pure@@ -162,22 +158,21 @@ junction1 <- p1 case junction1 of Left a -> case k2 a of HeadedParsec p2 -> p2- Right tailP1 -> return $ Right $ do- a <- tailP1- Megaparsec.contPossibly $ case k2 a of HeadedParsec p2 -> p2+ Right tailP1 -> return $+ Right $ do+ a <- tailP1+ Megaparsec.contPossibly $ case k2 a of HeadedParsec p2 -> p2 -{-|-Alternation is performed only the basis of heads.-Bodies do not participate.--}+-- |+-- Alternation is performed only the basis of heads.+-- Bodies do not participate. instance (Ord err, Stream strm) => Alternative (HeadedParsec err strm) where empty = HeadedParsec empty (<|>) (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec (Megaparsec.try p1 <|> p2) -{-|-Alternation is performed only the basis of heads.-Bodies do not participate.--}+-- |+-- Alternation is performed only the basis of heads.+-- Bodies do not participate. instance (Ord err, Stream strm) => MonadPlus (HeadedParsec err strm) where mzero = empty mplus = (<|>)@@ -185,115 +180,103 @@ instance (Ord err, Stream strm) => MonadFail (HeadedParsec err strm) where fail = HeadedParsec . fail - -- * Execution-------------------------- -{-|-Convert headed parser into megaparsec parser.--}+-- |+-- Convert headed parser into megaparsec parser. toParsec :: (Ord err, Stream strm) => HeadedParsec err strm a -> Parsec err strm a toParsec (HeadedParsec p) = Megaparsec.contPossibly p - -- * Helpers-------------------------- mapParsec :: (Parsec err1 strm1 (Either res1 (Parsec err1 strm1 res1)) -> Parsec err2 strm2 (Either res2 (Parsec err2 strm2 res2))) -> HeadedParsec err1 strm1 res1 -> HeadedParsec err2 strm2 res2 mapParsec fn (HeadedParsec p) = HeadedParsec (fn p) - -- * Transformation-------------------------- -{-|-Wrap a parser to be usable as a whole in a head block,-allowing it in effect to be composed with the following parsers into a single `try` when executed,-no matter whether it contains `endHead` or not.--}+-- |+-- Wrap a parser to be usable as a whole in a head block,+-- allowing it in effect to be composed with the following parsers into a single `try` when executed,+-- no matter whether it contains `endHead` or not. wrapToHead :: (Ord err, Stream strm) => HeadedParsec err strm a -> HeadedParsec err strm a wrapToHead = mapParsec $ fmap Left . Megaparsec.contPossibly -{-|-Label a headed parser.-Works the same way as megaparsec's `Megaparsec.label`.--}+-- |+-- Label a headed parser.+-- Works the same way as megaparsec's `Megaparsec.label`. label :: (Ord err, Stream strm) => String -> HeadedParsec err strm a -> HeadedParsec err strm a label label = mapParsec (Megaparsec.label label) -{-|-Make a parser print debugging information when evaluated.-The first parameter is a custom label.+-- |+-- Adaptation of 'Megaparsec.hidden'.+hidden :: (Ord err, Stream strm) => HeadedParsec err strm a -> HeadedParsec err strm a+hidden = mapParsec Megaparsec.hidden -This function is a wrapper around `Megaparsec.dbg`.-It generates two debugging entries: one for head and one for tail.--}+-- |+-- Make a parser print debugging information when evaluated.+-- The first parameter is a custom label.+--+-- This function is a wrapper around `Megaparsec.dbg`.+-- It generates two debugging entries: one for head and one for tail. dbg :: (Ord err, Megaparsec.ShowErrorComponent err, Megaparsec.VisualStream strm, Show a) => String -> HeadedParsec err strm a -> HeadedParsec err strm a-dbg label = mapParsec $ \ p -> do- Showable _ junction <- Megaparsec.dbg (label <> "/head") (fmap (either (\ a -> Showable (show a) (Left a)) (Showable "<tail parser>" . Right)) p)+dbg label = mapParsec $ \p -> do+ Showable _ junction <- Megaparsec.dbg (label <> "/head") (fmap (either (\a -> Showable (show a) (Left a)) (Showable "<tail parser>" . Right)) p) case junction of Left a -> return (Left a) Right tailP -> return $ Right $ Megaparsec.dbg (label <> "/tail") tailP -{-|-Filter the results of parser based on a predicate,-failing with a parameterized message.--}+-- |+-- Filter the results of parser based on a predicate,+-- failing with a parameterized message. filter :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> HeadedParsec err strm a -> HeadedParsec err strm a-filter err pred = mapParsec $ \ p -> do+filter err pred = mapParsec $ \p -> do junction <- p case junction of- Left a -> if pred a- then return (Left a)- else fail (err a)- Right tailP -> return $ Right $ do- a <- tailP+ Left a -> if pred a- then return a+ then return (Left a) else fail (err a)-+ Right tailP -> return $+ Right $ do+ a <- tailP+ if pred a+ then return a+ else fail (err a) -- *-------------------------- -{-|-Lift a megaparsec parser as a head parser.--}+-- |+-- Lift a megaparsec parser as a head parser. head :: (Ord err, Stream strm) => Parsec err strm a -> HeadedParsec err strm a head = HeadedParsec . fmap Left -{-|-Lift a megaparsec parser as a tail parser.--Composing consecutive tails results in one tail.--Composing consecutive head and tail leaves the head still composable with preceding head.--}+-- |+-- Lift a megaparsec parser as a tail parser.+--+-- Composing consecutive tails results in one tail.+--+-- Composing consecutive head and tail leaves the head still composable with preceding head. tail :: (Stream strm) => Parsec err strm a -> HeadedParsec err strm a tail = HeadedParsec . return . Right -{-|-Lift both head and tail megaparsec parsers, composing their results.--}+-- |+-- Lift both head and tail megaparsec parsers, composing their results. headAndTail :: (Ord err, Stream strm) => (head -> tail -> a) -> Parsec err strm head -> Parsec err strm tail -> HeadedParsec err strm a headAndTail fn headP tailP = HeadedParsec $ do a <- headP- return $ Right $ do- b <- tailP- return (fn a b)+ return $+ Right $ do+ b <- tailP+ return (fn a b) -{-|-Lift a megaparsec parser.--}+-- |+-- Lift a megaparsec parser. parse :: (Ord err, Stream strm) => Parsec err strm a -> HeadedParsec err strm a parse = head - -- * Control-------------------------- -{-|-Make all the following parsers compose as tail.--}+-- |+-- Make all the following parsers compose as tail. endHead :: (Stream strm) => HeadedParsec err strm () endHead = HeadedParsec (return (Right (return ())))
library/HeadedMegaparsec/Megaparsec.hs view
@@ -1,15 +1,12 @@-{-|-Extra megaparsec combinators.--}-module HeadedMegaparsec.Megaparsec-where+-- |+-- Extra megaparsec combinators.+module HeadedMegaparsec.Megaparsec where -import HeadedMegaparsec.Prelude hiding (try, head, body)-import Text.Megaparsec hiding (some, endBy1, someTill, sepBy1, sepEndBy1)-import Text.Megaparsec.Char import Control.Applicative.Combinators+import HeadedMegaparsec.Prelude hiding (body, head, try)+import Text.Megaparsec hiding (endBy1, sepBy1, sepEndBy1, some, someTill)+import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as Lexer- contPossibly :: (Ord err, Stream strm) => Parsec err strm (Either a (Parsec err strm a)) -> Parsec err strm a contPossibly p = do
library/HeadedMegaparsec/Prelude.hs view
@@ -1,24 +1,23 @@ module HeadedMegaparsec.Prelude-( - module Exports,-)+ ( module Exports,+ ) where --- base-------------------------- import Control.Applicative as Exports import Control.Arrow as Exports hiding (first, second) import Control.Category as Exports import Control.Concurrent as Exports import Control.Exception as Exports-import Control.Monad as Exports hiding (fail, mapM_, sequence_, forM_, msum, mapM, sequence, forM)-import Control.Monad.IO.Class as Exports+import Control.Monad as Exports hiding (fail, forM, forM_, mapM, mapM_, msum, sequence, sequence_) import Control.Monad.Fail as Exports import Control.Monad.Fix as Exports hiding (fix)+import Control.Monad.IO.Class as Exports import Control.Monad.ST as Exports+import Control.Selective as Exports import Data.Bifunctor as Exports import Data.Bits as Exports import Data.Bool as Exports+import Data.CaseInsensitive as Exports (CI, FoldCase) import Data.Char as Exports import Data.Coerce as Exports import Data.Complex as Exports@@ -30,18 +29,18 @@ import Data.Function as Exports hiding (id, (.)) import Data.Functor as Exports import Data.Functor.Identity as Exports-import Data.Int as Exports import Data.IORef as Exports+import Data.Int as Exports import Data.Ix as Exports-import Data.List as Exports hiding (sortOn, isSubsequenceOf, uncons, concat, foldr, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, find, maximumBy, minimumBy, mapAccumL, mapAccumR, foldl')-import Data.List.NonEmpty as Exports (NonEmpty(..))+import Data.List as Exports hiding (all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1, isSubsequenceOf, mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sortOn, sum, uncons)+import Data.List.NonEmpty as Exports (NonEmpty (..)) import Data.Maybe as Exports-import Data.Monoid as Exports hiding (Last(..), First(..), (<>))+import Data.Monoid as Exports hiding (First (..), Last (..), (<>)) import Data.Ord as Exports import Data.Proxy as Exports import Data.Ratio as Exports-import Data.Semigroup as Exports import Data.STRef as Exports+import Data.Semigroup as Exports import Data.String as Exports import Data.Traversable as Exports import Data.Tuple as Exports@@ -53,13 +52,12 @@ import Foreign.ForeignPtr as Exports import Foreign.Ptr as Exports import Foreign.StablePtr as Exports-import Foreign.Storable as Exports hiding (sizeOf, alignment)-import GHC.Conc as Exports hiding (orElse, withMVar, threadWaitWriteSTM, threadWaitWrite, threadWaitReadSTM, threadWaitRead)-import GHC.Exts as Exports (lazy, inline, sortWith, groupWith, IsList(fromList, Item))+import Foreign.Storable as Exports hiding (alignment, sizeOf)+import GHC.Conc as Exports hiding (orElse, threadWaitRead, threadWaitReadSTM, threadWaitWrite, threadWaitWriteSTM, withMVar)+import GHC.Exts as Exports (IsList (Item, fromList), groupWith, inline, lazy, sortWith) import GHC.Generics as Exports (Generic, Generic1) import GHC.IO.Exception as Exports import Numeric as Exports-import Prelude as Exports hiding (fail, concat, foldr, mapM_, sequence_, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, mapM, sequence, id, (.)) import System.Environment as Exports import System.Exit as Exports import System.IO as Exports@@ -69,15 +67,8 @@ import System.Mem.StableName as Exports import System.Timeout as Exports import Text.ParserCombinators.ReadP as Exports (ReadP, ReadS, readP_to_S, readS_to_P)-import Text.ParserCombinators.ReadPrec as Exports (ReadPrec, readPrec_to_P, readP_to_Prec, readPrec_to_S, readS_to_Prec)-import Text.Printf as Exports (printf, hPrintf)-import Text.Read as Exports (Read(..), readMaybe, readEither)+import Text.ParserCombinators.ReadPrec as Exports (ReadPrec, readP_to_Prec, readPrec_to_P, readPrec_to_S, readS_to_Prec)+import Text.Printf as Exports (hPrintf, printf)+import Text.Read as Exports (Read (..), readEither, readMaybe) import Unsafe.Coerce as Exports---- selective---------------------------import Control.Selective as Exports---- case-insensitive---------------------------import Data.CaseInsensitive as Exports (CI, FoldCase)+import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, fail, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))