packages feed

headed-megaparsec 0.1.0.2 → 0.1.0.3

raw patch · 4 files changed

+432/−299 lines, 4 filesdep ~selectivePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: selective

API changes (from Hackage documentation)

- HeadedMegaparsec: data HeadedParsec err strm a
- HeadedMegaparsec: dbg :: (Ord err, ShowErrorComponent err, Stream strm, Show a) => String -> HeadedParsec err strm a -> HeadedParsec err strm a
- HeadedMegaparsec: endHead :: Stream strm => HeadedParsec err strm ()
- HeadedMegaparsec: filter :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> HeadedParsec err strm a -> HeadedParsec err strm a
- HeadedMegaparsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => Control.Monad.Fail.MonadFail (HeadedMegaparsec.HeadedParsec err strm)
- HeadedMegaparsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => Control.Selective.Selective (HeadedMegaparsec.HeadedParsec err strm)
- HeadedMegaparsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Alternative (HeadedMegaparsec.HeadedParsec err strm)
- HeadedMegaparsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Applicative (HeadedMegaparsec.HeadedParsec err strm)
- HeadedMegaparsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Monad (HeadedMegaparsec.HeadedParsec err strm)
- HeadedMegaparsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.MonadPlus (HeadedMegaparsec.HeadedParsec err strm)
- HeadedMegaparsec: instance GHC.Base.Functor (HeadedMegaparsec.HeadedParsec err strm)
- HeadedMegaparsec: instance GHC.Show.Show (HeadedMegaparsec.Showable a)
- HeadedMegaparsec: label :: (Ord err, Stream strm) => String -> HeadedParsec err strm a -> HeadedParsec err strm a
- HeadedMegaparsec: parse :: (Ord err, Stream strm) => Parsec err strm a -> HeadedParsec err strm a
- HeadedMegaparsec: toParsec :: (Ord err, Stream strm) => HeadedParsec err strm a -> Parsec err strm a
- HeadedMegaparsec: wrapToHead :: (Ord err, Stream strm) => HeadedParsec err strm a -> HeadedParsec err strm a
+ HeadedMegaparsec.HeadedParsec: data HeadedParsec err strm a
+ HeadedMegaparsec.HeadedParsec: dbg :: (Ord err, ShowErrorComponent err, Stream strm, Show a) => String -> HeadedParsec err strm a -> HeadedParsec err strm a
+ HeadedMegaparsec.HeadedParsec: endHead :: Stream strm => HeadedParsec err strm ()
+ HeadedMegaparsec.HeadedParsec: filter :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> HeadedParsec err strm a -> HeadedParsec err strm a
+ HeadedMegaparsec.HeadedParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => Control.Monad.Fail.MonadFail (HeadedMegaparsec.HeadedParsec.HeadedParsec err strm)
+ HeadedMegaparsec.HeadedParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => Control.Selective.Selective (HeadedMegaparsec.HeadedParsec.HeadedParsec err strm)
+ HeadedMegaparsec.HeadedParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Alternative (HeadedMegaparsec.HeadedParsec.HeadedParsec err strm)
+ HeadedMegaparsec.HeadedParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Applicative (HeadedMegaparsec.HeadedParsec.HeadedParsec err strm)
+ HeadedMegaparsec.HeadedParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Monad (HeadedMegaparsec.HeadedParsec.HeadedParsec err strm)
+ HeadedMegaparsec.HeadedParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.MonadPlus (HeadedMegaparsec.HeadedParsec.HeadedParsec err strm)
+ HeadedMegaparsec.HeadedParsec: instance GHC.Base.Functor (HeadedMegaparsec.HeadedParsec.HeadedParsec err strm)
+ HeadedMegaparsec.HeadedParsec: instance GHC.Show.Show (HeadedMegaparsec.HeadedParsec.Showable a)
+ HeadedMegaparsec.HeadedParsec: label :: (Ord err, Stream strm) => String -> HeadedParsec err strm a -> HeadedParsec err strm a
+ HeadedMegaparsec.HeadedParsec: parse :: (Ord err, Stream strm) => Parsec err strm a -> HeadedParsec err strm a
+ HeadedMegaparsec.HeadedParsec: toParsec :: (Ord err, Stream strm) => HeadedParsec err strm a -> Parsec err strm a
+ HeadedMegaparsec.HeadedParsec: wrapToHead :: (Ord err, Stream strm) => HeadedParsec err strm a -> HeadedParsec err strm a
+ HeadedMegaparsec.TrailingParsec: data TrailingParsec err strm a
+ HeadedMegaparsec.TrailingParsec: dbg :: (Ord err, ShowErrorComponent err, Stream strm, Show a) => String -> TrailingParsec err strm a -> TrailingParsec err strm a
+ HeadedMegaparsec.TrailingParsec: endHead :: Stream strm => TrailingParsec err strm ()
+ HeadedMegaparsec.TrailingParsec: filter :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> TrailingParsec err strm a -> TrailingParsec err strm a
+ HeadedMegaparsec.TrailingParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => Control.Monad.Fail.MonadFail (HeadedMegaparsec.TrailingParsec.TrailingParsec err strm)
+ HeadedMegaparsec.TrailingParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => Control.Selective.Selective (HeadedMegaparsec.TrailingParsec.TrailingParsec err strm)
+ HeadedMegaparsec.TrailingParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Alternative (HeadedMegaparsec.TrailingParsec.TrailingParsec err strm)
+ HeadedMegaparsec.TrailingParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Applicative (HeadedMegaparsec.TrailingParsec.TrailingParsec err strm)
+ HeadedMegaparsec.TrailingParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.Monad (HeadedMegaparsec.TrailingParsec.TrailingParsec err strm)
+ HeadedMegaparsec.TrailingParsec: instance (GHC.Classes.Ord err, Text.Megaparsec.Stream.Stream strm) => GHC.Base.MonadPlus (HeadedMegaparsec.TrailingParsec.TrailingParsec err strm)
+ HeadedMegaparsec.TrailingParsec: instance GHC.Base.Functor (HeadedMegaparsec.TrailingParsec.TrailingParsec err strm)
+ HeadedMegaparsec.TrailingParsec: label :: (Ord err, Stream strm) => String -> TrailingParsec err strm a -> TrailingParsec err strm a
+ HeadedMegaparsec.TrailingParsec: parse :: (Ord err, Stream strm) => Parsec err strm a -> TrailingParsec err strm a
+ HeadedMegaparsec.TrailingParsec: parseHeaded :: (Ord err, Stream strm) => HeadedParsec err strm a -> TrailingParsec err strm a
+ HeadedMegaparsec.TrailingParsec: toHeadedParsec :: (Ord err, Stream strm) => TrailingParsec err strm a -> HeadedParsec err strm a
+ HeadedMegaparsec.TrailingParsec: toParsec :: (Ord err, Stream strm) => TrailingParsec err strm a -> Parsec err strm a

