flatparse 0.1.1.2 → 0.2.0.0
raw patch · 7 files changed
+329/−315 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- FlatParse.Basic: ask :: Parser r e r
- FlatParse.Basic: instance GHC.Base.Applicative (FlatParse.Basic.Parser r e)
- FlatParse.Basic: instance GHC.Base.Functor (FlatParse.Basic.Parser r e)
- FlatParse.Basic: instance GHC.Base.Monad (FlatParse.Basic.Parser r e)
- FlatParse.Basic: local :: (r' -> r) -> Parser r e a -> Parser r' e a
- FlatParse.Stateful: instance GHC.Base.Applicative (FlatParse.Stateful.Parser r e)
- FlatParse.Stateful: instance GHC.Base.Functor (FlatParse.Stateful.Parser r e)
- FlatParse.Stateful: instance GHC.Base.Monad (FlatParse.Stateful.Parser r e)
+ FlatParse.Basic: instance GHC.Base.Applicative (FlatParse.Basic.Parser e)
+ FlatParse.Basic: instance GHC.Base.Functor (FlatParse.Basic.Parser e)
+ FlatParse.Basic: instance GHC.Base.Monad (FlatParse.Basic.Parser e)
+ FlatParse.Stateful: instance GHC.Base.Applicative (FlatParse.Stateful.Parser e)
+ FlatParse.Stateful: instance GHC.Base.Functor (FlatParse.Stateful.Parser e)
+ FlatParse.Stateful: instance GHC.Base.Monad (FlatParse.Stateful.Parser e)
- FlatParse.Basic: (<|>) :: Parser r e a -> Parser r e a -> Parser r e a
+ FlatParse.Basic: (<|>) :: Parser e a -> Parser e a -> Parser e a
- FlatParse.Basic: Parser :: (ForeignPtrContents -> r -> Addr# -> Addr# -> Res# e a) -> Parser r e a
+ FlatParse.Basic: Parser :: (ForeignPtrContents -> Addr# -> Addr# -> Res# e a) -> Parser e a
- FlatParse.Basic: [runParser#] :: Parser r e a -> ForeignPtrContents -> r -> Addr# -> Addr# -> Res# e a
+ FlatParse.Basic: [runParser#] :: Parser e a -> ForeignPtrContents -> Addr# -> Addr# -> Res# e a
- FlatParse.Basic: anyChar :: Parser r e Char
+ FlatParse.Basic: anyChar :: Parser e Char
- FlatParse.Basic: anyCharASCII :: Parser r e Char
+ FlatParse.Basic: anyCharASCII :: Parser e Char
- FlatParse.Basic: anyCharASCII_ :: Parser r e ()
+ FlatParse.Basic: anyCharASCII_ :: Parser e ()
- FlatParse.Basic: anyChar_ :: Parser r e ()
+ FlatParse.Basic: anyChar_ :: Parser e ()
- FlatParse.Basic: anyWord :: Parser r e Word
+ FlatParse.Basic: anyWord :: Parser e Word
- FlatParse.Basic: anyWord16 :: Parser r e Word16
+ FlatParse.Basic: anyWord16 :: Parser e Word16
- FlatParse.Basic: anyWord32 :: Parser r e Word32
+ FlatParse.Basic: anyWord32 :: Parser e Word32
- FlatParse.Basic: anyWord8 :: Parser r e Word8
+ FlatParse.Basic: anyWord8 :: Parser e Word8
- FlatParse.Basic: branch :: Parser r e a -> Parser r e b -> Parser r e b -> Parser r e b
+ FlatParse.Basic: branch :: Parser e a -> Parser e b -> Parser e b -> Parser e b
- FlatParse.Basic: byte :: Word8 -> Parser r e ()
+ FlatParse.Basic: byte :: Word8 -> Parser e ()
- FlatParse.Basic: byteStringOf :: Parser r e a -> Parser r e ByteString
+ FlatParse.Basic: byteStringOf :: Parser e a -> Parser e ByteString
- FlatParse.Basic: byteStringed :: Parser r e a -> (a -> ByteString -> Parser r e b) -> Parser r e b
+ FlatParse.Basic: byteStringed :: Parser e a -> (a -> ByteString -> Parser e b) -> Parser e b
- FlatParse.Basic: chainl :: (b -> a -> b) -> Parser r e b -> Parser r e a -> Parser r e b
+ FlatParse.Basic: chainl :: (b -> a -> b) -> Parser e b -> Parser e a -> Parser e b
- FlatParse.Basic: chainr :: (a -> b -> b) -> Parser r e a -> Parser r e b -> Parser r e b
+ FlatParse.Basic: chainr :: (a -> b -> b) -> Parser e a -> Parser e b -> Parser e b
- FlatParse.Basic: cut :: Parser r e a -> e -> Parser r e a
+ FlatParse.Basic: cut :: Parser e a -> e -> Parser e a
- FlatParse.Basic: cutting :: Parser r e a -> e -> (e -> e -> e) -> Parser r e a
+ FlatParse.Basic: cutting :: Parser e a -> e -> (e -> e -> e) -> Parser e a
- FlatParse.Basic: empty :: Parser r e a
+ FlatParse.Basic: empty :: Parser e a
- FlatParse.Basic: ensureBytes# :: Int -> Parser r e ()
+ FlatParse.Basic: ensureBytes# :: Int -> Parser e ()
- FlatParse.Basic: eof :: Parser r e ()
+ FlatParse.Basic: eof :: Parser e ()
- FlatParse.Basic: err :: e -> Parser r e a
+ FlatParse.Basic: err :: e -> Parser e a
- FlatParse.Basic: fails :: Parser r e a -> Parser r e ()
+ FlatParse.Basic: fails :: Parser e a -> Parser e ()
- FlatParse.Basic: fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser r e Char
+ FlatParse.Basic: fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser e Char
- FlatParse.Basic: getPos :: Parser r e Pos
+ FlatParse.Basic: getPos :: Parser e Pos
- FlatParse.Basic: inSpan :: Span -> Parser r e a -> Parser r e a
+ FlatParse.Basic: inSpan :: Span -> Parser e a -> Parser e a
- FlatParse.Basic: lookahead :: Parser r e a -> Parser r e a
+ FlatParse.Basic: lookahead :: Parser e a -> Parser e a
- FlatParse.Basic: many :: Parser r e a -> Parser r e [a]
+ FlatParse.Basic: many :: Parser e a -> Parser e [a]
- FlatParse.Basic: many_ :: Parser r e a -> Parser r e ()
+ FlatParse.Basic: many_ :: Parser e a -> Parser e ()
- FlatParse.Basic: newtype Parser r e a
+ FlatParse.Basic: newtype Parser e a
- FlatParse.Basic: notFollowedBy :: Parser r e a -> Parser r e b -> Parser r e a
+ FlatParse.Basic: notFollowedBy :: Parser e a -> Parser e b -> Parser e a
- FlatParse.Basic: optional :: Parser r e a -> Parser r e (Maybe a)
+ FlatParse.Basic: optional :: Parser e a -> Parser e (Maybe a)
- FlatParse.Basic: optional_ :: Parser r e a -> Parser r e ()
+ FlatParse.Basic: optional_ :: Parser e a -> Parser e ()
- FlatParse.Basic: optioned :: Parser r e a -> (a -> Parser r e b) -> Parser r e b -> Parser r e b
+ FlatParse.Basic: optioned :: Parser e a -> (a -> Parser e b) -> Parser e b -> Parser e b
- FlatParse.Basic: runParser :: Parser r e a -> r -> ByteString -> Result e a
+ FlatParse.Basic: runParser :: Parser e a -> ByteString -> Result e a
- FlatParse.Basic: runParserS :: Parser r e a -> r -> String -> Result e a
+ FlatParse.Basic: runParserS :: Parser e a -> String -> Result e a
- FlatParse.Basic: satisfy :: (Char -> Bool) -> Parser r e Char
+ FlatParse.Basic: satisfy :: (Char -> Bool) -> Parser e Char
- FlatParse.Basic: satisfyASCII :: (Char -> Bool) -> Parser r e Char
+ FlatParse.Basic: satisfyASCII :: (Char -> Bool) -> Parser e Char
- FlatParse.Basic: satisfyASCII_ :: (Char -> Bool) -> Parser r e ()
+ FlatParse.Basic: satisfyASCII_ :: (Char -> Bool) -> Parser e ()
- FlatParse.Basic: scan16# :: Word -> Parser r e ()
+ FlatParse.Basic: scan16# :: Word -> Parser e ()
- FlatParse.Basic: scan32# :: Word -> Parser r e ()
+ FlatParse.Basic: scan32# :: Word -> Parser e ()
- FlatParse.Basic: scan64# :: Word -> Parser r e ()
+ FlatParse.Basic: scan64# :: Word -> Parser e ()
- FlatParse.Basic: scan8# :: Word -> Parser r e ()
+ FlatParse.Basic: scan8# :: Word -> Parser e ()
- FlatParse.Basic: scanAny8# :: Parser r e Word8
+ FlatParse.Basic: scanAny8# :: Parser e Word8
- FlatParse.Basic: setBack# :: Int -> Parser r e ()
+ FlatParse.Basic: setBack# :: Int -> Parser e ()
- FlatParse.Basic: setPos :: Pos -> Parser r e ()
+ FlatParse.Basic: setPos :: Pos -> Parser e ()
- FlatParse.Basic: some :: Parser r e a -> Parser r e [a]
+ FlatParse.Basic: some :: Parser e a -> Parser e [a]
- FlatParse.Basic: some_ :: Parser r e a -> Parser r e ()
+ FlatParse.Basic: some_ :: Parser e a -> Parser e ()
- FlatParse.Basic: spanOf :: Parser r e a -> Parser r e Span
+ FlatParse.Basic: spanOf :: Parser e a -> Parser e Span
- FlatParse.Basic: spanned :: Parser r e a -> (a -> Span -> Parser r e b) -> Parser r e b
+ FlatParse.Basic: spanned :: Parser e a -> (a -> Span -> Parser e b) -> Parser e b
- FlatParse.Basic: takeLine :: Parser r e String
+ FlatParse.Basic: takeLine :: Parser e String
- FlatParse.Basic: takeRest :: Parser r e String
+ FlatParse.Basic: takeRest :: Parser e String
- FlatParse.Basic: traceLine :: Parser r e String
+ FlatParse.Basic: traceLine :: Parser e String
- FlatParse.Basic: traceRest :: Parser r e String
+ FlatParse.Basic: traceRest :: Parser e String
- FlatParse.Basic: try :: Parser r e a -> Parser r e a
+ FlatParse.Basic: try :: Parser e a -> Parser e a
- FlatParse.Basic: unsafeSpanToByteString :: Span -> Parser r e ByteString
+ FlatParse.Basic: unsafeSpanToByteString :: Span -> Parser e ByteString
- FlatParse.Examples.BasicLambda.Lexer: type Parser = Parser () Error
+ FlatParse.Examples.BasicLambda.Lexer: type Parser = Parser Error
- FlatParse.Stateful: (<|>) :: Parser r e a -> Parser r e a -> Parser r e a
+ FlatParse.Stateful: (<|>) :: Parser e a -> Parser e a -> Parser e a
- FlatParse.Stateful: Parser :: (ForeignPtrContents -> r -> Addr# -> Addr# -> Int# -> Res# e a) -> Parser r e a
+ FlatParse.Stateful: Parser :: (ForeignPtrContents -> Int# -> Addr# -> Addr# -> Int# -> Res# e a) -> Parser e a
- FlatParse.Stateful: [runParser#] :: Parser r e a -> ForeignPtrContents -> r -> Addr# -> Addr# -> Int# -> Res# e a
+ FlatParse.Stateful: [runParser#] :: Parser e a -> ForeignPtrContents -> Int# -> Addr# -> Addr# -> Int# -> Res# e a
- FlatParse.Stateful: anyChar :: Parser r e Char
+ FlatParse.Stateful: anyChar :: Parser e Char
- FlatParse.Stateful: anyCharASCII :: Parser r e Char
+ FlatParse.Stateful: anyCharASCII :: Parser e Char
- FlatParse.Stateful: anyCharASCII_ :: Parser r e ()
+ FlatParse.Stateful: anyCharASCII_ :: Parser e ()
- FlatParse.Stateful: anyChar_ :: Parser r e ()
+ FlatParse.Stateful: anyChar_ :: Parser e ()
- FlatParse.Stateful: anyWord :: Parser r e Word
+ FlatParse.Stateful: anyWord :: Parser e Word
- FlatParse.Stateful: anyWord16 :: Parser r e Word16
+ FlatParse.Stateful: anyWord16 :: Parser e Word16
- FlatParse.Stateful: anyWord32 :: Parser r e Word32
+ FlatParse.Stateful: anyWord32 :: Parser e Word32
- FlatParse.Stateful: anyWord8 :: Parser r e Word8
+ FlatParse.Stateful: anyWord8 :: Parser e Word8
- FlatParse.Stateful: ask :: Parser r e r
+ FlatParse.Stateful: ask :: Parser e Int
- FlatParse.Stateful: branch :: Parser r e a -> Parser r e b -> Parser r e b -> Parser r e b
+ FlatParse.Stateful: branch :: Parser e a -> Parser e b -> Parser e b -> Parser e b
- FlatParse.Stateful: byte :: Word8 -> Parser r e ()
+ FlatParse.Stateful: byte :: Word8 -> Parser e ()
- FlatParse.Stateful: byteStringOf :: Parser r e a -> Parser r e ByteString
+ FlatParse.Stateful: byteStringOf :: Parser e a -> Parser e ByteString
- FlatParse.Stateful: byteStringed :: Parser r e a -> (a -> ByteString -> Parser r e b) -> Parser r e b
+ FlatParse.Stateful: byteStringed :: Parser e a -> (a -> ByteString -> Parser e b) -> Parser e b
- FlatParse.Stateful: chainl :: (b -> a -> b) -> Parser r e b -> Parser r e a -> Parser r e b
+ FlatParse.Stateful: chainl :: (b -> a -> b) -> Parser e b -> Parser e a -> Parser e b
- FlatParse.Stateful: chainr :: (a -> b -> b) -> Parser r e a -> Parser r e b -> Parser r e b
+ FlatParse.Stateful: chainr :: (a -> b -> b) -> Parser e a -> Parser e b -> Parser e b
- FlatParse.Stateful: cut :: Parser r e a -> e -> Parser r e a
+ FlatParse.Stateful: cut :: Parser e a -> e -> Parser e a
- FlatParse.Stateful: cutting :: Parser r e a -> e -> (e -> e -> e) -> Parser r e a
+ FlatParse.Stateful: cutting :: Parser e a -> e -> (e -> e -> e) -> Parser e a
- FlatParse.Stateful: empty :: Parser r e a
+ FlatParse.Stateful: empty :: Parser e a
- FlatParse.Stateful: ensureBytes# :: Int -> Parser r e ()
+ FlatParse.Stateful: ensureBytes# :: Int -> Parser e ()
- FlatParse.Stateful: eof :: Parser r e ()
+ FlatParse.Stateful: eof :: Parser e ()
- FlatParse.Stateful: err :: e -> Parser r e a
+ FlatParse.Stateful: err :: e -> Parser e a
- FlatParse.Stateful: fails :: Parser r e a -> Parser r e ()
+ FlatParse.Stateful: fails :: Parser e a -> Parser e ()
- FlatParse.Stateful: fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser r e Char
+ FlatParse.Stateful: fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser e Char
- FlatParse.Stateful: get :: Parser r e Int
+ FlatParse.Stateful: get :: Parser e Int
- FlatParse.Stateful: getPos :: Parser r e Pos
+ FlatParse.Stateful: getPos :: Parser e Pos
- FlatParse.Stateful: inSpan :: Span -> Parser r e a -> Parser r e a
+ FlatParse.Stateful: inSpan :: Span -> Parser e a -> Parser e a
- FlatParse.Stateful: local :: (r' -> r) -> Parser r e a -> Parser r' e a
+ FlatParse.Stateful: local :: (Int -> Int) -> Parser e a -> Parser e a
- FlatParse.Stateful: lookahead :: Parser r e a -> Parser r e a
+ FlatParse.Stateful: lookahead :: Parser e a -> Parser e a
- FlatParse.Stateful: many :: Parser r e a -> Parser r e [a]
+ FlatParse.Stateful: many :: Parser e a -> Parser e [a]
- FlatParse.Stateful: many_ :: Parser r e a -> Parser r e ()
+ FlatParse.Stateful: many_ :: Parser e a -> Parser e ()
- FlatParse.Stateful: modify :: (Int -> Int) -> Parser r e ()
+ FlatParse.Stateful: modify :: (Int -> Int) -> Parser e ()
- FlatParse.Stateful: newtype Parser r e a
+ FlatParse.Stateful: newtype Parser e a
- FlatParse.Stateful: notFollowedBy :: Parser r e a -> Parser r e b -> Parser r e a
+ FlatParse.Stateful: notFollowedBy :: Parser e a -> Parser e b -> Parser e a
- FlatParse.Stateful: optional :: Parser r e a -> Parser r e (Maybe a)
+ FlatParse.Stateful: optional :: Parser e a -> Parser e (Maybe a)
- FlatParse.Stateful: optional_ :: Parser r e a -> Parser r e ()
+ FlatParse.Stateful: optional_ :: Parser e a -> Parser e ()
- FlatParse.Stateful: optioned :: Parser r e a -> (a -> Parser r e b) -> Parser r e b -> Parser r e b
+ FlatParse.Stateful: optioned :: Parser e a -> (a -> Parser e b) -> Parser e b -> Parser e b
- FlatParse.Stateful: put :: Int -> Parser r e ()
+ FlatParse.Stateful: put :: Int -> Parser e ()
- FlatParse.Stateful: runParser :: Parser r e a -> r -> Int -> ByteString -> Result e a
+ FlatParse.Stateful: runParser :: Parser e a -> Int -> Int -> ByteString -> Result e a
- FlatParse.Stateful: runParserS :: Parser r e a -> r -> Int -> String -> Result e a
+ FlatParse.Stateful: runParserS :: Parser e a -> Int -> Int -> String -> Result e a
- FlatParse.Stateful: satisfy :: (Char -> Bool) -> Parser r e Char
+ FlatParse.Stateful: satisfy :: (Char -> Bool) -> Parser e Char
- FlatParse.Stateful: satisfyASCII :: (Char -> Bool) -> Parser r e Char
+ FlatParse.Stateful: satisfyASCII :: (Char -> Bool) -> Parser e Char
- FlatParse.Stateful: satisfyASCII_ :: (Char -> Bool) -> Parser r e ()
+ FlatParse.Stateful: satisfyASCII_ :: (Char -> Bool) -> Parser e ()
- FlatParse.Stateful: scan16# :: Word -> Parser r e ()
+ FlatParse.Stateful: scan16# :: Word -> Parser e ()
- FlatParse.Stateful: scan32# :: Word -> Parser r e ()
+ FlatParse.Stateful: scan32# :: Word -> Parser e ()
- FlatParse.Stateful: scan64# :: Word -> Parser r e ()
+ FlatParse.Stateful: scan64# :: Word -> Parser e ()
- FlatParse.Stateful: scan8# :: Word -> Parser r e ()
+ FlatParse.Stateful: scan8# :: Word -> Parser e ()
- FlatParse.Stateful: scanAny8# :: Parser r e Word8
+ FlatParse.Stateful: scanAny8# :: Parser e Word8
- FlatParse.Stateful: setBack# :: Int -> Parser r e ()
+ FlatParse.Stateful: setBack# :: Int -> Parser e ()
- FlatParse.Stateful: setPos :: Pos -> Parser r e ()
+ FlatParse.Stateful: setPos :: Pos -> Parser e ()
- FlatParse.Stateful: some :: Parser r e a -> Parser r e [a]
+ FlatParse.Stateful: some :: Parser e a -> Parser e [a]
- FlatParse.Stateful: some_ :: Parser r e a -> Parser r e ()
+ FlatParse.Stateful: some_ :: Parser e a -> Parser e ()
- FlatParse.Stateful: spanOf :: Parser r e a -> Parser r e Span
+ FlatParse.Stateful: spanOf :: Parser e a -> Parser e Span
- FlatParse.Stateful: spanned :: Parser r e a -> (a -> Span -> Parser r e b) -> Parser r e b
+ FlatParse.Stateful: spanned :: Parser e a -> (a -> Span -> Parser e b) -> Parser e b
- FlatParse.Stateful: takeLine :: Parser r e String
+ FlatParse.Stateful: takeLine :: Parser e String
- FlatParse.Stateful: takeRest :: Parser r e String
+ FlatParse.Stateful: takeRest :: Parser e String
- FlatParse.Stateful: traceLine :: Parser r e String
+ FlatParse.Stateful: traceLine :: Parser e String
- FlatParse.Stateful: traceRest :: Parser r e String
+ FlatParse.Stateful: traceRest :: Parser e String
- FlatParse.Stateful: try :: Parser r e a -> Parser r e a
+ FlatParse.Stateful: try :: Parser e a -> Parser e a
- FlatParse.Stateful: unsafeSpanToByteString :: Span -> Parser r e ByteString
+ FlatParse.Stateful: unsafeSpanToByteString :: Span -> Parser e ByteString
Files
- README.md +10/−6
- bench/FPBasic.hs +3/−3
- bench/FPStateful.hs +3/−3
- flatparse.cabal +2/−2
- src/FlatParse/Basic.hs +156/−158
- src/FlatParse/Examples/BasicLambda/Lexer.hs +2/−2
- src/FlatParse/Stateful.hs +153/−141
README.md view
@@ -15,16 +15,20 @@ * __Support for fast source location handling, indentation parsing and informative error messages__. `flatparse` provides a low-level interface to these. Batteries are _not included_, but it should be possible for users to build custom solutions, which are more sophisticated, but still as fast as possible. In my experience, the included batteries in other libraries often come with major unavoidable overheads, and often we still have to extend existing machinery in order to scale to production features. * The __backtracking model__ of `flatparse` is different to parsec libraries, and is more close to the [nom](https://github.com/Geal/nom) library in Rust. The idea is that _parser failure_ is distinguished from _parsing error_. The former is used for control flow, and we can backtrack from it. The latter is used for unrecoverable errors, and by default it's propagated to the top. `flatparse` does not track whether parsers have consumed inputs. In my experience, what we really care about is the failure/error distinction, and in `parsec` or `megaparsec` the consumed/non-consumed separation is often muddled and discarded in larger parser implementations. By default, basic `flatparse` parsers can fail but can not throw errors, with the exception of the specifically error-throwing operations. Hence, `flatparse` users have to be mindful about grammar, and explicitly insert errors where it is known that the input can't be valid. -`flatparse` comes in two flavors: [`FlatParse.Basic`][basic] and [`FlatParse.Stateful`][stateful]. Both support a custom error type and a custom reader environment. - -* [`FlatParse.Basic`][basic] only supports the above features. If you don't need indentation parsing, this is sufficient. -* [`FlatParse.Stateful`][stateful] additionally supports a built-in `Int` worth of internal state. This can support a wide range of indentation parsing features. There is a slight overhead in performance and code size compared to `Basic`. However, in small parsers and microbenchmarks the difference between `Basic` and `Stateful` is often reduced to near zero by GHC and LLVM optimization. The difference is more marked if we use native code backend instead of LLVM. +`flatparse` comes in two flavors: [`FlatParse.Basic`][basic] and [`FlatParse.Stateful`][stateful]. Both support a custom error type. -The reason for baking a reader into the parsers, is that if we need it, it's convenient, and if we don't, then GHC very reliably optimizes unused environments away. In contrast, GHC optimizes much less reliably if we try to wrap the existing `Reader` from `transformers` around our parsers. +* [`FlatParse.Basic`][basic] only supports the above features. If you don't need indentation + parsing, this is sufficient. +* [`FlatParse.Stateful`][stateful] additionally supports a built-in `Int` worth of internal state + and an additional `Int` reader environment. This can support a wide range of indentation parsing + features. There is a slight overhead in performance and code size compared to `Basic`. However, in + small parsers and microbenchmarks the difference between `Basic` and `Stateful` is often reduced + to near zero by GHC and/or LLVM optimization. ## Tutorial -Informative tutorials are work in progress. See [`src/FlatParse/Examples`](src/FlatParse/Examples) for a lexer/parser example with acceptably good error messages. +Informative tutorials are work in progress. See [`src/FlatParse/Examples`](src/FlatParse/Examples) +for a lexer/parser example with acceptably good error messages. ## Contribution
bench/FPBasic.hs view
@@ -12,13 +12,13 @@ ident = some_ (satisfyASCII isLatinLetter) >> ws sexp = branch open (some_ sexp >> close) ident src = sexp >> eof-runSexp = runParser src ()+runSexp = runParser src longw = $(string "thisisalongkeyword") longws = some_ (longw >> ws) >> eof-runLongws = runParser longws ()+runLongws = runParser longws numeral = some_ (satisfyASCII isDigit) >> ws comma = $(char ',') >> ws numcsv = numeral >> many_ (comma >> numeral) >> eof-runNumcsv = runParser numcsv ()+runNumcsv = runParser numcsv
bench/FPStateful.hs view
@@ -12,13 +12,13 @@ ident = some_ (satisfyASCII isLatinLetter) >> ws sexp = branch open (some_ sexp >> close) ident src = sexp >> eof-runSexp = runParser src () 0+runSexp = runParser src 0 0 longw = $(string "thisisalongkeyword") longws = some_ (longw >> ws) >> eof-runLongws = runParser longws () 0+runLongws = runParser longws 0 0 numeral = some_ (satisfyASCII isDigit) >> ws comma = $(char ',') >> ws numcsv = numeral >> many_ (comma >> numeral) >> eof-runNumcsv = runParser numcsv () 0+runNumcsv = runParser numcsv 0 0
flatparse.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 6fc2738e15d36543cda3fca41f2488ee555e8d976429e2d1f0798f033e10ea20+-- hash: dd4124fa98babb251701a98ec5a31a5016b54b6af73c2732c85c9e13fdb07478 name: flatparse-version: 0.1.1.2+version: 0.2.0.0 synopsis: High-performance parsing from strict bytestrings description: @Flatparse@ is a high-performance parsing library, focusing on programming languages and human-readable data formats. See the README for more information:
src/FlatParse/Basic.hs view
@@ -1,10 +1,11 @@ {-|-This module implements a `Parser` supporting a reader environment and custom error types. If you-need efficient indentation parsing, use "FlatParse.Stateful" instead.+This module implements a `Parser` supporting custom error types. If you need efficient indentation+parsing, use "FlatParse.Stateful" instead. -} module FlatParse.Basic (+ -- * Parser types and constructors type Parser(..) , type Res#@@ -17,10 +18,6 @@ , runParser , runParserS - -- * Reader environment- , ask- , local- -- * Errors and failures , empty , err@@ -151,49 +148,49 @@ pattern Fail# = (# | (# #) | #) {-# complete OK#, Err#, Fail# #-} --- | @Parser r e a@ has a reader environment @r@, an error type @e@ and a return type @a@.-newtype Parser r e a = Parser {runParser# :: ForeignPtrContents -> r -> Addr# -> Addr# -> Res# e a}+-- | @Parser e a@ has an error type @e@ and a return type @a@.+newtype Parser e a = Parser {runParser# :: ForeignPtrContents -> Addr# -> Addr# -> Res# e a} -instance Functor (Parser r e) where- fmap f (Parser g) = Parser \fp r eob s -> case g fp r eob s of+instance Functor (Parser e) where+ fmap f (Parser g) = Parser \fp eob s -> case g fp eob s of OK# a s -> let !b = f a in OK# b s x -> unsafeCoerce# x {-# inline fmap #-} - (<$) a' (Parser g) = Parser \fp r eob s -> case g fp r eob s of+ (<$) a' (Parser g) = Parser \fp eob s -> case g fp eob s of OK# a s -> OK# a' s x -> unsafeCoerce# x {-# inline (<$) #-} -instance Applicative (Parser r e) where- pure a = Parser \fp r eob s -> OK# a s+instance Applicative (Parser e) where+ pure a = Parser \fp eob s -> OK# a s {-# inline pure #-}- Parser ff <*> Parser fa = Parser \fp r eob s -> case ff fp r eob s of- OK# f s -> case fa fp r eob s of+ Parser ff <*> Parser fa = Parser \fp eob s -> case ff fp eob s of+ OK# f s -> case fa fp eob s of OK# a s -> let !b = f a in OK# b s x -> unsafeCoerce# x x -> unsafeCoerce# x {-# inline (<*>) #-}- Parser fa <* Parser fb = Parser \fp r eob s -> case fa fp r eob s of- OK# a s -> case fb fp r eob s of+ Parser fa <* Parser fb = Parser \fp eob s -> case fa fp eob s of+ OK# a s -> case fb fp eob s of OK# b s -> OK# a s x -> unsafeCoerce# x x -> unsafeCoerce# x {-# inline (<*) #-}- Parser fa *> Parser fb = Parser \fp r eob s -> case fa fp r eob s of- OK# a s -> fb fp r eob s+ Parser fa *> Parser fb = Parser \fp eob s -> case fa fp eob s of+ OK# a s -> fb fp eob s x -> unsafeCoerce# x {-# inline (*>) #-} -instance Monad (Parser r e) where+instance Monad (Parser e) where return = pure {-# inline return #-}- Parser fa >>= f = Parser \fp r eob s -> case fa fp r eob s of- OK# a s -> runParser# (f a) fp r eob s+ Parser fa >>= f = Parser \fp eob s -> case fa fp eob s of+ OK# a s -> runParser# (f a) fp eob s x -> unsafeCoerce# x {-# inline (>>=) #-}- Parser fa >> Parser fb = Parser \fp r eob s -> case fa fp r eob s of- OK# a s -> fb fp r eob s+ Parser fa >> Parser fb = Parser \fp eob s -> case fa fp eob s of+ OK# a s -> fb fp eob s x -> unsafeCoerce# x {-# inline (>>) #-} @@ -206,18 +203,21 @@ instance Functor (Result e) where fmap f (OK a s) = let !b = f a in OK b s- fmap f Fail = Fail- fmap f (Err e) = Err e+ fmap f r = unsafeCoerce# r {-# inline fmap #-}+ (<$) a (OK _ s) = OK a s+ (<$) _ r = unsafeCoerce# r+ {-# inline (<$) #-} + -------------------------------------------------------------------------------- -- | Run a parser.-runParser :: Parser r e a -> r -> B.ByteString -> Result e a-runParser (Parser f) r b@(B.PS (ForeignPtr _ fp) _ (I# len)) = unsafeDupablePerformIO do+runParser :: Parser e a -> B.ByteString -> Result e a+runParser (Parser f) b@(B.PS (ForeignPtr _ fp) _ (I# len)) = unsafeDupablePerformIO do B.unsafeUseAsCString b \(Ptr buf) -> do let end = plusAddr# buf len- case f fp r end buf of+ case f fp end buf of Err# e -> pure (Err e) OK# a s -> do@@ -230,82 +230,70 @@ -- | Run a parser on a `String` input. Reminder: @OverloadedStrings@ for `B.ByteString` does not -- yield a valid UTF-8 encoding! For non-ASCII `B.ByteString` literal input, use `runParserS` or -- `packUTF8` for testing.-runParserS :: Parser r e a -> r -> String -> Result e a-runParserS pa r s = runParser pa r (packUTF8 s)-------------------------------------------------------------------------------------- | Query the read-only environment.-ask :: Parser r e r-ask = Parser \fp r eob s -> OK# r s-{-# inline ask #-}---- | Run a parser in a modified environment.-local :: (r' -> r) -> Parser r e a -> Parser r' e a-local f (Parser g) = Parser \fp r eob s -> let!r' = f r in g fp r' eob s-{-# inline local #-}+runParserS :: Parser e a -> String -> Result e a+runParserS pa s = runParser pa (packUTF8 s) -------------------------------------------------------------------------------- -- | The failing parser. By default, parser choice `(<|>)` arbitrarily backtracks -- on parser failure.-empty :: Parser r e a-empty = Parser \fp r eob s -> Fail#+empty :: Parser e a+empty = Parser \fp eob s -> Fail# {-# inline empty #-} -- | Throw a parsing error. By default, parser choice `(<|>)` can't backtrack -- on parser error. Use `try` to convert an error to a recoverable failure.-err :: e -> Parser r e a-err e = Parser \fp r eob s -> Err# e+err :: e -> Parser e a+err e = Parser \fp eob s -> Err# e {-# inline err #-} -- | Save the parsing state, then run a parser, then restore the state.-lookahead :: Parser r e a -> Parser r e a-lookahead (Parser f) = Parser \fp r eob s ->- case f fp r eob s of+lookahead :: Parser e a -> Parser e a+lookahead (Parser f) = Parser \fp eob s ->+ case f fp eob s of OK# a _ -> OK# a s x -> x {-# inline lookahead #-} -- | Convert a parsing failure to a success.-fails :: Parser r e a -> Parser r e ()-fails (Parser f) = Parser \fp r eob s ->- case f fp r eob s of+fails :: Parser e a -> Parser e ()+fails (Parser f) = Parser \fp eob s ->+ case f fp eob s of OK# _ _ -> Fail# Fail# -> OK# () s Err# e -> Err# e {-# inline fails #-} -- | Convert a parsing error into failure.-try :: Parser r e a -> Parser r e a-try (Parser f) = Parser \fp r eob s -> case f fp r eob s of+try :: Parser e a -> Parser e a+try (Parser f) = Parser \fp eob s -> case f fp eob s of Err# _ -> Fail# x -> x {-# inline try #-} -- | Convert a parsing failure to a `Maybe`. If possible, use `optioned` instead.-optional :: Parser r e a -> Parser r e (Maybe a)+optional :: Parser e a -> Parser e (Maybe a) optional p = (Just <$> p) <|> pure Nothing {-# inline optional #-} -- | Convert a parsing failure to a `()`.-optional_ :: Parser r e a -> Parser r e ()+optional_ :: Parser e a -> Parser e () optional_ p = (() <$ p) <|> pure () {-# inline optional_ #-} -- | CPS'd version of `optional`. This is usually more efficient, since it gets rid of the -- extra `Maybe` allocation.-optioned :: Parser r e a -> (a -> Parser r e b) -> Parser r e b -> Parser r e b-optioned (Parser f) just (Parser nothing) = Parser \fp r eob s -> case f fp r eob s of- OK# a s -> runParser# (just a) fp r eob s- Fail# -> nothing fp r eob s+optioned :: Parser e a -> (a -> Parser e b) -> Parser e b -> Parser e b+optioned (Parser f) just (Parser nothing) = Parser \fp eob s -> case f fp eob s of+ OK# a s -> runParser# (just a) fp eob s+ Fail# -> nothing fp eob s Err# e -> Err# e {-# inline optioned #-} -- | Convert a parsing failure to an error.-cut :: Parser r e a -> e -> Parser r e a-cut (Parser f) e = Parser \fp r eob s -> case f fp r eob s of+cut :: Parser e a -> e -> Parser e a+cut (Parser f) e = Parser \fp eob s -> case f fp eob s of Fail# -> Err# e x -> x {-# inline cut #-}@@ -313,8 +301,8 @@ -- | Run the parser, if we get a failure, throw the given error, but if we get an error, merge the -- inner and the newly given errors using the @e -> e -> e@ function. This can be useful for -- implementing parsing errors which may propagate hints or accummulate contextual information.-cutting :: Parser r e a -> e -> (e -> e -> e) -> Parser r e a-cutting (Parser f) e merge = Parser \fp r eob s -> case f fp r eob s of+cutting :: Parser e a -> e -> (e -> e -> e) -> Parser e a+cutting (Parser f) e merge = Parser \fp eob s -> case f fp eob s of Fail# -> Err# e Err# e' -> let !e'' = merge e' e in Err# e'' x -> x@@ -324,31 +312,31 @@ -- | Succeed if the input is empty.-eof :: Parser r e ()-eof = Parser \fp r eob s -> case eqAddr# eob s of+eof :: Parser e ()+eof = Parser \fp eob s -> case eqAddr# eob s of 1# -> OK# () s _ -> Fail# {-# inline eof #-} -- | Parse a UTF-8 character literal. This is a template function, you can use it as--- @$(char \'x\')@, for example, and the splice in this case has type @Parser r e ()@.+-- @$(char \'x\')@, for example, and the splice in this case has type @Parser e ()@. char :: Char -> Q Exp char c = string [c] -- | Read a `Word8`.-byte :: Word8 -> Parser r e ()+byte :: Word8 -> Parser e () byte (W8# w) = ensureBytes# 1 >> scan8# (W# w) {-# inline byte #-} -- | Read a sequence of bytes. This is a template function, you can use it as @$(bytes [3, 4, 5])@,--- for example, and the splice has type @Parser r e ()@.+-- for example, and the splice has type @Parser e ()@. bytes :: [Word8] -> Q Exp bytes bytes = do let !len = length bytes [| ensureBytes# len >> $(scanBytes# bytes) |] -- | Parse a UTF-8 string literal. This is a template function, you can use it as @$(string "foo")@,--- for example, and the splice has type @Parser r e ()@.+-- for example, and the splice has type @Parser e ()@. string :: String -> Q Exp string str = bytes (strToBytes str) @@ -391,7 +379,7 @@ {-| Switch expression with an optional first argument for performing a post-processing action after-every successful branch matching. For example, if we have @ws :: Parser r e ()@ for a+every successful branch matching. For example, if we have @ws :: Parser e ()@ for a whitespace parser, we might want to consume whitespace after matching on any of the switch cases. For that case, we can define a "lexeme" version of `switch` as follows. @@ -419,8 +407,8 @@ genTrie $! genSwitchTrie' postAction cases fallback -- | Parse a UTF-8 `Char` for which a predicate holds.-satisfy :: (Char -> Bool) -> Parser r e Char-satisfy f = Parser \fp r eob s -> case runParser# anyChar fp r eob s of+satisfy :: (Char -> Bool) -> Parser e Char+satisfy f = Parser \fp eob s -> case runParser# anyChar fp eob s of OK# c s | f c -> OK# c s _ -> Fail# {-# inline satisfy #-}@@ -428,8 +416,8 @@ -- | Parse an ASCII `Char` for which a predicate holds. Assumption: the predicate must only return -- `True` for ASCII-range characters. Otherwise this function might read a 128-255 range byte, -- thereby breaking UTF-8 decoding.-satisfyASCII :: (Char -> Bool) -> Parser r e Char-satisfyASCII f = Parser \fp r eob s -> case eqAddr# eob s of+satisfyASCII :: (Char -> Bool) -> Parser e Char+satisfyASCII f = Parser \fp eob s -> case eqAddr# eob s of 1# -> Fail# _ -> case derefChar8# s of c1 | f (C# c1) -> OK# (C# c1) (plusAddr# s 1#)@@ -437,7 +425,7 @@ {-# inline satisfyASCII #-} -- | Parse an ASCII `Char` for which a predicate holds.-satisfyASCII_ :: (Char -> Bool) -> Parser r e ()+satisfyASCII_ :: (Char -> Bool) -> Parser e () satisfyASCII_ f = () <$ satisfyASCII f {-# inline satisfyASCII_ #-} @@ -451,8 +439,8 @@ -- can do better with @fusedSatisfy isLatinLetter isLetter isLetter isLetter@, since here the -- `isLatinLetter` is inlined into the UTF-8 decoding, and it probably handles a great majority of -- all cases without accessing the character table.-fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser r e Char-fusedSatisfy f1 f2 f3 f4 = Parser \fp r eob buf -> case eqAddr# eob buf of+fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser e Char+fusedSatisfy f1 f2 f3 f4 = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -493,40 +481,40 @@ {-# inline fusedSatisfy #-} -- | Parse any `Word8`.-anyWord8 :: Parser r e Word8-anyWord8 = Parser \fp r eob buf -> case eqAddr# eob buf of+anyWord8 :: Parser e Word8+anyWord8 = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWord8OffAddr# buf 0# of w -> OK# (W8# w) (plusAddr# buf 1#) {-# inline anyWord8 #-} -- | Parse any `Word16`.-anyWord16 :: Parser r e Word16-anyWord16 = Parser \fp r eob buf -> case eqAddr# eob buf of+anyWord16 :: Parser e Word16+anyWord16 = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWord16OffAddr# buf 0# of w -> OK# (W16# w) (plusAddr# buf 2#) {-# inline anyWord16 #-} -- | Parse any `Word32`.-anyWord32 :: Parser r e Word32-anyWord32 = Parser \fp r eob buf -> case eqAddr# eob buf of+anyWord32 :: Parser e Word32+anyWord32 = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWord32OffAddr# buf 0# of w -> OK# (W32# w) (plusAddr# buf 4#) {-# inline anyWord32 #-} -- | Parse any `Word`.-anyWord :: Parser r e Word-anyWord = Parser \fp r eob buf -> case eqAddr# eob buf of+anyWord :: Parser e Word+anyWord = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWordOffAddr# buf 0# of w -> OK# (W# w) (plusAddr# buf 8#) {-# inline anyWord #-} -- | Parse any UTF-8-encoded `Char`.-anyChar :: Parser r e Char-anyChar = Parser \fp r eob buf -> case eqAddr# eob buf of+anyChar :: Parser e Char+anyChar = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -560,8 +548,8 @@ {-# inline anyChar #-} -- | Skip any UTF-8-encoded `Char`.-anyChar_ :: Parser r e ()-anyChar_ = Parser \fp r eob buf -> case eqAddr# eob buf of+anyChar_ :: Parser e ()+anyChar_ = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -581,8 +569,8 @@ -- | Parse any `Char` in the ASCII range, fail if the next input character is not in the range. -- This is more efficient than `anyChar` if we are only working with ASCII.-anyCharASCII :: Parser r e Char-anyCharASCII = Parser \fp r eob buf -> case eqAddr# eob buf of+anyCharASCII :: Parser e Char+anyCharASCII = Parser \fp eob buf -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -592,7 +580,7 @@ -- | Skip any `Char` in the ASCII range. More efficient than `anyChar_` if we're working only with -- ASCII.-anyCharASCII_ :: Parser r e ()+anyCharASCII_ :: Parser e () anyCharASCII_ = () <$ anyCharASCII {-# inline anyCharASCII_ #-} @@ -617,27 +605,27 @@ -- | Choose between two parsers. If the first parser fails, try the second one, but if the first one -- throws an error, propagate the error. infixr 6 <|>-(<|>) :: Parser r e a -> Parser r e a -> Parser r e a-(<|>) (Parser f) (Parser g) = Parser \fp r eob s ->- case f fp r eob s of- Fail# -> g fp r eob s+(<|>) :: Parser e a -> Parser e a -> Parser e a+(<|>) (Parser f) (Parser g) = Parser \fp eob s ->+ case f fp eob s of+ Fail# -> g fp eob s x -> x {-# inline (<|>) #-} -- | Branch on a parser: if the first argument fails, continue with the second, else with the third. -- This can produce slightly more efficient code than `(<|>)`. Moreover, `ḃranch` does not -- backtrack from the true/false cases.-branch :: Parser r e a -> Parser r e b -> Parser r e b -> Parser r e b-branch pa pt pf = Parser \fp r eob s -> case runParser# pa fp r eob s of- OK# _ s -> runParser# pt fp r eob s- Fail# -> runParser# pf fp r eob s+branch :: Parser e a -> Parser e b -> Parser e b -> Parser e b+branch pa pt pf = Parser \fp eob s -> case runParser# pa fp eob s of+ OK# _ s -> runParser# pt fp eob s+ Fail# -> runParser# pf fp eob s Err# e -> Err# e {-# inline branch #-} -- | An analogue of the list `foldl` function: first parse a @b@, then parse zero or more @a@-s, -- and combine the results in a left-nested way by the @b -> a -> b@ function. Note: this is not -- the usual `chainl` function from the parsec libraries!-chainl :: (b -> a -> b) -> Parser r e b -> Parser r e a -> Parser r e b+chainl :: (b -> a -> b) -> Parser e b -> Parser e a -> Parser e b chainl f start elem = start >>= go where go b = do {!a <- elem; go $! f b a} <|> pure b {-# inline chainl #-}@@ -645,24 +633,34 @@ -- | An analogue of the list `foldr` function: parse zero or more @a@-s, terminated by a @b@, and -- combine the results in a right-nested way using the @a -> b -> b@ function. Note: this is not -- the usual `chainr` function from the parsec libraries!-chainr :: (a -> b -> b) -> Parser r e a -> Parser r e b -> Parser r e b-chainr f elem end = go where- go = (f <$> elem <*> go) <|> end+chainr :: (a -> b -> b) -> Parser e a -> Parser e b -> Parser e b+chainr f (Parser elem) (Parser end) = go where+ go = Parser \fp eob s -> case elem fp eob s of+ OK# a s -> case runParser# go fp eob s of+ OK# b s -> let !b' = f a b in OK# b' s+ x -> x+ Fail# -> end fp eob s+ Err# e -> Err# e {-# inline chainr #-} -- | Run a parser zero or more times, collect the results in a list. Note: for optimal performance, -- try to avoid this. Often it is possible to get rid of the intermediate list by using a -- combinator or a custom parser.-many :: Parser r e a -> Parser r e [a]-many p = go where- go = ((:) <$> p <*> go) <|> pure []+many :: Parser e a -> Parser e [a]+many (Parser f) = go where+ go = Parser \fp eob s -> case f fp eob s of+ OK# a s -> case runParser# go fp eob s of+ OK# as s -> OK# (a:as) s+ x -> x+ Fail# -> OK# [] s+ Err# e -> Err# e {-# inline many #-} -- | Skip a parser zero or more times.-many_ :: Parser r e a -> Parser r e ()+many_ :: Parser e a -> Parser e () many_ (Parser f) = go where- go = Parser \fp r eob s -> case f fp r eob s of- OK# a s -> runParser# go fp r eob s+ go = Parser \fp eob s -> case f fp eob s of+ OK# a s -> runParser# go fp eob s Fail# -> OK# () s Err# e -> Err# e {-# inline many_ #-}@@ -670,17 +668,17 @@ -- | Run a parser one or more times, collect the results in a list. Note: for optimal performance, -- try to avoid this. Often it is possible to get rid of the intermediate list by using a -- combinator or a custom parser.-some :: Parser r e a -> Parser r e [a]+some :: Parser e a -> Parser e [a] some p = (:) <$> p <*> many p {-# inline some #-} -- | Skip a parser one or more times.-some_ :: Parser r e a -> Parser r e ()+some_ :: Parser e a -> Parser e () some_ pa = pa >> many_ pa {-# inline some_ #-} -- | Succeed if the first parser succeeds and the second one fails.-notFollowedBy :: Parser r e a -> Parser r e b -> Parser r e a+notFollowedBy :: Parser e a -> Parser e b -> Parser e a notFollowedBy p1 p2 = p1 <* fails p2 {-# inline notFollowedBy #-} @@ -704,15 +702,15 @@ {-# inline (>=) #-} -- | Get the current position in the input.-getPos :: Parser r e Pos-getPos = Parser \fp r eob s -> OK# (addrToPos# eob s) s+getPos :: Parser e Pos+getPos = Parser \fp eob s -> OK# (addrToPos# eob s) s {-# inline getPos #-} -- | Set the input position. Warning: this can result in crashes if the position points outside the -- current buffer. It is always safe to `setPos` values which came from `getPos` with the current -- input.-setPos :: Pos -> Parser r e ()-setPos s = Parser \fp r eob _ -> OK# () (posToAddr# eob s)+setPos :: Pos -> Parser e ()+setPos s = Parser \fp eob _ -> OK# () (posToAddr# eob s) {-# inline setPos #-} -- | The end of the input.@@ -722,33 +720,33 @@ -- | Return the consumed span of a parser.-spanOf :: Parser r e a -> Parser r e Span-spanOf (Parser f) = Parser \fp r eob s -> case f fp r eob s of+spanOf :: Parser e a -> Parser e Span+spanOf (Parser f) = Parser \fp eob s -> case f fp eob s of OK# a s' -> OK# (Span (addrToPos# eob s) (addrToPos# eob s')) s' x -> unsafeCoerce# x {-# inline spanOf #-} -- | Bind the result together with the span of the result. CPS'd version of `spanOf` -- for better unboxing.-spanned :: Parser r e a -> (a -> Span -> Parser r e b) -> Parser r e b-spanned (Parser f) g = Parser \fp r eob s -> case f fp r eob s of- OK# a s' -> runParser# (g a (Span (addrToPos# eob s) (addrToPos# eob s'))) fp r eob s'+spanned :: Parser e a -> (a -> Span -> Parser e b) -> Parser e b+spanned (Parser f) g = Parser \fp eob s -> case f fp eob s of+ OK# a s' -> runParser# (g a (Span (addrToPos# eob s) (addrToPos# eob s'))) fp eob s' x -> unsafeCoerce# x {-# inline spanned #-} -- | Return the `B.ByteString` consumed by a parser. Note: it's more efficient to use `spanOf` and -- `spanned` instead.-byteStringOf :: Parser r e a -> Parser r e B.ByteString-byteStringOf (Parser f) = Parser \fp r eob s -> case f fp r eob s of+byteStringOf :: Parser e a -> Parser e B.ByteString+byteStringOf (Parser f) = Parser \fp eob s -> case f fp eob s of OK# a s' -> OK# (B.PS (ForeignPtr s fp) 0 (I# (minusAddr# s' s))) s' x -> unsafeCoerce# x {-# inline byteStringOf #-} -- | CPS'd version of `byteStringOf`. Can be more efficient, because the result is more eagerly unboxed -- by GHC. It's more efficient to use `spanOf` or `spanned` instead.-byteStringed :: Parser r e a -> (a -> B.ByteString -> Parser r e b) -> Parser r e b-byteStringed (Parser f) g = Parser \fp r eob s -> case f fp r eob s of- OK# a s' -> runParser# (g a (B.PS (ForeignPtr s fp) 0 (I# (minusAddr# s' s)))) fp r eob s'+byteStringed :: Parser e a -> (a -> B.ByteString -> Parser e b) -> Parser e b+byteStringed (Parser f) g = Parser \fp eob s -> case f fp eob s of+ OK# a s' -> runParser# (g a (B.PS (ForeignPtr s fp) 0 (I# (minusAddr# s' s)))) fp eob s' x -> unsafeCoerce# x {-# inline byteStringed #-} @@ -757,9 +755,9 @@ -- this operation may crash if the given span points outside the current parsing buffer. It's -- always safe to use `inSpan` if the span comes from a previous `spanned` or `spanOf` call on -- the current input.-inSpan :: Span -> Parser r e a -> Parser r e a-inSpan (Span s eob) (Parser f) = Parser \fp r eob' s' ->- case f fp r (posToAddr# eob' eob) (posToAddr# eob' s) of+inSpan :: Span -> Parser e a -> Parser e a+inSpan (Span s eob) (Parser f) = Parser \fp eob' s' ->+ case f fp (posToAddr# eob' eob) (posToAddr# eob' s) of OK# a _ -> OK# a s' x -> unsafeCoerce# x {-# inline inSpan #-}@@ -772,7 +770,7 @@ let go = do start <- getPos pure (start <= pos && pos <= endPos)- in case runParser go () str of+ in case runParser go str of OK b _ -> b _ -> error "impossible" {-# inline validPos #-}@@ -797,13 +795,13 @@ sorted :: [(Int, Pos)] sorted = sortBy (comparing snd) (zip [0..] poss) - in case runParser (go 0 0 sorted) () str of+ in case runParser (go 0 0 sorted) str of OK res _ -> snd <$> sortBy (comparing fst) res _ -> error "invalid position" -- | Create a `B.ByteString` from a `Span`. The result is invalid is the `Span` points -- outside the current buffer, or if the `Span` start is greater than the end position.-unsafeSpanToByteString :: Span -> Parser r e B.ByteString+unsafeSpanToByteString :: Span -> Parser e B.ByteString unsafeSpanToByteString (Span l r) = lookahead (setPos l >> byteStringOf (setPos r)) {-# inline unsafeSpanToByteString #-}@@ -817,7 +815,7 @@ c <- anyChar if c == '\n' then go (line + 1) 0 else go line (col + 1)) <|> error "mkPos: invalid position"- in case runParser (go 0 0) () str of+ in case runParser (go 0 0) str of OK res _ -> res _ -> error "impossible" @@ -827,7 +825,7 @@ lines :: B.ByteString -> [String] lines str = let go = ([] <$ eof) <|> ((:) <$> takeLine <*> go)- in case runParser go () str of+ in case runParser go str of OK ls _ -> ls _ -> error "linesUTF8: invalid input" @@ -836,7 +834,7 @@ -- | Parse the rest of the current line as a `String`. Assumes UTF-8 encoding, -- throws an error if the encoding is invalid.-takeLine :: Parser r e String+takeLine :: Parser e String takeLine = branch eof (pure "") do c <- anyChar@@ -846,16 +844,16 @@ -- | Parse the rest of the current line as a `String`, but restore the parsing state. -- Assumes UTF-8 encoding. This can be used for debugging.-traceLine :: Parser r e String+traceLine :: Parser e String traceLine = lookahead takeLine -- | Take the rest of the input as a `String`. Assumes UTF-8 encoding.-takeRest :: Parser r e String+takeRest :: Parser e String takeRest = ((:) <$> anyChar <*> takeRest) <|> pure [] -- | Get the rest of the input as a `String`, but restore the parsing state. Assumes UTF-8 encoding. -- This can be used for debugging.-traceRest :: Parser r e String+traceRest :: Parser e String traceRest = lookahead traceRest --------------------------------------------------------------------------------@@ -909,8 +907,8 @@ {-# inline derefChar8# #-} -- | Check that the input has at least the given number of bytes.-ensureBytes# :: Int -> Parser r e ()-ensureBytes# (I# len) = Parser \fp r eob s ->+ensureBytes# :: Int -> Parser e ()+ensureBytes# (I# len) = Parser \fp eob s -> case len <=# minusAddr# eob s of 1# -> OK# () s _ -> Fail#@@ -918,8 +916,8 @@ -- | Unsafely read a concrete byte from the input. It's not checked that the input has -- enough bytes.-scan8# :: Word -> Parser r e ()-scan8# (W# c) = Parser \fp r eob s ->+scan8# :: Word -> Parser e ()+scan8# (W# c) = Parser \fp eob s -> case indexWord8OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 1#)@@ -928,8 +926,8 @@ -- | Unsafely read two concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan16# :: Word -> Parser r e ()-scan16# (W# c) = Parser \fp r eob s ->+scan16# :: Word -> Parser e ()+scan16# (W# c) = Parser \fp eob s -> case indexWord16OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 2#)@@ -938,8 +936,8 @@ -- | Unsafely read four concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan32# :: Word -> Parser r e ()-scan32# (W# c) = Parser \fp r eob s ->+scan32# :: Word -> Parser e ()+scan32# (W# c) = Parser \fp eob s -> case indexWord32OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 4#)@@ -948,8 +946,8 @@ -- | Unsafely read eight concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan64# :: Word -> Parser r e ()-scan64# (W# c) = Parser \fp r eob s ->+scan64# :: Word -> Parser e ()+scan64# (W# c) = Parser \fp eob s -> case indexWord64OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 8#)@@ -957,12 +955,12 @@ {-# inline scan64# #-} -- | Unsafely read and return a byte from the input. It's not checked that the input is non-empty.-scanAny8# :: Parser r e Word8-scanAny8# = Parser \fp r eob s -> OK# (W8# (indexWord8OffAddr# s 0#)) (plusAddr# s 1#)+scanAny8# :: Parser e Word8+scanAny8# = Parser \fp eob s -> OK# (W8# (indexWord8OffAddr# s 0#)) (plusAddr# s 1#) {-# inline scanAny8# #-} -scanPartial64# :: Int -> Word -> Parser r e ()-scanPartial64# (I# len) (W# w) = Parser \fp r eob s ->+scanPartial64# :: Int -> Word -> Parser e ()+scanPartial64# (I# len) (W# w) = Parser \fp eob s -> case indexWordOffAddr# s 0# of w' -> case uncheckedIShiftL# (8# -# len) 3# of sh -> case uncheckedShiftL# w' sh of@@ -973,12 +971,12 @@ {-# inline scanPartial64# #-} -- | Decrease the current input position by the given number of bytes.-setBack# :: Int -> Parser r e ()-setBack# (I# i) = Parser \fp r eob s ->+setBack# :: Int -> Parser e ()+setBack# (I# i) = Parser \fp eob s -> OK# () (plusAddr# s (negateInt# i)) {-# inline setBack# #-} --- | Template function, creates a @Parser r e ()@ which unsafely scans a given+-- | Template function, creates a @Parser e ()@ which unsafely scans a given -- sequence of bytes. scanBytes# :: [Word8] -> Q Exp scanBytes# bytes = do
src/FlatParse/Examples/BasicLambda/Lexer.hs view
@@ -54,7 +54,7 @@ (Imprecise _ es , Imprecise _ es' ) -> Imprecise p (es ++ es') {-# noinline merge #-} -- merge is "cold" code, so we shouldn't inline it. -type Parser = FP.Parser () Error+type Parser = FP.Parser Error -- | Pretty print an error. The `B.ByteString` input is the source file. The offending line from the -- source is displayed in the output.@@ -104,7 +104,7 @@ FP.cutting p (Precise pos e) merge runParser :: Parser a -> B.ByteString -> Result Error a-runParser p = FP.runParser p ()+runParser = FP.runParser -- | Run parser, print pretty error on failure. testParser :: Show a => Parser a -> String -> IO ()
src/FlatParse/Stateful.hs view
@@ -1,7 +1,7 @@ {-|-This module implements a `Parser` supporting a reader environment, custom error types, and an `Int`-state.+This module implements a `Parser` supporting an `Int` reader environment, custom error types, and an+`Int` state. -} module FlatParse.Stateful (@@ -154,48 +154,48 @@ pattern Fail# = (# | (# #) | #) {-# complete OK#, Err#, Fail# #-} --- | @Parser r e a@ has a reader environment @r@, an error type @e@ and a return type @a@.-newtype Parser r e a = Parser {runParser# :: ForeignPtrContents -> r -> Addr# -> Addr# -> Int# -> Res# e a}+-- | @Parser e a@ has an error type @e@ and a return type @a@.+newtype Parser e a = Parser {runParser# :: ForeignPtrContents -> Int# -> Addr# -> Addr# -> Int# -> Res# e a} -instance Functor (Parser r e) where- fmap f (Parser g) = Parser \fp r eob s n -> case g fp r eob s n of+instance Functor (Parser e) where+ fmap f (Parser g) = Parser \fp !r eob s n -> case g fp r eob s n of OK# a s n -> let !b = f a in OK# b s n x -> unsafeCoerce# x {-# inline fmap #-} - (<$) a' (Parser g) = Parser \fp r eob s n -> case g fp r eob s n of+ (<$) a' (Parser g) = Parser \fp !r eob s n -> case g fp r eob s n of OK# a s n -> OK# a' s n x -> unsafeCoerce# x {-# inline (<$) #-} -instance Applicative (Parser r e) where- pure a = Parser \fp r eob s n -> OK# a s n+instance Applicative (Parser e) where+ pure a = Parser \fp !r eob s n -> OK# a s n {-# inline pure #-}- Parser ff <*> Parser fa = Parser \fp r eob s n -> case ff fp r eob s n of+ Parser ff <*> Parser fa = Parser \fp !r eob s n -> case ff fp r eob s n of OK# f s n -> case fa fp r eob s n of OK# a s n -> let !b = f a in OK# b s n x -> unsafeCoerce# x x -> unsafeCoerce# x {-# inline (<*>) #-}- Parser fa <* Parser fb = Parser \fp r eob s n -> case fa fp r eob s n of+ Parser fa <* Parser fb = Parser \fp !r eob s n -> case fa fp r eob s n of OK# a s n -> case fb fp r eob s n of OK# b s n -> OK# a s n x -> unsafeCoerce# x x -> unsafeCoerce# x {-# inline (<*) #-}- Parser fa *> Parser fb = Parser \fp r eob s n -> case fa fp r eob s n of+ Parser fa *> Parser fb = Parser \fp !r eob s n -> case fa fp r eob s n of OK# a s n -> fb fp r eob s n x -> unsafeCoerce# x {-# inline (*>) #-} -instance Monad (Parser r e) where+instance Monad (Parser e) where return = pure {-# inline return #-}- Parser fa >>= f = Parser \fp r eob s n -> case fa fp r eob s n of+ Parser fa >>= f = Parser \fp !r eob s n -> case fa fp r eob s n of OK# a s n -> runParser# (f a) fp r eob s n x -> unsafeCoerce# x {-# inline (>>=) #-}- Parser fa >> Parser fb = Parser \fp r eob s n -> case fa fp r eob s n of+ Parser fa >> Parser fb = Parser \fp !r eob s n -> case fa fp r eob s n of OK# a s n -> fb fp r eob s n x -> unsafeCoerce# x {-# inline (>>) #-}@@ -208,16 +208,19 @@ deriving Show instance Functor (Result e) where- fmap f (OK a n s) = let !b = f a in OK b n s- fmap f Fail = Fail- fmap f (Err e) = Err e+ fmap f (OK a s n) = let !b = f a in OK b s n+ fmap f r = unsafeCoerce# r {-# inline fmap #-}+ (<$) a (OK _ s n) = OK a s n+ (<$) _ r = unsafeCoerce# r+ {-# inline (<$) #-} -------------------------------------------------------------------------------- --- | Run a parser.-runParser :: Parser r e a -> r -> Int -> B.ByteString -> Result e a-runParser (Parser f) r (I# n) b@(B.PS (ForeignPtr _ fp) _ (I# len)) = unsafeDupablePerformIO do+-- | Run a parser. The first `Int` argument is the reader environment, while the second one is the+-- state.+runParser :: Parser e a -> Int -> Int -> B.ByteString -> Result e a+runParser (Parser f) (I# r) (I# n) b@(B.PS (ForeignPtr _ fp) _ (I# len)) = unsafeDupablePerformIO do B.unsafeUseAsCString b \(Ptr buf) -> do let end = plusAddr# buf len case f fp r end buf n of@@ -233,64 +236,63 @@ -- | Run a parser on a `String` input. Reminder: @OverloadedStrings@ for `B.ByteString` does not -- yield a valid UTF-8 encoding! For non-ASCII `B.ByteString` literal input, use `runParserS` or -- `packUTF8` for testing.-runParserS :: Parser r e a -> r -> Int -> String -> Result e a-runParserS pa r n s = runParser pa r n (packUTF8 s)+runParserS :: Parser e a -> Int -> Int -> String -> Result e a+runParserS pa r !n s = runParser pa r n (packUTF8 s) -------------------------------------------------------------------------------- -- | Query the `Int` state.-get :: Parser r e Int-get = Parser \fp r eob s n -> OK# (I# n) s n+get :: Parser e Int+get = Parser \fp !r eob s n -> OK# (I# n) s n {-# inline get #-} -- | Write the `Int` state.-put :: Int -> Parser r e ()-put (I# n) = Parser \fp r eob s _ -> OK# () s n+put :: Int -> Parser e ()+put (I# n) = Parser \fp !r eob s _ -> OK# () s n {-# inline put #-} -- | Modify the `Int` state.-modify :: (Int -> Int) -> Parser r e ()-modify f = Parser \fp r eob s n ->+modify :: (Int -> Int) -> Parser e ()+modify f = Parser \fp !r eob s n -> case f (I# n) of I# n -> OK# () s n {-# inline modify #-} --- | Query the read-only environment.-ask :: Parser r e r-ask = Parser \fp r eob s n -> OK# r s n+-- | Query the `Int` environment.+ask :: Parser e Int+ask = Parser \fp !r eob s n -> OK# (I# r) s n {-# inline ask #-} -- | Run a parser in a modified environment.-local :: (r' -> r) -> Parser r e a -> Parser r' e a-local f (Parser g) = Parser \fp r eob s n -> let!r' = f r in g fp r' eob s n+local :: (Int -> Int) -> Parser e a -> Parser e a+local f (Parser g) = Parser \fp !r eob s n -> let !(I# r') = f (I# r) in g fp r' eob s n {-# inline local #-} - -------------------------------------------------------------------------------- -- | The failing parser. By default, parser choice `(<|>)` arbitrarily backtracks -- on parser failure.-empty :: Parser r e a-empty = Parser \fp r eob s n -> Fail#+empty :: Parser e a+empty = Parser \fp !r eob s n -> Fail# {-# inline empty #-} -- | Throw a parsing error. By default, parser choice `(<|>)` can't backtrack -- on parser error. Use `try` to convert an error to a recoverable failure.-err :: e -> Parser r e a-err e = Parser \fp r eob s n -> Err# e+err :: e -> Parser e a+err e = Parser \fp !r eob s n -> Err# e {-# inline err #-} -- | Save the parsing state, then run a parser, then restore the state.-lookahead :: Parser r e a -> Parser r e a-lookahead (Parser f) = Parser \fp r eob s n ->+lookahead :: Parser e a -> Parser e a+lookahead (Parser f) = Parser \fp !r eob s n -> case f fp r eob s n of OK# a _ _ -> OK# a s n x -> x {-# inline lookahead #-} -- | Convert a parsing failure to a success.-fails :: Parser r e a -> Parser r e ()-fails (Parser f) = Parser \fp r eob s n ->+fails :: Parser e a -> Parser e ()+fails (Parser f) = Parser \fp !r eob s n -> case f fp r eob s n of OK# _ _ _ -> Fail# Fail# -> OK# () s n@@ -298,34 +300,34 @@ {-# inline fails #-} -- | Convert a parsing error into failure.-try :: Parser r e a -> Parser r e a-try (Parser f) = Parser \fp r eob s n -> case f fp r eob s n of+try :: Parser e a -> Parser e a+try (Parser f) = Parser \fp !r eob s n -> case f fp r eob s n of Err# _ -> Fail# x -> x {-# inline try #-} -- | Convert a parsing failure to a `Maybe`. If possible, use `optioned` instead.-optional :: Parser r e a -> Parser r e (Maybe a)+optional :: Parser e a -> Parser e (Maybe a) optional p = (Just <$> p) <|> pure Nothing {-# inline optional #-} -- | Convert a parsing failure to a `()`.-optional_ :: Parser r e a -> Parser r e ()+optional_ :: Parser e a -> Parser e () optional_ p = (() <$ p) <|> pure () {-# inline optional_ #-} -- | CPS'd version of `optional`. This is usually more efficient, since it gets rid of the -- extra `Maybe` allocation.-optioned :: Parser r e a -> (a -> Parser r e b) -> Parser r e b -> Parser r e b-optioned (Parser f) just (Parser nothing) = Parser \fp r eob s n -> case f fp r eob s n of+optioned :: Parser e a -> (a -> Parser e b) -> Parser e b -> Parser e b+optioned (Parser f) just (Parser nothing) = Parser \fp !r eob s n -> case f fp r eob s n of OK# a s n -> runParser# (just a) fp r eob s n Fail# -> nothing fp r eob s n Err# e -> Err# e {-# inline optioned #-} -- | Convert a parsing failure to an error.-cut :: Parser r e a -> e -> Parser r e a-cut (Parser f) e = Parser \fp r eob s n -> case f fp r eob s n of+cut :: Parser e a -> e -> Parser e a+cut (Parser f) e = Parser \fp !r eob s n -> case f fp r eob s n of Fail# -> Err# e x -> x {-# inline cut #-}@@ -333,8 +335,8 @@ -- | Run the parser, if we get a failure, throw the given error, but if we get an error, merge the -- inner and the newly given errors using the @e -> e -> e@ function. This can be useful for -- implementing parsing errors which may propagate hints or accummulate contextual information.-cutting :: Parser r e a -> e -> (e -> e -> e) -> Parser r e a-cutting (Parser f) e merge = Parser \fp r eob s n -> case f fp r eob s n of+cutting :: Parser e a -> e -> (e -> e -> e) -> Parser e a+cutting (Parser f) e merge = Parser \fp !r eob s n -> case f fp r eob s n of Fail# -> Err# e Err# e' -> let !e'' = merge e' e in Err# e'' x -> x@@ -344,31 +346,31 @@ -- | Succeed if the input is empty.-eof :: Parser r e ()-eof = Parser \fp r eob s n -> case eqAddr# eob s of+eof :: Parser e ()+eof = Parser \fp !r eob s n -> case eqAddr# eob s of 1# -> OK# () s n _ -> Fail# {-# inline eof #-} -- | Parse a UTF-8 character literal. This is a template function, you can use it as--- @$(char \'x\')@, for example, and the splice in this case has type @Parser r e ()@.+-- @$(char \'x\')@, for example, and the splice in this case has type @Parser e ()@. char :: Char -> Q Exp char c = string [c] -- | Read a `Word8`.-byte :: Word8 -> Parser r e ()+byte :: Word8 -> Parser e () byte (W8# w) = ensureBytes# 1 >> scan8# (W# w) {-# inline byte #-} -- | Read a sequence of bytes. This is a template function, you can use it as @$(bytes [3, 4, 5])@,--- for example, and the splice has type @Parser r e ()@.+-- for example, and the splice has type @Parser e ()@. bytes :: [Word8] -> Q Exp bytes bytes = do let !len = length bytes [| ensureBytes# len >> $(scanBytes# bytes) |] -- | Parse a UTF-8 string literal. This is a template function, you can use it as @$(string "foo")@,--- for example, and the splice has type @Parser r e ()@.+-- for example, and the splice has type @Parser e ()@. string :: String -> Q Exp string str = bytes (strToBytes str) @@ -411,7 +413,7 @@ {-| Switch expression with an optional first argument for performing a post-processing action after-every successful branch matching. For example, if we have @ws :: Parser r e ()@ for a+every successful branch matching. For example, if we have @ws :: Parser e ()@ for a whitespace parser, we might want to consume whitespace after matching on any of the switch cases. For that case, we can define a "lexeme" version of `switch` as follows. @@ -439,8 +441,8 @@ genTrie $! genSwitchTrie' postAction cases fallback -- | Parse a UTF-8 `Char` for which a predicate holds.-satisfy :: (Char -> Bool) -> Parser r e Char-satisfy f = Parser \fp r eob s n -> case runParser# anyChar fp r eob s n of+satisfy :: (Char -> Bool) -> Parser e Char+satisfy f = Parser \fp !r eob s n -> case runParser# anyChar fp r eob s n of OK# c s n | f c -> OK# c s n _ -> Fail# {-# inline satisfy #-}@@ -448,8 +450,8 @@ -- | Parse an ASCII `Char` for which a predicate holds. Assumption: the predicate must only return -- `True` for ASCII-range characters. Otherwise this function might read a 128-255 range byte, -- thereby breaking UTF-8 decoding.-satisfyASCII :: (Char -> Bool) -> Parser r e Char-satisfyASCII f = Parser \fp r eob s n -> case eqAddr# eob s of+satisfyASCII :: (Char -> Bool) -> Parser e Char+satisfyASCII f = Parser \fp !r eob s n -> case eqAddr# eob s of 1# -> Fail# _ -> case derefChar8# s of c1 | f (C# c1) -> OK# (C# c1) (plusAddr# s 1#) n@@ -457,7 +459,7 @@ {-# inline satisfyASCII #-} -- | Parse an ASCII `Char` for which a predicate holds.-satisfyASCII_ :: (Char -> Bool) -> Parser r e ()+satisfyASCII_ :: (Char -> Bool) -> Parser e () satisfyASCII_ f = () <$ satisfyASCII f {-# inline satisfyASCII_ #-} @@ -471,8 +473,8 @@ -- can do better with @fusedSatisfy isLatinLetter isLetter isLetter isLetter@, since here the -- `isLatinLetter` is inlined into the UTF-8 decoding, and it probably handles a great majority of -- all cases without accessing the character table.-fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser r e Char-fusedSatisfy f1 f2 f3 f4 = Parser \fp r eob buf n -> case eqAddr# eob buf of+fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser e Char+fusedSatisfy f1 f2 f3 f4 = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -513,40 +515,40 @@ {-# inline fusedSatisfy #-} -- | Parse any `Word8`.-anyWord8 :: Parser r e Word8-anyWord8 = Parser \fp r eob buf n -> case eqAddr# eob buf of+anyWord8 :: Parser e Word8+anyWord8 = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWord8OffAddr# buf 0# of w -> OK# (W8# w) (plusAddr# buf 1#) n {-# inline anyWord8 #-} -- | Parse any `Word16`.-anyWord16 :: Parser r e Word16-anyWord16 = Parser \fp r eob buf n -> case eqAddr# eob buf of+anyWord16 :: Parser e Word16+anyWord16 = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWord16OffAddr# buf 0# of w -> OK# (W16# w) (plusAddr# buf 2#) n {-# inline anyWord16 #-} -- | Parse any `Word32`.-anyWord32 :: Parser r e Word32-anyWord32 = Parser \fp r eob buf n -> case eqAddr# eob buf of+anyWord32 :: Parser e Word32+anyWord32 = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWord32OffAddr# buf 0# of w -> OK# (W32# w) (plusAddr# buf 4#) n {-# inline anyWord32 #-} -- | Parse any `Word`.-anyWord :: Parser r e Word-anyWord = Parser \fp r eob buf n -> case eqAddr# eob buf of+anyWord :: Parser e Word+anyWord = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case indexWordOffAddr# buf 0# of w -> OK# (W# w) (plusAddr# buf 8#) n {-# inline anyWord #-} -- | Parse any UTF-8-encoded `Char`.-anyChar :: Parser r e Char-anyChar = Parser \fp r eob buf n -> case eqAddr# eob buf of+anyChar :: Parser e Char+anyChar = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -580,8 +582,8 @@ {-# inline anyChar #-} -- | Skip any UTF-8-encoded `Char`.-anyChar_ :: Parser r e ()-anyChar_ = Parser \fp r eob buf n -> case eqAddr# eob buf of+anyChar_ :: Parser e ()+anyChar_ = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -601,8 +603,8 @@ -- | Parse any `Char` in the ASCII range, fail if the next input character is not in the range. -- This is more efficient than `anyChar` if we are only working with ASCII.-anyCharASCII :: Parser r e Char-anyCharASCII = Parser \fp r eob buf n -> case eqAddr# eob buf of+anyCharASCII :: Parser e Char+anyCharASCII = Parser \fp !r eob buf n -> case eqAddr# eob buf of 1# -> Fail# _ -> case derefChar8# buf of c1 -> case c1 `leChar#` '\x7F'# of@@ -612,7 +614,7 @@ -- | Skip any `Char` in the ASCII range. More efficient than `anyChar_` if we're working only with -- ASCII.-anyCharASCII_ :: Parser r e ()+anyCharASCII_ :: Parser e () anyCharASCII_ = () <$ anyCharASCII {-# inline anyCharASCII_ #-} @@ -637,8 +639,8 @@ -- | Choose between two parsers. If the first parser fails, try the second one, but if the first one -- throws an error, propagate the error. infixr 6 <|>-(<|>) :: Parser r e a -> Parser r e a -> Parser r e a-(<|>) (Parser f) (Parser g) = Parser \fp r eob s n ->+(<|>) :: Parser e a -> Parser e a -> Parser e a+(<|>) (Parser f) (Parser g) = Parser \fp !r eob s n -> case f fp r eob s n of Fail# -> g fp r eob s n x -> x@@ -647,8 +649,8 @@ -- | Branch on a parser: if the first argument fails, continue with the second, else with the third. -- This can produce slightly more efficient code than `(<|>)`. Moreover, `ḃranch` does not -- backtrack from the true/false cases.-branch :: Parser r e a -> Parser r e b -> Parser r e b -> Parser r e b-branch pa pt pf = Parser \fp r eob s n -> case runParser# pa fp r eob s n of+branch :: Parser e a -> Parser e b -> Parser e b -> Parser e b+branch pa pt pf = Parser \fp !r eob s n -> case runParser# pa fp r eob s n of OK# _ s n -> runParser# pt fp r eob s n Fail# -> runParser# pf fp r eob s n Err# e -> Err# e@@ -657,7 +659,7 @@ -- | An analogue of the list `foldl` function: first parse a @b@, then parse zero or more @a@-s, -- and combine the results in a left-nested way by the @b -> a -> b@ function. Note: this is not -- the usual `chainl` function from the parsec libraries!-chainl :: (b -> a -> b) -> Parser r e b -> Parser r e a -> Parser r e b+chainl :: (b -> a -> b) -> Parser e b -> Parser e a -> Parser e b chainl f start elem = start >>= go where go b = do {!a <- elem; go $! f b a} <|> pure b {-# inline chainl #-}@@ -665,23 +667,33 @@ -- | An analogue of the list `foldr` function: parse zero or more @a@-s, terminated by a @b@, and -- combine the results in a right-nested way using the @a -> b -> b@ function. Note: this is not -- the usual `chainr` function from the parsec libraries!-chainr :: (a -> b -> b) -> Parser r e a -> Parser r e b -> Parser r e b-chainr f elem end = go where- go = (f <$> elem <*> go) <|> end+chainr :: (a -> b -> b) -> Parser e a -> Parser e b -> Parser e b+chainr f (Parser elem) (Parser end) = go where+ go = Parser \fp !r eob s n -> case elem fp r eob s n of+ OK# a s n -> case runParser# go fp r eob s n of+ OK# b s n -> let !b' = f a b in OK# b' s n+ x -> x+ Fail# -> end fp r eob s n+ Err# e -> Err# e {-# inline chainr #-} -- | Run a parser zero or more times, collect the results in a list. Note: for optimal performance, -- try to avoid this. Often it is possible to get rid of the intermediate list by using a -- combinator or a custom parser.-many :: Parser r e a -> Parser r e [a]-many p = go where- go = ((:) <$> p <*> go) <|> pure []+many :: Parser e a -> Parser e [a]+many (Parser f) = go where+ go = Parser \fp !r eob s n -> case f fp r eob s n of+ OK# a s n -> case runParser# go fp r eob s n of+ OK# as s n -> OK# (a:as) s n+ x -> x+ Fail# -> OK# [] s n+ Err# e -> Err# e {-# inline many #-} -- | Skip a parser zero or more times.-many_ :: Parser r e a -> Parser r e ()+many_ :: Parser e a -> Parser e () many_ (Parser f) = go where- go = Parser \fp r eob s n -> case f fp r eob s n of+ go = Parser \fp !r eob s n -> case f fp r eob s n of OK# a s n -> runParser# go fp r eob s n Fail# -> OK# () s n Err# e -> Err# e@@ -690,18 +702,18 @@ -- | Run a parser one or more times, collect the results in a list. Note: for optimal performance, -- try to avoid this. Often it is possible to get rid of the intermediate list by using a -- combinator or a custom parser.-some :: Parser r e a -> Parser r e [a]+some :: Parser e a -> Parser e [a] some p = (:) <$> p <*> many p {-# inline some #-} -- | Skip a parser one or more times.-some_ :: Parser r e a -> Parser r e ()+some_ :: Parser e a -> Parser e () some_ pa = pa >> many_ pa {-# inline some_ #-} -- | Succeed if the first parser succeeds and the second one fails. The parsing -- state is restored to the point of the first argument's success.-notFollowedBy :: Parser r e a -> Parser r e b -> Parser r e a+notFollowedBy :: Parser e a -> Parser e b -> Parser e a notFollowedBy p1 p2 = p1 <* lookahead (fails p2) {-# inline notFollowedBy #-} @@ -725,15 +737,15 @@ {-# inline (>=) #-} -- | Get the current position in the input.-getPos :: Parser r e Pos-getPos = Parser \fp r eob s n -> OK# (addrToPos# eob s) s n+getPos :: Parser e Pos+getPos = Parser \fp !r eob s n -> OK# (addrToPos# eob s) s n {-# inline getPos #-} -- | Set the input position. Warning: this can result in crashes if the position points outside the -- current buffer. It is always safe to `setPos` values which came from `getPos` with the current -- input.-setPos :: Pos -> Parser r e ()-setPos s = Parser \fp r eob _ n -> OK# () (posToAddr# eob s) n+setPos :: Pos -> Parser e ()+setPos s = Parser \fp !r eob _ n -> OK# () (posToAddr# eob s) n {-# inline setPos #-} -- | The end of the input.@@ -743,32 +755,32 @@ -- | Return the consumed span of a parser. Use `spanned` if possible for better efficiency.-spanOf :: Parser r e a -> Parser r e Span-spanOf (Parser f) = Parser \fp r eob s n -> case f fp r eob s n of+spanOf :: Parser e a -> Parser e Span+spanOf (Parser f) = Parser \fp !r eob s n -> case f fp r eob s n of OK# a s' n -> OK# (Span (addrToPos# eob s) (addrToPos# eob s')) s' n x -> unsafeCoerce# x {-# inline spanOf #-} -- | Bind the result together with the span of the result. CPS'd version of `spanOf` -- for better unboxing.-spanned :: Parser r e a -> (a -> Span -> Parser r e b) -> Parser r e b-spanned (Parser f) g = Parser \fp r eob s n -> case f fp r eob s n of+spanned :: Parser e a -> (a -> Span -> Parser e b) -> Parser e b+spanned (Parser f) g = Parser \fp !r eob s n -> case f fp r eob s n of OK# a s' n -> runParser# (g a (Span (addrToPos# eob s) (addrToPos# eob s'))) fp r eob s' n x -> unsafeCoerce# x {-# inline spanned #-} -- | Return the `B.ByteString` consumed by a parser. Note: it's more efficient to use `spanOf` and -- `spanned` instead.-byteStringOf :: Parser r e a -> Parser r e B.ByteString-byteStringOf (Parser f) = Parser \fp r eob s n -> case f fp r eob s n of+byteStringOf :: Parser e a -> Parser e B.ByteString+byteStringOf (Parser f) = Parser \fp !r eob s n -> case f fp r eob s n of OK# a s' n -> OK# (B.PS (ForeignPtr s fp) 0 (I# (minusAddr# s' s))) s' n x -> unsafeCoerce# x {-# inline byteStringOf #-} -- | CPS'd version of `byteStringOf`. Can be more efficient, because the result is more eagerly unboxed -- by GHC. It's more efficient to use `spanOf` or `spanned` instead.-byteStringed :: Parser r e a -> (a -> B.ByteString -> Parser r e b) -> Parser r e b-byteStringed (Parser f) g = Parser \fp r eob s n -> case f fp r eob s n of+byteStringed :: Parser e a -> (a -> B.ByteString -> Parser e b) -> Parser e b+byteStringed (Parser f) g = Parser \fp !r eob s n -> case f fp r eob s n of OK# a s' n -> runParser# (g a (B.PS (ForeignPtr s fp) 0 (I# (minusAddr# s' s)))) fp r eob s' n x -> unsafeCoerce# x {-# inline byteStringed #-}@@ -778,8 +790,8 @@ -- this operation may crash if the given span points outside the current parsing buffer. It's -- always safe to use `inSpan` if the span comes from a previous `spanned` or `spanOf` call on -- the current input.-inSpan :: Span -> Parser r e a -> Parser r e a-inSpan (Span s eob) (Parser f) = Parser \fp r eob' s' n' ->+inSpan :: Span -> Parser e a -> Parser e a+inSpan (Span s eob) (Parser f) = Parser \fp !r eob' s' n' -> case f fp r (posToAddr# eob' eob) (posToAddr# eob' s) n' of OK# a _ _ -> OK# a s' n' x -> unsafeCoerce# x@@ -793,7 +805,7 @@ let go = do start <- getPos pure (start <= pos && pos <= endPos)- in case runParser go () 0 str of+ in case runParser go 0 0 str of OK b _ _ -> b _ -> error "impossible" {-# inline validPos #-}@@ -818,14 +830,14 @@ sorted :: [(Int, Pos)] sorted = sortBy (comparing snd) (zip [0..] poss) - in case runParser (go 0 0 sorted) () 0 str of+ in case runParser (go 0 0 sorted) 0 0 str of OK res _ _ -> snd <$> sortBy (comparing fst) res _ -> error "invalid position" -- | Create a `B.ByteString` from a `Span`. The result is invalid is the `Span` points -- outside the current buffer, or if the `Span` start is greater than the end position.-unsafeSpanToByteString :: Span -> Parser r e B.ByteString+unsafeSpanToByteString :: Span -> Parser e B.ByteString unsafeSpanToByteString (Span l r) = lookahead (setPos l >> byteStringOf (setPos r)) {-# inline unsafeSpanToByteString #-}@@ -840,7 +852,7 @@ c <- anyChar if c == '\n' then go (line + 1) 0 else go line (col + 1)) <|> error "mkPos: invalid position"- in case runParser (go 0 0) () 0 str of+ in case runParser (go 0 0) 0 0 str of OK res _ _ -> res _ -> error "impossible" @@ -851,7 +863,7 @@ lines :: B.ByteString -> [String] lines str = let go = ([] <$ eof) <|> ((:) <$> takeLine <*> go)- in case runParser go () 0 str of+ in case runParser go 0 0 str of OK ls _ _ -> ls _ -> error "linesUTF8: invalid input" @@ -861,7 +873,7 @@ -- | Parse the rest of the current line as a `String`. Assumes UTF-8 encoding, -- throws an error if the encoding is invalid.-takeLine :: Parser r e String+takeLine :: Parser e String takeLine = branch eof (pure "") do c <- anyChar@@ -871,16 +883,16 @@ -- | Parse the rest of the current line as a `String`, but restore the parsing state. -- Assumes UTF-8 encoding. This can be used for debugging.-traceLine :: Parser r e String+traceLine :: Parser e String traceLine = lookahead takeLine -- | Take the rest of the input as a `String`. Assumes UTF-8 encoding.-takeRest :: Parser r e String+takeRest :: Parser e String takeRest = ((:) <$> anyChar <*> takeRest) <|> pure [] -- | Get the rest of the input as a `String`, but restore the parsing state. Assumes UTF-8 encoding. -- This can be used for debugging.-traceRest :: Parser r e String+traceRest :: Parser e String traceRest = lookahead traceRest --------------------------------------------------------------------------------@@ -934,8 +946,8 @@ {-# inline derefChar8# #-} -- | Check that the input has at least the given number of bytes.-ensureBytes# :: Int -> Parser r e ()-ensureBytes# (I# len) = Parser \fp r eob s n ->+ensureBytes# :: Int -> Parser e ()+ensureBytes# (I# len) = Parser \fp !r eob s n -> case len <=# minusAddr# eob s of 1# -> OK# () s n _ -> Fail#@@ -943,8 +955,8 @@ -- | Unsafely read a concrete byte from the input. It's not checked that the input has -- enough bytes.-scan8# :: Word -> Parser r e ()-scan8# (W# c) = Parser \fp r eob s n ->+scan8# :: Word -> Parser e ()+scan8# (W# c) = Parser \fp !r eob s n -> case indexWord8OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 1#) n@@ -953,8 +965,8 @@ -- | Unsafely read two concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan16# :: Word -> Parser r e ()-scan16# (W# c) = Parser \fp r eob s n ->+scan16# :: Word -> Parser e ()+scan16# (W# c) = Parser \fp !r eob s n -> case indexWord16OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 2#) n@@ -963,8 +975,8 @@ -- | Unsafely read four concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan32# :: Word -> Parser r e ()-scan32# (W# c) = Parser \fp r eob s n ->+scan32# :: Word -> Parser e ()+scan32# (W# c) = Parser \fp !r eob s n -> case indexWord32OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 4#) n@@ -973,8 +985,8 @@ -- | Unsafely read eight concrete bytes from the input. It's not checked that the input has -- enough bytes.-scan64# :: Word -> Parser r e ()-scan64# (W# c) = Parser \fp r eob s n ->+scan64# :: Word -> Parser e ()+scan64# (W# c) = Parser \fp !r eob s n -> case indexWord64OffAddr# s 0# of c' -> case eqWord# c c' of 1# -> OK# () (plusAddr# s 8#) n@@ -982,12 +994,12 @@ {-# inline scan64# #-} -- | Unsafely read and return a byte from the input. It's not checked that the input is non-empty.-scanAny8# :: Parser r e Word8-scanAny8# = Parser \fp r eob s n -> OK# (W8# (indexWord8OffAddr# s 0#)) (plusAddr# s 1#) n+scanAny8# :: Parser e Word8+scanAny8# = Parser \fp !r eob s n -> OK# (W8# (indexWord8OffAddr# s 0#)) (plusAddr# s 1#) n {-# inline scanAny8# #-} -scanPartial64# :: Int -> Word -> Parser r e ()-scanPartial64# (I# len) (W# w) = Parser \fp r eob s n ->+scanPartial64# :: Int -> Word -> Parser e ()+scanPartial64# (I# len) (W# w) = Parser \fp !r eob s n -> case indexWordOffAddr# s 0# of w' -> case uncheckedIShiftL# (8# -# len) 3# of sh -> case uncheckedShiftL# w' sh of@@ -998,12 +1010,12 @@ {-# inline scanPartial64# #-} -- | Decrease the current input position by the given number of bytes.-setBack# :: Int -> Parser r e ()-setBack# (I# i) = Parser \fp r eob s n ->+setBack# :: Int -> Parser e ()+setBack# (I# i) = Parser \fp !r eob s n -> OK# () (plusAddr# s (negateInt# i)) n {-# inline setBack# #-} --- | Template function, creates a @Parser r e ()@ which unsafely scans a given+-- | Template function, creates a @Parser e ()@ which unsafely scans a given -- sequence of bytes. scanBytes# :: [Word8] -> Q Exp scanBytes# bytes = do@@ -1053,7 +1065,7 @@ Branch rule' (M.alter (Just . maybe (go cs nilTrie) (go cs)) c ts) fromList :: [(Int, String)] -> Trie Rule-fromList = foldl' (\t (!r, !s) -> insert r (charToBytes =<< s) t) nilTrie+fromList = foldl' (\t (r, !s) -> insert r (charToBytes =<< s) t) nilTrie -- | Decorate a trie with the minimum lengths of non-empty paths. This -- is used later to place `ensureBytes#`.@@ -1084,7 +1096,7 @@ fallbacks :: Trie' (Rule, Int) -> Trie' (Rule, Int, Int) fallbacks = go Nothing 0 where go :: Rule -> Int -> Trie' (Rule, Int) -> Trie' (Rule, Int, Int)- go !rule !n (Branch' (rule', d) ts)+ go rule !n (Branch' (rule', d) ts) | M.null ts = Branch' (rule', 0, d) mempty | Nothing <- rule' = Branch' (rule, n, d) (go rule (n + 1) <$> ts) | otherwise = Branch' (rule, n, d) (go rule' 1 <$> ts)@@ -1097,7 +1109,7 @@ ensureBytes :: Trie' (Rule, Int, Int) -> Trie' (Rule, Int, Maybe Int) ensureBytes = go 0 where go :: Int -> Trie' (Rule, Int, Int) -> Trie' (Rule, Int, Maybe Int)- go !res = \case+ go res = \case Branch' (r, n, d) ts | M.null ts -> Branch' (r, n, Nothing) mempty | res < 1 -> Branch' (r, n, Just d ) (go (d - 1) <$> ts)