{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-} #endif -- | -- Module : Data.Attoparsec.ByteString -- Copyright : Bryan O'Sullivan 2007-2015 -- License : BSD3 -- -- Maintainer : bos@serpentine.com -- Stability : experimental -- Portability : unknown -- -- Simple, efficient combinator parsing for 'B.ByteString' strings, -- loosely based on the Parsec library. module Data.Attoparsec.ByteString ( -- * Differences from Parsec -- $parsec -- * Incremental input -- $incremental -- * Performance considerations -- $performance -- * Parser types I.Parser , Result , T.IResult(..) , I.compareResults -- * Running parsers , parse , feed , I.parseOnly , parseWith , parseTest -- ** Result conversion , maybeResult , eitherResult -- * Parsing individual bytes , I.word8 , I.anyWord8 , I.notWord8 , I.satisfy , I.satisfyWith , I.skip -- ** Lookahead , I.peekWord8 , I.peekWord8' -- ** Byte classes , I.inClass , I.notInClass -- * Efficient string handling , I.string , I.skipWhile , I.take , I.scan , I.runScanner , I.takeWhile , I.takeWhile1 , I.takeWhileIncluding , I.takeTill , I.getChunk -- ** Consume all remaining input , I.takeByteString , I.takeLazyByteString -- * Combinators , try , (<?>) , choice , count , option , many' , many1 , many1' , manyTill , manyTill' , sepBy , sepBy' , sepBy1 , sepBy1' , skipMany , skipMany1 , eitherP , I.match -- * State observation and manipulation functions , I.endOfInput , I.atEnd ) where import Data.Attoparsec.Combinator import Data.List (intercalate) import qualified Data.Attoparsec.ByteString.Internal as I import qualified Data.Attoparsec.Internal as I import qualified Data.ByteString as B import Data.Attoparsec.ByteString.Internal (Result, parse) import qualified Data.Attoparsec.Internal.Types as T -- $parsec -- -- Compared to Parsec 3, attoparsec makes several tradeoffs. It is -- not intended for, or ideal for, all possible uses. -- -- * While attoparsec can consume input incrementally, Parsec cannot. -- Incremental input is a huge deal for efficient and secure network -- and system programming, since it gives much more control to users -- of the library over matters such as resource usage and the I/O -- model to use. -- -- * Much of the performance advantage of attoparsec is gained via -- high-performance parsers such as 'I.takeWhile' and 'I.string'. -- If you use complicated combinators that return lists of bytes or -- characters, there is less performance difference between the two -- libraries. -- -- * Unlike Parsec 3, attoparsec does not support being used as a -- monad transformer. -- -- * attoparsec is specialised to deal only with strict 'B.ByteString' -- input. Efficiency concerns rule out both lists and lazy -- bytestrings. The usual use for lazy bytestrings would be to -- allow consumption of very large input without a large footprint. -- For this need, attoparsec's incremental input provides an -- excellent substitute, with much more control over when input -- takes place. If you must use lazy bytestrings, see the -- "Data.Attoparsec.ByteString.Lazy" module, which feeds lazy chunks -- to a regular parser. -- -- * Parsec parsers can produce more helpful error messages than -- attoparsec parsers. This is a matter of focus: attoparsec avoids -- the extra book-keeping in favour of higher performance. -- $incremental -- -- attoparsec supports incremental input, meaning that you can feed it -- a bytestring that represents only part of the expected total amount -- of data to parse. If your parser reaches the end of a fragment of -- input and could consume more input, it will suspend parsing and -- return a 'T.Partial' continuation. -- -- Supplying the 'T.Partial' continuation with a bytestring will -- resume parsing at the point where it was suspended, with the -- bytestring you supplied used as new input at the end of the -- existing input. You must be prepared for the result of the resumed -- parse to be another 'T.Partial' continuation. -- -- To indicate that you have no more input, supply the 'T.Partial' -- continuation with an empty bytestring. -- -- Remember that some parsing combinators will not return a result -- until they reach the end of input. They may thus cause 'T.Partial' -- results to be returned. -- -- If you do not need support for incremental input, consider using -- the 'I.parseOnly' function to run your parser. It will never -- prompt for more input. -- -- /Note/: incremental input does /not/ imply that attoparsec will -- release portions of its internal state for garbage collection as it -- proceeds. Its internal representation is equivalent to a single -- 'ByteString': if you feed incremental input to a parser, it will -- require memory proportional to the amount of input you supply. -- (This is necessary to support arbitrary backtracking.) -- $performance -- -- If you write an attoparsec-based parser carefully, it can be -- realistic to expect it to perform similarly to a hand-rolled C -- parser (measuring megabytes parsed per second). -- -- To actually achieve high performance, there are a few guidelines -- that it is useful to follow. -- -- Use the 'B.ByteString'-oriented parsers whenever possible, -- e.g. 'I.takeWhile1' instead of 'many1' 'I.anyWord8'. There is -- about a factor of 100 difference in performance between the two -- kinds of parser. -- -- For very simple byte-testing predicates, write them by hand instead -- of using 'I.inClass' or 'I.notInClass'. For instance, both of -- these predicates test for an end-of-line byte, but the first is -- much faster than the second: -- -- >endOfLine_fast w = w == 13 || w == 10 -- >endOfLine_slow = inClass "\r\n" -- -- Make active use of benchmarking and profiling tools to measure, -- find the problems with, and improve the performance of your parser. -- | Run a parser and print its result to standard output. parseTest :: (Show a) => I.Parser a -> B.ByteString -> IO () parseTest :: Parser a -> ByteString -> IO () parseTest Parser a p ByteString s = Result a -> IO () forall a. Show a => a -> IO () print (Parser a -> ByteString -> Result a forall a. Parser a -> ByteString -> Result a parse Parser a p ByteString s) -- | Run a parser with an initial input string, and a monadic action -- that can supply more input if needed. parseWith :: Monad m => (m B.ByteString) -- ^ An action that will be executed to provide the parser -- with more input, if necessary. The action must return an -- 'B.empty' string when there is no more input available. -> I.Parser a -> B.ByteString -- ^ Initial input for the parser. -> m (Result a) parseWith :: m ByteString -> Parser a -> ByteString -> m (Result a) parseWith m ByteString refill Parser a p ByteString s = Result a -> m (Result a) forall r. IResult ByteString r -> m (IResult ByteString r) step (Result a -> m (Result a)) -> Result a -> m (Result a) forall a b. (a -> b) -> a -> b $ Parser a -> ByteString -> Result a forall a. Parser a -> ByteString -> Result a parse Parser a p ByteString s where step :: IResult ByteString r -> m (IResult ByteString r) step (T.Partial ByteString -> IResult ByteString r k) = (IResult ByteString r -> m (IResult ByteString r) step (IResult ByteString r -> m (IResult ByteString r)) -> (ByteString -> IResult ByteString r) -> ByteString -> m (IResult ByteString r) forall b c a. (b -> c) -> (a -> b) -> a -> c . ByteString -> IResult ByteString r k) (ByteString -> m (IResult ByteString r)) -> m ByteString -> m (IResult ByteString r) forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b =<< m ByteString refill step IResult ByteString r r = IResult ByteString r -> m (IResult ByteString r) forall (m :: * -> *) a. Monad m => a -> m a return IResult ByteString r r {-# INLINE parseWith #-} -- | Convert a 'Result' value to a 'Maybe' value. A 'T.Partial' result -- is treated as failure. maybeResult :: Result r -> Maybe r maybeResult :: Result r -> Maybe r maybeResult (T.Done ByteString _ r r) = r -> Maybe r forall a. a -> Maybe a Just r r maybeResult Result r _ = Maybe r forall a. Maybe a Nothing -- | Convert a 'Result' value to an 'Either' value. A 'T.Partial' -- result is treated as failure. eitherResult :: Result r -> Either String r eitherResult :: Result r -> Either String r eitherResult (T.Done ByteString _ r r) = r -> Either String r forall a b. b -> Either a b Right r r eitherResult (T.Fail ByteString _ [] String msg) = String -> Either String r forall a b. a -> Either a b Left String msg eitherResult (T.Fail ByteString _ [String] ctxs String msg) = String -> Either String r forall a b. a -> Either a b Left (String -> [String] -> String forall a. [a] -> [[a]] -> [a] intercalate String " > " [String] ctxs String -> String -> String forall a. [a] -> [a] -> [a] ++ String ": " String -> String -> String forall a. [a] -> [a] -> [a] ++ String msg) eitherResult Result r _ = String -> Either String r forall a b. a -> Either a b Left String "Result: incomplete input"