attoparsec 0.9.1.2 → 0.10.0.0
raw patch · 21 files changed
+2537/−1525 lines, 21 filesdep +QuickCheckdep +arraydep +attoparsecdep ~basedep ~bytestringdep ~containersPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, array, attoparsec, test-framework, test-framework-quickcheck2, text
Dependency ranges changed: base, bytestring, containers, deepseq
API changes (from Hackage documentation)
- Data.Attoparsec: (<?>) :: Parser a -> String -> Parser a
- Data.Attoparsec: Done :: ByteString -> r -> Result r
- Data.Attoparsec: Fail :: ByteString -> [String] -> String -> Result r
- Data.Attoparsec: Partial :: (ByteString -> Result r) -> Result r
- Data.Attoparsec: anyWord8 :: Parser Word8
- Data.Attoparsec: atEnd :: Parser Bool
- Data.Attoparsec: data Parser a
- Data.Attoparsec: data Result r
- Data.Attoparsec: eitherResult :: Result r -> Either String r
- Data.Attoparsec: endOfInput :: Parser ()
- Data.Attoparsec: feed :: Result r -> ByteString -> Result r
- Data.Attoparsec: inClass :: String -> Word8 -> Bool
- Data.Attoparsec: maybeResult :: Result r -> Maybe r
- Data.Attoparsec: notInClass :: String -> Word8 -> Bool
- Data.Attoparsec: notWord8 :: Word8 -> Parser Word8
- Data.Attoparsec: parse :: Parser a -> ByteString -> Result a
- Data.Attoparsec: parseOnly :: Parser a -> ByteString -> Either String a
- Data.Attoparsec: parseTest :: Show a => Parser a -> ByteString -> IO ()
- Data.Attoparsec: parseWith :: Monad m => (m ByteString) -> Parser a -> ByteString -> m (Result a)
- Data.Attoparsec: satisfy :: (Word8 -> Bool) -> Parser Word8
- Data.Attoparsec: satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a
- Data.Attoparsec: scan :: s -> (s -> Word8 -> Maybe s) -> Parser ByteString
- Data.Attoparsec: skip :: (Word8 -> Bool) -> Parser ()
- Data.Attoparsec: skipWhile :: (Word8 -> Bool) -> Parser ()
- Data.Attoparsec: string :: ByteString -> Parser ByteString
- Data.Attoparsec: take :: Int -> Parser ByteString
- Data.Attoparsec: takeByteString :: Parser ByteString
- Data.Attoparsec: takeLazyByteString :: Parser ByteString
- Data.Attoparsec: takeTill :: (Word8 -> Bool) -> Parser ByteString
- Data.Attoparsec: takeWhile :: (Word8 -> Bool) -> Parser ByteString
- Data.Attoparsec: takeWhile1 :: (Word8 -> Bool) -> Parser ByteString
- Data.Attoparsec: try :: Parser a -> Parser a
- Data.Attoparsec: word8 :: Word8 -> Parser Word8
- Data.Attoparsec.Char8: (<?>) :: Parser a -> String -> Parser a
- Data.Attoparsec.Char8: D :: {-# UNPACK #-} !Double -> Number
- Data.Attoparsec.Char8: Done :: ByteString -> r -> Result r
- Data.Attoparsec.Char8: Fail :: ByteString -> [String] -> String -> Result r
- Data.Attoparsec.Char8: I :: !Integer -> Number
- Data.Attoparsec.Char8: Partial :: (ByteString -> Result r) -> Result r
- Data.Attoparsec.Char8: anyChar :: Parser Char
- Data.Attoparsec.Char8: atEnd :: Parser Bool
- Data.Attoparsec.Char8: char :: Char -> Parser Char
- Data.Attoparsec.Char8: char8 :: Char -> Parser Word8
- Data.Attoparsec.Char8: data Number
- Data.Attoparsec.Char8: data Parser a
- Data.Attoparsec.Char8: data Result r
- Data.Attoparsec.Char8: decimal :: Integral a => Parser a
- Data.Attoparsec.Char8: digit :: Parser Char
- Data.Attoparsec.Char8: double :: Parser Double
- Data.Attoparsec.Char8: eitherResult :: Result r -> Either String r
- Data.Attoparsec.Char8: endOfInput :: Parser ()
- Data.Attoparsec.Char8: endOfLine :: Parser ()
- Data.Attoparsec.Char8: feed :: Result r -> ByteString -> Result r
- Data.Attoparsec.Char8: hexadecimal :: (Integral a, Bits a) => Parser a
- Data.Attoparsec.Char8: inClass :: String -> Char -> Bool
- Data.Attoparsec.Char8: instance IsString (Parser ByteString)
- Data.Attoparsec.Char8: isAlpha_ascii :: Char -> Bool
- Data.Attoparsec.Char8: isAlpha_iso8859_15 :: Char -> Bool
- Data.Attoparsec.Char8: isDigit :: Char -> Bool
- Data.Attoparsec.Char8: isDigit_w8 :: Word8 -> Bool
- Data.Attoparsec.Char8: isEndOfLine :: Word8 -> Bool
- Data.Attoparsec.Char8: isHorizontalSpace :: Word8 -> Bool
- Data.Attoparsec.Char8: isSpace :: Char -> Bool
- Data.Attoparsec.Char8: isSpace_w8 :: Word8 -> Bool
- Data.Attoparsec.Char8: letter_ascii :: Parser Char
- Data.Attoparsec.Char8: letter_iso8859_15 :: Parser Char
- Data.Attoparsec.Char8: maybeResult :: Result r -> Maybe r
- Data.Attoparsec.Char8: notChar :: Char -> Parser Char
- Data.Attoparsec.Char8: notInClass :: String -> Char -> Bool
- Data.Attoparsec.Char8: number :: Parser Number
- Data.Attoparsec.Char8: parse :: Parser a -> ByteString -> Result a
- Data.Attoparsec.Char8: parseOnly :: Parser a -> ByteString -> Either String a
- Data.Attoparsec.Char8: parseTest :: Show a => Parser a -> ByteString -> IO ()
- Data.Attoparsec.Char8: parseWith :: Monad m => (m ByteString) -> Parser a -> ByteString -> m (Result a)
- Data.Attoparsec.Char8: rational :: Fractional a => Parser a
- Data.Attoparsec.Char8: satisfy :: (Char -> Bool) -> Parser Char
- Data.Attoparsec.Char8: scan :: s -> (s -> Char -> Maybe s) -> Parser ByteString
- Data.Attoparsec.Char8: signed :: Num a => Parser a -> Parser a
- Data.Attoparsec.Char8: skipSpace :: Parser ()
- Data.Attoparsec.Char8: skipWhile :: (Char -> Bool) -> Parser ()
- Data.Attoparsec.Char8: space :: Parser Char
- Data.Attoparsec.Char8: string :: ByteString -> Parser ByteString
- Data.Attoparsec.Char8: stringCI :: ByteString -> Parser ByteString
- Data.Attoparsec.Char8: take :: Int -> Parser ByteString
- Data.Attoparsec.Char8: takeByteString :: Parser ByteString
- Data.Attoparsec.Char8: takeLazyByteString :: Parser ByteString
- Data.Attoparsec.Char8: takeTill :: (Char -> Bool) -> Parser ByteString
- Data.Attoparsec.Char8: takeWhile :: (Char -> Bool) -> Parser ByteString
- Data.Attoparsec.Char8: takeWhile1 :: (Char -> Bool) -> Parser ByteString
- Data.Attoparsec.Char8: try :: Parser a -> Parser a
- Data.Attoparsec.Combinator: many :: Alternative f => f a -> f [a]
- Data.Attoparsec.FastSet: charClass :: String -> FastSet
- Data.Attoparsec.FastSet: data FastSet
- Data.Attoparsec.FastSet: fromList :: [Word8] -> FastSet
- Data.Attoparsec.FastSet: fromSet :: FastSet -> ByteString
- Data.Attoparsec.FastSet: instance Eq FastSet
- Data.Attoparsec.FastSet: instance Ord FastSet
- Data.Attoparsec.FastSet: instance Show FastSet
- Data.Attoparsec.FastSet: memberChar :: Char -> FastSet -> Bool
- Data.Attoparsec.FastSet: memberWord8 :: Word8 -> FastSet -> Bool
- Data.Attoparsec.FastSet: set :: ByteString -> FastSet
- Data.Attoparsec.Lazy: Done :: ByteString -> r -> Result r
- Data.Attoparsec.Lazy: Fail :: ByteString -> [String] -> String -> Result r
- Data.Attoparsec.Lazy: data Result r
- Data.Attoparsec.Lazy: eitherResult :: Result r -> Either String r
- Data.Attoparsec.Lazy: instance Functor Result
- Data.Attoparsec.Lazy: instance Show r => Show (Result r)
- Data.Attoparsec.Lazy: maybeResult :: Result r -> Maybe r
- Data.Attoparsec.Lazy: parse :: Parser a -> ByteString -> Result a
- Data.Attoparsec.Lazy: parseTest :: Show a => Parser a -> ByteString -> IO ()
+ Data.Attoparsec.ByteString: (<?>) :: Parser a -> String -> Parser a
+ Data.Attoparsec.ByteString: Done :: t -> r -> IResult t r
+ Data.Attoparsec.ByteString: Fail :: t -> [String] -> String -> IResult t r
+ Data.Attoparsec.ByteString: Partial :: (t -> IResult t r) -> IResult t r
+ Data.Attoparsec.ByteString: anyWord8 :: Parser Word8
+ Data.Attoparsec.ByteString: atEnd :: Parser Bool
+ Data.Attoparsec.ByteString: data IResult t r
+ Data.Attoparsec.ByteString: eitherResult :: Result r -> Either String r
+ Data.Attoparsec.ByteString: endOfInput :: Parser ()
+ Data.Attoparsec.ByteString: feed :: Result r -> ByteString -> Result r
+ Data.Attoparsec.ByteString: inClass :: String -> Word8 -> Bool
+ Data.Attoparsec.ByteString: maybeResult :: Result r -> Maybe r
+ Data.Attoparsec.ByteString: notInClass :: String -> Word8 -> Bool
+ Data.Attoparsec.ByteString: notWord8 :: Word8 -> Parser Word8
+ Data.Attoparsec.ByteString: parse :: Parser a -> ByteString -> Result a
+ Data.Attoparsec.ByteString: parseOnly :: Parser a -> ByteString -> Either String a
+ Data.Attoparsec.ByteString: parseTest :: Show a => Parser a -> ByteString -> IO ()
+ Data.Attoparsec.ByteString: parseWith :: Monad m => (m ByteString) -> Parser a -> ByteString -> m (Result a)
+ Data.Attoparsec.ByteString: satisfy :: (Word8 -> Bool) -> Parser Word8
+ Data.Attoparsec.ByteString: satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a
+ Data.Attoparsec.ByteString: scan :: s -> (s -> Word8 -> Maybe s) -> Parser ByteString
+ Data.Attoparsec.ByteString: skip :: (Word8 -> Bool) -> Parser ()
+ Data.Attoparsec.ByteString: skipWhile :: (Word8 -> Bool) -> Parser ()
+ Data.Attoparsec.ByteString: string :: ByteString -> Parser ByteString
+ Data.Attoparsec.ByteString: take :: Int -> Parser ByteString
+ Data.Attoparsec.ByteString: takeByteString :: Parser ByteString
+ Data.Attoparsec.ByteString: takeLazyByteString :: Parser ByteString
+ Data.Attoparsec.ByteString: takeTill :: (Word8 -> Bool) -> Parser ByteString
+ Data.Attoparsec.ByteString: takeWhile :: (Word8 -> Bool) -> Parser ByteString
+ Data.Attoparsec.ByteString: takeWhile1 :: (Word8 -> Bool) -> Parser ByteString
+ Data.Attoparsec.ByteString: try :: Parser a -> Parser a
+ Data.Attoparsec.ByteString: type Parser a = Parser ByteString a
+ Data.Attoparsec.ByteString: type Result a = IResult ByteString a
+ Data.Attoparsec.ByteString: word8 :: Word8 -> Parser Word8
+ Data.Attoparsec.ByteString.Char8: (<?>) :: Parser a -> String -> Parser a
+ Data.Attoparsec.ByteString.Char8: D :: {-# UNPACK #-} !Double -> Number
+ Data.Attoparsec.ByteString.Char8: I :: !Integer -> Number
+ Data.Attoparsec.ByteString.Char8: anyChar :: Parser Char
+ Data.Attoparsec.ByteString.Char8: atEnd :: Parser Bool
+ Data.Attoparsec.ByteString.Char8: char :: Char -> Parser Char
+ Data.Attoparsec.ByteString.Char8: char8 :: Char -> Parser Word8
+ Data.Attoparsec.ByteString.Char8: data Number
+ Data.Attoparsec.ByteString.Char8: decimal :: Integral a => Parser a
+ Data.Attoparsec.ByteString.Char8: digit :: Parser Char
+ Data.Attoparsec.ByteString.Char8: double :: Parser Double
+ Data.Attoparsec.ByteString.Char8: eitherResult :: Result r -> Either String r
+ Data.Attoparsec.ByteString.Char8: endOfInput :: Parser ()
+ Data.Attoparsec.ByteString.Char8: endOfLine :: Parser ()
+ Data.Attoparsec.ByteString.Char8: feed :: Result r -> ByteString -> Result r
+ Data.Attoparsec.ByteString.Char8: hexadecimal :: (Integral a, Bits a) => Parser a
+ Data.Attoparsec.ByteString.Char8: inClass :: String -> Char -> Bool
+ Data.Attoparsec.ByteString.Char8: instance IsString (Parser ByteString)
+ Data.Attoparsec.ByteString.Char8: isAlpha_ascii :: Char -> Bool
+ Data.Attoparsec.ByteString.Char8: isAlpha_iso8859_15 :: Char -> Bool
+ Data.Attoparsec.ByteString.Char8: isDigit :: Char -> Bool
+ Data.Attoparsec.ByteString.Char8: isDigit_w8 :: Word8 -> Bool
+ Data.Attoparsec.ByteString.Char8: isEndOfLine :: Word8 -> Bool
+ Data.Attoparsec.ByteString.Char8: isHorizontalSpace :: Word8 -> Bool
+ Data.Attoparsec.ByteString.Char8: isSpace :: Char -> Bool
+ Data.Attoparsec.ByteString.Char8: isSpace_w8 :: Word8 -> Bool
+ Data.Attoparsec.ByteString.Char8: letter_ascii :: Parser Char
+ Data.Attoparsec.ByteString.Char8: letter_iso8859_15 :: Parser Char
+ Data.Attoparsec.ByteString.Char8: maybeResult :: Result r -> Maybe r
+ Data.Attoparsec.ByteString.Char8: notChar :: Char -> Parser Char
+ Data.Attoparsec.ByteString.Char8: notInClass :: String -> Char -> Bool
+ Data.Attoparsec.ByteString.Char8: number :: Parser Number
+ Data.Attoparsec.ByteString.Char8: parse :: Parser a -> ByteString -> Result a
+ Data.Attoparsec.ByteString.Char8: parseOnly :: Parser a -> ByteString -> Either String a
+ Data.Attoparsec.ByteString.Char8: parseTest :: Show a => Parser a -> ByteString -> IO ()
+ Data.Attoparsec.ByteString.Char8: parseWith :: Monad m => (m ByteString) -> Parser a -> ByteString -> m (Result a)
+ Data.Attoparsec.ByteString.Char8: rational :: Fractional a => Parser a
+ Data.Attoparsec.ByteString.Char8: satisfy :: (Char -> Bool) -> Parser Char
+ Data.Attoparsec.ByteString.Char8: scan :: s -> (s -> Char -> Maybe s) -> Parser ByteString
+ Data.Attoparsec.ByteString.Char8: signed :: Num a => Parser a -> Parser a
+ Data.Attoparsec.ByteString.Char8: skipSpace :: Parser ()
+ Data.Attoparsec.ByteString.Char8: skipWhile :: (Char -> Bool) -> Parser ()
+ Data.Attoparsec.ByteString.Char8: space :: Parser Char
+ Data.Attoparsec.ByteString.Char8: string :: ByteString -> Parser ByteString
+ Data.Attoparsec.ByteString.Char8: stringCI :: ByteString -> Parser ByteString
+ Data.Attoparsec.ByteString.Char8: take :: Int -> Parser ByteString
+ Data.Attoparsec.ByteString.Char8: takeByteString :: Parser ByteString
+ Data.Attoparsec.ByteString.Char8: takeLazyByteString :: Parser ByteString
+ Data.Attoparsec.ByteString.Char8: takeTill :: (Char -> Bool) -> Parser ByteString
+ Data.Attoparsec.ByteString.Char8: takeWhile :: (Char -> Bool) -> Parser ByteString
+ Data.Attoparsec.ByteString.Char8: takeWhile1 :: (Char -> Bool) -> Parser ByteString
+ Data.Attoparsec.ByteString.Char8: try :: Parser a -> Parser a
+ Data.Attoparsec.ByteString.Char8: type Parser a = Parser ByteString a
+ Data.Attoparsec.ByteString.Char8: type Result a = IResult ByteString a
+ Data.Attoparsec.ByteString.Lazy: Done :: ByteString -> r -> Result r
+ Data.Attoparsec.ByteString.Lazy: Fail :: ByteString -> [String] -> String -> Result r
+ Data.Attoparsec.ByteString.Lazy: data Result r
+ Data.Attoparsec.ByteString.Lazy: eitherResult :: Result r -> Either String r
+ Data.Attoparsec.ByteString.Lazy: instance Functor Result
+ Data.Attoparsec.ByteString.Lazy: instance Show r => Show (Result r)
+ Data.Attoparsec.ByteString.Lazy: maybeResult :: Result r -> Maybe r
+ Data.Attoparsec.ByteString.Lazy: parse :: Parser a -> ByteString -> Result a
+ Data.Attoparsec.ByteString.Lazy: parseTest :: Show a => Parser a -> ByteString -> IO ()
+ Data.Attoparsec.Text: (<?>) :: Parser a -> String -> Parser a
+ Data.Attoparsec.Text: D :: {-# UNPACK #-} !Double -> Number
+ Data.Attoparsec.Text: Done :: t -> r -> IResult t r
+ Data.Attoparsec.Text: Fail :: t -> [String] -> String -> IResult t r
+ Data.Attoparsec.Text: I :: !Integer -> Number
+ Data.Attoparsec.Text: Partial :: (t -> IResult t r) -> IResult t r
+ Data.Attoparsec.Text: anyChar :: Parser Char
+ Data.Attoparsec.Text: atEnd :: Parser Bool
+ Data.Attoparsec.Text: char :: Char -> Parser Char
+ Data.Attoparsec.Text: data IResult t r
+ Data.Attoparsec.Text: data Number
+ Data.Attoparsec.Text: decimal :: Integral a => Parser a
+ Data.Attoparsec.Text: double :: Parser Double
+ Data.Attoparsec.Text: eitherResult :: Result r -> Either String r
+ Data.Attoparsec.Text: endOfInput :: Parser ()
+ Data.Attoparsec.Text: endOfLine :: Parser ()
+ Data.Attoparsec.Text: feed :: Result r -> Text -> Result r
+ Data.Attoparsec.Text: hexadecimal :: (Integral a, Bits a) => Parser a
+ Data.Attoparsec.Text: inClass :: String -> Char -> Bool
+ Data.Attoparsec.Text: isEndOfLine :: Char -> Bool
+ Data.Attoparsec.Text: isHorizontalSpace :: Char -> Bool
+ Data.Attoparsec.Text: maybeResult :: Result r -> Maybe r
+ Data.Attoparsec.Text: notChar :: Char -> Parser Char
+ Data.Attoparsec.Text: notInClass :: String -> Char -> Bool
+ Data.Attoparsec.Text: number :: Parser Number
+ Data.Attoparsec.Text: parse :: Parser a -> Text -> Result a
+ Data.Attoparsec.Text: parseOnly :: Parser a -> Text -> Either String a
+ Data.Attoparsec.Text: parseTest :: Show a => Parser a -> Text -> IO ()
+ Data.Attoparsec.Text: parseWith :: Monad m => (m Text) -> Parser a -> Text -> m (Result a)
+ Data.Attoparsec.Text: rational :: Fractional a => Parser a
+ Data.Attoparsec.Text: satisfy :: (Char -> Bool) -> Parser Char
+ Data.Attoparsec.Text: satisfyWith :: (Char -> a) -> (a -> Bool) -> Parser a
+ Data.Attoparsec.Text: signed :: Num a => Parser a -> Parser a
+ Data.Attoparsec.Text: skip :: (Char -> Bool) -> Parser ()
+ Data.Attoparsec.Text: skipWhile :: (Char -> Bool) -> Parser ()
+ Data.Attoparsec.Text: string :: Text -> Parser Text
+ Data.Attoparsec.Text: take :: Int -> Parser Text
+ Data.Attoparsec.Text: takeLazyText :: Parser Text
+ Data.Attoparsec.Text: takeText :: Parser Text
+ Data.Attoparsec.Text: takeTill :: (Char -> Bool) -> Parser Text
+ Data.Attoparsec.Text: takeWhile :: (Char -> Bool) -> Parser Text
+ Data.Attoparsec.Text: takeWhile1 :: (Char -> Bool) -> Parser Text
+ Data.Attoparsec.Text: try :: Parser a -> Parser a
+ Data.Attoparsec.Text: type Parser a = Parser Text a
+ Data.Attoparsec.Text: type Result a = IResult Text a
+ Data.Attoparsec.Text.Lazy: Done :: Text -> r -> Result r
+ Data.Attoparsec.Text.Lazy: Fail :: Text -> [String] -> String -> Result r
+ Data.Attoparsec.Text.Lazy: data Result r
+ Data.Attoparsec.Text.Lazy: eitherResult :: Result r -> Either String r
+ Data.Attoparsec.Text.Lazy: instance Functor Result
+ Data.Attoparsec.Text.Lazy: instance Show r => Show (Result r)
+ Data.Attoparsec.Text.Lazy: maybeResult :: Result r -> Maybe r
+ Data.Attoparsec.Text.Lazy: parse :: Parser a -> Text -> Result a
+ Data.Attoparsec.Text.Lazy: parseTest :: Show a => Parser a -> Text -> IO ()
+ Data.Attoparsec.Types: Done :: t -> r -> IResult t r
+ Data.Attoparsec.Types: Fail :: t -> [String] -> String -> IResult t r
+ Data.Attoparsec.Types: Partial :: (t -> IResult t r) -> IResult t r
+ Data.Attoparsec.Types: data IResult t r
+ Data.Attoparsec.Types: data Parser t a
Files
- Data/Attoparsec.hs +3/−206
- Data/Attoparsec/ByteString.hs +202/−0
- Data/Attoparsec/ByteString/Char8.hs +502/−0
- Data/Attoparsec/ByteString/FastSet.hs +115/−0
- Data/Attoparsec/ByteString/Internal.hs +459/−0
- Data/Attoparsec/ByteString/Lazy.hs +91/−0
- Data/Attoparsec/Char8.hs +4/−488
- Data/Attoparsec/Combinator.hs +20/−23
- Data/Attoparsec/FastSet.hs +0/−115
- Data/Attoparsec/Internal.hs +0/−453
- Data/Attoparsec/Internal/Types.hs +106/−70
- Data/Attoparsec/Lazy.hs +2/−62
- Data/Attoparsec/Text.hs +398/−0
- Data/Attoparsec/Text/FastSet.hs +63/−0
- Data/Attoparsec/Text/Internal.hs +402/−0
- Data/Attoparsec/Text/Lazy.hs +90/−0
- Data/Attoparsec/Types.hs +19/−0
- README.markdown +5/−5
- attoparsec.cabal +41/−28
- tests/QC.hs +15/−23
- tests/QCSupport.hs +0/−52
Data/Attoparsec.hs view
@@ -7,215 +7,12 @@ -- Stability : experimental -- Portability : unknown ----- Simple, efficient combinator parsing for 'B.ByteString' strings,+-- Simple, efficient combinator parsing for 'ByteString' strings, -- loosely based on the Parsec library. module Data.Attoparsec (- -- * Differences from Parsec- -- $parsec-- -- * Incremental input- -- $incremental-- -- * Performance considerations- -- $performance-- -- * Parser types- I.Parser- , Result(..)-- -- ** Typeclass instances- -- $instances-- -- * Running parsers- , parse- , feed- , I.parseOnly- , parseWith- , parseTest-- -- ** Result conversion- , maybeResult- , eitherResult-- -- * Combinators- , (I.<?>)- , I.try- , module Data.Attoparsec.Combinator-- -- * Parsing individual bytes- , I.word8- , I.anyWord8- , I.notWord8- , I.satisfy- , I.satisfyWith- , I.skip-- -- ** Byte classes- , I.inClass- , I.notInClass-- -- * Efficient string handling- , I.string- , I.skipWhile- , I.take- , I.scan- , I.takeWhile- , I.takeWhile1- , I.takeTill-- -- ** Consume all remaining input- , I.takeByteString- , I.takeLazyByteString-- -- * State observation and manipulation functions- , I.endOfInput- , I.atEnd+ module Data.Attoparsec.ByteString ) where -import Data.Attoparsec.Combinator-import qualified Data.Attoparsec.Internal as I-import qualified Data.ByteString as B-import Data.Attoparsec.Internal (Result(..), parse)---- $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 '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 'Partial' continuation.------ Supplying the 'Partial' continuation with another bytestring will--- resume parsing at the point where it was suspended. You must be--- prepared for the result of the resumed parse to be another--- 'Partial' continuation.------ To indicate that you have no more input, supply the '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 '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.---- $performance------ If you write an Attoparsec-based parser carefully, it can be--- realistic to expect it to perform within a factor of 2 of 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.---- $instances------ The 'I.Parser' type is an instance of the following classes:------ * 'Monad', where 'fail' throws an exception (i.e. fails) with an--- error message.------ * 'Functor' and 'Applicative', which follow the usual definitions.------ * 'MonadPlus', where 'mzero' fails (with no error message) and--- 'mplus' executes the right-hand parser if the left-hand one--- fails.------ * 'Alternative', which follows 'MonadPlus'.------ The 'Result' type is an instance of 'Functor', where 'fmap'--- transforms the value in a 'Done' result.---- | If a parser has returned a 'Partial' result, supply it with more--- input.-feed :: Result r -> B.ByteString -> Result r-feed f@(Fail _ _ _) _ = f-feed (Partial k) d = k d-feed (Done bs r) d = Done (B.append bs d) r-{-# INLINE feed #-}---- | Run a parser and print its result to standard output.-parseTest :: (Show a) => I.Parser a -> B.ByteString -> IO ()-parseTest p s = print (parse p 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 refill p s = step $ parse p s- where step (Partial k) = (step . k) =<< refill- step r = return r-{-# INLINE parseWith #-}---- | Convert a 'Result' value to a 'Maybe' value. A 'Partial' result--- is treated as failure.-maybeResult :: Result r -> Maybe r-maybeResult (Done _ r) = Just r-maybeResult _ = Nothing---- | Convert a 'Result' value to an 'Either' value. A 'Partial' result--- is treated as failure.-eitherResult :: Result r -> Either String r-eitherResult (Done _ r) = Right r-eitherResult (Fail _ _ msg) = Left msg-eitherResult _ = Left "Result: incomplete input"+import Data.Attoparsec.ByteString
+ Data/Attoparsec/ByteString.hs view
@@ -0,0 +1,202 @@+-- |+-- Module : Data.Attoparsec.ByteString+-- Copyright : Bryan O'Sullivan 2007-2011+-- 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(..)++ -- * Running parsers+ , parse+ , feed+ , I.parseOnly+ , parseWith+ , parseTest++ -- ** Result conversion+ , maybeResult+ , eitherResult++ -- * Combinators+ , (I.<?>)+ , I.try+ , module Data.Attoparsec.Combinator++ -- * Parsing individual bytes+ , I.word8+ , I.anyWord8+ , I.notWord8+ , I.satisfy+ , I.satisfyWith+ , I.skip++ -- ** Byte classes+ , I.inClass+ , I.notInClass++ -- * Efficient string handling+ , I.string+ , I.skipWhile+ , I.take+ , I.scan+ , I.takeWhile+ , I.takeWhile1+ , I.takeTill++ -- ** Consume all remaining input+ , I.takeByteString+ , I.takeLazyByteString++ -- * State observation and manipulation functions+ , I.endOfInput+ , I.atEnd+ ) where++import Data.Attoparsec.Combinator+import qualified Data.Attoparsec.ByteString.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 '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 another bytestring will+-- resume parsing at the point where it was suspended. 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.++-- $performance+--+-- If you write an Attoparsec-based parser carefully, it can be+-- realistic to expect it to perform within a factor of 2 of 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.++-- | If a parser has returned a 'T.Partial' result, supply it with more+-- input.+feed :: Result r -> B.ByteString -> Result r+feed f@(T.Fail _ _ _) _ = f+feed (T.Partial k) d = k d+feed (T.Done bs r) d = T.Done (B.append bs d) r+{-# INLINE feed #-}++-- | Run a parser and print its result to standard output.+parseTest :: (Show a) => I.Parser a -> B.ByteString -> IO ()+parseTest p s = print (parse p 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 refill p s = step $ parse p s+ where step (T.Partial k) = (step . k) =<< refill+ step r = return 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 (T.Done _ r) = Just r+maybeResult _ = Nothing++-- | Convert a 'Result' value to an 'Either' value. A 'T.Partial'+-- result is treated as failure.+eitherResult :: Result r -> Either String r+eitherResult (T.Done _ r) = Right r+eitherResult (T.Fail _ _ msg) = Left msg+eitherResult _ = Left "Result: incomplete input"
+ Data/Attoparsec/ByteString/Char8.hs view
@@ -0,0 +1,502 @@+{-# LANGUAGE BangPatterns, FlexibleInstances, TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- |+-- Module : Data.Attoparsec.ByteString.Char8+-- Copyright : Bryan O'Sullivan 2007-2011+-- License : BSD3+-- +-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Simple, efficient, character-oriented combinator parsing for+-- 'B.ByteString' strings, loosely based on the Parsec library.++module Data.Attoparsec.ByteString.Char8+ (+ -- * Character encodings+ -- $encodings++ -- * Parser types+ Parser+ , A.Result++ -- * Running parsers+ , A.parse+ , A.feed+ , A.parseOnly+ , A.parseTest+ , A.parseWith++ -- ** Result conversion+ , A.maybeResult+ , A.eitherResult++ -- * Combinators+ , (I.<?>)+ , I.try+ , module Data.Attoparsec.Combinator++ -- * Parsing individual characters+ , char+ , char8+ , anyChar+ , notChar+ , satisfy++ -- ** Special character parsers+ , digit+ , letter_iso8859_15+ , letter_ascii+ , space++ -- ** Fast predicates+ , isDigit+ , isDigit_w8+ , isAlpha_iso8859_15+ , isAlpha_ascii+ , isSpace+ , isSpace_w8++ -- *** Character classes+ , inClass+ , notInClass++ -- * Efficient string handling+ , I.string+ , stringCI+ , skipSpace+ , skipWhile+ , I.take+ , scan+ , takeWhile+ , takeWhile1+ , takeTill++ -- ** Consume all remaining input+ , I.takeByteString+ , I.takeLazyByteString++ -- * Text parsing+ , I.endOfLine+ , isEndOfLine+ , isHorizontalSpace++ -- * Numeric parsers+ , decimal+ , hexadecimal+ , signed+ , double+ , Number(..)+ , number+ , rational++ -- * State observation and manipulation functions+ , I.endOfInput+ , I.atEnd+ ) where++import Control.Applicative ((*>), (<$>), (<|>))+import Data.Attoparsec.ByteString.FastSet (charClass, memberChar)+import Data.Attoparsec.ByteString.Internal (Parser, (<?>))+import Data.Attoparsec.Combinator+import Data.Attoparsec.Number (Number(..))+import Data.Bits (Bits, (.|.), shiftL)+import Data.ByteString.Internal (c2w, w2c)+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Ratio ((%))+import Data.String (IsString(..))+import Data.Word (Word8, Word16, Word32, Word64, Word)+import Prelude hiding (takeWhile)+import qualified Data.Attoparsec.ByteString as A+import qualified Data.Attoparsec.ByteString.Internal as I+import qualified Data.ByteString as B8+import qualified Data.ByteString.Char8 as B++instance IsString (Parser B.ByteString) where+ fromString = I.string . B.pack++-- $encodings+--+-- This module is intended for parsing text that is+-- represented using an 8-bit character set, e.g. ASCII or+-- ISO-8859-15. It /does not/ make any attempt to deal with character+-- encodings, multibyte characters, or wide characters. In+-- particular, all attempts to use characters above code point U+00FF+-- will give wrong answers.+--+-- Code points below U+0100 are simply translated to and from their+-- numeric values, so e.g. the code point U+00A4 becomes the byte+-- @0xA4@ (which is the Euro symbol in ISO-8859-15, but the generic+-- currency sign in ISO-8859-1). Haskell 'Char' values above U+00FF+-- are truncated, so e.g. U+1D6B7 is truncated to the byte @0xB7@.++-- ASCII-specific but fast, oh yes.+toLower :: Word8 -> Word8+toLower w | w >= 65 && w <= 90 = w + 32+ | otherwise = w++-- | Satisfy a literal string, ignoring case.+stringCI :: B.ByteString -> Parser B.ByteString+stringCI = I.stringTransform (B8.map toLower)+{-# INLINE stringCI #-}++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser requires the predicate to succeed on at least one byte+-- of input: it will fail if the predicate never returns 'True' or if+-- there is no input left.+takeWhile1 :: (Char -> Bool) -> Parser B.ByteString+takeWhile1 p = I.takeWhile1 (p . w2c)+{-# INLINE takeWhile1 #-}++-- | The parser @satisfy p@ succeeds for any byte for which the+-- predicate @p@ returns 'True'. Returns the byte that is actually+-- parsed.+--+-- >digit = satisfy isDigit+-- > where isDigit c = c >= '0' && c <= '9'+satisfy :: (Char -> Bool) -> Parser Char+satisfy = I.satisfyWith w2c+{-# INLINE satisfy #-}++-- | Match a letter, in the ISO-8859-15 encoding.+letter_iso8859_15 :: Parser Char+letter_iso8859_15 = satisfy isAlpha_iso8859_15 <?> "letter_iso8859_15"+{-# INLINE letter_iso8859_15 #-}++-- | Match a letter, in the ASCII encoding.+letter_ascii :: Parser Char+letter_ascii = satisfy isAlpha_ascii <?> "letter_ascii"+{-# INLINE letter_ascii #-}++-- | A fast alphabetic predicate for the ISO-8859-15 encoding+--+-- /Note/: For all character encodings other than ISO-8859-15, and+-- almost all Unicode code points above U+00A3, this predicate gives+-- /wrong answers/.+isAlpha_iso8859_15 :: Char -> Bool+isAlpha_iso8859_15 c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||+ (c >= '\166' && moby c)+ where moby = notInClass "\167\169\171-\179\182\183\185\187\191\215\247"+ {-# NOINLINE moby #-}+{-# INLINE isAlpha_iso8859_15 #-}++-- | A fast alphabetic predicate for the ASCII encoding+--+-- /Note/: For all character encodings other than ASCII, and+-- almost all Unicode code points above U+007F, this predicate gives+-- /wrong answers/.+isAlpha_ascii :: Char -> Bool+isAlpha_ascii c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')+{-# INLINE isAlpha_ascii #-}++-- | Parse a single digit.+digit :: Parser Char+digit = satisfy isDigit <?> "digit"+{-# INLINE digit #-}++-- | A fast digit predicate.+isDigit :: Char -> Bool+isDigit c = c >= '0' && c <= '9'+{-# INLINE isDigit #-}++-- | A fast digit predicate.+isDigit_w8 :: Word8 -> Bool+isDigit_w8 w = w >= 48 && w <= 57+{-# INLINE isDigit_w8 #-}++-- | Match any character.+anyChar :: Parser Char+anyChar = satisfy $ const True+{-# INLINE anyChar #-}++-- | Fast predicate for matching ASCII space characters.+--+-- /Note/: This predicate only gives correct answers for the ASCII+-- encoding. For instance, it does not recognise U+00A0 (non-breaking+-- space) as a space character, even though it is a valid ISO-8859-15+-- byte. For a Unicode-aware and only slightly slower predicate,+-- use 'Data.Char.isSpace'+isSpace :: Char -> Bool+isSpace c = (c == ' ') || ('\t' <= c && c <= '\r')+{-# INLINE isSpace #-}++-- | Fast 'Word8' predicate for matching ASCII space characters.+isSpace_w8 :: Word8 -> Bool+isSpace_w8 w = (w == 32) || (9 <= w && w <= 13)+{-# INLINE isSpace_w8 #-}+++-- | Parse a space character.+--+-- /Note/: This parser only gives correct answers for the ASCII+-- encoding. For instance, it does not recognise U+00A0 (non-breaking+-- space) as a space character, even though it is a valid ISO-8859-15+-- byte.+space :: Parser Char+space = satisfy isSpace <?> "space"+{-# INLINE space #-}++-- | Match a specific character.+char :: Char -> Parser Char+char c = satisfy (== c) <?> [c]+{-# INLINE char #-}++-- | Match a specific character, but return its 'Word8' value.+char8 :: Char -> Parser Word8+char8 c = I.satisfy (== c2w c) <?> [c]+{-# INLINE char8 #-}++-- | Match any character except the given one.+notChar :: Char -> Parser Char+notChar c = satisfy (/= c) <?> "not " ++ [c]+{-# INLINE notChar #-}++-- | Match any character in a set.+--+-- >vowel = inClass "aeiou"+--+-- Range notation is supported.+--+-- >halfAlphabet = inClass "a-nA-N"+--+-- To add a literal \'-\' to a set, place it at the beginning or end+-- of the string.+inClass :: String -> Char -> Bool+inClass s = (`memberChar` mySet)+ where mySet = charClass s+{-# INLINE inClass #-}++-- | Match any character not in a set.+notInClass :: String -> Char -> Bool+notInClass s = not . inClass s+{-# INLINE notInClass #-}++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'False' on the first byte of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+takeWhile :: (Char -> Bool) -> Parser B.ByteString+takeWhile p = I.takeWhile (p . w2c)+{-# INLINE takeWhile #-}++-- | A stateful scanner. The predicate consumes and transforms a+-- state argument, and each transformed state is passed to successive+-- invocations of the predicate on each byte of the input until one+-- returns 'Nothing' or the input ends.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'Nothing' on the first byte of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+scan :: s -> (s -> Char -> Maybe s) -> Parser B.ByteString+scan s0 p = I.scan s0 (\s -> p s . w2c)+{-# INLINE scan #-}++-- | Consume input as long as the predicate returns 'False'+-- (i.e. until it returns 'True'), and return the consumed input.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'True' on the first byte of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+takeTill :: (Char -> Bool) -> Parser B.ByteString+takeTill p = I.takeTill (p . w2c)+{-# INLINE takeTill #-}++-- | Skip past input for as long as the predicate returns 'True'.+skipWhile :: (Char -> Bool) -> Parser ()+skipWhile p = I.skipWhile (p . w2c)+{-# INLINE skipWhile #-}++-- | Skip over white space.+skipSpace :: Parser ()+skipSpace = I.skipWhile isSpace_w8+{-# INLINE skipSpace #-}++-- | A predicate that matches either a carriage return @\'\\r\'@ or+-- newline @\'\\n\'@ character.+isEndOfLine :: Word8 -> Bool+isEndOfLine w = w == 13 || w == 10+{-# INLINE isEndOfLine #-}++-- | A predicate that matches either a space @\' \'@ or horizontal tab+-- @\'\\t\'@ character.+isHorizontalSpace :: Word8 -> Bool+isHorizontalSpace w = w == 32 || w == 9+{-# INLINE isHorizontalSpace #-}++-- | Parse and decode an unsigned hexadecimal number. The hex digits+-- @\'a\'@ through @\'f\'@ may be upper or lower case.+--+-- This parser does not accept a leading @\"0x\"@ string.+hexadecimal :: (Integral a, Bits a) => Parser a+hexadecimal = B8.foldl' step 0 `fmap` I.takeWhile1 isHexDigit+ where+ isHexDigit w = (w >= 48 && w <= 57) ||+ (w >= 97 && w <= 102) ||+ (w >= 65 && w <= 70)+ step a w | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)+ | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)+ | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)+{-# SPECIALISE hexadecimal :: Parser Int #-}+{-# SPECIALISE hexadecimal :: Parser Int8 #-}+{-# SPECIALISE hexadecimal :: Parser Int16 #-}+{-# SPECIALISE hexadecimal :: Parser Int32 #-}+{-# SPECIALISE hexadecimal :: Parser Int64 #-}+{-# SPECIALISE hexadecimal :: Parser Integer #-}+{-# SPECIALISE hexadecimal :: Parser Word #-}+{-# SPECIALISE hexadecimal :: Parser Word8 #-}+{-# SPECIALISE hexadecimal :: Parser Word16 #-}+{-# SPECIALISE hexadecimal :: Parser Word32 #-}+{-# SPECIALISE hexadecimal :: Parser Word64 #-}++-- | Parse and decode an unsigned decimal number.+decimal :: Integral a => Parser a+decimal = B8.foldl' step 0 `fmap` I.takeWhile1 isDig+ where isDig w = w >= 48 && w <= 57+ step a w = a * 10 + fromIntegral (w - 48)+{-# SPECIALISE decimal :: Parser Int #-}+{-# SPECIALISE decimal :: Parser Int8 #-}+{-# SPECIALISE decimal :: Parser Int16 #-}+{-# SPECIALISE decimal :: Parser Int32 #-}+{-# SPECIALISE decimal :: Parser Int64 #-}+{-# SPECIALISE decimal :: Parser Integer #-}+{-# SPECIALISE decimal :: Parser Word #-}+{-# SPECIALISE decimal :: Parser Word8 #-}+{-# SPECIALISE decimal :: Parser Word16 #-}+{-# SPECIALISE decimal :: Parser Word32 #-}+{-# SPECIALISE decimal :: Parser Word64 #-}++-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign+-- character.+signed :: Num a => Parser a -> Parser a+{-# SPECIALISE signed :: Parser Int -> Parser Int #-}+{-# SPECIALISE signed :: Parser Int8 -> Parser Int8 #-}+{-# SPECIALISE signed :: Parser Int16 -> Parser Int16 #-}+{-# SPECIALISE signed :: Parser Int32 -> Parser Int32 #-}+{-# SPECIALISE signed :: Parser Int64 -> Parser Int64 #-}+{-# SPECIALISE signed :: Parser Integer -> Parser Integer #-}+signed p = (negate <$> (char8 '-' *> p))+ <|> (char8 '+' *> p)+ <|> p++-- | Parse a rational number.+--+-- This parser accepts an optional leading sign character, followed by+-- at least one decimal digit. The syntax similar to that accepted by+-- the 'read' function, with the exception that a trailing @\'.\'@ or+-- @\'e\'@ /not/ followed by a number is not consumed.+--+-- Examples with behaviour identical to 'read', if you feed an empty+-- continuation to the first result:+--+-- >rational "3" == Done 3.0 ""+-- >rational "3.1" == Done 3.1 ""+-- >rational "3e4" == Done 30000.0 ""+-- >rational "3.1e4" == Done 31000.0, ""++-- Examples with behaviour identical to 'read':+--+-- >rational ".3" == Fail "input does not start with a digit"+-- >rational "e3" == Fail "input does not start with a digit"+--+-- Examples of differences from 'read':+--+-- >rational "3.foo" == Done 3.0 ".foo"+-- >rational "3e" == Done 3.0 "e"+--+-- This function does not accept string representations of \"NaN\" or+-- \"Infinity\".+rational :: Fractional a => Parser a+{-# SPECIALIZE rational :: Parser Double #-}+{-# SPECIALIZE rational :: Parser Float #-}+{-# SPECIALIZE rational :: Parser Rational #-}+rational = floaty $ \real frac fracDenom -> fromRational $+ real % 1 + frac % fracDenom++-- | Parse a rational number.+--+-- The syntax accepted by this parser is the same as for 'rational'.+--+-- /Note/: This function is almost ten times faster than 'rational',+-- but is slightly less accurate.+--+-- The 'Double' type supports about 16 decimal places of accuracy.+-- For 94.2% of numbers, this function and 'rational' give identical+-- results, but for the remaining 5.8%, this function loses precision+-- around the 15th decimal place. For 0.001% of numbers, this+-- function will lose precision at the 13th or 14th decimal place.+--+-- This function does not accept string representations of \"NaN\" or+-- \"Infinity\".+double :: Parser Double+double = floaty asDouble++asDouble :: Integer -> Integer -> Integer -> Double+asDouble real frac fracDenom =+ fromIntegral real + fromIntegral frac / fromIntegral fracDenom+{-# INLINE asDouble #-}++-- | Parse a number, attempting to preserve both speed and precision.+--+-- The syntax accepted by this parser is the same as for 'rational'.+--+-- /Note/: This function is almost ten times faster than 'rational'.+-- On integral inputs, it gives perfectly accurate answers, and on+-- floating point inputs, it is slightly less accurate than+-- 'rational'.+--+-- This function does not accept string representations of \"NaN\" or+-- \"Infinity\".+number :: Parser Number+number = floaty $ \real frac fracDenom ->+ if frac == 0 && fracDenom == 0+ then I real+ else D (asDouble real frac fracDenom)+{-# INLINE number #-}++data T = T !Integer !Int++floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a+{-# INLINE floaty #-}+floaty f = do+ let minus = 45+ plus = 43+ !positive <- ((== plus) <$> I.satisfy (\c -> c == minus || c == plus)) <|>+ return True+ real <- decimal+ let tryFraction = do+ let dot = 46+ _ <- I.satisfy (==dot)+ ds <- I.takeWhile isDigit_w8+ case I.parseOnly decimal ds of+ Right n -> return $ T n (B.length ds)+ _ -> fail "no digits after decimal"+ T fraction fracDigits <- tryFraction <|> return (T 0 0)+ let littleE = 101+ bigE = 69+ e w = w == littleE || w == bigE+ power <- (I.satisfy e *> signed decimal) <|> return (0::Int)+ let n = if fracDigits == 0+ then if power == 0+ then fromIntegral real+ else fromIntegral real * (10 ^^ power)+ else if power == 0+ then f real fraction (10 ^ fracDigits)+ else f real fraction (10 ^ fracDigits) * (10 ^^ power)+ return $ if positive+ then n+ else -n
+ Data/Attoparsec/ByteString/FastSet.hs view
@@ -0,0 +1,115 @@+{-# LANGUAGE BangPatterns, MagicHash #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Attoparsec.ByteString.FastSet+-- Copyright : Bryan O'Sullivan 2008+-- License : BSD3+-- +-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Fast set membership tests for 'Word8' and 8-bit 'Char' values. The+-- set representation is unboxed for efficiency. For small sets, we+-- test for membership using a binary search. For larger sets, we use+-- a lookup table.+-- +-----------------------------------------------------------------------------+module Data.Attoparsec.ByteString.FastSet+ (+ -- * Data type+ FastSet+ -- * Construction+ , fromList+ , set+ -- * Lookup+ , memberChar+ , memberWord8+ -- * Debugging+ , fromSet+ -- * Handy interface+ , charClass+ ) where++import Data.Bits ((.&.), (.|.))+import Foreign.Storable (peekByteOff, pokeByteOff)+import GHC.Base (Int(I#), iShiftRA#, narrow8Word#, shiftL#)+import GHC.Word (Word8(W8#))+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import qualified Data.ByteString.Internal as I+import qualified Data.ByteString.Unsafe as U++data FastSet = Sorted { fromSet :: !B.ByteString }+ | Table { fromSet :: !B.ByteString }+ deriving (Eq, Ord)++instance Show FastSet where+ show (Sorted s) = "FastSet Sorted " ++ show (B8.unpack s)+ show (Table _) = "FastSet Table"++-- | The lower bound on the size of a lookup table. We choose this to+-- balance table density against performance.+tableCutoff :: Int+tableCutoff = 8++-- | Create a set.+set :: B.ByteString -> FastSet+set s | B.length s < tableCutoff = Sorted . B.sort $ s+ | otherwise = Table . mkTable $ s++fromList :: [Word8] -> FastSet+fromList = set . B.pack++data I = I {-# UNPACK #-} !Int {-# UNPACK #-} !Word8++shiftR :: Int -> Int -> Int+shiftR (I# x#) (I# i#) = I# (x# `iShiftRA#` i#)++shiftL :: Word8 -> Int -> Word8+shiftL (W8# x#) (I# i#) = W8# (narrow8Word# (x# `shiftL#` i#))++index :: Int -> I+index i = I (i `shiftR` 3) (1 `shiftL` (i .&. 7))+{-# INLINE index #-}++-- | Check the set for membership.+memberWord8 :: Word8 -> FastSet -> Bool+memberWord8 w (Table t) =+ let I byte bit = index (fromIntegral w)+ in U.unsafeIndex t byte .&. bit /= 0+memberWord8 w (Sorted s) = search 0 (B.length s - 1)+ where search lo hi+ | hi < lo = False+ | otherwise =+ let mid = (lo + hi) `div` 2+ in case compare w (U.unsafeIndex s mid) of+ GT -> search (mid + 1) hi+ LT -> search lo (mid - 1)+ _ -> True++-- | Check the set for membership. Only works with 8-bit characters:+-- characters above code point 255 will give wrong answers.+memberChar :: Char -> FastSet -> Bool+memberChar c = memberWord8 (I.c2w c)+{-# INLINE memberChar #-}++mkTable :: B.ByteString -> B.ByteString+mkTable s = I.unsafeCreate 32 $ \t -> do+ _ <- I.memset t 0 32+ U.unsafeUseAsCStringLen s $ \(p, l) ->+ let loop n | n == l = return ()+ | otherwise = do+ c <- peekByteOff p n :: IO Word8+ let I byte bit = index (fromIntegral c)+ prev <- peekByteOff t byte :: IO Word8+ pokeByteOff t byte (prev .|. bit)+ loop (n + 1)+ in loop 0++charClass :: String -> FastSet+charClass = set . B8.pack . go+ where go (a:'-':b:xs) = [a..b] ++ go xs+ go (x:xs) = x : go xs+ go _ = ""
+ Data/Attoparsec/ByteString/Internal.hs view
@@ -0,0 +1,459 @@+{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings, RecordWildCards #-}+-- |+-- Module : Data.Attoparsec.ByteString.Internal+-- Copyright : Bryan O'Sullivan 2007-2011+-- License : BSD3+--+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Simple, efficient parser combinators for 'B.ByteString' strings,+-- loosely based on the Parsec library.++module Data.Attoparsec.ByteString.Internal+ (+ -- * Parser types+ Parser+ , Result++ -- * Running parsers+ , parse+ , parseOnly++ -- * Combinators+ , (<?>)+ , try+ , module Data.Attoparsec.Combinator++ -- * Parsing individual bytes+ , satisfy+ , satisfyWith+ , anyWord8+ , skip+ , word8+ , notWord8++ -- ** Byte classes+ , inClass+ , notInClass++ -- * Parsing more complicated structures+ , storable++ -- * Efficient string handling+ , skipWhile+ , string+ , stringTransform+ , take+ , scan+ , takeWhile+ , takeWhile1+ , takeTill++ -- ** Consume all remaining input+ , takeByteString+ , takeLazyByteString++ -- * State observation and manipulation functions+ , endOfInput+ , atEnd+ , ensure++ -- * Utilities+ , endOfLine+ ) where++import Control.Applicative ((<|>), (<$>))+import Control.Monad (when)+import Data.Attoparsec.ByteString.FastSet (charClass, memberWord8)+import Data.Attoparsec.Combinator+import Data.Attoparsec.Internal.Types+ hiding (Parser, Input, Added, Failure, Success)+import Data.Word (Word8)+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Ptr (castPtr, minusPtr, plusPtr)+import Foreign.Storable (Storable(peek, sizeOf))+import Prelude hiding (getChar, take, takeWhile)+import System.IO.Unsafe (unsafePerformIO)+import qualified Data.Attoparsec.Internal.Types as T+import qualified Data.ByteString as B8+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Internal as B+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Unsafe as B++type Parser a = T.Parser B.ByteString a+type Result a = IResult B.ByteString a+type Input = T.Input B.ByteString+type Added = T.Added B.ByteString+type Failure r = T.Failure B.ByteString r+type Success a r = T.Success B.ByteString a r++-- | If at least @n@ bytes of input are available, return the current+-- input, otherwise fail.+ensure :: Int -> Parser B.ByteString+ensure !n = T.Parser $ \i0 a0 m0 kf ks ->+ if B.length (unI i0) >= n+ then ks i0 a0 m0 (unI i0)+ else T.runParser (demandInput >> ensure n) i0 a0 m0 kf ks++-- | Ask for input. If we receive any, pass it to a success+-- continuation, otherwise to a failure continuation.+prompt :: Input -> Added -> More+ -> (Input -> Added -> More -> Result r)+ -> (Input -> Added -> More -> Result r)+ -> Result r+prompt i0 a0 _m0 kf ks = Partial $ \s ->+ if B.null s+ then kf i0 a0 Complete+ else ks (I (unI i0 <> s)) (A (unA a0 <> s)) Incomplete++-- | Immediately demand more input via a 'Partial' continuation+-- result.+demandInput :: Parser ()+demandInput = T.Parser $ \i0 a0 m0 kf ks ->+ if m0 == Complete+ then kf i0 a0 m0 ["demandInput"] "not enough bytes"+ else let kf' i a m = kf i a m ["demandInput"] "not enough bytes"+ ks' i a m = ks i a m ()+ in prompt i0 a0 m0 kf' ks'++-- | This parser always succeeds. It returns 'True' if any input is+-- available either immediately or on demand, and 'False' if the end+-- of all input has been reached.+wantInput :: Parser Bool+wantInput = T.Parser $ \i0 a0 m0 _kf ks ->+ case () of+ _ | not (B.null (unI i0)) -> ks i0 a0 m0 True+ | m0 == Complete -> ks i0 a0 m0 False+ | otherwise -> let kf' i a m = ks i a m False+ ks' i a m = ks i a m True+ in prompt i0 a0 m0 kf' ks'++get :: Parser B.ByteString+get = T.Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0)++put :: B.ByteString -> Parser ()+put s = T.Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 ()++-- | Attempt a parse, and if it fails, rewind the input so that no+-- input appears to have been consumed.+--+-- This combinator is provided for compatibility with Parsec.+-- Attoparsec parsers always backtrack on failure.+try :: Parser a -> Parser a+try p = p+{-# INLINE try #-}++-- | The parser @satisfy p@ succeeds for any byte for which the+-- predicate @p@ returns 'True'. Returns the byte that is actually+-- parsed.+--+-- >digit = satisfy isDigit+-- > where isDigit w = w >= 48 && w <= 57+satisfy :: (Word8 -> Bool) -> Parser Word8+satisfy p = do+ s <- ensure 1+ let w = B.unsafeHead s+ if p w+ then put (B.unsafeTail s) >> return w+ else fail "satisfy"++-- | The parser @skip p@ succeeds for any byte for which the predicate+-- @p@ returns 'True'.+--+-- >skipDigit = skip isDigit+-- > where isDigit w = w >= 48 && w <= 57+skip :: (Word8 -> Bool) -> Parser ()+skip p = do+ s <- ensure 1+ if p (B.unsafeHead s)+ then put (B.unsafeTail s)+ else fail "skip"++-- | The parser @satisfyWith f p@ transforms a byte, and succeeds if+-- the predicate @p@ returns 'True' on the transformed value. The+-- parser returns the transformed byte that was parsed.+satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a+satisfyWith f p = do+ s <- ensure 1+ let c = f (B.unsafeHead s)+ if p c+ then put (B.unsafeTail s) >> return c+ else fail "satisfyWith"++storable :: Storable a => Parser a+storable = hack undefined+ where+ hack :: Storable b => b -> Parser b+ hack dummy = do+ (fp,o,_) <- B.toForeignPtr `fmap` take (sizeOf dummy)+ return . B.inlinePerformIO . withForeignPtr fp $ \p ->+ peek (castPtr $ p `plusPtr` o)++-- | Consume @n@ bytes of input, but succeed only if the predicate+-- returns 'True'.+takeWith :: Int -> (B.ByteString -> Bool) -> Parser B.ByteString+takeWith n p = do+ s <- ensure n+ let h = B.unsafeTake n s+ t = B.unsafeDrop n s+ if p h+ then put t >> return h+ else fail "takeWith"++-- | Consume exactly @n@ bytes of input.+take :: Int -> Parser B.ByteString+take n = takeWith n (const True)+{-# INLINE take #-}++-- | @string s@ parses a sequence of bytes that identically match+-- @s@. Returns the parsed string (i.e. @s@). This parser consumes no+-- input if it fails (even if a partial match).+--+-- /Note/: The behaviour of this parser is different to that of the+-- similarly-named parser in Parsec, as this one is all-or-nothing.+-- To illustrate the difference, the following parser will fail under+-- Parsec given an input of @"for"@:+--+-- >string "foo" <|> string "for"+--+-- The reason for its failure is that that the first branch is a+-- partial match, and will consume the letters @\'f\'@ and @\'o\'@+-- before failing. In Attoparsec, the above parser will /succeed/ on+-- that input, because the failed first branch will consume nothing.+string :: B.ByteString -> Parser B.ByteString+string s = takeWith (B.length s) (==s)+{-# INLINE string #-}++stringTransform :: (B.ByteString -> B.ByteString) -> B.ByteString+ -> Parser B.ByteString+stringTransform f s = takeWith (B.length s) ((==f s) . f)+{-# INLINE stringTransform #-}++-- | Skip past input for as long as the predicate returns 'True'.+skipWhile :: (Word8 -> Bool) -> Parser ()+skipWhile p = go+ where+ go = do+ t <- B8.dropWhile p <$> get+ put t+ when (B.null t) $ do+ input <- wantInput+ when input go+{-# INLINE skipWhile #-}++-- | Consume input as long as the predicate returns 'False'+-- (i.e. until it returns 'True'), and return the consumed input.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'True' on the first byte of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+takeTill :: (Word8 -> Bool) -> Parser B.ByteString+takeTill p = takeWhile (not . p)+{-# INLINE takeTill #-}++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'False' on the first byte of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+takeWhile :: (Word8 -> Bool) -> Parser B.ByteString+takeWhile p = (B.concat . reverse) `fmap` go []+ where+ go acc = do+ (h,t) <- B8.span p <$> get+ put t+ if B.null t+ then do+ input <- wantInput+ if input+ then go (h:acc)+ else return (h:acc)+ else return (h:acc)++takeRest :: Parser [B.ByteString]+takeRest = go []+ where+ go acc = do+ input <- wantInput+ if input+ then do+ s <- get+ put B.empty+ go (s:acc)+ else return (reverse acc)++-- | Consume all remaining input and return it as a single string.+takeByteString :: Parser B.ByteString+takeByteString = B.concat `fmap` takeRest++-- | Consume all remaining input and return it as a single string.+takeLazyByteString :: Parser L.ByteString+takeLazyByteString = L.fromChunks `fmap` takeRest++data T s = T {-# UNPACK #-} !Int s++-- | A stateful scanner. The predicate consumes and transforms a+-- state argument, and each transformed state is passed to successive+-- invocations of the predicate on each byte of the input until one+-- returns 'Nothing' or the input ends.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'Nothing' on the first byte of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString+scan s0 p = do+ chunks <- go [] s0+ case chunks of+ [x] -> return x+ xs -> return . B.concat . reverse $ xs+ where+ go acc s1 = do+ let scanner (B.PS fp off len) =+ withForeignPtr fp $ \ptr0 -> do+ let start = ptr0 `plusPtr` off+ end = start `plusPtr` len+ inner ptr !s+ | ptr < end = do+ w <- peek ptr+ case p s w of+ Just s' -> inner (ptr `plusPtr` 1) s'+ _ -> done (ptr `minusPtr` start) s+ | otherwise = done (ptr `minusPtr` start) s+ done !i !s = return (T i s)+ inner start s1+ bs <- get+ let T i s' = unsafePerformIO $ scanner bs+ h = B.unsafeTake i bs+ t = B.unsafeDrop i bs+ put t+ if B.null t+ then do+ input <- wantInput+ if input+ then go (h:acc) s'+ else return (h:acc)+ else return (h:acc)+{-# INLINE scan #-}++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser requires the predicate to succeed on at least one byte+-- of input: it will fail if the predicate never returns 'True' or if+-- there is no input left.+takeWhile1 :: (Word8 -> Bool) -> Parser B.ByteString+takeWhile1 p = do+ (`when` demandInput) =<< B.null <$> get+ (h,t) <- B8.span p <$> get+ when (B.null h) $ fail "takeWhile1"+ put t+ if B.null t+ then (h<>) `fmap` takeWhile p+ else return h++-- | Match any byte in a set.+--+-- >vowel = inClass "aeiou"+--+-- Range notation is supported.+--+-- >halfAlphabet = inClass "a-nA-N"+--+-- To add a literal @\'-\'@ to a set, place it at the beginning or end+-- of the string.+inClass :: String -> Word8 -> Bool+inClass s = (`memberWord8` mySet)+ where mySet = charClass s+ {-# NOINLINE mySet #-}+{-# INLINE inClass #-}++-- | Match any byte not in a set.+notInClass :: String -> Word8 -> Bool+notInClass s = not . inClass s+{-# INLINE notInClass #-}++-- | Match any byte.+anyWord8 :: Parser Word8+anyWord8 = satisfy $ const True+{-# INLINE anyWord8 #-}++-- | Match a specific byte.+word8 :: Word8 -> Parser Word8+word8 c = satisfy (== c) <?> show c+{-# INLINE word8 #-}++-- | Match any byte except the given one.+notWord8 :: Word8 -> Parser Word8+notWord8 c = satisfy (/= c) <?> "not " ++ show c+{-# INLINE notWord8 #-}++-- | Match only if all input has been consumed.+endOfInput :: Parser ()+endOfInput = T.Parser $ \i0 a0 m0 kf ks ->+ if B.null (unI i0)+ then if m0 == Complete+ then ks i0 a0 m0 ()+ else let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $+ \ i2 a2 m2 -> ks i2 a2 m2 ()+ ks' i1 a1 m1 _ = addS i0 a0 m0 i1 a1 m1 $+ \ i2 a2 m2 -> kf i2 a2 m2 []+ "endOfInput"+ in T.runParser demandInput i0 a0 m0 kf' ks'+ else kf i0 a0 m0 [] "endOfInput"++-- | Return an indication of whether the end of input has been+-- reached.+atEnd :: Parser Bool+atEnd = not <$> wantInput+{-# INLINE atEnd #-}++-- | Match either a single newline character @\'\\n\'@, or a carriage+-- return followed by a newline character @\"\\r\\n\"@.+endOfLine :: Parser ()+endOfLine = (word8 10 >> return ()) <|> (string "\r\n" >> return ())++--- | Name the parser, in case failure occurs.+(<?>) :: Parser a+ -> String -- ^ the name to use if parsing fails+ -> Parser a+p <?> msg0 = T.Parser $ \i0 a0 m0 kf ks ->+ let kf' i a m strs msg = kf i a m (msg0:strs) msg+ in T.runParser p i0 a0 m0 kf' ks+{-# INLINE (<?>) #-}+infix 0 <?>++-- | Terminal failure continuation.+failK :: Failure a+failK i0 _a0 _m0 stack msg = Fail (unI i0) stack msg+{-# INLINE failK #-}++-- | Terminal success continuation.+successK :: Success a a+successK i0 _a0 _m0 a = Done (unI i0) a+{-# INLINE successK #-}++-- | Run a parser.+parse :: Parser a -> B.ByteString -> Result a+parse m s = T.runParser m (I s) (A B.empty) Incomplete failK successK+{-# INLINE parse #-}++-- | Run a parser that cannot be resupplied via a 'Partial' result.+parseOnly :: Parser a -> B.ByteString -> Either String a+parseOnly m s = case T.runParser m (I s) (A B.empty) Complete failK successK of+ Fail _ _ err -> Left err+ Done _ a -> Right a+ _ -> error "parseOnly: impossible error!"+{-# INLINE parseOnly #-}
+ Data/Attoparsec/ByteString/Lazy.hs view
@@ -0,0 +1,91 @@+-- |+-- Module : Data.Attoparsec.ByteString.Lazy+-- Copyright : Bryan O'Sullivan 2010, 2011+-- License : BSD3+-- +-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Simple, efficient combinator parsing for lazy 'ByteString'+-- strings, loosely based on the Parsec library.+--+-- This is essentially the same code as in the 'Data.Attoparsec'+-- module, only with a 'parse' function that can consume a lazy+-- 'ByteString' incrementally, and a 'Result' type that does not allow+-- more input to be fed in. Think of this as suitable for use with a+-- lazily read file, e.g. via 'L.readFile' or 'L.hGetContents'.+--+-- Behind the scenes, strict 'B.ByteString' values are still used+-- internally to store parser input and manipulate it efficiently.+-- High-performance parsers such as 'string' still expect strict+-- 'B.ByteString' parameters.++module Data.Attoparsec.ByteString.Lazy+ (+ Result(..)+ , module Data.Attoparsec.ByteString+ -- * Running parsers+ , parse+ , parseTest+ -- ** Result conversion+ , maybeResult+ , eitherResult+ ) where++import Data.ByteString.Lazy.Internal (ByteString(..), chunk)+import qualified Data.ByteString as B+import qualified Data.Attoparsec.ByteString as A+import qualified Data.Attoparsec.Internal.Types as T+import Data.Attoparsec.ByteString+ hiding (IResult(..), Result, eitherResult, maybeResult,+ parse, parseWith, parseTest)++-- | The result of a parse.+data Result r = Fail ByteString [String] String+ -- ^ The parse failed. The 'ByteString' is the input+ -- that had not yet been consumed when the failure+ -- occurred. The @[@'String'@]@ is a list of contexts+ -- in which the error occurred. The 'String' is the+ -- message describing the error, if any.+ | Done ByteString r+ -- ^ The parse succeeded. The 'ByteString' is the+ -- input that had not yet been consumed (if any) when+ -- the parse succeeded.++instance Show r => Show (Result r) where+ show (Fail bs stk msg) =+ "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg+ show (Done bs r) = "Done " ++ show bs ++ " " ++ show r++fmapR :: (a -> b) -> Result a -> Result b+fmapR _ (Fail st stk msg) = Fail st stk msg+fmapR f (Done bs r) = Done bs (f r)++instance Functor Result where+ fmap = fmapR++-- | Run a parser and return its result.+parse :: A.Parser a -> ByteString -> Result a+parse p s = case s of+ Chunk x xs -> go (A.parse p x) xs+ empty -> go (A.parse p B.empty) empty+ where+ go (T.Fail x stk msg) ys = Fail (chunk x ys) stk msg+ go (T.Done x r) ys = Done (chunk x ys) r+ go (T.Partial k) (Chunk y ys) = go (k y) ys+ go (T.Partial k) empty = go (k B.empty) empty++-- | Run a parser and print its result to standard output.+parseTest :: (Show a) => A.Parser a -> ByteString -> IO ()+parseTest p s = print (parse p s)++-- | Convert a 'Result' value to a 'Maybe' value.+maybeResult :: Result r -> Maybe r+maybeResult (Done _ r) = Just r+maybeResult _ = Nothing++-- | Convert a 'Result' value to an 'Either' value.+eitherResult :: Result r -> Either String r+eitherResult (Done _ r) = Right r+eitherResult (Fail _ _ msg) = Left msg
Data/Attoparsec/Char8.hs view
@@ -1,9 +1,6 @@-{-# LANGUAGE BangPatterns, FlexibleInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}- -- | -- Module : Data.Attoparsec.Char8--- Copyright : Bryan O'Sullivan 2007-2010+-- Copyright : Bryan O'Sullivan 2007-2011 -- License : BSD3 -- -- Maintainer : bos@serpentine.com@@ -11,492 +8,11 @@ -- Portability : unknown -- -- Simple, efficient, character-oriented combinator parsing for--- 'B.ByteString' strings, loosely based on the Parsec library.+-- 'ByteString' strings, loosely based on the Parsec library. module Data.Attoparsec.Char8 (- -- * Character encodings- -- $encodings-- -- * Parser types- Parser- , A.Result(..)-- -- * Running parsers- , A.parse- , A.feed- , A.parseOnly- , A.parseTest- , A.parseWith-- -- ** Result conversion- , A.maybeResult- , A.eitherResult-- -- * Combinators- , (I.<?>)- , I.try- , module Data.Attoparsec.Combinator-- -- * Parsing individual characters- , char- , char8- , anyChar- , notChar- , satisfy-- -- ** Special character parsers- , digit- , letter_iso8859_15- , letter_ascii- , space-- -- ** Fast predicates- , isDigit- , isDigit_w8- , isAlpha_iso8859_15- , isAlpha_ascii- , isSpace- , isSpace_w8-- -- *** Character classes- , inClass- , notInClass-- -- * Efficient string handling- , I.string- , stringCI- , skipSpace- , skipWhile- , I.take- , scan- , takeWhile- , takeWhile1- , takeTill-- -- ** Consume all remaining input- , I.takeByteString- , I.takeLazyByteString-- -- * Text parsing- , I.endOfLine- , isEndOfLine- , isHorizontalSpace-- -- * Numeric parsers- , decimal- , hexadecimal- , signed- , double- , Number(..)- , number- , rational-- -- * State observation and manipulation functions- , I.endOfInput- , I.atEnd+ module Data.Attoparsec.ByteString.Char8 ) where -import Control.Applicative ((*>), (<$>), (<|>))-import Data.Attoparsec.Combinator-import Data.Attoparsec.FastSet (charClass, memberChar)-import Data.Attoparsec.Internal (Parser, (<?>))-import Data.Attoparsec.Number (Number(..))-import Data.Bits (Bits, (.|.), shiftL)-import Data.ByteString.Internal (c2w, w2c)-import Data.Int (Int8, Int16, Int32, Int64)-import Data.Ratio ((%))-import Data.String (IsString(..))-import Data.Word (Word8, Word16, Word32, Word64, Word)-import Prelude hiding (takeWhile)-import qualified Data.Attoparsec as A-import qualified Data.Attoparsec.Internal as I-import qualified Data.ByteString as B8-import qualified Data.ByteString.Char8 as B--instance IsString (Parser B.ByteString) where- fromString = I.string . B.pack---- $encodings------ This module is intended for parsing text that is--- represented using an 8-bit character set, e.g. ASCII or--- ISO-8859-15. It /does not/ make any attempt to deal with character--- encodings, multibyte characters, or wide characters. In--- particular, all attempts to use characters above code point U+00FF--- will give wrong answers.------ Code points below U+0100 are simply translated to and from their--- numeric values, so e.g. the code point U+00A4 becomes the byte--- @0xA4@ (which is the Euro symbol in ISO-8859-15, but the generic--- currency sign in ISO-8859-1). Haskell 'Char' values above U+00FF--- are truncated, so e.g. U+1D6B7 is truncated to the byte @0xB7@.---- ASCII-specific but fast, oh yes.-toLower :: Word8 -> Word8-toLower w | w >= 65 && w <= 90 = w + 32- | otherwise = w---- | Satisfy a literal string, ignoring case.-stringCI :: B.ByteString -> Parser B.ByteString-stringCI = I.stringTransform (B8.map toLower)-{-# INLINE stringCI #-}---- | Consume input as long as the predicate returns 'True', and return--- the consumed input.------ This parser requires the predicate to succeed on at least one byte--- of input: it will fail if the predicate never returns 'True' or if--- there is no input left.-takeWhile1 :: (Char -> Bool) -> Parser B.ByteString-takeWhile1 p = I.takeWhile1 (p . w2c)-{-# INLINE takeWhile1 #-}---- | The parser @satisfy p@ succeeds for any byte for which the--- predicate @p@ returns 'True'. Returns the byte that is actually--- parsed.------ >digit = satisfy isDigit--- > where isDigit c = c >= '0' && c <= '9'-satisfy :: (Char -> Bool) -> Parser Char-satisfy = I.satisfyWith w2c-{-# INLINE satisfy #-}---- | Match a letter, in the ISO-8859-15 encoding.-letter_iso8859_15 :: Parser Char-letter_iso8859_15 = satisfy isAlpha_iso8859_15 <?> "letter_iso8859_15"-{-# INLINE letter_iso8859_15 #-}---- | Match a letter, in the ASCII encoding.-letter_ascii :: Parser Char-letter_ascii = satisfy isAlpha_ascii <?> "letter_ascii"-{-# INLINE letter_ascii #-}---- | A fast alphabetic predicate for the ISO-8859-15 encoding------ /Note/: For all character encodings other than ISO-8859-15, and--- almost all Unicode code points above U+00A3, this predicate gives--- /wrong answers/.-isAlpha_iso8859_15 :: Char -> Bool-isAlpha_iso8859_15 c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||- (c >= '\166' && moby c)- where moby = notInClass "\167\169\171-\179\182\183\185\187\191\215\247"- {-# NOINLINE moby #-}-{-# INLINE isAlpha_iso8859_15 #-}---- | A fast alphabetic predicate for the ASCII encoding------ /Note/: For all character encodings other than ASCII, and--- almost all Unicode code points above U+007F, this predicate gives--- /wrong answers/.-isAlpha_ascii :: Char -> Bool-isAlpha_ascii c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')-{-# INLINE isAlpha_ascii #-}---- | Parse a single digit.-digit :: Parser Char-digit = satisfy isDigit <?> "digit"-{-# INLINE digit #-}---- | A fast digit predicate.-isDigit :: Char -> Bool-isDigit c = c >= '0' && c <= '9'-{-# INLINE isDigit #-}---- | A fast digit predicate.-isDigit_w8 :: Word8 -> Bool-isDigit_w8 w = w >= 48 && w <= 57-{-# INLINE isDigit_w8 #-}---- | Match any character.-anyChar :: Parser Char-anyChar = satisfy $ const True-{-# INLINE anyChar #-}---- | Fast predicate for matching ASCII space characters.------ /Note/: This predicate only gives correct answers for the ASCII--- encoding. For instance, it does not recognise U+00A0 (non-breaking--- space) as a space character, even though it is a valid ISO-8859-15--- byte. For a Unicode-aware and only slightly slower predicate,--- use 'Data.Char.isSpace'-isSpace :: Char -> Bool-isSpace c = (c == ' ') || ('\t' <= c && c <= '\r')-{-# INLINE isSpace #-}---- | Fast 'Word8' predicate for matching ASCII space characters.-isSpace_w8 :: Word8 -> Bool-isSpace_w8 w = (w == 32) || (9 <= w && w <= 13)-{-# INLINE isSpace_w8 #-}----- | Parse a space character.------ /Note/: This parser only gives correct answers for the ASCII--- encoding. For instance, it does not recognise U+00A0 (non-breaking--- space) as a space character, even though it is a valid ISO-8859-15--- byte.-space :: Parser Char-space = satisfy isSpace <?> "space"-{-# INLINE space #-}---- | Match a specific character.-char :: Char -> Parser Char-char c = satisfy (== c) <?> [c]-{-# INLINE char #-}---- | Match a specific character, but return its 'Word8' value.-char8 :: Char -> Parser Word8-char8 c = I.satisfy (== c2w c) <?> [c]-{-# INLINE char8 #-}---- | Match any character except the given one.-notChar :: Char -> Parser Char-notChar c = satisfy (/= c) <?> "not " ++ [c]-{-# INLINE notChar #-}---- | Match any character in a set.------ >vowel = inClass "aeiou"------ Range notation is supported.------ >halfAlphabet = inClass "a-nA-N"------ To add a literal \'-\' to a set, place it at the beginning or end--- of the string.-inClass :: String -> Char -> Bool-inClass s = (`memberChar` mySet)- where mySet = charClass s-{-# INLINE inClass #-}---- | Match any character not in a set.-notInClass :: String -> Char -> Bool-notInClass s = not . inClass s-{-# INLINE notInClass #-}---- | Consume input as long as the predicate returns 'True', and return--- the consumed input.------ This parser does not fail. It will return an empty string if the--- predicate returns 'False' on the first byte of input.------ /Note/: Because this parser does not fail, do not use it with--- combinators such as 'many', because such parsers loop until a--- failure occurs. Careless use will thus result in an infinite loop.-takeWhile :: (Char -> Bool) -> Parser B.ByteString-takeWhile p = I.takeWhile (p . w2c)-{-# INLINE takeWhile #-}---- | A stateful scanner. The predicate consumes and transforms a--- state argument, and each transformed state is passed to successive--- invocations of the predicate on each byte of the input until one--- returns 'Nothing' or the input ends.------ This parser does not fail. It will return an empty string if the--- predicate returns 'Nothing' on the first byte of input.------ /Note/: Because this parser does not fail, do not use it with--- combinators such as 'many', because such parsers loop until a--- failure occurs. Careless use will thus result in an infinite loop.-scan :: s -> (s -> Char -> Maybe s) -> Parser B.ByteString-scan s0 p = I.scan s0 (\s -> p s . w2c)-{-# INLINE scan #-}---- | Consume input as long as the predicate returns 'False'--- (i.e. until it returns 'True'), and return the consumed input.------ This parser does not fail. It will return an empty string if the--- predicate returns 'True' on the first byte of input.------ /Note/: Because this parser does not fail, do not use it with--- combinators such as 'many', because such parsers loop until a--- failure occurs. Careless use will thus result in an infinite loop.-takeTill :: (Char -> Bool) -> Parser B.ByteString-takeTill p = I.takeTill (p . w2c)-{-# INLINE takeTill #-}---- | Skip past input for as long as the predicate returns 'True'.-skipWhile :: (Char -> Bool) -> Parser ()-skipWhile p = I.skipWhile (p . w2c)-{-# INLINE skipWhile #-}---- | Skip over white space.-skipSpace :: Parser ()-skipSpace = I.skipWhile isSpace_w8-{-# INLINE skipSpace #-}---- | A predicate that matches either a carriage return @\'\\r\'@ or--- newline @\'\\n\'@ character.-isEndOfLine :: Word8 -> Bool-isEndOfLine w = w == 13 || w == 10-{-# INLINE isEndOfLine #-}---- | A predicate that matches either a space @\' \'@ or horizontal tab--- @\'\\t\'@ character.-isHorizontalSpace :: Word8 -> Bool-isHorizontalSpace w = w == 32 || w == 9-{-# INLINE isHorizontalSpace #-}---- | Parse and decode an unsigned hexadecimal number. The hex digits--- @\'a\'@ through @\'f\'@ may be upper or lower case.------ This parser does not accept a leading @\"0x\"@ string.-hexadecimal :: (Integral a, Bits a) => Parser a-hexadecimal = B8.foldl' step 0 `fmap` I.takeWhile1 isHexDigit- where- isHexDigit w = (w >= 48 && w <= 57) ||- (w >= 97 && w <= 102) ||- (w >= 65 && w <= 90)- step a w | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)- | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)- | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)-{-# SPECIALISE hexadecimal :: Parser Int #-}-{-# SPECIALISE hexadecimal :: Parser Int8 #-}-{-# SPECIALISE hexadecimal :: Parser Int16 #-}-{-# SPECIALISE hexadecimal :: Parser Int32 #-}-{-# SPECIALISE hexadecimal :: Parser Int64 #-}-{-# SPECIALISE hexadecimal :: Parser Integer #-}-{-# SPECIALISE hexadecimal :: Parser Word #-}-{-# SPECIALISE hexadecimal :: Parser Word8 #-}-{-# SPECIALISE hexadecimal :: Parser Word16 #-}-{-# SPECIALISE hexadecimal :: Parser Word32 #-}-{-# SPECIALISE hexadecimal :: Parser Word64 #-}---- | Parse and decode an unsigned decimal number.-decimal :: Integral a => Parser a-decimal = B8.foldl' step 0 `fmap` I.takeWhile1 isDig- where isDig w = w >= 48 && w <= 57- step a w = a * 10 + fromIntegral (w - 48)-{-# SPECIALISE decimal :: Parser Int #-}-{-# SPECIALISE decimal :: Parser Int8 #-}-{-# SPECIALISE decimal :: Parser Int16 #-}-{-# SPECIALISE decimal :: Parser Int32 #-}-{-# SPECIALISE decimal :: Parser Int64 #-}-{-# SPECIALISE decimal :: Parser Integer #-}-{-# SPECIALISE decimal :: Parser Word #-}-{-# SPECIALISE decimal :: Parser Word8 #-}-{-# SPECIALISE decimal :: Parser Word16 #-}-{-# SPECIALISE decimal :: Parser Word32 #-}-{-# SPECIALISE decimal :: Parser Word64 #-}---- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign--- character.-signed :: Num a => Parser a -> Parser a-{-# SPECIALISE signed :: Parser Int -> Parser Int #-}-{-# SPECIALISE signed :: Parser Int8 -> Parser Int8 #-}-{-# SPECIALISE signed :: Parser Int16 -> Parser Int16 #-}-{-# SPECIALISE signed :: Parser Int32 -> Parser Int32 #-}-{-# SPECIALISE signed :: Parser Int64 -> Parser Int64 #-}-{-# SPECIALISE signed :: Parser Integer -> Parser Integer #-}-signed p = (negate <$> (char8 '-' *> p))- <|> (char8 '+' *> p)- <|> p---- | Parse a rational number.------ This parser accepts an optional leading sign character, followed by--- at least one decimal digit. The syntax similar to that accepted by--- the 'read' function, with the exception that a trailing @\'.\'@ or--- @\'e\'@ /not/ followed by a number is not consumed.------ Examples with behaviour identical to 'read', if you feed an empty--- continuation to the first result:------ >rational "3" == Done 3.0 ""--- >rational "3.1" == Done 3.1 ""--- >rational "3e4" == Done 30000.0 ""--- >rational "3.1e4" == Done 31000.0, ""---- Examples with behaviour identical to 'read':------ >rational ".3" == Fail "input does not start with a digit"--- >rational "e3" == Fail "input does not start with a digit"------ Examples of differences from 'read':------ >rational "3.foo" == Done 3.0 ".foo"--- >rational "3e" == Done 3.0 "e"------ This function does not accept string representations of \"NaN\" or--- \"Infinity\".-rational :: Fractional a => Parser a-{-# SPECIALIZE rational :: Parser Double #-}-{-# SPECIALIZE rational :: Parser Float #-}-{-# SPECIALIZE rational :: Parser Rational #-}-rational = floaty $ \real frac fracDenom -> fromRational $- real % 1 + frac % fracDenom---- | Parse a rational number.------ The syntax accepted by this parser is the same as for 'rational'.------ /Note/: This function is almost ten times faster than 'rational',--- but is slightly less accurate.------ The 'Double' type supports about 16 decimal places of accuracy.--- For 94.2% of numbers, this function and 'rational' give identical--- results, but for the remaining 5.8%, this function loses precision--- around the 15th decimal place. For 0.001% of numbers, this--- function will lose precision at the 13th or 14th decimal place.------ This function does not accept string representations of \"NaN\" or--- \"Infinity\".-double :: Parser Double-double = floaty asDouble--asDouble :: Integer -> Integer -> Integer -> Double-asDouble real frac fracDenom =- fromIntegral real + fromIntegral frac / fromIntegral fracDenom-{-# INLINE asDouble #-}---- | Parse a number, attempting to preserve both speed and precision.------ The syntax accepted by this parser is the same as for 'rational'.------ /Note/: This function is almost ten times faster than 'rational'.--- On integral inputs, it gives perfectly accurate answers, and on--- floating point inputs, it is slightly less accurate than--- 'rational'.------ This function does not accept string representations of \"NaN\" or--- \"Infinity\".-number :: Parser Number-number = floaty $ \real frac fracDenom ->- if frac == 0 && fracDenom == 0- then I real- else D (asDouble real frac fracDenom)-{-# INLINE number #-}--data T = T !Integer !Int--floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a-{-# INLINE floaty #-}-floaty f = do- let minus = 45- plus = 43- !positive <- ((== plus) <$> I.satisfy (\c -> c == minus || c == plus)) <|>- return True- real <- decimal- let tryFraction = do- let dot = 46- _ <- I.satisfy (==dot)- ds <- I.takeWhile isDigit_w8- case I.parseOnly decimal ds of- Right n -> return $ T n (B.length ds)- _ -> fail "no digits after decimal"- T fraction fracDigits <- tryFraction <|> return (T 0 0)- let littleE = 101- bigE = 69- e w = w == littleE || w == bigE- power <- (I.satisfy e *> signed decimal) <|> return (0::Int)- let n = if fracDigits == 0- then if power == 0- then fromIntegral real- else fromIntegral real * (10 ^^ power)- else if power == 0- then f real fraction (10 ^ fracDigits)- else f real fraction (10 ^ fracDigits) * (10 ^^ power)- return $ if positive- then n- else -n+import Data.Attoparsec.ByteString.Char8
Data/Attoparsec/Combinator.hs view
@@ -21,21 +21,15 @@ , skipMany , skipMany1 , eitherP-- -- * Inlined implementations of existing functions- --- -- These are exact duplicates of functions already exported by the- -- 'Control.Applicative' module, but whose definitions are- -- inlined. In many cases, this leads to 2x performance- -- improvements.- , many ) where -import Control.Applicative (Alternative, Applicative(..), empty, liftA2,+import Control.Applicative (Alternative(..), Applicative(..), empty, liftA2, (<|>), (*>), (<$>)) #if __GLASGOW_HASKELL__ >= 700 import Data.Attoparsec.Internal.Types (Parser) import qualified Data.Attoparsec.Zepto as Z+import Data.ByteString (ByteString)+import Data.Text (Text) #endif -- | @choice ps@ tries to apply the actions in the list @ps@ in order,@@ -44,7 +38,8 @@ choice :: Alternative f => [f a] -> f a choice = foldr (<|>) empty #if __GLASGOW_HASKELL__ >= 700-{-# SPECIALIZE choice :: [Parser a] -> Parser a #-}+{-# SPECIALIZE choice :: [Parser ByteString a] -> Parser ByteString a #-}+{-# SPECIALIZE choice :: [Parser Text a] -> Parser Text a #-} {-# SPECIALIZE choice :: [Z.Parser a] -> Z.Parser a #-} #endif @@ -56,7 +51,8 @@ option :: Alternative f => a -> f a -> f a option x p = p <|> pure x #if __GLASGOW_HASKELL__ >= 700-{-# SPECIALIZE option :: a -> Parser a -> Parser a #-}+{-# SPECIALIZE option :: a -> Parser ByteString a -> Parser ByteString a #-}+{-# SPECIALIZE option :: a -> Parser Text a -> Parser Text a #-} {-# SPECIALIZE option :: a -> Z.Parser a -> Z.Parser a #-} #endif @@ -75,7 +71,9 @@ sepBy :: Alternative f => f a -> f s -> f [a] sepBy p s = liftA2 (:) p ((s *> sepBy1 p s) <|> pure []) <|> pure [] #if __GLASGOW_HASKELL__ >= 700-{-# SPECIALIZE sepBy :: Parser a -> Parser s -> Parser [a] #-}+{-# SPECIALIZE sepBy :: Parser ByteString a -> Parser ByteString s+ -> Parser ByteString [a] #-}+{-# SPECIALIZE sepBy :: Parser Text a -> Parser Text s -> Parser Text [a] #-} {-# SPECIALIZE sepBy :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-} #endif @@ -87,7 +85,9 @@ sepBy1 p s = scan where scan = liftA2 (:) p ((s *> scan) <|> pure []) #if __GLASGOW_HASKELL__ >= 700-{-# SPECIALIZE sepBy1 :: Parser a -> Parser s -> Parser [a] #-}+{-# SPECIALIZE sepBy1 :: Parser ByteString a -> Parser ByteString s+ -> Parser ByteString [a] #-}+{-# SPECIALIZE sepBy1 :: Parser Text a -> Parser Text s -> Parser Text [a] #-} {-# SPECIALIZE sepBy1 :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-} #endif @@ -103,7 +103,9 @@ manyTill p end = scan where scan = (end *> pure []) <|> liftA2 (:) p scan #if __GLASGOW_HASKELL__ >= 700-{-# SPECIALIZE manyTill :: Parser a -> Parser b -> Parser [a] #-}+{-# SPECIALIZE manyTill :: Parser ByteString a -> Parser ByteString b+ -> Parser ByteString [a] #-}+{-# SPECIALIZE manyTill :: Parser Text a -> Parser Text b -> Parser Text [a] #-} {-# SPECIALIZE manyTill :: Z.Parser a -> Z.Parser b -> Z.Parser [a] #-} #endif @@ -112,7 +114,8 @@ skipMany p = scan where scan = (p *> scan) <|> pure () #if __GLASGOW_HASKELL__ >= 700-{-# SPECIALIZE skipMany :: Parser a -> Parser () #-}+{-# SPECIALIZE skipMany :: Parser ByteString a -> Parser ByteString () #-}+{-# SPECIALIZE skipMany :: Parser Text a -> Parser Text () #-} {-# SPECIALIZE skipMany :: Z.Parser a -> Z.Parser () #-} #endif @@ -120,7 +123,8 @@ skipMany1 :: Alternative f => f a -> f () skipMany1 p = p *> skipMany p #if __GLASGOW_HASKELL__ >= 700-{-# SPECIALIZE skipMany1 :: Parser a -> Parser () #-}+{-# SPECIALIZE skipMany1 :: Parser ByteString a -> Parser ByteString () #-}+{-# SPECIALIZE skipMany1 :: Parser Text a -> Parser Text () #-} {-# SPECIALIZE skipMany1 :: Z.Parser a -> Z.Parser () #-} #endif @@ -133,10 +137,3 @@ eitherP :: (Alternative f) => f a -> f b -> f (Either a b) eitherP a b = (Left <$> a) <|> (Right <$> b) {-# INLINE eitherP #-}---- | Zero or more.-many :: (Alternative f) => f a -> f [a]-many v = many_v- where many_v = some_v <|> pure []- some_v = (:) <$> v <*> many_v-{-# INLINE many #-}
− Data/Attoparsec/FastSet.hs
@@ -1,115 +0,0 @@-{-# LANGUAGE BangPatterns, MagicHash #-}---------------------------------------------------------------------------------- |--- Module : Data.Attoparsec.FastSet--- Copyright : Bryan O'Sullivan 2008--- License : BSD3--- --- Maintainer : bos@serpentine.com--- Stability : experimental--- Portability : unknown------ Fast set membership tests for 'Word8' and 8-bit 'Char' values. The--- set representation is unboxed for efficiency. For small sets, we--- test for membership using a binary search. For larger sets, we use--- a lookup table.--- -------------------------------------------------------------------------------module Data.Attoparsec.FastSet- (- -- * Data type- FastSet- -- * Construction- , fromList- , set- -- * Lookup- , memberChar- , memberWord8- -- * Debugging- , fromSet- -- * Handy interface- , charClass- ) where--import Data.Bits ((.&.), (.|.))-import Foreign.Storable (peekByteOff, pokeByteOff)-import GHC.Base (Int(I#), iShiftRA#, narrow8Word#, shiftL#)-import GHC.Word (Word8(W8#))-import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as B8-import qualified Data.ByteString.Internal as I-import qualified Data.ByteString.Unsafe as U--data FastSet = Sorted { fromSet :: !B.ByteString }- | Table { fromSet :: !B.ByteString }- deriving (Eq, Ord)--instance Show FastSet where- show (Sorted s) = "FastSet Sorted " ++ show (B8.unpack s)- show (Table _) = "FastSet Table"---- | The lower bound on the size of a lookup table. We choose this to--- balance table density against performance.-tableCutoff :: Int-tableCutoff = 8---- | Create a set.-set :: B.ByteString -> FastSet-set s | B.length s < tableCutoff = Sorted . B.sort $ s- | otherwise = Table . mkTable $ s--fromList :: [Word8] -> FastSet-fromList = set . B.pack--data I = I {-# UNPACK #-} !Int {-# UNPACK #-} !Word8--shiftR :: Int -> Int -> Int-shiftR (I# x#) (I# i#) = I# (x# `iShiftRA#` i#)--shiftL :: Word8 -> Int -> Word8-shiftL (W8# x#) (I# i#) = W8# (narrow8Word# (x# `shiftL#` i#))--index :: Int -> I-index i = I (i `shiftR` 3) (1 `shiftL` (i .&. 7))-{-# INLINE index #-}---- | Check the set for membership.-memberWord8 :: Word8 -> FastSet -> Bool-memberWord8 w (Table t) =- let I byte bit = index (fromIntegral w)- in U.unsafeIndex t byte .&. bit /= 0-memberWord8 w (Sorted s) = search 0 (B.length s - 1)- where search lo hi- | hi < lo = False- | otherwise =- let mid = (lo + hi) `div` 2- in case compare w (U.unsafeIndex s mid) of- GT -> search (mid + 1) hi- LT -> search lo (mid - 1)- _ -> True---- | Check the set for membership. Only works with 8-bit characters:--- characters above code point 255 will give wrong answers.-memberChar :: Char -> FastSet -> Bool-memberChar c = memberWord8 (I.c2w c)-{-# INLINE memberChar #-}--mkTable :: B.ByteString -> B.ByteString-mkTable s = I.unsafeCreate 32 $ \t -> do- _ <- I.memset t 0 32- U.unsafeUseAsCStringLen s $ \(p, l) ->- let loop n | n == l = return ()- | otherwise = do- c <- peekByteOff p n :: IO Word8- let I byte bit = index (fromIntegral c)- prev <- peekByteOff t byte :: IO Word8- pokeByteOff t byte (prev .|. bit)- loop (n + 1)- in loop 0--charClass :: String -> FastSet-charClass = set . B8.pack . go- where go (a:'-':b:xs) = [a..b] ++ go xs- go (x:xs) = x : go xs- go _ = ""
− Data/Attoparsec/Internal.hs
@@ -1,453 +0,0 @@-{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings, RecordWildCards #-}--- |--- Module : Data.Attoparsec.Internal--- Copyright : Bryan O'Sullivan 2007-2011--- License : BSD3------ Maintainer : bos@serpentine.com--- Stability : experimental--- Portability : unknown------ Simple, efficient parser combinators for 'B.ByteString' strings,--- loosely based on the Parsec library.--module Data.Attoparsec.Internal- (- -- * Parser types- Parser- , Result(..)-- -- * Running parsers- , parse- , parseOnly-- -- * Combinators- , (<?>)- , try- , module Data.Attoparsec.Combinator-- -- * Parsing individual bytes- , satisfy- , satisfyWith- , anyWord8- , skip- , word8- , notWord8-- -- ** Byte classes- , inClass- , notInClass-- -- * Parsing more complicated structures- , storable-- -- * Efficient string handling- , skipWhile- , string- , stringTransform- , take- , scan- , takeWhile- , takeWhile1- , takeTill-- -- ** Consume all remaining input- , takeByteString- , takeLazyByteString-- -- * State observation and manipulation functions- , endOfInput- , atEnd- , ensure-- -- * Utilities- , endOfLine- ) where--import Control.Applicative ((<|>), (<$>))-import Control.Monad (when)-import Data.Attoparsec.Combinator-import Data.Attoparsec.FastSet (charClass, memberWord8)-import Data.Attoparsec.Internal.Types-import Data.Word (Word8)-import Foreign.ForeignPtr (withForeignPtr)-import Foreign.Ptr (castPtr, minusPtr, plusPtr)-import Foreign.Storable (Storable(peek, sizeOf))-import Prelude hiding (getChar, take, takeWhile)-import System.IO.Unsafe (unsafePerformIO)-import qualified Data.ByteString as B8-import qualified Data.ByteString.Char8 as B-import qualified Data.ByteString.Internal as B-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString.Unsafe as B---- | If at least @n@ bytes of input are available, return the current--- input, otherwise fail.-ensure :: Int -> Parser B.ByteString-ensure !n = Parser $ \i0 a0 m0 kf ks ->- if B.length (unI i0) >= n- then ks i0 a0 m0 (unI i0)- else runParser (demandInput >> ensure n) i0 a0 m0 kf ks---- | Ask for input. If we receive any, pass it to a success--- continuation, otherwise to a failure continuation.-prompt :: Input -> Added -> More- -> (Input -> Added -> More -> Result r)- -> (Input -> Added -> More -> Result r)- -> Result r-prompt i0 a0 _m0 kf ks = Partial $ \s ->- if B.null s- then kf i0 a0 Complete- else ks (I (unI i0 +++ s)) (A (unA a0 +++ s)) Incomplete---- | Immediately demand more input via a 'Partial' continuation--- result.-demandInput :: Parser ()-demandInput = Parser $ \i0 a0 m0 kf ks ->- if m0 == Complete- then kf i0 a0 m0 ["demandInput"] "not enough bytes"- else let kf' i a m = kf i a m ["demandInput"] "not enough bytes"- ks' i a m = ks i a m ()- in prompt i0 a0 m0 kf' ks'---- | This parser always succeeds. It returns 'True' if any input is--- available either immediately or on demand, and 'False' if the end--- of all input has been reached.-wantInput :: Parser Bool-wantInput = Parser $ \i0 a0 m0 _kf ks ->- case () of- _ | not (B.null (unI i0)) -> ks i0 a0 m0 True- | m0 == Complete -> ks i0 a0 m0 False- | otherwise -> let kf' i a m = ks i a m False- ks' i a m = ks i a m True- in prompt i0 a0 m0 kf' ks'--get :: Parser B.ByteString-get = Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0)--put :: B.ByteString -> Parser ()-put s = Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 ()---- | Attempt a parse, and if it fails, rewind the input so that no--- input appears to have been consumed.------ This combinator is useful in cases where a parser might consume--- some input before failing, i.e. the parser needs arbitrary--- lookahead. The downside to using this combinator is that it can--- retain input for longer than is desirable.-try :: Parser a -> Parser a-try p = Parser $ \i0 a0 m0 kf ks ->- noAdds i0 a0 m0 $ \i1 a1 m1 ->- let kf' i2 a2 m2 = addS i0 a0 m0 i2 a2 m2 kf- in runParser p i1 a1 m1 kf' ks---- | The parser @satisfy p@ succeeds for any byte for which the--- predicate @p@ returns 'True'. Returns the byte that is actually--- parsed.------ >digit = satisfy isDigit--- > where isDigit w = w >= 48 && w <= 57-satisfy :: (Word8 -> Bool) -> Parser Word8-satisfy p = do- s <- ensure 1- let w = B.unsafeHead s- if p w- then put (B.unsafeTail s) >> return w- else fail "satisfy"---- | The parser @skip p@ succeeds for any byte for which the predicate--- @p@ returns 'True'.------ >skipDigit = skip isDigit--- > where isDigit w = w >= 48 && w <= 57-skip :: (Word8 -> Bool) -> Parser ()-skip p = do- s <- ensure 1- if p (B.unsafeHead s)- then put (B.unsafeTail s)- else fail "skip"---- | The parser @satisfyWith f p@ transforms a byte, and succeeds if--- the predicate @p@ returns 'True' on the transformed value. The--- parser returns the transformed byte that was parsed.-satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a-satisfyWith f p = do- s <- ensure 1- let c = f (B.unsafeHead s)- if p c- then put (B.unsafeTail s) >> return c- else fail "satisfyWith"--storable :: Storable a => Parser a-storable = hack undefined- where- hack :: Storable b => b -> Parser b- hack dummy = do- (fp,o,_) <- B.toForeignPtr `fmap` take (sizeOf dummy)- return . B.inlinePerformIO . withForeignPtr fp $ \p ->- peek (castPtr $ p `plusPtr` o)---- | Consume @n@ bytes of input, but succeed only if the predicate--- returns 'True'.-takeWith :: Int -> (B.ByteString -> Bool) -> Parser B.ByteString-takeWith n p = do- s <- ensure n- let h = B.unsafeTake n s- t = B.unsafeDrop n s- if p h- then put t >> return h- else fail "takeWith"---- | Consume exactly @n@ bytes of input.-take :: Int -> Parser B.ByteString-take n = takeWith n (const True)-{-# INLINE take #-}---- | @string s@ parses a sequence of bytes that identically match--- @s@. Returns the parsed string (i.e. @s@). This parser consumes no--- input if it fails (even if a partial match).------ /Note/: The behaviour of this parser is different to that of the--- similarly-named parser in Parsec, as this one is all-or-nothing.--- To illustrate the difference, the following parser will fail under--- Parsec given an input of @"for"@:------ >string "foo" <|> string "for"------ The reason for its failure is that that the first branch is a--- partial match, and will consume the letters @\'f\'@ and @\'o\'@--- before failing. In Attoparsec, the above parser will /succeed/ on--- that input, because the failed first branch will consume nothing.-string :: B.ByteString -> Parser B.ByteString-string s = takeWith (B.length s) (==s)-{-# INLINE string #-}--stringTransform :: (B.ByteString -> B.ByteString) -> B.ByteString- -> Parser B.ByteString-stringTransform f s = takeWith (B.length s) ((==f s) . f)-{-# INLINE stringTransform #-}---- | Skip past input for as long as the predicate returns 'True'.-skipWhile :: (Word8 -> Bool) -> Parser ()-skipWhile p = go- where- go = do- t <- B8.dropWhile p <$> get- put t- when (B.null t) $ do- input <- wantInput- when input go-{-# INLINE skipWhile #-}---- | Consume input as long as the predicate returns 'False'--- (i.e. until it returns 'True'), and return the consumed input.------ This parser does not fail. It will return an empty string if the--- predicate returns 'True' on the first byte of input.------ /Note/: Because this parser does not fail, do not use it with--- combinators such as 'many', because such parsers loop until a--- failure occurs. Careless use will thus result in an infinite loop.-takeTill :: (Word8 -> Bool) -> Parser B.ByteString-takeTill p = takeWhile (not . p)-{-# INLINE takeTill #-}---- | Consume input as long as the predicate returns 'True', and return--- the consumed input.------ This parser does not fail. It will return an empty string if the--- predicate returns 'False' on the first byte of input.------ /Note/: Because this parser does not fail, do not use it with--- combinators such as 'many', because such parsers loop until a--- failure occurs. Careless use will thus result in an infinite loop.-takeWhile :: (Word8 -> Bool) -> Parser B.ByteString-takeWhile p = (B.concat . reverse) `fmap` go []- where- go acc = do- (h,t) <- B8.span p <$> get- put t- if B.null t- then do- input <- wantInput- if input- then go (h:acc)- else return (h:acc)- else return (h:acc)--takeRest :: Parser [B.ByteString]-takeRest = go []- where- go acc = do- input <- wantInput- if input- then do- s <- get- put B.empty- go (s:acc)- else return (reverse acc)---- | Consume all remaining input and return it as a single string.-takeByteString :: Parser B.ByteString-takeByteString = B.concat `fmap` takeRest---- | Consume all remaining input and return it as a single string.-takeLazyByteString :: Parser L.ByteString-takeLazyByteString = L.fromChunks `fmap` takeRest--data T s = T {-# UNPACK #-} !Int s---- | A stateful scanner. The predicate consumes and transforms a--- state argument, and each transformed state is passed to successive--- invocations of the predicate on each byte of the input until one--- returns 'Nothing' or the input ends.------ This parser does not fail. It will return an empty string if the--- predicate returns 'Nothing' on the first byte of input.------ /Note/: Because this parser does not fail, do not use it with--- combinators such as 'many', because such parsers loop until a--- failure occurs. Careless use will thus result in an infinite loop.-scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString-scan s0 p = do- chunks <- go [] s0- case chunks of- [x] -> return x- xs -> return . B.concat . reverse $ xs- where- go acc s1 = do- let scanner (B.PS fp off len) =- withForeignPtr fp $ \ptr0 -> do- let start = ptr0 `plusPtr` off- end = start `plusPtr` len- inner ptr !s- | ptr < end = do- w <- peek ptr- case p s w of- Just s' -> inner (ptr `plusPtr` 1) s'- _ -> done (ptr `minusPtr` start) s- | otherwise = done (ptr `minusPtr` start) s- done !i !s = return (T i s)- inner start s1- bs <- get- let T i s' = unsafePerformIO $ scanner bs- h = B.unsafeTake i bs- t = B.unsafeDrop i bs- put t- if B.null t- then do- input <- wantInput- if input- then go (h:acc) s'- else return (h:acc)- else return (h:acc)-{-# INLINE scan #-}---- | Consume input as long as the predicate returns 'True', and return--- the consumed input.------ This parser requires the predicate to succeed on at least one byte--- of input: it will fail if the predicate never returns 'True' or if--- there is no input left.-takeWhile1 :: (Word8 -> Bool) -> Parser B.ByteString-takeWhile1 p = do- (`when` demandInput) =<< B.null <$> get- (h,t) <- B8.span p <$> get- when (B.null h) $ fail "takeWhile1"- put t- if B.null t- then (h+++) `fmap` takeWhile p- else return h---- | Match any byte in a set.------ >vowel = inClass "aeiou"------ Range notation is supported.------ >halfAlphabet = inClass "a-nA-N"------ To add a literal @\'-\'@ to a set, place it at the beginning or end--- of the string.-inClass :: String -> Word8 -> Bool-inClass s = (`memberWord8` mySet)- where mySet = charClass s-{-# INLINE inClass #-}---- | Match any byte not in a set.-notInClass :: String -> Word8 -> Bool-notInClass s = not . inClass s-{-# INLINE notInClass #-}---- | Match any byte.-anyWord8 :: Parser Word8-anyWord8 = satisfy $ const True-{-# INLINE anyWord8 #-}---- | Match a specific byte.-word8 :: Word8 -> Parser Word8-word8 c = satisfy (== c) <?> show c-{-# INLINE word8 #-}---- | Match any byte except the given one.-notWord8 :: Word8 -> Parser Word8-notWord8 c = satisfy (/= c) <?> "not " ++ show c-{-# INLINE notWord8 #-}---- | Match only if all input has been consumed.-endOfInput :: Parser ()-endOfInput = Parser $ \i0 a0 m0 kf ks ->- if B.null (unI i0)- then if m0 == Complete- then ks i0 a0 m0 ()- else let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $- \ i2 a2 m2 -> ks i2 a2 m2 ()- ks' i1 a1 m1 _ = addS i0 a0 m0 i1 a1 m1 $- \ i2 a2 m2 -> kf i2 a2 m2 []- "endOfInput"- in runParser demandInput i0 a0 m0 kf' ks'- else kf i0 a0 m0 [] "endOfInput"---- | Return an indication of whether the end of input has been--- reached.-atEnd :: Parser Bool-atEnd = not <$> wantInput-{-# INLINE atEnd #-}---- | Match either a single newline character @\'\\n\'@, or a carriage--- return followed by a newline character @\"\\r\\n\"@.-endOfLine :: Parser ()-endOfLine = (word8 10 >> return ()) <|> (string "\r\n" >> return ())----- | Name the parser, in case failure occurs.-(<?>) :: Parser a- -> String -- ^ the name to use if parsing fails- -> Parser a-p <?> msg0 = Parser $ \i0 a0 m0 kf ks ->- let kf' i a m strs msg = kf i a m (msg0:strs) msg- in runParser p i0 a0 m0 kf' ks-{-# INLINE (<?>) #-}-infix 0 <?>---- | Terminal failure continuation.-failK :: Failure a-failK i0 _a0 _m0 stack msg = Fail (unI i0) stack msg-{-# INLINE failK #-}---- | Terminal success continuation.-successK :: Success a a-successK i0 _a0 _m0 a = Done (unI i0) a-{-# INLINE successK #-}---- | Run a parser.-parse :: Parser a -> B.ByteString -> Result a-parse m s = runParser m (I s) (A B.empty) Incomplete failK successK-{-# INLINE parse #-}---- | Run a parser that cannot be resupplied via a 'Partial' result.-parseOnly :: Parser a -> B.ByteString -> Either String a-parseOnly m s = case runParser m (I s) (A B.empty) Complete failK successK of- Fail _ _ err -> Left err- Done _ a -> Right a- _ -> error "parseOnly: impossible error!"-{-# INLINE parseOnly #-}
Data/Attoparsec/Internal/Types.hs view
@@ -8,148 +8,172 @@ -- Stability : experimental -- Portability : unknown ----- Simple, efficient parser combinators for 'B.ByteString' strings,--- loosely based on the Parsec library.+-- Simple, efficient parser combinators, loosely based on the Parsec+-- library. module Data.Attoparsec.Internal.Types ( Parser(..) , Failure , Success- , Result(..)+ , IResult(..) , Input(..) , Added(..) , More(..) , addS , noAdds- , (+++)+ , (<>) ) where -import Control.Applicative (Alternative(..), Applicative(..))+import Control.Applicative (Alternative(..), Applicative(..), (<$>)) import Control.DeepSeq (NFData(rnf)) import Control.Monad (MonadPlus(..)) import Data.Monoid (Monoid(..)) import Prelude hiding (getChar, take, takeWhile)-import qualified Data.ByteString.Char8 as B --- | The result of a parse.-data Result r = Fail B.ByteString [String] String- -- ^ The parse failed. The 'B.ByteString' is the input- -- that had not yet been consumed when the failure- -- occurred. The @[@'String'@]@ is a list of contexts- -- in which the error occurred. The 'String' is the- -- message describing the error, if any.- | Partial (B.ByteString -> Result r)- -- ^ Supply this continuation with more input so that- -- the parser can resume. To indicate that no more- -- input is available, use an 'B.empty' string.- | Done B.ByteString r- -- ^ The parse succeeded. The 'B.ByteString' is the- -- input that had not yet been consumed (if any) when- -- the parse succeeded.+-- | The result of a parse. This is parameterised over the type @t@+-- of string that was processed.+--+-- This type is an instance of 'Functor', where 'fmap' transforms the+-- value in a 'Done' result.+data IResult t r = Fail t [String] String+ -- ^ The parse failed. The 't' parameter is the+ -- input that had not yet been consumed when the+ -- failure occurred. The @[@'String'@]@ is a list of+ -- contexts in which the error occurred. The+ -- 'String' is the message describing the error, if+ -- any.+ | Partial (t -> IResult t r)+ -- ^ Supply this continuation with more input so that+ -- the parser can resume. To indicate that no more+ -- input is available, use an empty string.+ | Done t r+ -- ^ The parse succeeded. The 't' parameter is the+ -- input that had not yet been consumed (if any) when+ -- the parse succeeded. -instance Show r => Show (Result r) where- show (Fail bs stk msg) =- "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg- show (Partial _) = "Partial _"- show (Done bs r) = "Done " ++ show bs ++ " " ++ show r+instance (Show t, Show r) => Show (IResult t r) where+ show (Fail t stk msg) =+ "Fail " ++ show t ++ " " ++ show stk ++ " " ++ show msg+ show (Partial _) = "Partial _"+ show (Done t r) = "Done " ++ show t ++ " " ++ show r -instance (NFData r) => NFData (Result r) where- rnf (Fail _ _ _) = ()+instance (NFData t, NFData r) => NFData (IResult t r) where+ rnf (Fail t stk msg) = rnf t `seq` rnf stk `seq` rnf msg rnf (Partial _) = ()- rnf (Done _ r) = rnf r+ rnf (Done t r) = rnf t `seq` rnf r {-# INLINE rnf #-} -fmapR :: (a -> b) -> Result a -> Result b-fmapR _ (Fail st stk msg) = Fail st stk msg+fmapR :: (a -> b) -> IResult t a -> IResult t b+fmapR _ (Fail t stk msg) = Fail t stk msg fmapR f (Partial k) = Partial (fmapR f . k)-fmapR f (Done bs r) = Done bs (f r)+fmapR f (Done t r) = Done t (f r) -instance Functor Result where+instance Functor (IResult t) where fmap = fmapR {-# INLINE fmap #-} -newtype Input = I {unI :: B.ByteString}-newtype Added = A {unA :: B.ByteString}+newtype Input t = I {unI :: t}+newtype Added t = A {unA :: t} --- | The 'Parser' type is a monad.-newtype Parser a = Parser {- runParser :: forall r. Input -> Added -> More- -> Failure r- -> Success a r- -> Result r+-- | The core parser type. This is parameterised over the type @t@ of+-- string being processed.+--+-- This type is an instance of the following classes:+--+-- * 'Monad', where 'fail' throws an exception (i.e. fails) with an+-- error message.+--+-- * 'Functor' and 'Applicative', which follow the usual definitions.+--+-- * 'MonadPlus', where 'mzero' fails (with no error message) and+-- 'mplus' executes the right-hand parser if the left-hand one+-- fails. When the parser on the right executes, the input is reset+-- to the same state as the parser on the left started with. (In+-- other words, Attoparsec is a backtracking parser that supports+-- arbitrary lookahead.)+--+-- * 'Alternative', which follows 'MonadPlus'.+newtype Parser t a = Parser {+ runParser :: forall r. Input t -> Added t -> More+ -> Failure t r+ -> Success t a r+ -> IResult t r } -type Failure r = Input -> Added -> More -> [String] -> String -> Result r-type Success a r = Input -> Added -> More -> a -> Result r+type Failure t r = Input t -> Added t -> More -> [String] -> String+ -> IResult t r+type Success t a r = Input t -> Added t -> More -> a -> IResult t r -- | Have we read all available input? data More = Complete | Incomplete deriving (Eq, Show) -addS :: Input -> Added -> More- -> Input -> Added -> More- -> (Input -> Added -> More -> r) -> r+addS :: (Monoid t) =>+ Input t -> Added t -> More+ -> Input t -> Added t -> More+ -> (Input t -> Added t -> More -> r) -> r addS i0 a0 m0 _i1 a1 m1 f =- let !i = I (unI i0 +++ unA a1)- a = A (unA a0 +++ unA a1)- !m = m0 <> m1+ let !i = I (unI i0 <> unA a1)+ a = A (unA a0 <> unA a1)+ !m = m0 <?> m1 in f i a m where- Complete <> _ = Complete- _ <> Complete = Complete- _ <> _ = Incomplete+ Complete <?> _ = Complete+ _ <?> Complete = Complete+ _ <?> _ = Incomplete {-# INLINE addS #-} -bindP :: Parser a -> (a -> Parser b) -> Parser b+bindP :: Parser t a -> (a -> Parser t b) -> Parser t b bindP m g = Parser $ \i0 a0 m0 kf ks -> runParser m i0 a0 m0 kf $ \i1 a1 m1 a -> runParser (g a) i1 a1 m1 kf ks {-# INLINE bindP #-} -returnP :: a -> Parser a+returnP :: a -> Parser t a returnP a = Parser (\i0 a0 m0 _kf ks -> ks i0 a0 m0 a) {-# INLINE returnP #-} -instance Monad Parser where+instance Monad (Parser t) where return = returnP (>>=) = bindP fail = failDesc -noAdds :: Input -> Added -> More- -> (Input -> Added -> More -> r) -> r-noAdds i0 _a0 m0 f = f i0 (A B.empty) m0+noAdds :: (Monoid t) =>+ Input t -> Added t -> More+ -> (Input t -> Added t -> More -> r) -> r+noAdds i0 _a0 m0 f = f i0 (A mempty) m0 {-# INLINE noAdds #-} -plus :: Parser a -> Parser a -> Parser a+plus :: (Monoid t) => Parser t a -> Parser t a -> Parser t a plus a b = Parser $ \i0 a0 m0 kf ks -> let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $ \ i2 a2 m2 -> runParser b i2 a2 m2 kf ks in noAdds i0 a0 m0 $ \i2 a2 m2 -> runParser a i2 a2 m2 kf' ks {-# INLINE plus #-} -instance MonadPlus Parser where+instance (Monoid t) => MonadPlus (Parser t) where mzero = failDesc "mzero" {-# INLINE mzero #-} mplus = plus -fmapP :: (a -> b) -> Parser a -> Parser b+fmapP :: (a -> b) -> Parser t a -> Parser t b fmapP p m = Parser $ \i0 a0 m0 f k -> runParser m i0 a0 m0 f $ \i1 a1 s1 a -> k i1 a1 s1 (p a) {-# INLINE fmapP #-} -instance Functor Parser where+instance Functor (Parser t) where fmap = fmapP {-# INLINE fmap #-} -apP :: Parser (a -> b) -> Parser a -> Parser b+apP :: Parser t (a -> b) -> Parser t a -> Parser t b apP d e = do b <- d a <- e return (b a) {-# INLINE apP #-} -instance Applicative Parser where+instance Applicative (Parser t) where pure = returnP {-# INLINE pure #-} (<*>) = apP@@ -165,23 +189,35 @@ {-# INLINE (<*) #-} #endif -instance Monoid (Parser a) where+instance (Monoid t) => Monoid (Parser t a) where mempty = failDesc "mempty" {-# INLINE mempty #-} mappend = plus {-# INLINE mappend #-} -instance Alternative Parser where+instance (Monoid t) => Alternative (Parser t) where empty = failDesc "empty" {-# INLINE empty #-}+ (<|>) = plus {-# INLINE (<|>) #-} -failDesc :: String -> Parser a+ many v = many_v+ where many_v = some_v <|> pure []+ some_v = (:) <$> v <*> many_v+ {-# INLINE many #-}++ some v = some_v+ where+ many_v = some_v <|> pure []+ some_v = (:) <$> v <*> many_v+ {-# INLINE some #-}++failDesc :: String -> Parser t a failDesc err = Parser (\i0 a0 m0 kf _ks -> kf i0 a0 m0 [] msg) where msg = "Failed reading: " ++ err {-# INLINE failDesc #-} -(+++) :: B.ByteString -> B.ByteString -> B.ByteString-(+++) = B.append-{-# INLINE (+++) #-}+(<>) :: (Monoid m) => m -> m -> m+(<>) = mappend+{-# INLINE (<>) #-}
Data/Attoparsec/Lazy.hs view
@@ -23,67 +23,7 @@ module Data.Attoparsec.Lazy (- Result(..)- , module Data.Attoparsec- -- * Running parsers- , parse- , parseTest- -- ** Result conversion- , maybeResult- , eitherResult+ module Data.Attoparsec.ByteString.Lazy ) where -import Data.ByteString.Lazy.Internal (ByteString(..), chunk)-import qualified Data.ByteString as B-import qualified Data.Attoparsec as A-import Data.Attoparsec hiding (Result(..), eitherResult, maybeResult,- parse, parseWith, parseTest)---- | The result of a parse.-data Result r = Fail ByteString [String] String- -- ^ The parse failed. The 'ByteString' is the input- -- that had not yet been consumed when the failure- -- occurred. The @[@'String'@]@ is a list of contexts- -- in which the error occurred. The 'String' is the- -- message describing the error, if any.- | Done ByteString r- -- ^ The parse succeeded. The 'ByteString' is the- -- input that had not yet been consumed (if any) when- -- the parse succeeded.--instance Show r => Show (Result r) where- show (Fail bs stk msg) =- "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg- show (Done bs r) = "Done " ++ show bs ++ " " ++ show r--fmapR :: (a -> b) -> Result a -> Result b-fmapR _ (Fail st stk msg) = Fail st stk msg-fmapR f (Done bs r) = Done bs (f r)--instance Functor Result where- fmap = fmapR---- | Run a parser and return its result.-parse :: A.Parser a -> ByteString -> Result a-parse p s = case s of- Chunk x xs -> go (A.parse p x) xs- empty -> go (A.parse p B.empty) empty- where- go (A.Fail x stk msg) ys = Fail (chunk x ys) stk msg- go (A.Done x r) ys = Done (chunk x ys) r- go (A.Partial k) (Chunk y ys) = go (k y) ys- go (A.Partial k) empty = go (k B.empty) empty---- | Run a parser and print its result to standard output.-parseTest :: (Show a) => A.Parser a -> ByteString -> IO ()-parseTest p s = print (parse p s)---- | Convert a 'Result' value to a 'Maybe' value.-maybeResult :: Result r -> Maybe r-maybeResult (Done _ r) = Just r-maybeResult _ = Nothing---- | Convert a 'Result' value to an 'Either' value.-eitherResult :: Result r -> Either String r-eitherResult (Done _ r) = Right r-eitherResult (Fail _ _ msg) = Left msg+import Data.Attoparsec.ByteString.Lazy
+ Data/Attoparsec/Text.hs view
@@ -0,0 +1,398 @@+{-# LANGUAGE BangPatterns #-}+-- |+-- Module : Data.Attoparsec.Text+-- Copyright : Bryan O'Sullivan 2011+-- License : BSD3+-- +-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Simple, efficient combinator parsing for 'Text' strings,+-- loosely based on the Parsec library.++module Data.Attoparsec.Text+ (+ -- * Differences from Parsec+ -- $parsec++ -- * Incremental input+ -- $incremental++ -- * Performance considerations+ -- $performance++ -- * Parser types+ Parser+ , Result+ , T.IResult(..)++ -- * Running parsers+ , parse+ , feed+ , I.parseOnly+ , parseWith+ , parseTest++ -- ** Result conversion+ , maybeResult+ , eitherResult++ -- * Combinators+ , (I.<?>)+ , I.try+ , module Data.Attoparsec.Combinator++ -- * Parsing individual characters+ , I.char+ , I.anyChar+ , I.notChar+ , I.satisfy+ , I.satisfyWith+ , I.skip++ -- ** Character classes+ , I.inClass+ , I.notInClass++ -- * Efficient string handling+ , I.string+ , I.skipWhile+ , I.take+ , I.takeWhile+ , I.takeWhile1+ , I.takeTill++ -- ** Consume all remaining input+ , I.takeText+ , I.takeLazyText++ -- * Text parsing+ , I.endOfLine+ , isEndOfLine+ , isHorizontalSpace++ -- * Numeric parsers+ , decimal+ , hexadecimal+ , signed+ , double+ , Number(..)+ , number+ , rational++ -- * State observation and manipulation functions+ , I.endOfInput+ , I.atEnd+ ) where++import Control.Applicative ((<$>), (*>), (<|>))+import Data.Attoparsec.Combinator+import Data.Attoparsec.Number (Number(..))+import Data.Attoparsec.Text.Internal (Parser, Result, parse, takeWhile1)+import Data.Bits (Bits, (.|.), shiftL)+import Data.Char (ord)+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Ratio ((%))+import Data.Text (Text)+import Data.Word (Word8, Word16, Word32, Word64, Word)+import qualified Data.Attoparsec.Internal.Types as T+import qualified Data.Attoparsec.Text.Internal as I+import qualified Data.Text 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+-- 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 'Text'+-- input. Efficiency concerns rule out both lists and lazy text.+-- The usual use for lazy text 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 text, see the '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 'Text' 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 another string will+-- resume parsing at the point where it was suspended. You must be+-- prepared for the result of the resumed parse to be another+-- 'Partial' continuation.+--+-- To indicate that you have no more input, supply the 'Partial'+-- continuation with an 'T.empty' 'Text'.+--+-- 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.++-- $performance+--+-- If you write an Attoparsec-based parser carefully, it can be+-- realistic to expect it to perform within a factor of 2 of 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 'Text'-oriented parsers whenever possible,+-- e.g. 'I.takeWhile1' instead of 'many1' 'I.anyChar'. There is+-- about a factor of 100 difference in performance between the two+-- kinds of parser.+--+-- For very simple character-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 character, but the+-- first is much faster than the second:+--+-- >endOfLine_fast c = c == '\r' || c == '\n'+-- >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.++-- | If a parser has returned a 'Partial' result, supply it with more+-- input.+feed :: Result r -> Text -> Result r+feed f@(T.Fail _ _ _) _ = f+feed (T.Partial k) d = k d+feed (T.Done bs r) d = T.Done (T.append bs d) r+{-# INLINE feed #-}++-- | Run a parser and print its result to standard output.+parseTest :: (Show a) => I.Parser a -> Text -> IO ()+parseTest p s = print (parse p s)++-- | Run a parser with an initial input string, and a monadic action+-- that can supply more input if needed.+parseWith :: Monad m =>+ (m Text)+ -- ^ An action that will be executed to provide the parser+ -- with more input, if necessary. The action must return an+ -- 'T.empty' string when there is no more input available.+ -> I.Parser a+ -> Text+ -- ^ Initial input for the parser.+ -> m (Result a)+parseWith refill p s = step $ parse p s+ where step (T.Partial k) = (step . k) =<< refill+ step r = return r+{-# INLINE parseWith #-}++-- | Convert a 'Result' value to a 'Maybe' value. A 'Partial' result+-- is treated as failure.+maybeResult :: Result r -> Maybe r+maybeResult (T.Done _ r) = Just r+maybeResult _ = Nothing++-- | Convert a 'Result' value to an 'Either' value. A 'Partial' result+-- is treated as failure.+eitherResult :: Result r -> Either String r+eitherResult (T.Done _ r) = Right r+eitherResult (T.Fail _ _ msg) = Left msg+eitherResult _ = Left "Result: incomplete input"++-- | A predicate that matches either a carriage return @\'\\r\'@ or+-- newline @\'\\n\'@ character.+isEndOfLine :: Char -> Bool+isEndOfLine c = c == '\n' || c == '\r'+{-# INLINE isEndOfLine #-}++-- | A predicate that matches either a space @\' \'@ or horizontal tab+-- @\'\\t\'@ character.+isHorizontalSpace :: Char -> Bool+isHorizontalSpace c = c == ' ' || c == '\t'+{-# INLINE isHorizontalSpace #-}++-- | Parse and decode an unsigned hexadecimal number. The hex digits+-- @\'a\'@ through @\'f\'@ may be upper or lower case.+--+-- This parser does not accept a leading @\"0x\"@ string.+hexadecimal :: (Integral a, Bits a) => Parser a+hexadecimal = T.foldl' step 0 `fmap` takeWhile1 isHexDigit+ where+ isHexDigit c = (c >= '0' && c <= '9') ||+ (c >= 'a' && c <= 'f') ||+ (c >= 'A' && c <= 'F')+ step a c | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)+ | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)+ | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)+ where w = ord c+{-# SPECIALISE hexadecimal :: Parser Int #-}+{-# SPECIALISE hexadecimal :: Parser Int8 #-}+{-# SPECIALISE hexadecimal :: Parser Int16 #-}+{-# SPECIALISE hexadecimal :: Parser Int32 #-}+{-# SPECIALISE hexadecimal :: Parser Int64 #-}+{-# SPECIALISE hexadecimal :: Parser Integer #-}+{-# SPECIALISE hexadecimal :: Parser Word #-}+{-# SPECIALISE hexadecimal :: Parser Word8 #-}+{-# SPECIALISE hexadecimal :: Parser Word16 #-}+{-# SPECIALISE hexadecimal :: Parser Word32 #-}+{-# SPECIALISE hexadecimal :: Parser Word64 #-}++-- | Parse and decode an unsigned decimal number.+decimal :: Integral a => Parser a+decimal = T.foldl' step 0 `fmap` takeWhile1 isDigit+ where step a c = a * 10 + fromIntegral (ord c - 48)+{-# SPECIALISE decimal :: Parser Int #-}+{-# SPECIALISE decimal :: Parser Int8 #-}+{-# SPECIALISE decimal :: Parser Int16 #-}+{-# SPECIALISE decimal :: Parser Int32 #-}+{-# SPECIALISE decimal :: Parser Int64 #-}+{-# SPECIALISE decimal :: Parser Integer #-}+{-# SPECIALISE decimal :: Parser Word #-}+{-# SPECIALISE decimal :: Parser Word8 #-}+{-# SPECIALISE decimal :: Parser Word16 #-}+{-# SPECIALISE decimal :: Parser Word32 #-}+{-# SPECIALISE decimal :: Parser Word64 #-}++isDigit :: Char -> Bool+isDigit c = c >= '0' && c <= '9'+{-# INLINE isDigit #-}++-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign+-- character.+signed :: Num a => Parser a -> Parser a+{-# SPECIALISE signed :: Parser Int -> Parser Int #-}+{-# SPECIALISE signed :: Parser Int8 -> Parser Int8 #-}+{-# SPECIALISE signed :: Parser Int16 -> Parser Int16 #-}+{-# SPECIALISE signed :: Parser Int32 -> Parser Int32 #-}+{-# SPECIALISE signed :: Parser Int64 -> Parser Int64 #-}+{-# SPECIALISE signed :: Parser Integer -> Parser Integer #-}+signed p = (negate <$> (I.char '-' *> p))+ <|> (I.char '+' *> p)+ <|> p++-- | Parse a rational number.+--+-- This parser accepts an optional leading sign character, followed by+-- at least one decimal digit. The syntax similar to that accepted by+-- the 'read' function, with the exception that a trailing @\'.\'@ or+-- @\'e\'@ /not/ followed by a number is not consumed.+--+-- Examples with behaviour identical to 'read', if you feed an empty+-- continuation to the first result:+--+-- >rational "3" == Done 3.0 ""+-- >rational "3.1" == Done 3.1 ""+-- >rational "3e4" == Done 30000.0 ""+-- >rational "3.1e4" == Done 31000.0, ""++-- Examples with behaviour identical to 'read':+--+-- >rational ".3" == Fail "input does not start with a digit"+-- >rational "e3" == Fail "input does not start with a digit"+--+-- Examples of differences from 'read':+--+-- >rational "3.foo" == Done 3.0 ".foo"+-- >rational "3e" == Done 3.0 "e"+--+-- This function does not accept string representations of \"NaN\" or+-- \"Infinity\".+rational :: Fractional a => Parser a+{-# SPECIALIZE rational :: Parser Double #-}+{-# SPECIALIZE rational :: Parser Float #-}+{-# SPECIALIZE rational :: Parser Rational #-}+rational = floaty $ \real frac fracDenom -> fromRational $+ real % 1 + frac % fracDenom++-- | Parse a rational number.+--+-- The syntax accepted by this parser is the same as for 'rational'.+--+-- /Note/: This function is almost ten times faster than 'rational',+-- but is slightly less accurate.+--+-- The 'Double' type supports about 16 decimal places of accuracy.+-- For 94.2% of numbers, this function and 'rational' give identical+-- results, but for the remaining 5.8%, this function loses precision+-- around the 15th decimal place. For 0.001% of numbers, this+-- function will lose precision at the 13th or 14th decimal place.+--+-- This function does not accept string representations of \"NaN\" or+-- \"Infinity\".+double :: Parser Double+double = floaty asDouble++asDouble :: Integer -> Integer -> Integer -> Double+asDouble real frac fracDenom =+ fromIntegral real + fromIntegral frac / fromIntegral fracDenom+{-# INLINE asDouble #-}++-- | Parse a number, attempting to preserve both speed and precision.+--+-- The syntax accepted by this parser is the same as for 'rational'.+--+-- /Note/: This function is almost ten times faster than 'rational'.+-- On integral inputs, it gives perfectly accurate answers, and on+-- floating point inputs, it is slightly less accurate than+-- 'rational'.+--+-- This function does not accept string representations of \"NaN\" or+-- \"Infinity\".+number :: Parser Number+number = floaty $ \real frac fracDenom ->+ if frac == 0 && fracDenom == 0+ then I real+ else D (asDouble real frac fracDenom)+{-# INLINE number #-}++data T = T !Integer !Int++floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a+{-# INLINE floaty #-}+floaty f = do+ !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>+ return True+ real <- decimal+ let tryFraction = do+ _ <- I.satisfy (=='.')+ ds <- I.takeWhile isDigit+ case I.parseOnly decimal ds of+ Right n -> return $ T n (T.length ds)+ _ -> fail "no digits after decimal"+ T fraction fracDigits <- tryFraction <|> return (T 0 0)+ let e c = c == 'e' || c == 'E'+ power <- (I.satisfy e *> signed decimal) <|> return (0::Int)+ let n = if fracDigits == 0+ then if power == 0+ then fromIntegral real+ else fromIntegral real * (10 ^^ power)+ else if power == 0+ then f real fraction (10 ^ fracDigits)+ else f real fraction (10 ^ fracDigits) * (10 ^^ power)+ return $ if positive+ then n+ else -n
+ Data/Attoparsec/Text/FastSet.hs view
@@ -0,0 +1,63 @@+-----------------------------------------------------------------------------+-- |+-- Module : Data.Attoparsec.FastSet+-- Copyright : Felipe Lessa 2010, Bryan O'Sullivan 2008+-- License : BSD3+--+-- Maintainer : felipe.lessa@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- Fast set membership tests for 'Char' values. The set+-- representation is unboxed for efficiency. We test for+-- membership using a binary search.+--+-----------------------------------------------------------------------------+module Data.Attoparsec.Text.FastSet+ (+ -- * Data type+ FastSet+ -- * Construction+ , fromList+ , set+ -- * Lookup+ , member+ -- * Handy interface+ , charClass+ ) where++import Data.List (sort)+import qualified Data.Array.Base as AB+import qualified Data.Array.Unboxed as A+import qualified Data.Text as T++newtype FastSet = FastSet (A.UArray Int Char)+ deriving (Eq, Ord, Show)++-- | Create a set.+set :: T.Text -> FastSet+set t = mkSet (T.length t) (sort $ T.unpack t)++fromList :: [Char] -> FastSet+fromList cs = mkSet (length cs) (sort cs)++mkSet :: Int -> [Char] -> FastSet+mkSet l = FastSet . A.listArray (0,l-1)++-- | Check the set for membership.+member :: Char -> FastSet -> Bool+member c (FastSet a) = uncurry search (A.bounds a)+ where search lo hi+ | hi < lo = False+ | otherwise =+ let mid = (lo + hi) `div` 2+ in case compare c (AB.unsafeAt a mid) of+ GT -> search (mid + 1) hi+ LT -> search lo (mid - 1)+ _ -> True++charClass :: String -> FastSet+charClass = fromList . go+ where go (a:'-':b:xs) = [a..b] ++ go xs+ go (x:xs) = x : go xs+ go _ = ""
+ Data/Attoparsec/Text/Internal.hs view
@@ -0,0 +1,402 @@+{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings, RecordWildCards #-}+-- |+-- Module : Data.Attoparsec.Text.Internal+-- Copyright : Bryan O'Sullivan 2011+-- License : BSD3+--+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Simple, efficient parser combinators for 'T.Text' strings, loosely+-- based on the Parsec library.++module Data.Attoparsec.Text.Internal+ (+ -- * Parser types+ Parser+ , Result++ -- * Running parsers+ , parse+ , parseOnly++ -- * Combinators+ , (<?>)+ , try+ , module Data.Attoparsec.Combinator++ -- * Parsing individual characters+ , satisfy+ , satisfyWith+ , anyChar+ , skip+ , char+ , notChar++ -- ** Character classes+ , inClass+ , notInClass++ -- * Efficient string handling+ , skipWhile+ , string+ , stringTransform+ , take+ , takeWhile+ , takeWhile1+ , takeTill++ -- ** Consume all remaining input+ , takeText+ , takeLazyText++ -- * State observation and manipulation functions+ , endOfInput+ , atEnd+ , ensure++ -- * Utilities+ , endOfLine+ ) where++import Control.Applicative ((<|>), (<$>))+import Control.Monad (when)+import Data.Attoparsec.Combinator+import Data.Attoparsec.Internal.Types hiding (Parser, Input, Added, Failure, Success)+import Data.Text (Text)+import Prelude hiding (getChar, take, takeWhile)+import qualified Data.Attoparsec.Internal.Types as T+import qualified Data.Attoparsec.Text.FastSet as Set+import qualified Data.Text as T+import qualified Data.Text.Lazy as L++type Parser a = T.Parser Text a+type Result a = IResult Text a+type Input = T.Input Text+type Added = T.Added Text+type Failure r = T.Failure Text r+type Success a r = T.Success Text a r++-- | If at least @n@ characters of input are available, return the+-- current input, otherwise fail.+ensure :: Int -> Parser Text+ensure !n = T.Parser $ \i0 a0 m0 kf ks ->+ if T.length (unI i0) >= n+ then ks i0 a0 m0 (unI i0)+ else runParser (demandInput >> ensure n) i0 a0 m0 kf ks++-- | Ask for input. If we receive any, pass it to a success+-- continuation, otherwise to a failure continuation.+prompt :: Input -> Added -> More+ -> (Input -> Added -> More -> Result r)+ -> (Input -> Added -> More -> Result r)+ -> Result r+prompt i0 a0 _m0 kf ks = Partial $ \s ->+ if T.null s+ then kf i0 a0 Complete+ else ks (I (unI i0 <> s)) (A (unA a0 <> s)) Incomplete++-- | Immediately demand more input via a 'Partial' continuation+-- result.+demandInput :: Parser ()+demandInput = T.Parser $ \i0 a0 m0 kf ks ->+ if m0 == Complete+ then kf i0 a0 m0 ["demandInput"] "not enough input"+ else let kf' i a m = kf i a m ["demandInput"] "not enough input"+ ks' i a m = ks i a m ()+ in prompt i0 a0 m0 kf' ks'++-- | This parser always succeeds. It returns 'True' if any input is+-- available either immediately or on demand, and 'False' if the end+-- of all input has been reached.+wantInput :: Parser Bool+wantInput = T.Parser $ \i0 a0 m0 _kf ks ->+ case () of+ _ | not (T.null (unI i0)) -> ks i0 a0 m0 True+ | m0 == Complete -> ks i0 a0 m0 False+ | otherwise -> let kf' i a m = ks i a m False+ ks' i a m = ks i a m True+ in prompt i0 a0 m0 kf' ks'++get :: Parser Text+get = T.Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0)++put :: Text -> Parser ()+put s = T.Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 ()++-- | Attempt a parse, and if it fails, rewind the input so that no+-- input appears to have been consumed.+--+-- This combinator is provided for compatibility with Parsec.+-- Attoparsec parsers always backtrack on failure.+try :: Parser a -> Parser a+try p = p+{-# INLINE try #-}++unsafeHead :: Text -> Char+unsafeHead = T.head++unsafeTail :: Text -> Text+unsafeTail = T.tail++unsafeTake :: Int -> Text -> Text+unsafeTake = T.take++unsafeDrop :: Int -> Text -> Text+unsafeDrop = T.drop++-- | The parser @satisfy p@ succeeds for any character for which the+-- predicate @p@ returns 'True'. Returns the character that is+-- actually parsed.+--+-- >digit = satisfy isDigit+-- > where isDigit c = c >= '0' && c <= '9'+satisfy :: (Char -> Bool) -> Parser Char+satisfy p = do+ s <- ensure 1+ let w = unsafeHead s+ if p w+ then put (unsafeTail s) >> return w+ else fail "satisfy"++-- | The parser @skip p@ succeeds for any character for which the+-- predicate @p@ returns 'True'.+--+-- >skipDigit = skip isDigit+-- > where isDigit c = c >= '0' && c <= '9'+skip :: (Char -> Bool) -> Parser ()+skip p = do+ s <- ensure 1+ if p (unsafeHead s)+ then put (unsafeTail s)+ else fail "skip"++-- | The parser @satisfyWith f p@ transforms a character, and succeeds+-- if the predicate @p@ returns 'True' on the transformed value. The+-- parser returns the transformed character that was parsed.+satisfyWith :: (Char -> a) -> (a -> Bool) -> Parser a+satisfyWith f p = do+ s <- ensure 1+ let c = f (unsafeHead s)+ if p c+ then put (unsafeTail s) >> return c+ else fail "satisfyWith"++-- | Consume @n@ characters of input, but succeed only if the+-- predicate returns 'True'.+takeWith :: Int -> (Text -> Bool) -> Parser Text+takeWith n p = do+ s <- ensure n+ let h = unsafeTake n s+ t = unsafeDrop n s+ if p h+ then put t >> return h+ else fail "takeWith"++-- | Consume exactly @n@ characters of input.+take :: Int -> Parser Text+take n = takeWith n (const True)+{-# INLINE take #-}++-- | @string s@ parses a sequence of characters that identically match+-- @s@. Returns the parsed string (i.e. @s@). This parser consumes no+-- input if it fails (even if a partial match).+--+-- /Note/: The behaviour of this parser is different to that of the+-- similarly-named parser in Parsec, as this one is all-or-nothing.+-- To illustrate the difference, the following parser will fail under+-- Parsec given an input of @"for"@:+--+-- >string "foo" <|> string "for"+--+-- The reason for its failure is that that the first branch is a+-- partial match, and will consume the letters @\'f\'@ and @\'o\'@+-- before failing. In Attoparsec, the above parser will /succeed/ on+-- that input, because the failed first branch will consume nothing.+string :: Text -> Parser Text+string s = takeWith (T.length s) (==s)+{-# INLINE string #-}++stringTransform :: (Text -> Text) -> Text+ -> Parser Text+stringTransform f s = takeWith (T.length s) ((==f s) . f)+{-# INLINE stringTransform #-}++-- | Skip past input for as long as the predicate returns 'True'.+skipWhile :: (Char -> Bool) -> Parser ()+skipWhile p = go+ where+ go = do+ t <- T.dropWhile p <$> get+ put t+ when (T.null t) $ do+ input <- wantInput+ when input go+{-# INLINE skipWhile #-}++-- | Consume input as long as the predicate returns 'False'+-- (i.e. until it returns 'True'), and return the consumed input.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'True' on the first character of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+takeTill :: (Char -> Bool) -> Parser Text+takeTill p = takeWhile (not . p)+{-# INLINE takeTill #-}++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser does not fail. It will return an empty string if the+-- predicate returns 'False' on the first character of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+takeWhile :: (Char -> Bool) -> Parser Text+takeWhile p = (T.concat . reverse) `fmap` go []+ where+ go acc = do+ (h,t) <- T.span p <$> get+ put t+ if T.null t+ then do+ input <- wantInput+ if input+ then go (h:acc)+ else return (h:acc)+ else return (h:acc)++takeRest :: Parser [Text]+takeRest = go []+ where+ go acc = do+ input <- wantInput+ if input+ then do+ s <- get+ put T.empty+ go (s:acc)+ else return (reverse acc)++-- | Consume all remaining input and return it as a single string.+takeText :: Parser Text+takeText = T.concat `fmap` takeRest++-- | Consume all remaining input and return it as a single string.+takeLazyText :: Parser L.Text+takeLazyText = L.fromChunks `fmap` takeRest++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser requires the predicate to succeed on at least one+-- character of input: it will fail if the predicate never returns+-- 'True' or if there is no input left.+takeWhile1 :: (Char -> Bool) -> Parser Text+takeWhile1 p = do+ (`when` demandInput) =<< T.null <$> get+ (h,t) <- T.span p <$> get+ when (T.null h) $ fail "takeWhile1"+ put t+ if T.null t+ then (h<>) `fmap` takeWhile p+ else return h++-- | Match any character in a set.+--+-- >vowel = inClass "aeiou"+--+-- Range notation is supported.+--+-- >halfAlphabet = inClass "a-nA-N"+--+-- To add a literal @\'-\'@ to a set, place it at the beginning or end+-- of the string.+inClass :: String -> Char -> Bool+inClass s = (`Set.member` mySet)+ where mySet = Set.charClass s+ {-# NOINLINE mySet #-}+{-# INLINE inClass #-}++-- | Match any character not in a set.+notInClass :: String -> Char -> Bool+notInClass s = not . inClass s+{-# INLINE notInClass #-}++-- | Match any character.+anyChar :: Parser Char+anyChar = satisfy $ const True+{-# INLINE anyChar #-}++-- | Match a specific character.+char :: Char -> Parser Char+char c = satisfy (== c) <?> show c+{-# INLINE char #-}++-- | Match any character except the given one.+notChar :: Char -> Parser Char+notChar c = satisfy (/= c) <?> "not " ++ show c+{-# INLINE notChar #-}++-- | Match only if all input has been consumed.+endOfInput :: Parser ()+endOfInput = T.Parser $ \i0 a0 m0 kf ks ->+ if T.null (unI i0)+ then if m0 == Complete+ then ks i0 a0 m0 ()+ else let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $+ \ i2 a2 m2 -> ks i2 a2 m2 ()+ ks' i1 a1 m1 _ = addS i0 a0 m0 i1 a1 m1 $+ \ i2 a2 m2 -> kf i2 a2 m2 []+ "endOfInput"+ in runParser demandInput i0 a0 m0 kf' ks'+ else kf i0 a0 m0 [] "endOfInput"++-- | Return an indication of whether the end of input has been+-- reached.+atEnd :: Parser Bool+atEnd = not <$> wantInput+{-# INLINE atEnd #-}++-- | Match either a single newline character @\'\\n\'@, or a carriage+-- return followed by a newline character @\"\\r\\n\"@.+endOfLine :: Parser ()+endOfLine = (char '\n' >> return ()) <|> (string "\r\n" >> return ())++--- | Name the parser, in case failure occurs.+(<?>) :: Parser a+ -> String -- ^ the name to use if parsing fails+ -> Parser a+p <?> msg0 = T.Parser $ \i0 a0 m0 kf ks ->+ let kf' i a m strs msg = kf i a m (msg0:strs) msg+ in runParser p i0 a0 m0 kf' ks+{-# INLINE (<?>) #-}+infix 0 <?>++-- | Terminal failure continuation.+failK :: Failure a+failK i0 _a0 _m0 stack msg = Fail (unI i0) stack msg+{-# INLINE failK #-}++-- | Terminal success continuation.+successK :: Success a a+successK i0 _a0 _m0 a = Done (unI i0) a+{-# INLINE successK #-}++-- | Run a parser.+parse :: Parser a -> Text -> Result a+parse m s = runParser m (I s) (A T.empty) Incomplete failK successK+{-# INLINE parse #-}++-- | Run a parser that cannot be resupplied via a 'Partial' result.+parseOnly :: Parser a -> Text -> Either String a+parseOnly m s = case runParser m (I s) (A T.empty) Complete failK successK of+ Fail _ _ err -> Left err+ Done _ a -> Right a+ _ -> error "parseOnly: impossible error!"+{-# INLINE parseOnly #-}
+ Data/Attoparsec/Text/Lazy.hs view
@@ -0,0 +1,90 @@+-- |+-- Module : Data.Attoparsec.Text.Lazy+-- Copyright : Bryan O'Sullivan 2011+-- License : BSD3+-- +-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Simple, efficient combinator parsing for lazy 'Text'+-- strings, loosely based on the Parsec library.+--+-- This is essentially the same code as in the 'Data.Attoparsec.Text'+-- module, only with a 'parse' function that can consume a lazy+-- 'Text' incrementally, and a 'Result' type that does not allow+-- more input to be fed in. Think of this as suitable for use with a+-- lazily read file, e.g. via 'L.readFile' or 'L.hGetContents'.+--+-- Behind the scenes, strict 'T.Text' values are still used+-- internally to store parser input and manipulate it efficiently.+-- High-performance parsers such as 'string' still expect strict+-- 'T.Text' parameters.++module Data.Attoparsec.Text.Lazy+ (+ Result(..)+ , module Data.Attoparsec.Text+ -- * Running parsers+ , parse+ , parseTest+ -- ** Result conversion+ , maybeResult+ , eitherResult+ ) where++import Data.Text.Lazy.Internal (Text(..), chunk)+import qualified Data.Attoparsec.Internal.Types as T+import qualified Data.Attoparsec.Text as A+import qualified Data.Text as T+import Data.Attoparsec.Text hiding (IResult(..), Result, eitherResult,+ maybeResult, parse, parseWith, parseTest)++-- | The result of a parse.+data Result r = Fail Text [String] String+ -- ^ The parse failed. The 'ByteString' is the input+ -- that had not yet been consumed when the failure+ -- occurred. The @[@'String'@]@ is a list of contexts+ -- in which the error occurred. The 'String' is the+ -- message describing the error, if any.+ | Done Text r+ -- ^ The parse succeeded. The 'ByteString' is the+ -- input that had not yet been consumed (if any) when+ -- the parse succeeded.++instance Show r => Show (Result r) where+ show (Fail bs stk msg) =+ "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg+ show (Done bs r) = "Done " ++ show bs ++ " " ++ show r++fmapR :: (a -> b) -> Result a -> Result b+fmapR _ (Fail st stk msg) = Fail st stk msg+fmapR f (Done bs r) = Done bs (f r)++instance Functor Result where+ fmap = fmapR++-- | Run a parser and return its result.+parse :: A.Parser a -> Text -> Result a+parse p s = case s of+ Chunk x xs -> go (A.parse p x) xs+ empty -> go (A.parse p T.empty) empty+ where+ go (T.Fail x stk msg) ys = Fail (chunk x ys) stk msg+ go (T.Done x r) ys = Done (chunk x ys) r+ go (T.Partial k) (Chunk y ys) = go (k y) ys+ go (T.Partial k) empty = go (k T.empty) empty++-- | Run a parser and print its result to standard output.+parseTest :: (Show a) => A.Parser a -> Text -> IO ()+parseTest p s = print (parse p s)++-- | Convert a 'Result' value to a 'Maybe' value.+maybeResult :: Result r -> Maybe r+maybeResult (Done _ r) = Just r+maybeResult _ = Nothing++-- | Convert a 'Result' value to an 'Either' value.+eitherResult :: Result r -> Either String r+eitherResult (Done _ r) = Right r+eitherResult (Fail _ _ msg) = Left msg
+ Data/Attoparsec/Types.hs view
@@ -0,0 +1,19 @@+-- |+-- Module : Data.Attoparsec.Types+-- Copyright : Bryan O'Sullivan 2011+-- License : BSD3+--+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- Simple, efficient parser combinators for strings, loosely based on+-- the Parsec library.++module Data.Attoparsec.Types+ (+ Parser+ , IResult(..)+ ) where++import Data.Attoparsec.Internal.Types (Parser(..), IResult(..))
README.markdown view
@@ -10,15 +10,15 @@ and other improvements. Please report bugs via the-[bitbucket issue tracker](http://bitbucket.org/bos/attoparsec/issues).+[github issue tracker](https://github.com/bos/attoparsec/issues). -Master [Mercurial repository](http://bitbucket.org/bos/attoparsec):+Master [git repository](https://github.com/bos/attoparsec): -* `hg clone http://bitbucket.org/bos/attoparsec`+* `git clone git://github.com/bos/attoparsec.git` -There's also a [git mirror](http://github.com/bos/attoparsec):+There's also a [Mercurial mirror](https://bitbucket.org/bos/attoparsec): -* `git clone git://github.com/bos/attoparsec.git`+* `hg clone https://bitbucket.org/bos/attoparsec` (You can create and contribute changes using either Mercurial or git.)
attoparsec.cabal view
@@ -1,16 +1,16 @@ name: attoparsec-version: 0.9.1.2+version: 0.10.0.0 license: BSD3 license-file: LICENSE category: Text, Parsing author: Bryan O'Sullivan <bos@serpentine.com> maintainer: Bryan O'Sullivan <bos@serpentine.com> stability: experimental-tested-with: GHC == 6.10.4, GHC == 6.12.3, GHC == 7.0.3+tested-with: GHC == 6.12.3, GHC == 7.0.3, GHC == 7.2.1 synopsis: Fast combinator parsing for bytestrings-cabal-version: >= 1.6-homepage: https://bitbucket.org/bos/attoparsec-bug-reports: https://bitbucket.org/bos/attoparsec/issues+cabal-version: >= 1.8+homepage: https://github.com/bos/attoparsec+bug-reports: https://github.com/bos/attoparsec/issues build-type: Simple description: A fast parser combinator library, aimed particularly at dealing@@ -23,7 +23,6 @@ benchmarks/med.txt.bz2 tests/Makefile tests/QC.hs- tests/QCSupport.hs tests/TestFastSet.hs examples/Makefile examples/Parsec_RFC2616.hs@@ -35,44 +34,58 @@ Description: Whether to build the library in development mode Default: False -flag split-base-flag applicative-in-base- library- if flag(split-base)- -- bytestring was in base-2.0 and 2.1.1- build-depends: base >= 2.0 && < 2.2- else- -- in base 1.0 and >= 3.0 bytestring is a separate package- build-depends: base < 2.0 || >= 3, bytestring >= 0.9, containers >= 0.1.0.1-- if flag(applicative-in-base)- build-depends: base >= 2.0 && < 5.0- cpp-options: -DAPPLICATIVE_IN_BASE- else- build-depends: base < 2.0-- build-depends: deepseq+ build-depends: array,+ base >= 3 && < 5,+ bytestring,+ containers,+ deepseq,+ text >= 0.11.1.5 extensions: CPP exposed-modules: Data.Attoparsec+ Data.Attoparsec.ByteString+ Data.Attoparsec.ByteString.Char8+ Data.Attoparsec.ByteString.Lazy Data.Attoparsec.Char8 Data.Attoparsec.Combinator- Data.Attoparsec.FastSet Data.Attoparsec.Lazy Data.Attoparsec.Number+ Data.Attoparsec.Text+ Data.Attoparsec.Text.Lazy+ Data.Attoparsec.Types Data.Attoparsec.Zepto- other-modules: Data.Attoparsec.Internal+ other-modules: Data.Attoparsec.ByteString.FastSet+ Data.Attoparsec.ByteString.Internal Data.Attoparsec.Internal.Types+ Data.Attoparsec.Text.FastSet+ Data.Attoparsec.Text.Internal ghc-options: -Wall if flag(developer) ghc-prof-options: -auto-all -source-repository head- type: mercurial- location: https://bitbucket.org/bos/attoparsec+test-suite tests+ type: exitcode-stdio-1.0+ hs-source-dirs: tests+ main-is: QC.hs + ghc-options:+ -Wall -threaded -rtsopts++ build-depends:+ attoparsec,+ base >= 4 && < 5,+ bytestring,+ QuickCheck >= 2.4,+ test-framework >= 0.4,+ test-framework-quickcheck2 >= 0.2,+ text+ source-repository head type: git location: https://github.com/bos/attoparsec++source-repository head+ type: mercurial+ location: https://bitbucket.org/bos/attoparsec
tests/QC.hs view
@@ -1,24 +1,24 @@ {-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module Main (main) where -import Control.Monad (forM_)-import Data.Maybe (isJust)-import Data.Word (Word8)+import Control.Applicative ((<$>)) import Prelude hiding (takeWhile)-import QCSupport import Test.Framework (defaultMain, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.QuickCheck hiding (NonEmpty)+import Test.QuickCheck import qualified Data.Attoparsec as P import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as C+import qualified Data.ByteString as S+import qualified Data.ByteString.Lazy as L --- Make sure that structures whose types claim they are non-empty--- really are.+instance Arbitrary S.ByteString where+ arbitrary = S.pack <$> arbitrary -nonEmptyList l = length (nonEmpty l) > 0- where types = l :: NonEmpty [Int]-nonEmptyBS l = B.length (nonEmpty l) > 0+instance Arbitrary L.ByteString where+ arbitrary = sized $ \n -> resize (round (sqrt (toEnum n :: Double)))+ ((L.fromChunks . map (S.pack . nonEmpty)) <$> arbitrary)+ where nonEmpty (NonEmpty a) = a -- Naming. @@ -44,10 +44,11 @@ then Nothing else Just (B.head s) -notWord8 w (NonEmpty s) = maybeP (P.notWord8 w) s == if v == w+notWord8 w (NonEmpty s) = maybeP (P.notWord8 w) bs == if v == w then Nothing else Just v- where v = B.head s+ where v = B.head bs+ bs = B.pack s string s = maybeP (P.string s) s == Just s @@ -81,11 +82,6 @@ P.Done t' h' -> t == t' && h == h' _ -> False -ensure n s = case defP (P.ensure m) s of- P.Done _ () -> B.length s >= m- _ -> B.length s < m- where m = (n `mod` 220) - 20- takeWhile1_empty = maybeP (P.takeWhile1 undefined) B.empty == Nothing endOfInput s = maybeP P.endOfInput s == if B.null s@@ -96,8 +92,6 @@ tests = [ testGroup "fnord" [- testProperty "nonEmptyList" nonEmptyList,- testProperty "nonEmptyBS" nonEmptyBS, testProperty "satisfy" satisfy, testProperty "word8" word8, testProperty "notWord8" notWord8,@@ -109,8 +103,6 @@ testProperty "takeWhile1" takeWhile1, testProperty "takeWhile1_empty" takeWhile1_empty, testProperty "takeTill" takeTill,- testProperty "endOfInput" endOfInput,- testProperty "ensure" ensure+ testProperty "endOfInput" endOfInput ]- ]
− tests/QCSupport.hs
@@ -1,52 +0,0 @@-{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}-module QCSupport- (- NonEmpty(..)- ) where--import Control.Applicative-import Data.Attoparsec-import Data.Word (Word8)-import System.Random (RandomGen, Random(..))-import Test.QuickCheck hiding (NonEmpty)-import qualified Data.ByteString as S-import qualified Data.ByteString.Lazy as L--integralRandomR :: (Integral a, RandomGen g) => (a,a) -> g -> (a,g)-integralRandomR (a,b) g = case randomR (fromIntegral a :: Integer,- fromIntegral b :: Integer) g of- (x,g') -> (fromIntegral x, g')--newtype NonEmpty a = NonEmpty { nonEmpty :: a }- deriving (Eq, Ord, Read, Show)--instance Functor NonEmpty where- fmap f (NonEmpty a) = NonEmpty (f a)--instance Applicative NonEmpty where- NonEmpty f <*> NonEmpty a = NonEmpty (f a)- pure a = NonEmpty a--instance Arbitrary a => Arbitrary (NonEmpty [a]) where- arbitrary = NonEmpty <$> sized (\n -> choose (1,n+1) >>= vector)--instance Arbitrary S.ByteString where- arbitrary = S.pack <$> arbitrary--instance Arbitrary (NonEmpty S.ByteString) where- arbitrary = fmap S.pack <$> arbitrary--instance Arbitrary L.ByteString where- arbitrary = sized $ \n -> resize (round (sqrt (toEnum n :: Double)))- ((L.fromChunks . map nonEmpty) <$> arbitrary)--instance Arbitrary (NonEmpty L.ByteString) where- arbitrary = sized $ \n -> resize (round (sqrt (toEnum n :: Double)))- (fmap (L.fromChunks . map nonEmpty) <$> arbitrary)--instance Random Word8 where- randomR = integralRandomR- random = randomR (minBound,maxBound)--instance Arbitrary Word8 where- arbitrary = choose (minBound, maxBound)