packages feed

parsley 1.0.0.2 → 1.0.0.3

raw patch · 14 files changed

+391/−49 lines, 14 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Parsley: class ParserOps (rep :: Type -> Type)
+ Parsley: class ParserOps rep
- Parsley.Register: newRegister :: Parser a -> (forall r. () => Reg r a -> Parser b) -> Parser b
+ Parsley.Register: newRegister :: Parser a -> (forall r. Reg r a -> Parser b) -> Parser b

Files

ChangeLog.md view
@@ -27,3 +27,8 @@ ## 1.0.0.2 -- 2021-08-13  * Added small optimisation to accomodate new core changes: added `try` for all top-level parsers.++## 1.0.0.3 -- 2021-10-29++* Support for `parsley-core-2.0.0` and `parsley-core-1.7.1`.+* Re-exports less from `parsley-core`, instead using (currently hidden) redefinition.
benchmarks/BrainfuckBench/Main.hs view
@@ -11,7 +11,8 @@ import Control.DeepSeq        (NFData) import GHC.Generics           (Generic) import Data.ByteString        (ByteString)-import Parsley.InputExtras    (Text16(..), CharList(..))+import Parsley.InputExtras    (CharList(..))+import Data.Text              (Text) --import Parsley.Internal.Verbose () import qualified BrainfuckBench.Parsley.Parser import qualified BrainfuckBench.Parsec.Parser@@ -33,7 +34,7 @@ brainfuckParsleyS :: String -> Maybe [BrainFuckOp] brainfuckParsleyS = $$(Parsley.runParser BrainfuckBench.Parsley.Parser.brainfuck) -brainfuckParsleyT :: Text16 -> Maybe [BrainFuckOp]+brainfuckParsleyT :: Text -> Maybe [BrainFuckOp] brainfuckParsleyT = $$(Parsley.runParser BrainfuckBench.Parsley.Parser.brainfuck)  brainfuckParsleyB :: ByteString -> Maybe [BrainFuckOp]@@ -50,9 +51,9 @@   let bfTest :: NFData rep => (FilePath -> IO rep) -> String -> (rep -> Maybe [BrainFuckOp]) -> Benchmark       bfTest = benchmark ["benchmarks/inputs/helloworld.bf", "benchmarks/inputs/helloworld_golfed.bf", "benchmarks/inputs/compiler.bf"]   in bgroup "Brainfuck"-       [ bfTest string          "Parsley (Stream)"          (brainfuckParsleySS . CharList)+       [ bfTest string          "Parsley (CharList)"        (brainfuckParsleySS . CharList)        , bfTest string          "Parsley (String)"          brainfuckParsleyS-       , bfTest text            "Parsley (Text)"            (brainfuckParsleyT . Text16)+       , bfTest text            "Parsley (Text)"            brainfuckParsleyT        , bfTest bytestring      "Parsley (ByteString)"      brainfuckParsleyB        --, bfTest lazy_bytestring "Parsley (Lazy ByteString)" brainfuckParsleyLB        , bfTest string          "Handrolled"                BrainfuckBench.Handrolled.Parser.brainfuck
benchmarks/BrainfuckBench/Parsley/Parser.hs view
@@ -12,6 +12,9 @@ --import Parsley.Garnish import Language.Haskell.TH.Syntax (Lift(..)) +import Parsley.Register+import Parsley.Defunctionalized+ deriving instance Lift BrainFuckOp  brainfuck :: Parser [BrainFuckOp]@@ -34,3 +37,30 @@     op '.' = item $> [|Output|]     op ',' = item $> [|Input|]     op '[' = between (lexeme item) (try (char ']')) ([|Loop|] <$> bf)++-- This is as closed to the handrolled version as it's possible to get: it's /very/ fast+-- If register elimination can be performed, this would be equivalent to the handrolled I think+brainfuck' :: Parser [BrainFuckOp]+brainfuck' = newRegister_ EMPTY $ \acc ->+  let walk :: Parser [BrainFuckOp]+      -- This `eof` is interesting+      -- The "obvious" way of thinking about this is to just move that `gets_` clause last+      -- This works because `item` only fails if `eof` wouldn't have done.+      -- However, at the /moment/, Parsley knows that `eof`'s failure doesn't consume input, and+      -- optimises the handlers appropriately, but the scope of the failure of the match covers+      -- the cases too, and so failing there generates a length check etc. Interestingly, the fix+      -- here is to add a `try` (!!!), which improves performance considerably (but GHC then decides+      -- not to inline something to make them otherwise identical). That's wild.+      walk = eof *> gets_ acc [|reverse|]+         <|> lookAhead (char ']') *> gets_ acc [|reverse|]+         <|> {- try ( -}match "><+-.,[" item op walk -- )+         -- <|> gets_ acc [|reverse|]+      op :: Char -> Parser [BrainFuckOp]+      op '>' = modify_ acc (APP_H CONS (LIFTED RightPointer)) *> walk+      op '<' = modify_ acc (APP_H CONS (LIFTED LeftPointer)) *> walk+      op '+' = modify_ acc (APP_H CONS (LIFTED Increment)) *> walk+      op '-' = modify_ acc (APP_H CONS (LIFTED Decrement)) *> walk+      op '.' = modify_ acc (APP_H CONS (LIFTED Output)) *> walk+      op ',' = modify_ acc (APP_H CONS (LIFTED Input)) *> walk+      op '[' = modify acc (CONS <$> ([|Loop|] <$> local acc (pure EMPTY) (walk <* char ']'))) *> walk+  in walk <* eof
parsley.cabal view
@@ -5,7 +5,7 @@ --                   | +------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             1.0.0.2+version:             1.0.0.3 synopsis:            A fast parser combinator library backed by Typed Template Haskell description:         Parsley is a staged selective parser combinator library, which means                      it does not support monadic operations, and relies on Typed Template@@ -43,6 +43,9 @@                        Parsley.InputExtras,                        Parsley.Precedence +  other-modules:       Parsley.Debug+                       Parsley.ParserOps+   default-extensions:  BangPatterns,                        DataKinds,                        GADTs,@@ -59,7 +62,7 @@  --                     ghc                  >= 8.6     && < 9.2,   build-depends:       base                 >= 4.10    && < 4.16,-                       parsley-core         >= 1       && < 2,+                       parsley-core         >= 1       && < 3,                        template-haskell     >= 2.14    && < 3,                        text                 >= 1.2.3   && < 1.3,   hs-source-dirs:      src/ghc@@ -136,8 +139,8 @@   other-extensions:    TemplateHaskellQuotes, TemplateHaskell   other-modules:       Shared.BenchmarkUtils, Shared.Attoparsec.Extended, Shared.Megaparsec.Extended, Shared.Parsec.Extended   default-language:    Haskell2010-  ghc-options:         -rtsopts -fno-spec-constr-  if false && impl(ghc < 8.8)+  ghc-options:         -rtsopts+  if false && impl(ghc < 9)     build-depends:     dump-core     ghc-options:       -fplugin=DumpCore 
src/ghc/Parsley.hs view
@@ -1,5 +1,5 @@ {-# OPTIONS_GHC -Wno-orphans #-}-{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE MultiParamTypeClasses, CPP #-} {-| Module      : Parsley Description : Main functionality exports@@ -29,17 +29,24 @@ import Prelude hiding            (readFile) import Data.Text.IO              (readFile) import Parsley.InputExtras       (Text16(..))-import Parsley.Internal          (codeGen, Input, eval, compile, Trace(trace))+import Parsley.Internal          (Input, Trace(trace))  import Parsley.Alternative              as Alternative import Parsley.Applicative              as Applicative import Parsley.Combinator               as Combinator  (item, char, string, satisfy, notFollowedBy, lookAhead, try) import Parsley.Fold                     as Fold        (many, some)-import Parsley.Internal                 as Core        (Parser, ParserOps)+import Parsley.Internal                 as Core        (Parser)+import Parsley.ParserOps                as Core        (ParserOps) import Parsley.Internal                 as THUtils     (Quapplicative(..), WQ, Code)-import Parsley.Internal                 as Primitives  (debug)+import Parsley.Debug                    as Primitives  (debug) import Parsley.Selective                as Selective +#if MIN_VERSION_parsley_core(1,7,1)+import qualified Parsley.Internal as Internal (parse)+#else+import qualified Parsley.Internal as Internal (eval, compile, codeGen)+#endif+ {-| The standard way to compile a parser, it returns `Code`, which means that it must be /spliced/ into a function definition to produce a@@ -68,7 +75,11 @@ runParser :: (Trace, Input input)           => Parser a                -- ^ The parser to be compiled           -> Code (input -> Maybe a) -- ^ The generated parsing function-runParser p = [||\input -> $$(eval [||input||] (compile (try p) codeGen))||]+#if MIN_VERSION_parsley_core(1,7,1)+runParser = Internal.parse+#else+runParser p = [||\input -> $$(Internal.eval [||input||] (Internal.compile (try p) Internal.codeGen))||]+#endif  {-| This function generates a function that reads input from a file
src/ghc/Parsley/Alternative.hs view
@@ -18,9 +18,32 @@     (<+>), option, optionally, optional, choice, maybeP, manyTill   ) where -import Prelude hiding      (pure, (<$>))-import Parsley.Applicative (pure, (<$>), ($>), (<:>))-import Parsley.Internal    (makeQ, Parser, Defunc(EMPTY), pattern UNIT, ParserOps, (<|>), empty)+import Prelude hiding           (pure, (<$>))+import Parsley.Applicative      (pure, (<$>), ($>), (<:>))+import Parsley.Defunctionalized (Defunc(EMPTY), pattern UNIT)+import Parsley.Internal         (makeQ, Parser)+import Parsley.ParserOps        (ParserOps)++import qualified Parsley.Internal as Internal ((<|>), empty)++{-|+This combinator always fails.++@since 0.1.0.0+-}+empty :: Parser a+empty = Internal.empty++{-|+This combinator implements branching within a parser. It is left-biased, so that if the first branch+succeeds, the second will not be attempted. In accordance with @parsec@ semantics, if the first+branch failed having consumed input the second branch cannot be taken. (see `Parsley.Combinator.try`)++@since 0.1.0.0+-}+infixr 3 <|>+(<|>) :: Parser a -> Parser a -> Parser a+(<|>) = (Internal.<|>)  {-| This combinator is similar to @(`<|>`)@, except it allows both branches to differ in type by
src/ghc/Parsley/Applicative.hs view
@@ -23,8 +23,41 @@     (>>)   ) where -import Prelude hiding   (pure, (<*>), (*>), (<*), (>>), (<$>), fmap, (<$), traverse, sequence, repeat)-import Parsley.Internal (makeQ, Parser, Defunc(CONS, CONST, ID, EMPTY), pattern FLIP_H, pattern UNIT, ParserOps, pure, (<*>), (*>), (<*))+import Prelude hiding           (pure, (<*>), (*>), (<*), (>>), (<$>), fmap, (<$), traverse, sequence, repeat)+import Parsley.Defunctionalized (Defunc(CONS, CONST, ID, EMPTY), pattern FLIP_H, pattern UNIT)+import Parsley.Internal         (makeQ, Parser)+import Parsley.ParserOps        (ParserOps, pure)++import qualified Parsley.Internal as Internal ((<*>), (*>), (<*))++-- Applicative Operations+{-|+Sequential application of one parser's result to another's. The parsers must both succeed, one after+the other to combine their results. If either parser fails then the combinator will fail.++@since 0.1.0.0+-}+infixl 4 <*>+(<*>) :: Parser (a -> b) -> Parser a -> Parser b+(<*>) = (Internal.<*>)++{-|+Sequence two parsers, keeping the result of the second and discarding the result of the first.++@since 0.1.0.0+-}+infixl 4 <*+(<*) :: Parser a -> Parser b -> Parser a+(<*) = (Internal.<*)++{-|+Sequence two parsers, keeping the result of the first and discarding the result of the second.++@since 0.1.0.0+-}+infixl 4 *>+(*>) :: Parser a -> Parser b -> Parser b+(*>) = (Internal.*>)  -- Functor Operations {-|
src/ghc/Parsley/Combinator.hs view
@@ -22,11 +22,51 @@     lookAhead, notFollowedBy   ) where -import Prelude hiding      (traverse, (*>))-import Data.List           (sort)-import Parsley.Alternative (manyTill)-import Parsley.Applicative (($>), void, traverse, (<:>), (*>))-import Parsley.Internal    (Code, Quapplicative(..), Parser, Defunc(LIFTED, EQ_H, CONST, LAM_S), pattern APP_H, pattern COMPOSE_H, satisfy, lookAhead, try, notFollowedBy)+import Prelude hiding           (traverse, (*>))+import Data.List                (sort)+import Parsley.Alternative      (manyTill)+import Parsley.Applicative      (($>), void, traverse, (<:>), (*>))+import Parsley.Defunctionalized (Defunc(LIFTED, EQ_H, CONST, LAM_S), pattern APP_H, pattern COMPOSE_H)+import Parsley.Internal         (Code, Quapplicative(..), Parser)+import Parsley.ParserOps        (satisfy)++import qualified Parsley.Internal as Internal (try, lookAhead, notFollowedBy)++{-|+This combinator will attempt to parse a given parser. If it succeeds, the result is returned without+having consumed any input. If it fails, however, any consumed input remains consumed.++@since 0.1.0.0+-}+lookAhead :: Parser a -> Parser a+lookAhead = Internal.lookAhead++{-|+This combinator will ensure that a given parser fails. If the parser does fail, a @()@ is returned+and no input is consumed. If the parser succeeded, then this combinator will fail, however it will+not consume any input.++@since 0.1.0.0+-}+notFollowedBy :: Parser a -> Parser ()+notFollowedBy = Internal.notFollowedBy++{-|+This combinator allows a parser to backtrack on failure, which is to say that it will+not have consumed any input if it were to fail. This is important since @parsec@ semantics demand+that the second branch of @(`Parsley.Alternative.<|>`)@ can only be taken if the first did not consume input on failure.++Excessive use of `try` will reduce the efficiency of the parser and effect the generated error+messages. It should only be used in one of two circumstances:++* When two branches of a parser share a common leading prefix (in which case, it is often better+  to try and factor this out).+* When a parser needs to be executed atomically (for example, tokens).++@since 0.1.0.0+-}+try :: Parser a -> Parser a+try = Internal.try  {-| This combinator will attempt match a given string. If the parser fails midway through, this
+ src/ghc/Parsley/Debug.hs view
@@ -0,0 +1,18 @@+module Parsley.Debug (debug) where++import Parsley.Internal (Parser)++import qualified Parsley.Internal as Internal (debug)++{-|+This combinator can be used to debug parsers that have gone wrong. Simply+wrap a parser with @debug name@ and when that parser is executed it will+print a debug trace on entry and exit along with the current context of the+input.++@since 0.1.0.0+-}+debug :: String   -- ^ The name that identifies the wrapped parser in the debug trace+      -> Parser a -- ^ The parser to track during execution+      -> Parser a+debug = Internal.debug
src/ghc/Parsley/Fold.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PatternSynonyms, CPP #-} {-| Module      : Parsley.Fold Description : The "folding" combinators: chains and iterators@@ -13,7 +13,7 @@ -} module Parsley.Fold (     many, some, manyN,-    skipMany, skipSome, skipManyN,+    skipMany, skipSome, skipManyN, --loop,     sepBy, sepBy1, endBy, endBy1, sepEndBy, sepEndBy1,     chainl1, chainr1, chainl, chainr,     chainl1', chainr1', chainPre, chainPost,@@ -21,24 +21,80 @@     pfoldr1, pfoldl1   ) where -import Prelude hiding      (pure, (<*>), (<$>), (*>), (<*))-import Parsley.Alternative ((<|>), option)-import Parsley.Applicative (pure, (<*>), (<$>), (*>), (<*), (<:>), (<**>), void)-import Parsley.Internal    (Parser, Defunc(FLIP, ID, COMPOSE, EMPTY, CONS, CONST), ParserOps, pattern FLIP_H, pattern COMPOSE_H, pattern UNIT, chainPre, chainPost)-import Parsley.Register    (bind, get, modify, newRegister_)+import Prelude hiding           (pure, (<*>), (<$>), (*>), (<*))+import Parsley.Alternative      ((<|>), option)+import Parsley.Applicative      (pure, (<*>), (<$>), (*>), (<*), (<:>), (<**>), void)+import Parsley.Defunctionalized (Defunc(FLIP, ID, COMPOSE, EMPTY, CONS, CONST), pattern FLIP_H, pattern COMPOSE_H, pattern UNIT)+import Parsley.Internal         (Parser)+import Parsley.ParserOps        (ParserOps)+#if MIN_VERSION_parsley_core(1,7,1)+import Parsley.Register         (bind, get, put, modify, newRegister, newRegister_)+#else+import Parsley.Register         (bind, get, modify, newRegister_)+#endif -{-chainPre :: Parser (a -> a) -> Parser a -> Parser a-chainPre op p = newRegister_ ID $ \acc ->-  let go = modify acc (FLIP_H COMPOSE <$> op) *> go-       <|> get acc-  in go <*> p-}+#if MIN_VERSION_parsley_core(1,7,1)+import qualified Parsley.Internal as Internal (loop)+#else+import qualified Parsley.Internal as Internal (chainPre, chainPost)+#endif -{-chainPost :: Parser a -> Parser (a -> a) -> Parser a-chainPost p op = newRegister p $ \acc ->-  let go = modify acc op *> go-       <|> get acc-  in go-}+#if MIN_VERSION_parsley_core(1,7,1)+{-|+The combinator @loop body exit@ parses @body@ zero or more times until it fails. If the final @body@+failed having not consumed input, @exit@ is performed, otherwise the combinator fails: +> loop body exit = let go = body *> go <|> exit in go++@since 1.1.0.0+-}+loop :: Parser () -> Parser a -> Parser a+loop = Internal.loop++{-|+This combinator parses repeated applications of an operator to a single final operand. This is+primarily used to parse prefix operators in expressions.++@since 0.1.0.0+-}+chainPre :: Parser (a -> a) -> Parser a -> Parser a+chainPre op p =+  newRegister (pure ID) (\r ->+    loop (put r (pure (FLIP_H COMPOSE) <*> op <*> get r))+         (get r))+  <*> p++{-|+This combinator parses repeated applications of an operator to a single initial operand. This is+primarily used to parse postfix operators in expressions.++@since 0.1.0.0+-}+chainPost :: Parser a -> Parser (a -> a) -> Parser a+chainPost p op =+  newRegister p $ \r ->+    loop (put r (op <*> get r))+         (get r)+#else+{-|+This combinator parses repeated applications of an operator to a single final operand. This is+primarily used to parse prefix operators in expressions.++@since 0.1.0.0+-}+chainPre :: Parser (a -> a) -> Parser a -> Parser a+chainPre = Internal.chainPre++{-|+This combinator parses repeated applications of an operator to a single initial operand. This is+primarily used to parse postfix operators in expressions.++@since 0.1.0.0+-}+chainPost :: Parser a -> Parser (a -> a) -> Parser a+chainPost = Internal.chainPost+#endif+ -- Parser Folds {-| @pfoldr f k p@ parses __zero__ or more @p@s and combines the results using the function @f@. When @p@@@ -92,7 +148,7 @@ chainl1' f p op = chainPost (f <$> p) (FLIP <$> op <*> p)  {-|-The classic version of the left-associative chain combinator. See `chainl1'`.+The classic version of the left-associative chain combinator. See 'chainl1''.  > chainl1 p op = chainl1' ID p op @@ -116,7 +172,7 @@   in go <**> get acc  {-|-The classic version of the right-associative chain combinator. See `chainr1'`.+The classic version of the right-associative chain combinator. See 'chainr1''.  > chainr1 p op = chainr1' ID p op @@ -177,6 +233,7 @@ skipMany :: Parser a -> Parser () --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp skipMany = void . pfoldl CONST UNIT -- the void here will encourage the optimiser to recognise that the register is unused+--skipMany = flip loop (pure UNIT) . void -- This should be the optimal one, with register removed, but apparently not?! something is amiss, perhaps space leak?  {-| Like `manyN`, excepts discards its results.
+ src/ghc/Parsley/ParserOps.hs view
@@ -0,0 +1,64 @@+module Parsley.ParserOps (module Parsley.ParserOps) where++import Prelude hiding (pure)+import Parsley.Internal (Parser, WQ, Defunc(BLACK))++import qualified Parsley.Internal as Internal (pure, satisfy, conditional)++{-|+This typeclass is used to allow abstraction of the representation of user-level functions.+See the instances for information on what these representations are. This may be required+as a constraint on custom built combinators that make use of one of the minimal required methods+of this class.++@since 0.1.0.0+-}+class ParserOps rep where+  {-|+  Lift a value into the parser world without consuming input or having any other effect.++  @since 0.1.0.0+  -}+  pure :: rep a -> Parser a++  {-|+  Attempts to read a single character matching the provided predicate. If it succeeds, the+  character will be returned and consumed, otherwise the parser will fail having consumed no input.++  @since 0.1.0.0+  -}+  satisfy :: rep (Char -> Bool) -- ^ The predicate that a character must satisfy to be parsed+          -> Parser Char        -- ^ A parser that matches a single character matching the predicate++  {-|+  @conditional fqs p def@ first parses @p@, then it will try each of the predicates in @fqs@ in turn+  until one of them returns @True@. The corresponding parser for the first predicate that succeeded+  is then executes, or if none of the predicates succeeded then the @def@ parser is executed.++  @since 0.1.0.0+  -}+  conditional :: [(rep (a -> Bool), Parser b)] -- ^ A list of predicates and their outcomes+              -> Parser a                      -- ^ A parser whose result is used to choose an outcome+              -> Parser b                      -- ^ A parser who will be executed if no predicates succeed+              -> Parser b++{-|+This is the default representation used for user-level functions and values: plain old code.++@since 0.1.0.0+-}+instance ParserOps WQ where+  pure = pure . BLACK+  satisfy = satisfy . BLACK+  conditional = conditional . map (\(f, t) -> (BLACK f, t))++{-|+This is used to allow defunctionalised versions of many standard Haskell functions to be used+directly as an argument to relevant combinators.++@since 0.1.0.0+-}+instance {-# INCOHERENT #-} x ~ Defunc => ParserOps x where+  pure = Internal.pure+  satisfy = Internal.satisfy+  conditional = Internal.conditional
src/ghc/Parsley/Precedence.hs view
@@ -16,11 +16,12 @@ -} module Parsley.Precedence (module Parsley.Precedence) where -import Prelude hiding      ((<$>))-import Parsley.Alternative (choice)-import Parsley.Applicative ((<$>))-import Parsley.Fold        (chainPre, chainPost, chainl1', chainr1')-import Parsley.Internal    (WQ, Parser, Defunc(BLACK, ID))+import Prelude hiding           ((<$>))+import Parsley.Alternative      (choice)+import Parsley.Applicative      ((<$>))+import Parsley.Defunctionalized (Defunc(BLACK, ID))+import Parsley.Fold             (chainPre, chainPost, chainl1', chainr1')+import Parsley.Internal         (WQ, Parser)  {-| This combinator will construct and expression parser will provided with a table of precedence along
src/ghc/Parsley/Register.hs view
@@ -28,8 +28,44 @@ import Prelude hiding      (pure, (<*>), (*>), (<*)) import Parsley.Alternative (empty, (<|>)) import Parsley.Applicative (pure, (<*>), (*>), (<*))-import Parsley.Internal    (Parser, ParserOps, Reg, newRegister, get, put)+import Parsley.Internal    (Parser, Reg)+import Parsley.ParserOps   (ParserOps) import Parsley.Selective   (when, while)++import qualified Parsley.Internal as Internal (newRegister, get, put)++{-|+Creates a new register initialised with the value obtained from parsing the first+argument. This register is provided to the second argument, a function that generates a parser+depending on operations derived from the register. This parser is then performed.++Note: The rank-2 type here serves a similar purpose to that in the @ST@ monad. It prevents the+register from leaking outside of the scope of the function, safely encapsulating the stateful+effect of the register.++@since 0.1.0.0+-}+newRegister :: Parser a                        -- ^ Parser with which to initialise the register+            -> (forall r. Reg r a -> Parser b) -- ^ Used to generate the second parser to execute+            -> Parser b+newRegister = Internal.newRegister++{-|+Fetches a value from a register and returns it as its result.++@since 0.1.0.0+-}+get :: Reg r a -> Parser a+get = Internal.get++{-|+Puts the result of the given parser into the given register. The old value in the register will be+lost.++@since 0.1.0.0+-}+put :: Reg r a -> Parser a -> Parser ()+put = Internal.put  {-| Like `newRegister`, except the initial value of the register is seeded from a pure value as opposed
src/ghc/Parsley/Selective.hs view
@@ -27,7 +27,27 @@ import Language.Haskell.TH.Syntax (Lift(..)) import Parsley.Alternative        (empty) import Parsley.Applicative        (pure, (<$>), liftA2, unit, constp)-import Parsley.Internal           (makeQ, Parser, Defunc(ID, EQ_H, IF_S, LAM_S, LET_S, APP_H), ParserOps, conditional, branch)+import Parsley.Defunctionalized   (Defunc(ID, EQ_H, IF_S, LAM_S, LET_S, APP_H))+import Parsley.Internal           (makeQ, Parser)+import Parsley.ParserOps          (ParserOps, conditional)++import qualified Parsley.Internal as Internal (branch)++{-|+One of the core @Selective@ operations. The behaviour of @branch p l r@ is to first to parse+@p@, if it fails then the combinator fails. If @p@ succeeded then if its result is a @Left@, then+the parser @l@ is executed and applied to the result of @p@, otherwise @r@ is executed and applied+to the right from a @Right@.++Crucially, only one of @l@ or @r@ will be executed on @p@'s success.++@since 0.1.0.0+-}+branch :: Parser (Either a b) -- ^ The first parser to execute+       -> Parser (a -> c)     -- ^ The parser to execute if the first returned a @Left@+       -> Parser (b -> c)     -- ^ The parser to execute if the first returned a @Right@+       -> Parser c+branch = Internal.branch  {-| Similar to `branch`, except the given branch is only executed on a @Left@ returned.