Files

headed-megaparsec.cabal view
@@ -1,5 +1,5 @@ name: headed-megaparsec-version: 0.1.0.2+version: 0.1.0.3 category: Parsers, Parsing, Megaparsec synopsis: More informative parser homepage: https://github.com/nikita-volkov/headed-megaparsec@@ -21,7 +21,8 @@   default-extensions: ApplicativeDo, Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, DuplicateRecordFields, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples   default-language: Haskell2010   exposed-modules:-    HeadedMegaparsec+    HeadedMegaparsec.HeadedParsec+    HeadedMegaparsec.TrailingParsec   other-modules:     HeadedMegaparsec.Megaparsec     HeadedMegaparsec.Prelude@@ -30,4 +31,4 @@     case-insensitive >=1.2 && <2,     megaparsec >=7 && <9,     parser-combinators >=1.1 && <1.3,-    selective >=0.3 && <0.4+    selective >=0.4 && <0.5
− library/HeadedMegaparsec.hs
@@ -1,296 +0,0 @@-module HeadedMegaparsec-(-  -- * Types-  HeadedParsec,-  -- * Execution-  toParsec,-  -- * Transformation-  wrapToHead,-  label,-  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 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---}---- * 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 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 = 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`.--}-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)--instance (Ord err, Stream strm) => Applicative (HeadedParsec err strm) where-  pure = HeadedParsec . pure . Left-  (<*>) (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec $ do-    junction1 <- p1-    case junction1 of-      Left aToB -> do-        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)--instance (Ord err, Stream strm) => Selective (HeadedParsec err strm) where-  select (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec $ do-    junction1 <- p1-    case junction1 of-      Left eitherAOrB -> case eitherAOrB of-        Right b -> return (Left b)-        Left a -> do-          junction2 <- p2-          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--instance (Ord err, Stream strm) => Monad (HeadedParsec err strm) where-  return = pure-  (>>=) (HeadedParsec p1) k2 = HeadedParsec $ do-    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--{-|-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.--}-instance (Ord err, Stream strm) => MonadPlus (HeadedParsec err strm) where-  mzero = empty-  mplus = (<|>)--instance (Ord err, Stream strm) => MonadFail (HeadedParsec err strm) where-  fail = HeadedParsec . fail----- * Execution----------------------------{-|-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.--}-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 :: (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.--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, Stream 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)-  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 :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> HeadedParsec err strm a -> HeadedParsec err strm a-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-      if pred a-        then return a-        else fail (err a)----- *----------------------------{-|-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.--}-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.--}-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)--{-|-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.--}-endHead :: (Stream strm) => HeadedParsec err strm ()-endHead = HeadedParsec (return (Right (return ())))
+ library/HeadedMegaparsec/HeadedParsec.hs view
@@ -0,0 +1,296 @@+module HeadedMegaparsec.HeadedParsec+(+  -- * Types+  HeadedParsec,+  -- * Execution+  toParsec,+  -- * Transformation+  wrapToHead,+  label,+  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 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++-}++-- * 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 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 = 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`.+-}+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)++instance (Ord err, Stream strm) => Applicative (HeadedParsec err strm) where+  pure = HeadedParsec . pure . Left+  (<*>) (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec $ do+    junction1 <- p1+    case junction1 of+      Left aToB -> do+        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)++instance (Ord err, Stream strm) => Selective (HeadedParsec err strm) where+  select (HeadedParsec p1) (HeadedParsec p2) = HeadedParsec $ do+    junction1 <- p1+    case junction1 of+      Left eitherAOrB -> case eitherAOrB of+        Right b -> return (Left b)+        Left a -> do+          junction2 <- p2+          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++instance (Ord err, Stream strm) => Monad (HeadedParsec err strm) where+  return = pure+  (>>=) (HeadedParsec p1) k2 = HeadedParsec $ do+    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++{-|+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.+-}+instance (Ord err, Stream strm) => MonadPlus (HeadedParsec err strm) where+  mzero = empty+  mplus = (<|>)++instance (Ord err, Stream strm) => MonadFail (HeadedParsec err strm) where+  fail = HeadedParsec . fail+++-- * Execution+-------------------------++{-|+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.+-}+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 :: (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.++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, Stream 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)+  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 :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> HeadedParsec err strm a -> HeadedParsec err strm a+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+      if pred a+        then return a+        else fail (err a)+++-- *+-------------------------++{-|+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.+-}+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.+-}+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)++{-|+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.+-}+endHead :: (Stream strm) => HeadedParsec err strm ()+endHead = HeadedParsec (return (Right (return ())))
+ library/HeadedMegaparsec/TrailingParsec.hs view
@@ -0,0 +1,132 @@+module HeadedMegaparsec.TrailingParsec+(+  TrailingParsec,+  -- * Execution+  toHeadedParsec,+  toParsec,+  -- * Transformation+  label,+  dbg,+  filter,+  -- * Construction+  parse,+  parseHeaded,+  endHead,+)+where++import HeadedMegaparsec.Prelude hiding (try, head, tail, filter)+import HeadedMegaparsec.HeadedParsec (HeadedParsec)+import Control.Applicative.Combinators+import Text.Megaparsec (Parsec, Stream)+import qualified HeadedMegaparsec.Megaparsec as Megaparsec+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+import qualified HeadedMegaparsec.HeadedParsec as HeadedParsec+++{-|+Accumulates the sequently composed alternatives,+alternating between all combinations when executed.+-}+newtype TrailingParsec err strm a = TrailingParsec [HeadedParsec err strm a]++deriving instance Functor (TrailingParsec err strm)++instance (Ord err, Stream strm) => Applicative (TrailingParsec err strm) where+  pure a = TrailingParsec [pure a]+  (<*>) = ap++instance (Ord err, Stream strm) => Selective (TrailingParsec err strm) where+  select = selectA++instance (Ord err, Stream strm) => Monad (TrailingParsec err strm) where+  return = pure+  (>>=) (TrailingParsec l1) k2 = TrailingParsec $ do+    hp1 <- l1+    return $ do+      a <- HeadedParsec.wrapToHead hp1+      toHeadedParsec (k2 a)++instance (Ord err, Stream strm) => Alternative (TrailingParsec err strm) where+  empty = TrailingParsec []+  (<|>) (TrailingParsec l1) (TrailingParsec l2) = TrailingParsec (l1 <> l2)++instance (Ord err, Stream strm) => MonadPlus (TrailingParsec err strm) where+  mzero = empty+  mplus = (<|>)++instance (Ord err, Stream strm) => MonadFail (TrailingParsec err strm) where+  fail = TrailingParsec . fail+++-- * Execution+-------------------------++toHeadedParsec :: (Ord err, Stream strm) => TrailingParsec err strm a -> HeadedParsec err strm a+toHeadedParsec (TrailingParsec l) = asum l++toParsec :: (Ord err, Stream strm) => TrailingParsec err strm a -> Parsec err strm a+toParsec = HeadedParsec.toParsec . toHeadedParsec+++-- * Helpers+-------------------------++mapHeadedParsec fn (TrailingParsec l) = TrailingParsec (fmap fn l)+++-- * Transformation+-------------------------++{-|+Label a headed parser.+Works the same way as megaparsec's `Megaparsec.label`.+-}+label :: (Ord err, Stream strm) => String -> TrailingParsec err strm a -> TrailingParsec err strm a+label label = mapHeadedParsec (HeadedParsec.label label)++{-|+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, Stream strm, Show a) => String -> TrailingParsec err strm a -> TrailingParsec err strm a+dbg label = mapHeadedParsec (HeadedParsec.dbg label)++{-|+Filter the results of parser based on a predicate,+failing with a parameterized message.+-}+filter :: (Ord err, Stream strm) => (a -> String) -> (a -> Bool) -> TrailingParsec err strm a -> TrailingParsec err strm a+filter err pred = mapHeadedParsec (HeadedParsec.filter err pred)+++-- *+-------------------------++{-|+Lift a megaparsec parser.+-}+parse :: (Ord err, Stream strm) => Parsec err strm a -> TrailingParsec err strm a+parse = parseHeaded . HeadedParsec.parse++{-|+Lift a headed parser.+-}+parseHeaded :: (Ord err, Stream strm) => HeadedParsec err strm a -> TrailingParsec err strm a+parseHeaded = TrailingParsec . pure+++-- * Control+-------------------------++{-|+Make all the following parsers compose as tail.+-}+endHead :: (Stream strm) => TrailingParsec err strm ()+endHead = TrailingParsec [HeadedParsec.endHead]