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 +5/−0
- benchmarks/BrainfuckBench/Main.hs +5/−4
- benchmarks/BrainfuckBench/Parsley/Parser.hs +30/−0
- parsley.cabal +7/−4
- src/ghc/Parsley.hs +16/−5
- src/ghc/Parsley/Alternative.hs +26/−3
- src/ghc/Parsley/Applicative.hs +35/−2
- src/ghc/Parsley/Combinator.hs +45/−5
- src/ghc/Parsley/Debug.hs +18/−0
- src/ghc/Parsley/Fold.hs +76/−19
- src/ghc/Parsley/ParserOps.hs +64/−0
- src/ghc/Parsley/Precedence.hs +6/−5
- src/ghc/Parsley/Register.hs +37/−1
- src/ghc/Parsley/Selective.hs +21/−1
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.