git.iko.soy/typeable/attoparsec
on master help sign in
Add support for the text package

--HG-- rename : Data/Attoparsec.hs => Data/Attoparsec/ByteString.hs rename : Data/Attoparsec/Char8.hs => Data/Attoparsec/ByteString/Char8.hs rename : Data/Attoparsec/FastSet.hs => Data/Attoparsec/ByteString/FastSet.hs rename : Data/Attoparsec/Internal.hs => Data/Attoparsec/ByteString/Internal.hs rename : Data/Attoparsec/Lazy.hs => Data/Attoparsec/ByteString/Lazy.hs rename : Data/Attoparsec.hs => Data/Attoparsec/Text.hs rename : Data/Attoparsec/Internal.hs => Data/Attoparsec/Text/Internal.hs rename : Data/Attoparsec/Lazy.hs => Data/Attoparsec/Text/Lazy.hs

commit4e443c8f535c95caccdc20549d72e3311fa8bbdb authorBryan O'Sullivan <bos@serpentine.com> dateMon 21 Nov 2011, 13:20 (15 years ago) parent90e0f74
19 files changed+1964−948
.hgignore+3−13 Data/Attoparsec.hs+3−206 Data/Attoparsec/ByteString.hs+202 Data/Attoparsec/ByteString/Char8.hs+502 Data/Attoparsec/FastSet.hs → Data/Attoparsec/ByteString/FastSet.hs+2−2 Data/Attoparsec/Internal.hs → Data/Attoparsec/ByteString/Internal.hs+32−26 Data/Attoparsec/ByteString/Lazy.hs+91 Data/Attoparsec/Char8.hs+4−488 Data/Attoparsec/Combinator.hs+20−23 Data/Attoparsec/Internal/Types.hs+101−71 Data/Attoparsec/Lazy.hs+2−62 Data/Attoparsec/Text.hs+398 Data/Attoparsec/Text/FastSet.hs+63 Data/Attoparsec/Text/Internal.hs+402 Data/Attoparsec/Text/Lazy.hs+90 Data/Attoparsec/Types.hs+19 attoparsec.cabal+16−6 tests/QC.hs+14−12 tests/QCSupport.hs−39
.hgignore+3−13
@@ -1,20 +1,10 @@
1−^dist$
1+^(?:cabal-dev|dist)$
2+\.(?:aux|eventlog|h[ip]|log|[oa]|orig|prof|ps|rej|swp)$
3+~$
24benchmarks/Arse
35benchmarks/med.txt
46benchmarks/tiny
57
68syntax: glob
7−*.aux
8−*.hi
9−*.hp
10−*.o
11−*.orig
12−*.out
13−*.pdf
14−*.prof
15−*.ps
16−*.rej
17−*~
18−.*.swp
199.\#*
2010\#*
Data/Attoparsec.hs+3−206
@@ -7,215 +7,12 @@
77-- Stability : experimental
88-- Portability : unknown
99--
10−-- Simple, efficient combinator parsing for 'B.ByteString' strings,
10+-- Simple, efficient combinator parsing for 'ByteString' strings,
1111-- loosely based on the Parsec library.
1212
1313module Data.Attoparsec
1414 (
15− -- * Differences from Parsec
16− -- $parsec
17−
18− -- * Incremental input
19− -- $incremental
20−
21− -- * Performance considerations
22− -- $performance
23−
24− -- * Parser types
25− I.Parser
26− , Result(..)
27−
28− -- ** Typeclass instances
29− -- $instances
30−
31− -- * Running parsers
32− , parse
33− , feed
34− , I.parseOnly
35− , parseWith
36− , parseTest
37−
38− -- ** Result conversion
39− , maybeResult
40− , eitherResult
41−
42− -- * Combinators
43− , (I.<?>)
44− , I.try
45− , module Data.Attoparsec.Combinator
46−
47− -- * Parsing individual bytes
48− , I.word8
49− , I.anyWord8
50− , I.notWord8
51− , I.satisfy
52− , I.satisfyWith
53− , I.skip
54−
55− -- ** Byte classes
56− , I.inClass
57− , I.notInClass
58−
59− -- * Efficient string handling
60− , I.string
61− , I.skipWhile
62− , I.take
63− , I.scan
64− , I.takeWhile
65− , I.takeWhile1
66− , I.takeTill
67−
68− -- ** Consume all remaining input
69− , I.takeByteString
70− , I.takeLazyByteString
71−
72− -- * State observation and manipulation functions
73− , I.endOfInput
74− , I.atEnd
15+ module Data.Attoparsec.ByteString
7516 ) where
7617
77−import Data.Attoparsec.Combinator
78−import qualified Data.Attoparsec.Internal as I
79−import qualified Data.ByteString as B
80−import Data.Attoparsec.Internal (Result(..), parse)
81−
82−-- $parsec
83−--
84−-- Compared to Parsec 3, Attoparsec makes several tradeoffs. It is
85−-- not intended for, or ideal for, all possible uses.
86−--
87−-- * While Attoparsec can consume input incrementally, Parsec cannot.
88−-- Incremental input is a huge deal for efficient and secure network
89−-- and system programming, since it gives much more control to users
90−-- of the library over matters such as resource usage and the I/O
91−-- model to use.
92−--
93−-- * Much of the performance advantage of Attoparsec is gained via
94−-- high-performance parsers such as 'I.takeWhile' and 'I.string'.
95−-- If you use complicated combinators that return lists of bytes or
96−-- characters, there is less performance difference between the two
97−-- libraries.
98−--
99−-- * Unlike Parsec 3, Attoparsec does not support being used as a
100−-- monad transformer.
101−--
102−-- * Attoparsec is specialised to deal only with strict 'B.ByteString'
103−-- input. Efficiency concerns rule out both lists and lazy
104−-- bytestrings. The usual use for lazy bytestrings would be to
105−-- allow consumption of very large input without a large footprint.
106−-- For this need, Attoparsec's incremental input provides an
107−-- excellent substitute, with much more control over when input
108−-- takes place. If you must use lazy bytestrings, see the 'Lazy'
109−-- module, which feeds lazy chunks to a regular parser.
110−--
111−-- * Parsec parsers can produce more helpful error messages than
112−-- Attoparsec parsers. This is a matter of focus: Attoparsec avoids
113−-- the extra book-keeping in favour of higher performance.
114−
115−-- $incremental
116−--
117−-- Attoparsec supports incremental input, meaning that you can feed it
118−-- a bytestring that represents only part of the expected total amount
119−-- of data to parse. If your parser reaches the end of a fragment of
120−-- input and could consume more input, it will suspend parsing and
121−-- return a 'Partial' continuation.
122−--
123−-- Supplying the 'Partial' continuation with another bytestring will
124−-- resume parsing at the point where it was suspended. You must be
125−-- prepared for the result of the resumed parse to be another
126−-- 'Partial' continuation.
127−--
128−-- To indicate that you have no more input, supply the 'Partial'
129−-- continuation with an empty bytestring.
130−--
131−-- Remember that some parsing combinators will not return a result
132−-- until they reach the end of input. They may thus cause 'Partial'
133−-- results to be returned.
134−--
135−-- If you do not need support for incremental input, consider using
136−-- the 'I.parseOnly' function to run your parser. It will never
137−-- prompt for more input.
138−
139−-- $performance
140−--
141−-- If you write an Attoparsec-based parser carefully, it can be
142−-- realistic to expect it to perform within a factor of 2 of a
143−-- hand-rolled C parser (measuring megabytes parsed per second).
144−--
145−-- To actually achieve high performance, there are a few guidelines
146−-- that it is useful to follow.
147−--
148−-- Use the 'B.ByteString'-oriented parsers whenever possible,
149−-- e.g. 'I.takeWhile1' instead of 'many1' 'I.anyWord8'. There is
150−-- about a factor of 100 difference in performance between the two
151−-- kinds of parser.
152−--
153−-- For very simple byte-testing predicates, write them by hand instead
154−-- of using 'I.inClass' or 'I.notInClass'. For instance, both of
155−-- these predicates test for an end-of-line byte, but the first is
156−-- much faster than the second:
157−--
158−-- >endOfLine_fast w = w == 13 || w == 10
159−-- >endOfLine_slow = inClass "\r\n"
160−--
161−-- Make active use of benchmarking and profiling tools to measure,
162−-- find the problems with, and improve the performance of your parser.
163−
164−-- $instances
165−--
166−-- The 'I.Parser' type is an instance of the following classes:
167−--
168−-- * 'Monad', where 'fail' throws an exception (i.e. fails) with an
169−-- error message.
170−--
171−-- * 'Functor' and 'Applicative', which follow the usual definitions.
172−--
173−-- * 'MonadPlus', where 'mzero' fails (with no error message) and
174−-- 'mplus' executes the right-hand parser if the left-hand one
175−-- fails.
176−--
177−-- * 'Alternative', which follows 'MonadPlus'.
178−--
179−-- The 'Result' type is an instance of 'Functor', where 'fmap'
180−-- transforms the value in a 'Done' result.
181−
182−-- | If a parser has returned a 'Partial' result, supply it with more
183−-- input.
184−feed :: Result r -> B.ByteString -> Result r
185−feed f@(Fail _ _ _) _ = f
186−feed (Partial k) d = k d
187−feed (Done bs r) d = Done (B.append bs d) r
188−{-# INLINE feed #-}
189−
190−-- | Run a parser and print its result to standard output.
191−parseTest :: (Show a) => I.Parser a -> B.ByteString -> IO ()
192−parseTest p s = print (parse p s)
193−
194−-- | Run a parser with an initial input string, and a monadic action
195−-- that can supply more input if needed.
196−parseWith :: Monad m =>
197− (m B.ByteString)
198− -- ^ An action that will be executed to provide the parser
199− -- with more input, if necessary. The action must return an
200− -- 'B.empty' string when there is no more input available.
201− -> I.Parser a
202− -> B.ByteString
203− -- ^ Initial input for the parser.
204− -> m (Result a)
205−parseWith refill p s = step $ parse p s
206− where step (Partial k) = (step . k) =<< refill
207− step r = return r
208−{-# INLINE parseWith #-}
209−
210−-- | Convert a 'Result' value to a 'Maybe' value. A 'Partial' result
211−-- is treated as failure.
212−maybeResult :: Result r -> Maybe r
213−maybeResult (Done _ r) = Just r
214−maybeResult _ = Nothing
215−
216−-- | Convert a 'Result' value to an 'Either' value. A 'Partial' result
217−-- is treated as failure.
218−eitherResult :: Result r -> Either String r
219−eitherResult (Done _ r) = Right r
220−eitherResult (Fail _ _ msg) = Left msg
221−eitherResult _ = Left "Result: incomplete input"
18+import Data.Attoparsec.ByteString
Data/Attoparsec/ByteString.hsnew file+202
@@ -0,0 +1,202 @@
1+-- |
2+-- Module : Data.Attoparsec.ByteString
3+-- Copyright : Bryan O'Sullivan 2007-2011
4+-- License : BSD3
5+--
6+-- Maintainer : bos@serpentine.com
7+-- Stability : experimental
8+-- Portability : unknown
9+--
10+-- Simple, efficient combinator parsing for 'B.ByteString' strings,
11+-- loosely based on the Parsec library.
12+
13+module Data.Attoparsec.ByteString
14+ (
15+ -- * Differences from Parsec
16+ -- $parsec
17+
18+ -- * Incremental input
19+ -- $incremental
20+
21+ -- * Performance considerations
22+ -- $performance
23+
24+ -- * Parser types
25+ I.Parser
26+ , Result
27+ , T.IResult(..)
28+
29+ -- * Running parsers
30+ , parse
31+ , feed
32+ , I.parseOnly
33+ , parseWith
34+ , parseTest
35+
36+ -- ** Result conversion
37+ , maybeResult
38+ , eitherResult
39+
40+ -- * Combinators
41+ , (I.<?>)
42+ , I.try
43+ , module Data.Attoparsec.Combinator
44+
45+ -- * Parsing individual bytes
46+ , I.word8
47+ , I.anyWord8
48+ , I.notWord8
49+ , I.satisfy
50+ , I.satisfyWith
51+ , I.skip
52+
53+ -- ** Byte classes
54+ , I.inClass
55+ , I.notInClass
56+
57+ -- * Efficient string handling
58+ , I.string
59+ , I.skipWhile
60+ , I.take
61+ , I.scan
62+ , I.takeWhile
63+ , I.takeWhile1
64+ , I.takeTill
65+
66+ -- ** Consume all remaining input
67+ , I.takeByteString
68+ , I.takeLazyByteString
69+
70+ -- * State observation and manipulation functions
71+ , I.endOfInput
72+ , I.atEnd
73+ ) where
74+
75+import Data.Attoparsec.Combinator
76+import qualified Data.Attoparsec.ByteString.Internal as I
77+import qualified Data.ByteString as B
78+import Data.Attoparsec.ByteString.Internal (Result, parse)
79+import qualified Data.Attoparsec.Internal.Types as T
80+
81+-- $parsec
82+--
83+-- Compared to Parsec 3, Attoparsec makes several tradeoffs. It is
84+-- not intended for, or ideal for, all possible uses.
85+--
86+-- * While Attoparsec can consume input incrementally, Parsec cannot.
87+-- Incremental input is a huge deal for efficient and secure network
88+-- and system programming, since it gives much more control to users
89+-- of the library over matters such as resource usage and the I/O
90+-- model to use.
91+--
92+-- * Much of the performance advantage of Attoparsec is gained via
93+-- high-performance parsers such as 'I.takeWhile' and 'I.string'.
94+-- If you use complicated combinators that return lists of bytes or
95+-- characters, there is less performance difference between the two
96+-- libraries.
97+--
98+-- * Unlike Parsec 3, Attoparsec does not support being used as a
99+-- monad transformer.
100+--
101+-- * Attoparsec is specialised to deal only with strict 'B.ByteString'
102+-- input. Efficiency concerns rule out both lists and lazy
103+-- bytestrings. The usual use for lazy bytestrings would be to
104+-- allow consumption of very large input without a large footprint.
105+-- For this need, Attoparsec's incremental input provides an
106+-- excellent substitute, with much more control over when input
107+-- takes place. If you must use lazy bytestrings, see the 'Lazy'
108+-- module, which feeds lazy chunks to a regular parser.
109+--
110+-- * Parsec parsers can produce more helpful error messages than
111+-- Attoparsec parsers. This is a matter of focus: Attoparsec avoids
112+-- the extra book-keeping in favour of higher performance.
113+
114+-- $incremental
115+--
116+-- Attoparsec supports incremental input, meaning that you can feed it
117+-- a bytestring that represents only part of the expected total amount
118+-- of data to parse. If your parser reaches the end of a fragment of
119+-- input and could consume more input, it will suspend parsing and
120+-- return a 'T.Partial' continuation.
121+--
122+-- Supplying the 'T.Partial' continuation with another bytestring will
123+-- resume parsing at the point where it was suspended. You must be
124+-- prepared for the result of the resumed parse to be another
125+-- 'T.Partial' continuation.
126+--
127+-- To indicate that you have no more input, supply the 'T.Partial'
128+-- continuation with an empty bytestring.
129+--
130+-- Remember that some parsing combinators will not return a result
131+-- until they reach the end of input. They may thus cause 'T.Partial'
132+-- results to be returned.
133+--
134+-- If you do not need support for incremental input, consider using
135+-- the 'I.parseOnly' function to run your parser. It will never
136+-- prompt for more input.
137+
138+-- $performance
139+--
140+-- If you write an Attoparsec-based parser carefully, it can be
141+-- realistic to expect it to perform within a factor of 2 of a
142+-- hand-rolled C parser (measuring megabytes parsed per second).
143+--
144+-- To actually achieve high performance, there are a few guidelines
145+-- that it is useful to follow.
146+--
147+-- Use the 'B.ByteString'-oriented parsers whenever possible,
148+-- e.g. 'I.takeWhile1' instead of 'many1' 'I.anyWord8'. There is
149+-- about a factor of 100 difference in performance between the two
150+-- kinds of parser.
151+--
152+-- For very simple byte-testing predicates, write them by hand instead
153+-- of using 'I.inClass' or 'I.notInClass'. For instance, both of
154+-- these predicates test for an end-of-line byte, but the first is
155+-- much faster than the second:
156+--
157+-- >endOfLine_fast w = w == 13 || w == 10
158+-- >endOfLine_slow = inClass "\r\n"
159+--
160+-- Make active use of benchmarking and profiling tools to measure,
161+-- find the problems with, and improve the performance of your parser.
162+
163+-- | If a parser has returned a 'T.Partial' result, supply it with more
164+-- input.
165+feed :: Result r -> B.ByteString -> Result r
166+feed f@(T.Fail _ _ _) _ = f
167+feed (T.Partial k) d = k d
168+feed (T.Done bs r) d = T.Done (B.append bs d) r
169+{-# INLINE feed #-}
170+
171+-- | Run a parser and print its result to standard output.
172+parseTest :: (Show a) => I.Parser a -> B.ByteString -> IO ()
173+parseTest p s = print (parse p s)
174+
175+-- | Run a parser with an initial input string, and a monadic action
176+-- that can supply more input if needed.
177+parseWith :: Monad m =>
178+ (m B.ByteString)
179+ -- ^ An action that will be executed to provide the parser
180+ -- with more input, if necessary. The action must return an
181+ -- 'B.empty' string when there is no more input available.
182+ -> I.Parser a
183+ -> B.ByteString
184+ -- ^ Initial input for the parser.
185+ -> m (Result a)
186+parseWith refill p s = step $ parse p s
187+ where step (T.Partial k) = (step . k) =<< refill
188+ step r = return r
189+{-# INLINE parseWith #-}
190+
191+-- | Convert a 'Result' value to a 'Maybe' value. A 'T.Partial' result
192+-- is treated as failure.
193+maybeResult :: Result r -> Maybe r
194+maybeResult (T.Done _ r) = Just r
195+maybeResult _ = Nothing
196+
197+-- | Convert a 'Result' value to an 'Either' value. A 'T.Partial'
198+-- result is treated as failure.
199+eitherResult :: Result r -> Either String r
200+eitherResult (T.Done _ r) = Right r
201+eitherResult (T.Fail _ _ msg) = Left msg
202+eitherResult _ = Left "Result: incomplete input"
Data/Attoparsec/ByteString/Char8.hsnew file+502
@@ -0,0 +1,502 @@
1+{-# LANGUAGE BangPatterns, FlexibleInstances, TypeSynonymInstances #-}
2+{-# OPTIONS_GHC -fno-warn-orphans #-}
3+
4+-- |
5+-- Module : Data.Attoparsec.ByteString.Char8
6+-- Copyright : Bryan O'Sullivan 2007-2011
7+-- License : BSD3
8+--
9+-- Maintainer : bos@serpentine.com
10+-- Stability : experimental
11+-- Portability : unknown
12+--
13+-- Simple, efficient, character-oriented combinator parsing for
14+-- 'B.ByteString' strings, loosely based on the Parsec library.
15+
16+module Data.Attoparsec.ByteString.Char8
17+ (
18+ -- * Character encodings
19+ -- $encodings
20+
21+ -- * Parser types
22+ Parser
23+ , A.Result
24+
25+ -- * Running parsers
26+ , A.parse
27+ , A.feed
28+ , A.parseOnly
29+ , A.parseTest
30+ , A.parseWith
31+
32+ -- ** Result conversion
33+ , A.maybeResult
34+ , A.eitherResult
35+
36+ -- * Combinators
37+ , (I.<?>)
38+ , I.try
39+ , module Data.Attoparsec.Combinator
40+
41+ -- * Parsing individual characters
42+ , char
43+ , char8
44+ , anyChar
45+ , notChar
46+ , satisfy
47+
48+ -- ** Special character parsers
49+ , digit
50+ , letter_iso8859_15
51+ , letter_ascii
52+ , space
53+
54+ -- ** Fast predicates
55+ , isDigit
56+ , isDigit_w8
57+ , isAlpha_iso8859_15
58+ , isAlpha_ascii
59+ , isSpace
60+ , isSpace_w8
61+
62+ -- *** Character classes
63+ , inClass
64+ , notInClass
65+
66+ -- * Efficient string handling
67+ , I.string
68+ , stringCI
69+ , skipSpace
70+ , skipWhile
71+ , I.take
72+ , scan
73+ , takeWhile
74+ , takeWhile1
75+ , takeTill
76+
77+ -- ** Consume all remaining input
78+ , I.takeByteString
79+ , I.takeLazyByteString
80+
81+ -- * Text parsing
82+ , I.endOfLine
83+ , isEndOfLine
84+ , isHorizontalSpace
85+
86+ -- * Numeric parsers
87+ , decimal
88+ , hexadecimal
89+ , signed
90+ , double
91+ , Number(..)
92+ , number
93+ , rational
94+
95+ -- * State observation and manipulation functions
96+ , I.endOfInput
97+ , I.atEnd
98+ ) where
99+
100+import Control.Applicative ((*>), (<$>), (<|>))
101+import Data.Attoparsec.ByteString.FastSet (charClass, memberChar)
102+import Data.Attoparsec.ByteString.Internal (Parser, (<?>))
103+import Data.Attoparsec.Combinator
104+import Data.Attoparsec.Number (Number(..))
105+import Data.Bits (Bits, (.|.), shiftL)
106+import Data.ByteString.Internal (c2w, w2c)
107+import Data.Int (Int8, Int16, Int32, Int64)
108+import Data.Ratio ((%))
109+import Data.String (IsString(..))
110+import Data.Word (Word8, Word16, Word32, Word64, Word)
111+import Prelude hiding (takeWhile)
112+import qualified Data.Attoparsec.ByteString as A
113+import qualified Data.Attoparsec.ByteString.Internal as I
114+import qualified Data.ByteString as B8
115+import qualified Data.ByteString.Char8 as B
116+
117+instance IsString (Parser B.ByteString) where
118+ fromString = I.string . B.pack
119+
120+-- $encodings
121+--
122+-- This module is intended for parsing text that is
123+-- represented using an 8-bit character set, e.g. ASCII or
124+-- ISO-8859-15. It /does not/ make any attempt to deal with character
125+-- encodings, multibyte characters, or wide characters. In
126+-- particular, all attempts to use characters above code point U+00FF
127+-- will give wrong answers.
128+--
129+-- Code points below U+0100 are simply translated to and from their
130+-- numeric values, so e.g. the code point U+00A4 becomes the byte
131+-- @0xA4@ (which is the Euro symbol in ISO-8859-15, but the generic
132+-- currency sign in ISO-8859-1). Haskell 'Char' values above U+00FF
133+-- are truncated, so e.g. U+1D6B7 is truncated to the byte @0xB7@.
134+
135+-- ASCII-specific but fast, oh yes.
136+toLower :: Word8 -> Word8
137+toLower w | w >= 65 && w <= 90 = w + 32
138+ | otherwise = w
139+
140+-- | Satisfy a literal string, ignoring case.
141+stringCI :: B.ByteString -> Parser B.ByteString
142+stringCI = I.stringTransform (B8.map toLower)
143+{-# INLINE stringCI #-}
144+
145+-- | Consume input as long as the predicate returns 'True', and return
146+-- the consumed input.
147+--
148+-- This parser requires the predicate to succeed on at least one byte
149+-- of input: it will fail if the predicate never returns 'True' or if
150+-- there is no input left.
151+takeWhile1 :: (Char -> Bool) -> Parser B.ByteString
152+takeWhile1 p = I.takeWhile1 (p . w2c)
153+{-# INLINE takeWhile1 #-}
154+
155+-- | The parser @satisfy p@ succeeds for any byte for which the
156+-- predicate @p@ returns 'True'. Returns the byte that is actually
157+-- parsed.
158+--
159+-- >digit = satisfy isDigit
160+-- > where isDigit c = c >= '0' && c <= '9'
161+satisfy :: (Char -> Bool) -> Parser Char
162+satisfy = I.satisfyWith w2c
163+{-# INLINE satisfy #-}
164+
165+-- | Match a letter, in the ISO-8859-15 encoding.
166+letter_iso8859_15 :: Parser Char
167+letter_iso8859_15 = satisfy isAlpha_iso8859_15 <?> "letter_iso8859_15"
168+{-# INLINE letter_iso8859_15 #-}
169+
170+-- | Match a letter, in the ASCII encoding.
171+letter_ascii :: Parser Char
172+letter_ascii = satisfy isAlpha_ascii <?> "letter_ascii"
173+{-# INLINE letter_ascii #-}
174+
175+-- | A fast alphabetic predicate for the ISO-8859-15 encoding
176+--
177+-- /Note/: For all character encodings other than ISO-8859-15, and
178+-- almost all Unicode code points above U+00A3, this predicate gives
179+-- /wrong answers/.
180+isAlpha_iso8859_15 :: Char -> Bool
181+isAlpha_iso8859_15 c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
182+ (c >= '\166' && moby c)
183+ where moby = notInClass "\167\169\171-\179\182\183\185\187\191\215\247"
184+ {-# NOINLINE moby #-}
185+{-# INLINE isAlpha_iso8859_15 #-}
186+
187+-- | A fast alphabetic predicate for the ASCII encoding
188+--
189+-- /Note/: For all character encodings other than ASCII, and
190+-- almost all Unicode code points above U+007F, this predicate gives
191+-- /wrong answers/.
192+isAlpha_ascii :: Char -> Bool
193+isAlpha_ascii c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
194+{-# INLINE isAlpha_ascii #-}
195+
196+-- | Parse a single digit.
197+digit :: Parser Char
198+digit = satisfy isDigit <?> "digit"
199+{-# INLINE digit #-}
200+
201+-- | A fast digit predicate.
202+isDigit :: Char -> Bool
203+isDigit c = c >= '0' && c <= '9'
204+{-# INLINE isDigit #-}
205+
206+-- | A fast digit predicate.
207+isDigit_w8 :: Word8 -> Bool
208+isDigit_w8 w = w >= 48 && w <= 57
209+{-# INLINE isDigit_w8 #-}
210+
211+-- | Match any character.
212+anyChar :: Parser Char
213+anyChar = satisfy $ const True
214+{-# INLINE anyChar #-}
215+
216+-- | Fast predicate for matching ASCII space characters.
217+--
218+-- /Note/: This predicate only gives correct answers for the ASCII
219+-- encoding. For instance, it does not recognise U+00A0 (non-breaking
220+-- space) as a space character, even though it is a valid ISO-8859-15
221+-- byte. For a Unicode-aware and only slightly slower predicate,
222+-- use 'Data.Char.isSpace'
223+isSpace :: Char -> Bool
224+isSpace c = (c == ' ') || ('\t' <= c && c <= '\r')
225+{-# INLINE isSpace #-}
226+
227+-- | Fast 'Word8' predicate for matching ASCII space characters.
228+isSpace_w8 :: Word8 -> Bool
229+isSpace_w8 w = (w == 32) || (9 <= w && w <= 13)
230+{-# INLINE isSpace_w8 #-}
231+
232+
233+-- | Parse a space character.
234+--
235+-- /Note/: This parser only gives correct answers for the ASCII
236+-- encoding. For instance, it does not recognise U+00A0 (non-breaking
237+-- space) as a space character, even though it is a valid ISO-8859-15
238+-- byte.
239+space :: Parser Char
240+space = satisfy isSpace <?> "space"
241+{-# INLINE space #-}
242+
243+-- | Match a specific character.
244+char :: Char -> Parser Char
245+char c = satisfy (== c) <?> [c]
246+{-# INLINE char #-}
247+
248+-- | Match a specific character, but return its 'Word8' value.
249+char8 :: Char -> Parser Word8
250+char8 c = I.satisfy (== c2w c) <?> [c]
251+{-# INLINE char8 #-}
252+
253+-- | Match any character except the given one.
254+notChar :: Char -> Parser Char
255+notChar c = satisfy (/= c) <?> "not " ++ [c]
256+{-# INLINE notChar #-}
257+
258+-- | Match any character in a set.
259+--
260+-- >vowel = inClass "aeiou"
261+--
262+-- Range notation is supported.
263+--
264+-- >halfAlphabet = inClass "a-nA-N"
265+--
266+-- To add a literal \'-\' to a set, place it at the beginning or end
267+-- of the string.
268+inClass :: String -> Char -> Bool
269+inClass s = (`memberChar` mySet)
270+ where mySet = charClass s
271+{-# INLINE inClass #-}
272+
273+-- | Match any character not in a set.
274+notInClass :: String -> Char -> Bool
275+notInClass s = not . inClass s
276+{-# INLINE notInClass #-}
277+
278+-- | Consume input as long as the predicate returns 'True', and return
279+-- the consumed input.
280+--
281+-- This parser does not fail. It will return an empty string if the
282+-- predicate returns 'False' on the first byte of input.
283+--
284+-- /Note/: Because this parser does not fail, do not use it with
285+-- combinators such as 'many', because such parsers loop until a
286+-- failure occurs. Careless use will thus result in an infinite loop.
287+takeWhile :: (Char -> Bool) -> Parser B.ByteString
288+takeWhile p = I.takeWhile (p . w2c)
289+{-# INLINE takeWhile #-}
290+
291+-- | A stateful scanner. The predicate consumes and transforms a
292+-- state argument, and each transformed state is passed to successive
293+-- invocations of the predicate on each byte of the input until one
294+-- returns 'Nothing' or the input ends.
295+--
296+-- This parser does not fail. It will return an empty string if the
297+-- predicate returns 'Nothing' on the first byte of input.
298+--
299+-- /Note/: Because this parser does not fail, do not use it with
300+-- combinators such as 'many', because such parsers loop until a
301+-- failure occurs. Careless use will thus result in an infinite loop.
302+scan :: s -> (s -> Char -> Maybe s) -> Parser B.ByteString
303+scan s0 p = I.scan s0 (\s -> p s . w2c)
304+{-# INLINE scan #-}
305+
306+-- | Consume input as long as the predicate returns 'False'
307+-- (i.e. until it returns 'True'), and return the consumed input.
308+--
309+-- This parser does not fail. It will return an empty string if the
310+-- predicate returns 'True' on the first byte of input.
311+--
312+-- /Note/: Because this parser does not fail, do not use it with
313+-- combinators such as 'many', because such parsers loop until a
314+-- failure occurs. Careless use will thus result in an infinite loop.
315+takeTill :: (Char -> Bool) -> Parser B.ByteString
316+takeTill p = I.takeTill (p . w2c)
317+{-# INLINE takeTill #-}
318+
319+-- | Skip past input for as long as the predicate returns 'True'.
320+skipWhile :: (Char -> Bool) -> Parser ()
321+skipWhile p = I.skipWhile (p . w2c)
322+{-# INLINE skipWhile #-}
323+
324+-- | Skip over white space.
325+skipSpace :: Parser ()
326+skipSpace = I.skipWhile isSpace_w8
327+{-# INLINE skipSpace #-}
328+
329+-- | A predicate that matches either a carriage return @\'\\r\'@ or
330+-- newline @\'\\n\'@ character.
331+isEndOfLine :: Word8 -> Bool
332+isEndOfLine w = w == 13 || w == 10
333+{-# INLINE isEndOfLine #-}
334+
335+-- | A predicate that matches either a space @\' \'@ or horizontal tab
336+-- @\'\\t\'@ character.
337+isHorizontalSpace :: Word8 -> Bool
338+isHorizontalSpace w = w == 32 || w == 9
339+{-# INLINE isHorizontalSpace #-}
340+
341+-- | Parse and decode an unsigned hexadecimal number. The hex digits
342+-- @\'a\'@ through @\'f\'@ may be upper or lower case.
343+--
344+-- This parser does not accept a leading @\"0x\"@ string.
345+hexadecimal :: (Integral a, Bits a) => Parser a
346+hexadecimal = B8.foldl' step 0 `fmap` I.takeWhile1 isHexDigit
347+ where
348+ isHexDigit w = (w >= 48 && w <= 57) ||
349+ (w >= 97 && w <= 102) ||
350+ (w >= 65 && w <= 90)
351+ step a w | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)
352+ | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)
353+ | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)
354+{-# SPECIALISE hexadecimal :: Parser Int #-}
355+{-# SPECIALISE hexadecimal :: Parser Int8 #-}
356+{-# SPECIALISE hexadecimal :: Parser Int16 #-}
357+{-# SPECIALISE hexadecimal :: Parser Int32 #-}
358+{-# SPECIALISE hexadecimal :: Parser Int64 #-}
359+{-# SPECIALISE hexadecimal :: Parser Integer #-}
360+{-# SPECIALISE hexadecimal :: Parser Word #-}
361+{-# SPECIALISE hexadecimal :: Parser Word8 #-}
362+{-# SPECIALISE hexadecimal :: Parser Word16 #-}
363+{-# SPECIALISE hexadecimal :: Parser Word32 #-}
364+{-# SPECIALISE hexadecimal :: Parser Word64 #-}
365+
366+-- | Parse and decode an unsigned decimal number.
367+decimal :: Integral a => Parser a
368+decimal = B8.foldl' step 0 `fmap` I.takeWhile1 isDig
369+ where isDig w = w >= 48 && w <= 57
370+ step a w = a * 10 + fromIntegral (w - 48)
371+{-# SPECIALISE decimal :: Parser Int #-}
372+{-# SPECIALISE decimal :: Parser Int8 #-}
373+{-# SPECIALISE decimal :: Parser Int16 #-}
374+{-# SPECIALISE decimal :: Parser Int32 #-}
375+{-# SPECIALISE decimal :: Parser Int64 #-}
376+{-# SPECIALISE decimal :: Parser Integer #-}
377+{-# SPECIALISE decimal :: Parser Word #-}
378+{-# SPECIALISE decimal :: Parser Word8 #-}
379+{-# SPECIALISE decimal :: Parser Word16 #-}
380+{-# SPECIALISE decimal :: Parser Word32 #-}
381+{-# SPECIALISE decimal :: Parser Word64 #-}
382+
383+-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign
384+-- character.
385+signed :: Num a => Parser a -> Parser a
386+{-# SPECIALISE signed :: Parser Int -> Parser Int #-}
387+{-# SPECIALISE signed :: Parser Int8 -> Parser Int8 #-}
388+{-# SPECIALISE signed :: Parser Int16 -> Parser Int16 #-}
389+{-# SPECIALISE signed :: Parser Int32 -> Parser Int32 #-}
390+{-# SPECIALISE signed :: Parser Int64 -> Parser Int64 #-}
391+{-# SPECIALISE signed :: Parser Integer -> Parser Integer #-}
392+signed p = (negate <$> (char8 '-' *> p))
393+ <|> (char8 '+' *> p)
394+ <|> p
395+
396+-- | Parse a rational number.
397+--
398+-- This parser accepts an optional leading sign character, followed by
399+-- at least one decimal digit. The syntax similar to that accepted by
400+-- the 'read' function, with the exception that a trailing @\'.\'@ or
401+-- @\'e\'@ /not/ followed by a number is not consumed.
402+--
403+-- Examples with behaviour identical to 'read', if you feed an empty
404+-- continuation to the first result:
405+--
406+-- >rational "3" == Done 3.0 ""
407+-- >rational "3.1" == Done 3.1 ""
408+-- >rational "3e4" == Done 30000.0 ""
409+-- >rational "3.1e4" == Done 31000.0, ""
410+
411+-- Examples with behaviour identical to 'read':
412+--
413+-- >rational ".3" == Fail "input does not start with a digit"
414+-- >rational "e3" == Fail "input does not start with a digit"
415+--
416+-- Examples of differences from 'read':
417+--
418+-- >rational "3.foo" == Done 3.0 ".foo"
419+-- >rational "3e" == Done 3.0 "e"
420+--
421+-- This function does not accept string representations of \"NaN\" or
422+-- \"Infinity\".
423+rational :: Fractional a => Parser a
424+{-# SPECIALIZE rational :: Parser Double #-}
425+{-# SPECIALIZE rational :: Parser Float #-}
426+{-# SPECIALIZE rational :: Parser Rational #-}
427+rational = floaty $ \real frac fracDenom -> fromRational $
428+ real % 1 + frac % fracDenom
429+
430+-- | Parse a rational number.
431+--
432+-- The syntax accepted by this parser is the same as for 'rational'.
433+--
434+-- /Note/: This function is almost ten times faster than 'rational',
435+-- but is slightly less accurate.
436+--
437+-- The 'Double' type supports about 16 decimal places of accuracy.
438+-- For 94.2% of numbers, this function and 'rational' give identical
439+-- results, but for the remaining 5.8%, this function loses precision
440+-- around the 15th decimal place. For 0.001% of numbers, this
441+-- function will lose precision at the 13th or 14th decimal place.
442+--
443+-- This function does not accept string representations of \"NaN\" or
444+-- \"Infinity\".
445+double :: Parser Double
446+double = floaty asDouble
447+
448+asDouble :: Integer -> Integer -> Integer -> Double
449+asDouble real frac fracDenom =
450+ fromIntegral real + fromIntegral frac / fromIntegral fracDenom
451+{-# INLINE asDouble #-}
452+
453+-- | Parse a number, attempting to preserve both speed and precision.
454+--
455+-- The syntax accepted by this parser is the same as for 'rational'.
456+--
457+-- /Note/: This function is almost ten times faster than 'rational'.
458+-- On integral inputs, it gives perfectly accurate answers, and on
459+-- floating point inputs, it is slightly less accurate than
460+-- 'rational'.
461+--
462+-- This function does not accept string representations of \"NaN\" or
463+-- \"Infinity\".
464+number :: Parser Number
465+number = floaty $ \real frac fracDenom ->
466+ if frac == 0 && fracDenom == 0
467+ then I real
468+ else D (asDouble real frac fracDenom)
469+{-# INLINE number #-}
470+
471+data T = T !Integer !Int
472+
473+floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
474+{-# INLINE floaty #-}
475+floaty f = do
476+ let minus = 45
477+ plus = 43
478+ !positive <- ((== plus) <$> I.satisfy (\c -> c == minus || c == plus)) <|>
479+ return True
480+ real <- decimal
481+ let tryFraction = do
482+ let dot = 46
483+ _ <- I.satisfy (==dot)
484+ ds <- I.takeWhile isDigit_w8
485+ case I.parseOnly decimal ds of
486+ Right n -> return $ T n (B.length ds)
487+ _ -> fail "no digits after decimal"
488+ T fraction fracDigits <- tryFraction <|> return (T 0 0)
489+ let littleE = 101
490+ bigE = 69
491+ e w = w == littleE || w == bigE
492+ power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
493+ let n = if fracDigits == 0
494+ then if power == 0
495+ then fromIntegral real
496+ else fromIntegral real * (10 ^^ power)
497+ else if power == 0
498+ then f real fraction (10 ^ fracDigits)
499+ else f real fraction (10 ^ fracDigits) * (10 ^^ power)
500+ return $ if positive
501+ then n
502+ else -n
Data/Attoparsec/FastSet.hs → Data/Attoparsec/ByteString/FastSet.hsrenamed+2−2
@@ -2,7 +2,7 @@
22
33-----------------------------------------------------------------------------
44-- |
5−-- Module : Data.Attoparsec.FastSet
5+-- Module : Data.Attoparsec.ByteString.FastSet
66-- Copyright : Bryan O'Sullivan 2008
77-- License : BSD3
88--
@@ -16,7 +16,7 @@
1616-- a lookup table.
1717--
1818-----------------------------------------------------------------------------
19−module Data.Attoparsec.FastSet
19+module Data.Attoparsec.ByteString.FastSet
2020 (
2121 -- * Data type
2222 FastSet
Data/Attoparsec/Internal.hs → Data/Attoparsec/ByteString/Internal.hsrenamed+32−26
@@ -1,6 +1,6 @@
11{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings, RecordWildCards #-}
22-- |
3−-- Module : Data.Attoparsec.Internal
3+-- Module : Data.Attoparsec.ByteString.Internal
44-- Copyright : Bryan O'Sullivan 2007-2011
55-- License : BSD3
66--
@@ -11,11 +11,11 @@
1111-- Simple, efficient parser combinators for 'B.ByteString' strings,
1212-- loosely based on the Parsec library.
1313
14−module Data.Attoparsec.Internal
14+module Data.Attoparsec.ByteString.Internal
1515 (
1616 -- * Parser types
1717 Parser
18− , Result(..)
18+ , Result
1919
2020 -- * Running parsers
2121 , parse
@@ -66,28 +66,37 @@ module Data.Attoparsec.Internal
6666
6767import Control.Applicative ((<|>), (<$>))
6868import Control.Monad (when)
69+import Data.Attoparsec.ByteString.FastSet (charClass, memberWord8)
6970import Data.Attoparsec.Combinator
70−import Data.Attoparsec.FastSet (charClass, memberWord8)
7171import Data.Attoparsec.Internal.Types
72+ hiding (Parser, Input, Added, Failure, Success)
7273import Data.Word (Word8)
7374import Foreign.ForeignPtr (withForeignPtr)
7475import Foreign.Ptr (castPtr, minusPtr, plusPtr)
7576import Foreign.Storable (Storable(peek, sizeOf))
7677import Prelude hiding (getChar, take, takeWhile)
7778import System.IO.Unsafe (unsafePerformIO)
79+import qualified Data.Attoparsec.Internal.Types as T
7880import qualified Data.ByteString as B8
7981import qualified Data.ByteString.Char8 as B
8082import qualified Data.ByteString.Internal as B
8183import qualified Data.ByteString.Lazy as L
8284import qualified Data.ByteString.Unsafe as B
8385
86+type Parser a = T.Parser B.ByteString a
87+type Result a = IResult B.ByteString a
88+type Input = T.Input B.ByteString
89+type Added = T.Added B.ByteString
90+type Failure r = T.Failure B.ByteString r
91+type Success a r = T.Success B.ByteString a r
92+
8493-- | If at least @n@ bytes of input are available, return the current
8594-- input, otherwise fail.
8695ensure :: Int -> Parser B.ByteString
87−ensure !n = Parser $ \i0 a0 m0 kf ks ->
96+ensure !n = T.Parser $ \i0 a0 m0 kf ks ->
8897 if B.length (unI i0) >= n
8998 then ks i0 a0 m0 (unI i0)
90− else runParser (demandInput >> ensure n) i0 a0 m0 kf ks
99+ else T.runParser (demandInput >> ensure n) i0 a0 m0 kf ks
91100
92101-- | Ask for input. If we receive any, pass it to a success
93102-- continuation, otherwise to a failure continuation.
@@ -98,12 +107,12 @@ prompt :: Input -> Added -> More
98107prompt i0 a0 _m0 kf ks = Partial $ \s ->
99108 if B.null s
100109 then kf i0 a0 Complete
101− else ks (I (unI i0 +++ s)) (A (unA a0 +++ s)) Incomplete
110+ else ks (I (unI i0 <> s)) (A (unA a0 <> s)) Incomplete
102111
103112-- | Immediately demand more input via a 'Partial' continuation
104113-- result.
105114demandInput :: Parser ()
106−demandInput = Parser $ \i0 a0 m0 kf ks ->
115+demandInput = T.Parser $ \i0 a0 m0 kf ks ->
107116 if m0 == Complete
108117 then kf i0 a0 m0 ["demandInput"] "not enough bytes"
109118 else let kf' i a m = kf i a m ["demandInput"] "not enough bytes"
@@ -114,7 +123,7 @@ demandInput = Parser $ \i0 a0 m0 kf ks ->
114123-- available either immediately or on demand, and 'False' if the end
115124-- of all input has been reached.
116125wantInput :: Parser Bool
117−wantInput = Parser $ \i0 a0 m0 _kf ks ->
126+wantInput = T.Parser $ \i0 a0 m0 _kf ks ->
118127 case () of
119128 _ | not (B.null (unI i0)) -> ks i0 a0 m0 True
120129 | m0 == Complete -> ks i0 a0 m0 False
@@ -123,23 +132,19 @@ wantInput = Parser $ \i0 a0 m0 _kf ks ->
123132 in prompt i0 a0 m0 kf' ks'
124133
125134get :: Parser B.ByteString
126−get = Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0)
135+get = T.Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0)
127136
128137put :: B.ByteString -> Parser ()
129−put s = Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 ()
138+put s = T.Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 ()
130139
131140-- | Attempt a parse, and if it fails, rewind the input so that no
132141-- input appears to have been consumed.
133142--
134−-- This combinator is useful in cases where a parser might consume
135−-- some input before failing, i.e. the parser needs arbitrary
136−-- lookahead. The downside to using this combinator is that it can
137−-- retain input for longer than is desirable.
143+-- This combinator is provided for compatibility with Parsec.
144+-- Attoparsec parsers always backtrack on failure.
138145try :: Parser a -> Parser a
139−try p = Parser $ \i0 a0 m0 kf ks ->
140− noAdds i0 a0 m0 $ \i1 a1 m1 ->
141− let kf' i2 a2 m2 = addS i0 a0 m0 i2 a2 m2 kf
142− in runParser p i1 a1 m1 kf' ks
146+try p = p
147+{-# INLINE try #-}
143148
144149-- | The parser @satisfy p@ succeeds for any byte for which the
145150-- predicate @p@ returns 'True'. Returns the byte that is actually
@@ -356,7 +361,7 @@ takeWhile1 p = do
356361 when (B.null h) $ fail "takeWhile1"
357362 put t
358363 if B.null t
359− then (h+++) `fmap` takeWhile p
364+ then (h<>) `fmap` takeWhile p
360365 else return h
361366
362367-- | Match any byte in a set.
@@ -372,6 +377,7 @@ takeWhile1 p = do
372377inClass :: String -> Word8 -> Bool
373378inClass s = (`memberWord8` mySet)
374379 where mySet = charClass s
380+ {-# NOINLINE mySet #-}
375381{-# INLINE inClass #-}
376382
377383-- | Match any byte not in a set.
@@ -396,7 +402,7 @@ notWord8 c = satisfy (/= c) <?> "not " ++ show c
396402
397403-- | Match only if all input has been consumed.
398404endOfInput :: Parser ()
399−endOfInput = Parser $ \i0 a0 m0 kf ks ->
405+endOfInput = T.Parser $ \i0 a0 m0 kf ks ->
400406 if B.null (unI i0)
401407 then if m0 == Complete
402408 then ks i0 a0 m0 ()
@@ -405,7 +411,7 @@ endOfInput = Parser $ \i0 a0 m0 kf ks ->
405411 ks' i1 a1 m1 _ = addS i0 a0 m0 i1 a1 m1 $
406412 \ i2 a2 m2 -> kf i2 a2 m2 []
407413 "endOfInput"
408− in runParser demandInput i0 a0 m0 kf' ks'
414+ in T.runParser demandInput i0 a0 m0 kf' ks'
409415 else kf i0 a0 m0 [] "endOfInput"
410416
411417-- | Return an indication of whether the end of input has been
@@ -423,9 +429,9 @@ endOfLine = (word8 10 >> return ()) <|> (string "\r\n" >> return ())
423429(<?>) :: Parser a
424430 -> String -- ^ the name to use if parsing fails
425431 -> Parser a
426−p <?> msg0 = Parser $ \i0 a0 m0 kf ks ->
432+p <?> msg0 = T.Parser $ \i0 a0 m0 kf ks ->
427433 let kf' i a m strs msg = kf i a m (msg0:strs) msg
428− in runParser p i0 a0 m0 kf' ks
434+ in T.runParser p i0 a0 m0 kf' ks
429435{-# INLINE (<?>) #-}
430436infix 0 <?>
431437
@@ -441,12 +447,12 @@ successK i0 _a0 _m0 a = Done (unI i0) a
441447
442448-- | Run a parser.
443449parse :: Parser a -> B.ByteString -> Result a
444−parse m s = runParser m (I s) (A B.empty) Incomplete failK successK
450+parse m s = T.runParser m (I s) (A B.empty) Incomplete failK successK
445451{-# INLINE parse #-}
446452
447453-- | Run a parser that cannot be resupplied via a 'Partial' result.
448454parseOnly :: Parser a -> B.ByteString -> Either String a
449−parseOnly m s = case runParser m (I s) (A B.empty) Complete failK successK of
455+parseOnly m s = case T.runParser m (I s) (A B.empty) Complete failK successK of
450456 Fail _ _ err -> Left err
451457 Done _ a -> Right a
452458 _ -> error "parseOnly: impossible error!"
Data/Attoparsec/ByteString/Lazy.hsnew file+91
@@ -0,0 +1,91 @@
1+-- |
2+-- Module : Data.Attoparsec.ByteString.Lazy
3+-- Copyright : Bryan O'Sullivan 2010, 2011
4+-- License : BSD3
5+--
6+-- Maintainer : bos@serpentine.com
7+-- Stability : experimental
8+-- Portability : unknown
9+--
10+-- Simple, efficient combinator parsing for lazy 'ByteString'
11+-- strings, loosely based on the Parsec library.
12+--
13+-- This is essentially the same code as in the 'Data.Attoparsec'
14+-- module, only with a 'parse' function that can consume a lazy
15+-- 'ByteString' incrementally, and a 'Result' type that does not allow
16+-- more input to be fed in. Think of this as suitable for use with a
17+-- lazily read file, e.g. via 'L.readFile' or 'L.hGetContents'.
18+--
19+-- Behind the scenes, strict 'B.ByteString' values are still used
20+-- internally to store parser input and manipulate it efficiently.
21+-- High-performance parsers such as 'string' still expect strict
22+-- 'B.ByteString' parameters.
23+
24+module Data.Attoparsec.ByteString.Lazy
25+ (
26+ Result(..)
27+ , module Data.Attoparsec.ByteString
28+ -- * Running parsers
29+ , parse
30+ , parseTest
31+ -- ** Result conversion
32+ , maybeResult
33+ , eitherResult
34+ ) where
35+
36+import Data.ByteString.Lazy.Internal (ByteString(..), chunk)
37+import qualified Data.ByteString as B
38+import qualified Data.Attoparsec.ByteString as A
39+import qualified Data.Attoparsec.Internal.Types as T
40+import Data.Attoparsec.ByteString
41+ hiding (IResult(..), Result, eitherResult, maybeResult,
42+ parse, parseWith, parseTest)
43+
44+-- | The result of a parse.
45+data Result r = Fail ByteString [String] String
46+ -- ^ The parse failed. The 'ByteString' is the input
47+ -- that had not yet been consumed when the failure
48+ -- occurred. The @[@'String'@]@ is a list of contexts
49+ -- in which the error occurred. The 'String' is the
50+ -- message describing the error, if any.
51+ | Done ByteString r
52+ -- ^ The parse succeeded. The 'ByteString' is the
53+ -- input that had not yet been consumed (if any) when
54+ -- the parse succeeded.
55+
56+instance Show r => Show (Result r) where
57+ show (Fail bs stk msg) =
58+ "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg
59+ show (Done bs r) = "Done " ++ show bs ++ " " ++ show r
60+
61+fmapR :: (a -> b) -> Result a -> Result b
62+fmapR _ (Fail st stk msg) = Fail st stk msg
63+fmapR f (Done bs r) = Done bs (f r)
64+
65+instance Functor Result where
66+ fmap = fmapR
67+
68+-- | Run a parser and return its result.
69+parse :: A.Parser a -> ByteString -> Result a
70+parse p s = case s of
71+ Chunk x xs -> go (A.parse p x) xs
72+ empty -> go (A.parse p B.empty) empty
73+ where
74+ go (T.Fail x stk msg) ys = Fail (chunk x ys) stk msg
75+ go (T.Done x r) ys = Done (chunk x ys) r
76+ go (T.Partial k) (Chunk y ys) = go (k y) ys
77+ go (T.Partial k) empty = go (k B.empty) empty
78+
79+-- | Run a parser and print its result to standard output.
80+parseTest :: (Show a) => A.Parser a -> ByteString -> IO ()
81+parseTest p s = print (parse p s)
82+
83+-- | Convert a 'Result' value to a 'Maybe' value.
84+maybeResult :: Result r -> Maybe r
85+maybeResult (Done _ r) = Just r
86+maybeResult _ = Nothing
87+
88+-- | Convert a 'Result' value to an 'Either' value.
89+eitherResult :: Result r -> Either String r
90+eitherResult (Done _ r) = Right r
91+eitherResult (Fail _ _ msg) = Left msg
Data/Attoparsec/Char8.hs+4−488
@@ -1,9 +1,6 @@
1−{-# LANGUAGE BangPatterns, FlexibleInstances #-}
2−{-# OPTIONS_GHC -fno-warn-orphans #-}
3−
41-- |
52-- Module : Data.Attoparsec.Char8
6−-- Copyright : Bryan O'Sullivan 2007-2010
3+-- Copyright : Bryan O'Sullivan 2007-2011
74-- License : BSD3
85--
96-- Maintainer : bos@serpentine.com
@@ -11,492 +8,11 @@
118-- Portability : unknown
129--
1310-- Simple, efficient, character-oriented combinator parsing for
14−-- 'B.ByteString' strings, loosely based on the Parsec library.
11+-- 'ByteString' strings, loosely based on the Parsec library.
1512
1613module Data.Attoparsec.Char8
1714 (
18− -- * Character encodings
19− -- $encodings
20−
21− -- * Parser types
22− Parser
23− , A.Result(..)
24−
25− -- * Running parsers
26− , A.parse
27− , A.feed
28− , A.parseOnly
29− , A.parseTest
30− , A.parseWith
31−
32− -- ** Result conversion
33− , A.maybeResult
34− , A.eitherResult
35−
36− -- * Combinators
37− , (I.<?>)
38− , I.try
39− , module Data.Attoparsec.Combinator
40−
41− -- * Parsing individual characters
42− , char
43− , char8
44− , anyChar
45− , notChar
46− , satisfy
47−
48− -- ** Special character parsers
49− , digit
50− , letter_iso8859_15
51− , letter_ascii
52− , space
53−
54− -- ** Fast predicates
55− , isDigit
56− , isDigit_w8
57− , isAlpha_iso8859_15
58− , isAlpha_ascii
59− , isSpace
60− , isSpace_w8
61−
62− -- *** Character classes
63− , inClass
64− , notInClass
65−
66− -- * Efficient string handling
67− , I.string
68− , stringCI
69− , skipSpace
70− , skipWhile
71− , I.take
72− , scan
73− , takeWhile
74− , takeWhile1
75− , takeTill
76−
77− -- ** Consume all remaining input
78− , I.takeByteString
79− , I.takeLazyByteString
80−
81− -- * Text parsing
82− , I.endOfLine
83− , isEndOfLine
84− , isHorizontalSpace
85−
86− -- * Numeric parsers
87− , decimal
88− , hexadecimal
89− , signed
90− , double
91− , Number(..)
92− , number
93− , rational
94−
95− -- * State observation and manipulation functions
96− , I.endOfInput
97− , I.atEnd
15+ module Data.Attoparsec.ByteString.Char8
9816 ) where
9917
100−import Control.Applicative ((*>), (<$>), (<|>))
101−import Data.Attoparsec.Combinator
102−import Data.Attoparsec.FastSet (charClass, memberChar)
103−import Data.Attoparsec.Internal (Parser, (<?>))
104−import Data.Attoparsec.Number (Number(..))
105−import Data.Bits (Bits, (.|.), shiftL)
106−import Data.ByteString.Internal (c2w, w2c)
107−import Data.Int (Int8, Int16, Int32, Int64)
108−import Data.Ratio ((%))
109−import Data.String (IsString(..))
110−import Data.Word (Word8, Word16, Word32, Word64, Word)
111−import Prelude hiding (takeWhile)
112−import qualified Data.Attoparsec as A
113−import qualified Data.Attoparsec.Internal as I
114−import qualified Data.ByteString as B8
115−import qualified Data.ByteString.Char8 as B
116−
117−instance IsString (Parser B.ByteString) where
118− fromString = I.string . B.pack
119−
120−-- $encodings
121−--
122−-- This module is intended for parsing text that is
123−-- represented using an 8-bit character set, e.g. ASCII or
124−-- ISO-8859-15. It /does not/ make any attempt to deal with character
125−-- encodings, multibyte characters, or wide characters. In
126−-- particular, all attempts to use characters above code point U+00FF
127−-- will give wrong answers.
128−--
129−-- Code points below U+0100 are simply translated to and from their
130−-- numeric values, so e.g. the code point U+00A4 becomes the byte
131−-- @0xA4@ (which is the Euro symbol in ISO-8859-15, but the generic
132−-- currency sign in ISO-8859-1). Haskell 'Char' values above U+00FF
133−-- are truncated, so e.g. U+1D6B7 is truncated to the byte @0xB7@.
134−
135−-- ASCII-specific but fast, oh yes.
136−toLower :: Word8 -> Word8
137−toLower w | w >= 65 && w <= 90 = w + 32
138− | otherwise = w
139−
140−-- | Satisfy a literal string, ignoring case.
141−stringCI :: B.ByteString -> Parser B.ByteString
142−stringCI = I.stringTransform (B8.map toLower)
143−{-# INLINE stringCI #-}
144−
145−-- | Consume input as long as the predicate returns 'True', and return
146−-- the consumed input.
147−--
148−-- This parser requires the predicate to succeed on at least one byte
149−-- of input: it will fail if the predicate never returns 'True' or if
150−-- there is no input left.
151−takeWhile1 :: (Char -> Bool) -> Parser B.ByteString
152−takeWhile1 p = I.takeWhile1 (p . w2c)
153−{-# INLINE takeWhile1 #-}
154−
155−-- | The parser @satisfy p@ succeeds for any byte for which the
156−-- predicate @p@ returns 'True'. Returns the byte that is actually
157−-- parsed.
158−--
159−-- >digit = satisfy isDigit
160−-- > where isDigit c = c >= '0' && c <= '9'
161−satisfy :: (Char -> Bool) -> Parser Char
162−satisfy = I.satisfyWith w2c
163−{-# INLINE satisfy #-}
164−
165−-- | Match a letter, in the ISO-8859-15 encoding.
166−letter_iso8859_15 :: Parser Char
167−letter_iso8859_15 = satisfy isAlpha_iso8859_15 <?> "letter_iso8859_15"
168−{-# INLINE letter_iso8859_15 #-}
169−
170−-- | Match a letter, in the ASCII encoding.
171−letter_ascii :: Parser Char
172−letter_ascii = satisfy isAlpha_ascii <?> "letter_ascii"
173−{-# INLINE letter_ascii #-}
174−
175−-- | A fast alphabetic predicate for the ISO-8859-15 encoding
176−--
177−-- /Note/: For all character encodings other than ISO-8859-15, and
178−-- almost all Unicode code points above U+00A3, this predicate gives
179−-- /wrong answers/.
180−isAlpha_iso8859_15 :: Char -> Bool
181−isAlpha_iso8859_15 c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
182− (c >= '\166' && moby c)
183− where moby = notInClass "\167\169\171-\179\182\183\185\187\191\215\247"
184− {-# NOINLINE moby #-}
185−{-# INLINE isAlpha_iso8859_15 #-}
186−
187−-- | A fast alphabetic predicate for the ASCII encoding
188−--
189−-- /Note/: For all character encodings other than ASCII, and
190−-- almost all Unicode code points above U+007F, this predicate gives
191−-- /wrong answers/.
192−isAlpha_ascii :: Char -> Bool
193−isAlpha_ascii c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
194−{-# INLINE isAlpha_ascii #-}
195−
196−-- | Parse a single digit.
197−digit :: Parser Char
198−digit = satisfy isDigit <?> "digit"
199−{-# INLINE digit #-}
200−
201−-- | A fast digit predicate.
202−isDigit :: Char -> Bool
203−isDigit c = c >= '0' && c <= '9'
204−{-# INLINE isDigit #-}
205−
206−-- | A fast digit predicate.
207−isDigit_w8 :: Word8 -> Bool
208−isDigit_w8 w = w >= 48 && w <= 57
209−{-# INLINE isDigit_w8 #-}
210−
211−-- | Match any character.
212−anyChar :: Parser Char
213−anyChar = satisfy $ const True
214−{-# INLINE anyChar #-}
215−
216−-- | Fast predicate for matching ASCII space characters.
217−--
218−-- /Note/: This predicate only gives correct answers for the ASCII
219−-- encoding. For instance, it does not recognise U+00A0 (non-breaking
220−-- space) as a space character, even though it is a valid ISO-8859-15
221−-- byte. For a Unicode-aware and only slightly slower predicate,
222−-- use 'Data.Char.isSpace'
223−isSpace :: Char -> Bool
224−isSpace c = (c == ' ') || ('\t' <= c && c <= '\r')
225−{-# INLINE isSpace #-}
226−
227−-- | Fast 'Word8' predicate for matching ASCII space characters.
228−isSpace_w8 :: Word8 -> Bool
229−isSpace_w8 w = (w == 32) || (9 <= w && w <= 13)
230−{-# INLINE isSpace_w8 #-}
231−
232−
233−-- | Parse a space character.
234−--
235−-- /Note/: This parser only gives correct answers for the ASCII
236−-- encoding. For instance, it does not recognise U+00A0 (non-breaking
237−-- space) as a space character, even though it is a valid ISO-8859-15
238−-- byte.
239−space :: Parser Char
240−space = satisfy isSpace <?> "space"
241−{-# INLINE space #-}
242−
243−-- | Match a specific character.
244−char :: Char -> Parser Char
245−char c = satisfy (== c) <?> [c]
246−{-# INLINE char #-}
247−
248−-- | Match a specific character, but return its 'Word8' value.
249−char8 :: Char -> Parser Word8
250−char8 c = I.satisfy (== c2w c) <?> [c]
251−{-# INLINE char8 #-}
252−
253−-- | Match any character except the given one.
254−notChar :: Char -> Parser Char
255−notChar c = satisfy (/= c) <?> "not " ++ [c]
256−{-# INLINE notChar #-}
257−
258−-- | Match any character in a set.
259−--
260−-- >vowel = inClass "aeiou"
261−--
262−-- Range notation is supported.
263−--
264−-- >halfAlphabet = inClass "a-nA-N"
265−--
266−-- To add a literal \'-\' to a set, place it at the beginning or end
267−-- of the string.
268−inClass :: String -> Char -> Bool
269−inClass s = (`memberChar` mySet)
270− where mySet = charClass s
271−{-# INLINE inClass #-}
272−
273−-- | Match any character not in a set.
274−notInClass :: String -> Char -> Bool
275−notInClass s = not . inClass s
276−{-# INLINE notInClass #-}
277−
278−-- | Consume input as long as the predicate returns 'True', and return
279−-- the consumed input.
280−--
281−-- This parser does not fail. It will return an empty string if the
282−-- predicate returns 'False' on the first byte of input.
283−--
284−-- /Note/: Because this parser does not fail, do not use it with
285−-- combinators such as 'many', because such parsers loop until a
286−-- failure occurs. Careless use will thus result in an infinite loop.
287−takeWhile :: (Char -> Bool) -> Parser B.ByteString
288−takeWhile p = I.takeWhile (p . w2c)
289−{-# INLINE takeWhile #-}
290−
291−-- | A stateful scanner. The predicate consumes and transforms a
292−-- state argument, and each transformed state is passed to successive
293−-- invocations of the predicate on each byte of the input until one
294−-- returns 'Nothing' or the input ends.
295−--
296−-- This parser does not fail. It will return an empty string if the
297−-- predicate returns 'Nothing' on the first byte of input.
298−--
299−-- /Note/: Because this parser does not fail, do not use it with
300−-- combinators such as 'many', because such parsers loop until a
301−-- failure occurs. Careless use will thus result in an infinite loop.
302−scan :: s -> (s -> Char -> Maybe s) -> Parser B.ByteString
303−scan s0 p = I.scan s0 (\s -> p s . w2c)
304−{-# INLINE scan #-}
305−
306−-- | Consume input as long as the predicate returns 'False'
307−-- (i.e. until it returns 'True'), and return the consumed input.
308−--
309−-- This parser does not fail. It will return an empty string if the
310−-- predicate returns 'True' on the first byte of input.
311−--
312−-- /Note/: Because this parser does not fail, do not use it with
313−-- combinators such as 'many', because such parsers loop until a
314−-- failure occurs. Careless use will thus result in an infinite loop.
315−takeTill :: (Char -> Bool) -> Parser B.ByteString
316−takeTill p = I.takeTill (p . w2c)
317−{-# INLINE takeTill #-}
318−
319−-- | Skip past input for as long as the predicate returns 'True'.
320−skipWhile :: (Char -> Bool) -> Parser ()
321−skipWhile p = I.skipWhile (p . w2c)
322−{-# INLINE skipWhile #-}
323−
324−-- | Skip over white space.
325−skipSpace :: Parser ()
326−skipSpace = I.skipWhile isSpace_w8
327−{-# INLINE skipSpace #-}
328−
329−-- | A predicate that matches either a carriage return @\'\\r\'@ or
330−-- newline @\'\\n\'@ character.
331−isEndOfLine :: Word8 -> Bool
332−isEndOfLine w = w == 13 || w == 10
333−{-# INLINE isEndOfLine #-}
334−
335−-- | A predicate that matches either a space @\' \'@ or horizontal tab
336−-- @\'\\t\'@ character.
337−isHorizontalSpace :: Word8 -> Bool
338−isHorizontalSpace w = w == 32 || w == 9
339−{-# INLINE isHorizontalSpace #-}
340−
341−-- | Parse and decode an unsigned hexadecimal number. The hex digits
342−-- @\'a\'@ through @\'f\'@ may be upper or lower case.
343−--
344−-- This parser does not accept a leading @\"0x\"@ string.
345−hexadecimal :: (Integral a, Bits a) => Parser a
346−hexadecimal = B8.foldl' step 0 `fmap` I.takeWhile1 isHexDigit
347− where
348− isHexDigit w = (w >= 48 && w <= 57) ||
349− (w >= 97 && w <= 102) ||
350− (w >= 65 && w <= 90)
351− step a w | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)
352− | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)
353− | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)
354−{-# SPECIALISE hexadecimal :: Parser Int #-}
355−{-# SPECIALISE hexadecimal :: Parser Int8 #-}
356−{-# SPECIALISE hexadecimal :: Parser Int16 #-}
357−{-# SPECIALISE hexadecimal :: Parser Int32 #-}
358−{-# SPECIALISE hexadecimal :: Parser Int64 #-}
359−{-# SPECIALISE hexadecimal :: Parser Integer #-}
360−{-# SPECIALISE hexadecimal :: Parser Word #-}
361−{-# SPECIALISE hexadecimal :: Parser Word8 #-}
362−{-# SPECIALISE hexadecimal :: Parser Word16 #-}
363−{-# SPECIALISE hexadecimal :: Parser Word32 #-}
364−{-# SPECIALISE hexadecimal :: Parser Word64 #-}
365−
366−-- | Parse and decode an unsigned decimal number.
367−decimal :: Integral a => Parser a
368−decimal = B8.foldl' step 0 `fmap` I.takeWhile1 isDig
369− where isDig w = w >= 48 && w <= 57
370− step a w = a * 10 + fromIntegral (w - 48)
371−{-# SPECIALISE decimal :: Parser Int #-}
372−{-# SPECIALISE decimal :: Parser Int8 #-}
373−{-# SPECIALISE decimal :: Parser Int16 #-}
374−{-# SPECIALISE decimal :: Parser Int32 #-}
375−{-# SPECIALISE decimal :: Parser Int64 #-}
376−{-# SPECIALISE decimal :: Parser Integer #-}
377−{-# SPECIALISE decimal :: Parser Word #-}
378−{-# SPECIALISE decimal :: Parser Word8 #-}
379−{-# SPECIALISE decimal :: Parser Word16 #-}
380−{-# SPECIALISE decimal :: Parser Word32 #-}
381−{-# SPECIALISE decimal :: Parser Word64 #-}
382−
383−-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign
384−-- character.
385−signed :: Num a => Parser a -> Parser a
386−{-# SPECIALISE signed :: Parser Int -> Parser Int #-}
387−{-# SPECIALISE signed :: Parser Int8 -> Parser Int8 #-}
388−{-# SPECIALISE signed :: Parser Int16 -> Parser Int16 #-}
389−{-# SPECIALISE signed :: Parser Int32 -> Parser Int32 #-}
390−{-# SPECIALISE signed :: Parser Int64 -> Parser Int64 #-}
391−{-# SPECIALISE signed :: Parser Integer -> Parser Integer #-}
392−signed p = (negate <$> (char8 '-' *> p))
393− <|> (char8 '+' *> p)
394− <|> p
395−
396−-- | Parse a rational number.
397−--
398−-- This parser accepts an optional leading sign character, followed by
399−-- at least one decimal digit. The syntax similar to that accepted by
400−-- the 'read' function, with the exception that a trailing @\'.\'@ or
401−-- @\'e\'@ /not/ followed by a number is not consumed.
402−--
403−-- Examples with behaviour identical to 'read', if you feed an empty
404−-- continuation to the first result:
405−--
406−-- >rational "3" == Done 3.0 ""
407−-- >rational "3.1" == Done 3.1 ""
408−-- >rational "3e4" == Done 30000.0 ""
409−-- >rational "3.1e4" == Done 31000.0, ""
410−
411−-- Examples with behaviour identical to 'read':
412−--
413−-- >rational ".3" == Fail "input does not start with a digit"
414−-- >rational "e3" == Fail "input does not start with a digit"
415−--
416−-- Examples of differences from 'read':
417−--
418−-- >rational "3.foo" == Done 3.0 ".foo"
419−-- >rational "3e" == Done 3.0 "e"
420−--
421−-- This function does not accept string representations of \"NaN\" or
422−-- \"Infinity\".
423−rational :: Fractional a => Parser a
424−{-# SPECIALIZE rational :: Parser Double #-}
425−{-# SPECIALIZE rational :: Parser Float #-}
426−{-# SPECIALIZE rational :: Parser Rational #-}
427−rational = floaty $ \real frac fracDenom -> fromRational $
428− real % 1 + frac % fracDenom
429−
430−-- | Parse a rational number.
431−--
432−-- The syntax accepted by this parser is the same as for 'rational'.
433−--
434−-- /Note/: This function is almost ten times faster than 'rational',
435−-- but is slightly less accurate.
436−--
437−-- The 'Double' type supports about 16 decimal places of accuracy.
438−-- For 94.2% of numbers, this function and 'rational' give identical
439−-- results, but for the remaining 5.8%, this function loses precision
440−-- around the 15th decimal place. For 0.001% of numbers, this
441−-- function will lose precision at the 13th or 14th decimal place.
442−--
443−-- This function does not accept string representations of \"NaN\" or
444−-- \"Infinity\".
445−double :: Parser Double
446−double = floaty asDouble
447−
448−asDouble :: Integer -> Integer -> Integer -> Double
449−asDouble real frac fracDenom =
450− fromIntegral real + fromIntegral frac / fromIntegral fracDenom
451−{-# INLINE asDouble #-}
452−
453−-- | Parse a number, attempting to preserve both speed and precision.
454−--
455−-- The syntax accepted by this parser is the same as for 'rational'.
456−--
457−-- /Note/: This function is almost ten times faster than 'rational'.
458−-- On integral inputs, it gives perfectly accurate answers, and on
459−-- floating point inputs, it is slightly less accurate than
460−-- 'rational'.
461−--
462−-- This function does not accept string representations of \"NaN\" or
463−-- \"Infinity\".
464−number :: Parser Number
465−number = floaty $ \real frac fracDenom ->
466− if frac == 0 && fracDenom == 0
467− then I real
468− else D (asDouble real frac fracDenom)
469−{-# INLINE number #-}
470−
471−data T = T !Integer !Int
472−
473−floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
474−{-# INLINE floaty #-}
475−floaty f = do
476− let minus = 45
477− plus = 43
478− !positive <- ((== plus) <$> I.satisfy (\c -> c == minus || c == plus)) <|>
479− return True
480− real <- decimal
481− let tryFraction = do
482− let dot = 46
483− _ <- I.satisfy (==dot)
484− ds <- I.takeWhile isDigit_w8
485− case I.parseOnly decimal ds of
486− Right n -> return $ T n (B.length ds)
487− _ -> fail "no digits after decimal"
488− T fraction fracDigits <- tryFraction <|> return (T 0 0)
489− let littleE = 101
490− bigE = 69
491− e w = w == littleE || w == bigE
492− power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
493− let n = if fracDigits == 0
494− then if power == 0
495− then fromIntegral real
496− else fromIntegral real * (10 ^^ power)
497− else if power == 0
498− then f real fraction (10 ^ fracDigits)
499− else f real fraction (10 ^ fracDigits) * (10 ^^ power)
500− return $ if positive
501− then n
502− else -n
18+import Data.Attoparsec.ByteString.Char8
Data/Attoparsec/Combinator.hs+20−23
@@ -21,21 +21,15 @@ module Data.Attoparsec.Combinator
2121 , skipMany
2222 , skipMany1
2323 , eitherP
24−
25− -- * Inlined implementations of existing functions
26− --
27− -- These are exact duplicates of functions already exported by the
28− -- 'Control.Applicative' module, but whose definitions are
29− -- inlined. In many cases, this leads to 2x performance
30− -- improvements.
31− , many
3224 ) where
3325
34−import Control.Applicative (Alternative, Applicative(..), empty, liftA2,
26+import Control.Applicative (Alternative(..), Applicative(..), empty, liftA2,
3527 (<|>), (*>), (<$>))
3628#if __GLASGOW_HASKELL__ >= 700
3729import Data.Attoparsec.Internal.Types (Parser)
3830import qualified Data.Attoparsec.Zepto as Z
31+import Data.ByteString (ByteString)
32+import Data.Text (Text)
3933#endif
4034
4135-- | @choice ps@ tries to apply the actions in the list @ps@ in order,
@@ -44,7 +38,8 @@ import qualified Data.Attoparsec.Zepto as Z
4438choice :: Alternative f => [f a] -> f a
4539choice = foldr (<|>) empty
4640#if __GLASGOW_HASKELL__ >= 700
47−{-# SPECIALIZE choice :: [Parser a] -> Parser a #-}
41+{-# SPECIALIZE choice :: [Parser ByteString a] -> Parser ByteString a #-}
42+{-# SPECIALIZE choice :: [Parser Text a] -> Parser Text a #-}
4843{-# SPECIALIZE choice :: [Z.Parser a] -> Z.Parser a #-}
4944#endif
5045
@@ -56,7 +51,8 @@ choice = foldr (<|>) empty
5651option :: Alternative f => a -> f a -> f a
5752option x p = p <|> pure x
5853#if __GLASGOW_HASKELL__ >= 700
59−{-# SPECIALIZE option :: a -> Parser a -> Parser a #-}
54+{-# SPECIALIZE option :: a -> Parser ByteString a -> Parser ByteString a #-}
55+{-# SPECIALIZE option :: a -> Parser Text a -> Parser Text a #-}
6056{-# SPECIALIZE option :: a -> Z.Parser a -> Z.Parser a #-}
6157#endif
6258
@@ -75,7 +71,9 @@ many1 p = liftA2 (:) p (many p)
7571sepBy :: Alternative f => f a -> f s -> f [a]
7672sepBy p s = liftA2 (:) p ((s *> sepBy1 p s) <|> pure []) <|> pure []
7773#if __GLASGOW_HASKELL__ >= 700
78−{-# SPECIALIZE sepBy :: Parser a -> Parser s -> Parser [a] #-}
74+{-# SPECIALIZE sepBy :: Parser ByteString a -> Parser ByteString s
75+ -> Parser ByteString [a] #-}
76+{-# SPECIALIZE sepBy :: Parser Text a -> Parser Text s -> Parser Text [a] #-}
7977{-# SPECIALIZE sepBy :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-}
8078#endif
8179
@@ -87,7 +85,9 @@ sepBy1 :: Alternative f => f a -> f s -> f [a]
8785sepBy1 p s = scan
8886 where scan = liftA2 (:) p ((s *> scan) <|> pure [])
8987#if __GLASGOW_HASKELL__ >= 700
90−{-# SPECIALIZE sepBy1 :: Parser a -> Parser s -> Parser [a] #-}
88+{-# SPECIALIZE sepBy1 :: Parser ByteString a -> Parser ByteString s
89+ -> Parser ByteString [a] #-}
90+{-# SPECIALIZE sepBy1 :: Parser Text a -> Parser Text s -> Parser Text [a] #-}
9191{-# SPECIALIZE sepBy1 :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-}
9292#endif
9393
@@ -103,7 +103,9 @@ manyTill :: Alternative f => f a -> f b -> f [a]
103103manyTill p end = scan
104104 where scan = (end *> pure []) <|> liftA2 (:) p scan
105105#if __GLASGOW_HASKELL__ >= 700
106−{-# SPECIALIZE manyTill :: Parser a -> Parser b -> Parser [a] #-}
106+{-# SPECIALIZE manyTill :: Parser ByteString a -> Parser ByteString b
107+ -> Parser ByteString [a] #-}
108+{-# SPECIALIZE manyTill :: Parser Text a -> Parser Text b -> Parser Text [a] #-}
107109{-# SPECIALIZE manyTill :: Z.Parser a -> Z.Parser b -> Z.Parser [a] #-}
108110#endif
109111
@@ -112,7 +114,8 @@ skipMany :: Alternative f => f a -> f ()
112114skipMany p = scan
113115 where scan = (p *> scan) <|> pure ()
114116#if __GLASGOW_HASKELL__ >= 700
115−{-# SPECIALIZE skipMany :: Parser a -> Parser () #-}
117+{-# SPECIALIZE skipMany :: Parser ByteString a -> Parser ByteString () #-}
118+{-# SPECIALIZE skipMany :: Parser Text a -> Parser Text () #-}
116119{-# SPECIALIZE skipMany :: Z.Parser a -> Z.Parser () #-}
117120#endif
118121
@@ -120,7 +123,8 @@ skipMany p = scan
120123skipMany1 :: Alternative f => f a -> f ()
121124skipMany1 p = p *> skipMany p
122125#if __GLASGOW_HASKELL__ >= 700
123−{-# SPECIALIZE skipMany1 :: Parser a -> Parser () #-}
126+{-# SPECIALIZE skipMany1 :: Parser ByteString a -> Parser ByteString () #-}
127+{-# SPECIALIZE skipMany1 :: Parser Text a -> Parser Text () #-}
124128{-# SPECIALIZE skipMany1 :: Z.Parser a -> Z.Parser () #-}
125129#endif
126130
@@ -133,10 +137,3 @@ count n p = sequence (replicate n p)
133137eitherP :: (Alternative f) => f a -> f b -> f (Either a b)
134138eitherP a b = (Left <$> a) <|> (Right <$> b)
135139{-# INLINE eitherP #-}
136−
137−-- | Zero or more.
138−many :: (Alternative f) => f a -> f [a]
139−many v = many_v
140− where many_v = some_v <|> pure []
141− some_v = (:) <$> v <*> many_v
142−{-# INLINE many #-}
Data/Attoparsec/Internal/Types.hs+101−71
@@ -8,148 +8,166 @@
88-- Stability : experimental
99-- Portability : unknown
1010--
11−-- Simple, efficient parser combinators for 'B.ByteString' strings,
12−-- loosely based on the Parsec library.
11+-- Simple, efficient parser combinators for strings, loosely based on
12+-- the Parsec library.
1313
1414module Data.Attoparsec.Internal.Types
1515 (
1616 Parser(..)
1717 , Failure
1818 , Success
19− , Result(..)
19+ , IResult(..)
2020 , Input(..)
2121 , Added(..)
2222 , More(..)
2323 , addS
2424 , noAdds
25− , (+++)
25+ , (<>)
2626 ) where
2727
28−import Control.Applicative (Alternative(..), Applicative(..))
28+import Control.Applicative (Alternative(..), Applicative(..), (<$>))
2929import Control.DeepSeq (NFData(rnf))
3030import Control.Monad (MonadPlus(..))
3131import Data.Monoid (Monoid(..))
3232import Prelude hiding (getChar, take, takeWhile)
33−import qualified Data.ByteString.Char8 as B
3433
3534-- | The result of a parse.
36−data Result r = Fail B.ByteString [String] String
37− -- ^ The parse failed. The 'B.ByteString' is the input
38− -- that had not yet been consumed when the failure
39− -- occurred. The @[@'String'@]@ is a list of contexts
40− -- in which the error occurred. The 'String' is the
41− -- message describing the error, if any.
42− | Partial (B.ByteString -> Result r)
43− -- ^ Supply this continuation with more input so that
44− -- the parser can resume. To indicate that no more
45− -- input is available, use an 'B.empty' string.
46− | Done B.ByteString r
47− -- ^ The parse succeeded. The 'B.ByteString' is the
48− -- input that had not yet been consumed (if any) when
49− -- the parse succeeded.
50−
51−instance Show r => Show (Result r) where
52− show (Fail bs stk msg) =
53− "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg
54− show (Partial _) = "Partial _"
55− show (Done bs r) = "Done " ++ show bs ++ " " ++ show r
56−
57−instance (NFData r) => NFData (Result r) where
58− rnf (Fail _ _ _) = ()
35+--
36+-- This type is an instance of 'Functor', where 'fmap' transforms the
37+-- value in a 'Done' result.
38+data IResult t r = Fail t [String] String
39+ -- ^ The parse failed. The 't' is the input that had
40+ -- not yet been consumed when the failure occurred.
41+ -- The @[@'String'@]@ is a list of contexts in which
42+ -- the error occurred. The 'String' is the message
43+ -- describing the error, if any.
44+ | Partial (t -> IResult t r)
45+ -- ^ Supply this continuation with more input so that
46+ -- the parser can resume. To indicate that no more
47+ -- input is available, use an empty string.
48+ | Done t r
49+ -- ^ The parse succeeded. The 't' is the input that
50+ -- had not yet been consumed (if any) when the parse
51+ -- succeeded.
52+
53+instance (Show t, Show r) => Show (IResult t r) where
54+ show (Fail t stk msg) =
55+ "Fail " ++ show t ++ " " ++ show stk ++ " " ++ show msg
56+ show (Partial _) = "Partial _"
57+ show (Done t r) = "Done " ++ show t ++ " " ++ show r
58+
59+instance (NFData t, NFData r) => NFData (IResult t r) where
60+ rnf (Fail t _ _) = rnf t
5961 rnf (Partial _) = ()
60− rnf (Done _ r) = rnf r
62+ rnf (Done t r) = rnf t `seq` rnf r
6163 {-# INLINE rnf #-}
6264
63−fmapR :: (a -> b) -> Result a -> Result b
64−fmapR _ (Fail st stk msg) = Fail st stk msg
65+fmapR :: (a -> b) -> IResult t a -> IResult t b
66+fmapR _ (Fail t stk msg) = Fail t stk msg
6567fmapR f (Partial k) = Partial (fmapR f . k)
66−fmapR f (Done bs r) = Done bs (f r)
68+fmapR f (Done t r) = Done t (f r)
6769
68−instance Functor Result where
70+instance Functor (IResult t) where
6971 fmap = fmapR
7072 {-# INLINE fmap #-}
7173
72−newtype Input = I {unI :: B.ByteString}
73−newtype Added = A {unA :: B.ByteString}
74+newtype Input t = I {unI :: t}
75+newtype Added t = A {unA :: t}
7476
75−-- | The 'Parser' type is a monad.
76−newtype Parser a = Parser {
77− runParser :: forall r. Input -> Added -> More
78− -> Failure r
79− -> Success a r
80− -> Result r
77+-- | The 'Parser' type.
78+--
79+-- This type is an instance of the following classes:
80+--
81+-- * 'Monad', where 'fail' throws an exception (i.e. fails) with an
82+-- error message.
83+--
84+-- * 'Functor' and 'Applicative', which follow the usual definitions.
85+--
86+-- * 'MonadPlus', where 'mzero' fails (with no error message) and
87+-- 'mplus' executes the right-hand parser if the left-hand one
88+-- fails.
89+--
90+-- * 'Alternative', which follows 'MonadPlus'.
91+newtype Parser t a = Parser {
92+ runParser :: forall r. Input t -> Added t -> More
93+ -> Failure t r
94+ -> Success t a r
95+ -> IResult t r
8196 }
8297
83−type Failure r = Input -> Added -> More -> [String] -> String -> Result r
84−type Success a r = Input -> Added -> More -> a -> Result r
98+type Failure t r = Input t -> Added t -> More -> [String] -> String
99+ -> IResult t r
100+type Success t a r = Input t -> Added t -> More -> a -> IResult t r
85101
86102-- | Have we read all available input?
87103data More = Complete | Incomplete
88104 deriving (Eq, Show)
89105
90−addS :: Input -> Added -> More
91− -> Input -> Added -> More
92− -> (Input -> Added -> More -> r) -> r
106+addS :: (Monoid t) =>
107+ Input t -> Added t -> More
108+ -> Input t -> Added t -> More
109+ -> (Input t -> Added t -> More -> r) -> r
93110addS i0 a0 m0 _i1 a1 m1 f =
94− let !i = I (unI i0 +++ unA a1)
95− a = A (unA a0 +++ unA a1)
96− !m = m0 <> m1
111+ let !i = I (unI i0 <> unA a1)
112+ a = A (unA a0 <> unA a1)
113+ !m = m0 <?> m1
97114 in f i a m
98115 where
99− Complete <> _ = Complete
100− _ <> Complete = Complete
101− _ <> _ = Incomplete
116+ Complete <?> _ = Complete
117+ _ <?> Complete = Complete
118+ _ <?> _ = Incomplete
102119{-# INLINE addS #-}
103120
104−bindP :: Parser a -> (a -> Parser b) -> Parser b
121+bindP :: Parser t a -> (a -> Parser t b) -> Parser t b
105122bindP m g =
106123 Parser $ \i0 a0 m0 kf ks -> runParser m i0 a0 m0 kf $
107124 \i1 a1 m1 a -> runParser (g a) i1 a1 m1 kf ks
108125{-# INLINE bindP #-}
109126
110−returnP :: a -> Parser a
127+returnP :: a -> Parser t a
111128returnP a = Parser (\i0 a0 m0 _kf ks -> ks i0 a0 m0 a)
112129{-# INLINE returnP #-}
113130
114−instance Monad Parser where
131+instance Monad (Parser t) where
115132 return = returnP
116133 (>>=) = bindP
117134 fail = failDesc
118135
119−noAdds :: Input -> Added -> More
120− -> (Input -> Added -> More -> r) -> r
121−noAdds i0 _a0 m0 f = f i0 (A B.empty) m0
136+noAdds :: (Monoid t) =>
137+ Input t -> Added t -> More
138+ -> (Input t -> Added t -> More -> r) -> r
139+noAdds i0 _a0 m0 f = f i0 (A mempty) m0
122140{-# INLINE noAdds #-}
123141
124−plus :: Parser a -> Parser a -> Parser a
142+plus :: (Monoid t) => Parser t a -> Parser t a -> Parser t a
125143plus a b = Parser $ \i0 a0 m0 kf ks ->
126144 let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $
127145 \ i2 a2 m2 -> runParser b i2 a2 m2 kf ks
128146 in noAdds i0 a0 m0 $ \i2 a2 m2 -> runParser a i2 a2 m2 kf' ks
129147{-# INLINE plus #-}
130148
131−instance MonadPlus Parser where
149+instance (Monoid t) => MonadPlus (Parser t) where
132150 mzero = failDesc "mzero"
133151 {-# INLINE mzero #-}
134152 mplus = plus
135153
136−fmapP :: (a -> b) -> Parser a -> Parser b
154+fmapP :: (a -> b) -> Parser t a -> Parser t b
137155fmapP p m = Parser $ \i0 a0 m0 f k ->
138156 runParser m i0 a0 m0 f $ \i1 a1 s1 a -> k i1 a1 s1 (p a)
139157{-# INLINE fmapP #-}
140158
141−instance Functor Parser where
159+instance Functor (Parser t) where
142160 fmap = fmapP
143161 {-# INLINE fmap #-}
144162
145−apP :: Parser (a -> b) -> Parser a -> Parser b
163+apP :: Parser t (a -> b) -> Parser t a -> Parser t b
146164apP d e = do
147165 b <- d
148166 a <- e
149167 return (b a)
150168{-# INLINE apP #-}
151169
152−instance Applicative Parser where
170+instance Applicative (Parser t) where
153171 pure = returnP
154172 {-# INLINE pure #-}
155173 (<*>) = apP
@@ -165,23 +183,35 @@ instance Applicative Parser where
165183 {-# INLINE (<*) #-}
166184#endif
167185
168−instance Monoid (Parser a) where
186+instance (Monoid t) => Monoid (Parser t a) where
169187 mempty = failDesc "mempty"
170188 {-# INLINE mempty #-}
171189 mappend = plus
172190 {-# INLINE mappend #-}
173191
174−instance Alternative Parser where
192+instance (Monoid t) => Alternative (Parser t) where
175193 empty = failDesc "empty"
176194 {-# INLINE empty #-}
195+
177196 (<|>) = plus
178197 {-# INLINE (<|>) #-}
179198
180−failDesc :: String -> Parser a
199+ many v = many_v
200+ where many_v = some_v <|> pure []
201+ some_v = (:) <$> v <*> many_v
202+ {-# INLINE many #-}
203+
204+ some v = some_v
205+ where
206+ many_v = some_v <|> pure []
207+ some_v = (:) <$> v <*> many_v
208+ {-# INLINE some #-}
209+
210+failDesc :: String -> Parser t a
181211failDesc err = Parser (\i0 a0 m0 kf _ks -> kf i0 a0 m0 [] msg)
182212 where msg = "Failed reading: " ++ err
183213{-# INLINE failDesc #-}
184214
185−(+++) :: B.ByteString -> B.ByteString -> B.ByteString
186−(+++) = B.append
187−{-# INLINE (+++) #-}
215+(<>) :: (Monoid m) => m -> m -> m
216+(<>) = mappend
217+{-# INLINE (<>) #-}
Data/Attoparsec/Lazy.hs+2−62
@@ -23,67 +23,7 @@
2323
2424module Data.Attoparsec.Lazy
2525 (
26− Result(..)
27− , module Data.Attoparsec
28− -- * Running parsers
29− , parse
30− , parseTest
31− -- ** Result conversion
32− , maybeResult
33− , eitherResult
26+ module Data.Attoparsec.ByteString.Lazy
3427 ) where
3528
36−import Data.ByteString.Lazy.Internal (ByteString(..), chunk)
37−import qualified Data.ByteString as B
38−import qualified Data.Attoparsec as A
39−import Data.Attoparsec hiding (Result(..), eitherResult, maybeResult,
40− parse, parseWith, parseTest)
41−
42−-- | The result of a parse.
43−data Result r = Fail ByteString [String] String
44− -- ^ The parse failed. The 'ByteString' is the input
45− -- that had not yet been consumed when the failure
46− -- occurred. The @[@'String'@]@ is a list of contexts
47− -- in which the error occurred. The 'String' is the
48− -- message describing the error, if any.
49− | Done ByteString r
50− -- ^ The parse succeeded. The 'ByteString' is the
51− -- input that had not yet been consumed (if any) when
52− -- the parse succeeded.
53−
54−instance Show r => Show (Result r) where
55− show (Fail bs stk msg) =
56− "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg
57− show (Done bs r) = "Done " ++ show bs ++ " " ++ show r
58−
59−fmapR :: (a -> b) -> Result a -> Result b
60−fmapR _ (Fail st stk msg) = Fail st stk msg
61−fmapR f (Done bs r) = Done bs (f r)
62−
63−instance Functor Result where
64− fmap = fmapR
65−
66−-- | Run a parser and return its result.
67−parse :: A.Parser a -> ByteString -> Result a
68−parse p s = case s of
69− Chunk x xs -> go (A.parse p x) xs
70− empty -> go (A.parse p B.empty) empty
71− where
72− go (A.Fail x stk msg) ys = Fail (chunk x ys) stk msg
73− go (A.Done x r) ys = Done (chunk x ys) r
74− go (A.Partial k) (Chunk y ys) = go (k y) ys
75− go (A.Partial k) empty = go (k B.empty) empty
76−
77−-- | Run a parser and print its result to standard output.
78−parseTest :: (Show a) => A.Parser a -> ByteString -> IO ()
79−parseTest p s = print (parse p s)
80−
81−-- | Convert a 'Result' value to a 'Maybe' value.
82−maybeResult :: Result r -> Maybe r
83−maybeResult (Done _ r) = Just r
84−maybeResult _ = Nothing
85−
86−-- | Convert a 'Result' value to an 'Either' value.
87−eitherResult :: Result r -> Either String r
88−eitherResult (Done _ r) = Right r
89−eitherResult (Fail _ _ msg) = Left msg
29+import Data.Attoparsec.ByteString.Lazy
Data/Attoparsec/Text.hsnew file+398
@@ -0,0 +1,398 @@
1+{-# LANGUAGE BangPatterns #-}
2+-- |
3+-- Module : Data.Attoparsec.Text
4+-- Copyright : Bryan O'Sullivan 2011
5+-- License : BSD3
6+--
7+-- Maintainer : bos@serpentine.com
8+-- Stability : experimental
9+-- Portability : unknown
10+--
11+-- Simple, efficient combinator parsing for 'Text' strings,
12+-- loosely based on the Parsec library.
13+
14+module Data.Attoparsec.Text
15+ (
16+ -- * Differences from Parsec
17+ -- $parsec
18+
19+ -- * Incremental input
20+ -- $incremental
21+
22+ -- * Performance considerations
23+ -- $performance
24+
25+ -- * Parser types
26+ Parser
27+ , Result
28+ , T.IResult(..)
29+
30+ -- * Running parsers
31+ , parse
32+ , feed
33+ , I.parseOnly
34+ , parseWith
35+ , parseTest
36+
37+ -- ** Result conversion
38+ , maybeResult
39+ , eitherResult
40+
41+ -- * Combinators
42+ , (I.<?>)
43+ , I.try
44+ , module Data.Attoparsec.Combinator
45+
46+ -- * Parsing individual characters
47+ , I.char
48+ , I.anyChar
49+ , I.notChar
50+ , I.satisfy
51+ , I.satisfyWith
52+ , I.skip
53+
54+ -- ** Character classes
55+ , I.inClass
56+ , I.notInClass
57+
58+ -- * Efficient string handling
59+ , I.string
60+ , I.skipWhile
61+ , I.take
62+ , I.takeWhile
63+ , I.takeWhile1
64+ , I.takeTill
65+
66+ -- ** Consume all remaining input
67+ , I.takeText
68+ , I.takeLazyText
69+
70+ -- * Text parsing
71+ , I.endOfLine
72+ , isEndOfLine
73+ , isHorizontalSpace
74+
75+ -- * Numeric parsers
76+ , decimal
77+ , hexadecimal
78+ , signed
79+ , double
80+ , Number(..)
81+ , number
82+ , rational
83+
84+ -- * State observation and manipulation functions
85+ , I.endOfInput
86+ , I.atEnd
87+ ) where
88+
89+import Control.Applicative ((<$>), (*>), (<|>))
90+import Data.Attoparsec.Combinator
91+import Data.Attoparsec.Number (Number(..))
92+import Data.Attoparsec.Text.Internal (Parser, Result, parse, takeWhile1)
93+import Data.Bits (Bits, (.|.), shiftL)
94+import Data.Char (ord)
95+import Data.Int (Int8, Int16, Int32, Int64)
96+import Data.Ratio ((%))
97+import Data.Text (Text)
98+import Data.Word (Word8, Word16, Word32, Word64, Word)
99+import qualified Data.Attoparsec.Internal.Types as T
100+import qualified Data.Attoparsec.Text.Internal as I
101+import qualified Data.Text as T
102+
103+-- $parsec
104+--
105+-- Compared to Parsec 3, Attoparsec makes several tradeoffs. It is
106+-- not intended for, or ideal for, all possible uses.
107+--
108+-- * While Attoparsec can consume input incrementally, Parsec cannot.
109+-- Incremental input is a huge deal for efficient and secure network
110+-- and system programming, since it gives much more control to users
111+-- of the library over matters such as resource usage and the I/O
112+-- model to use.
113+--
114+-- * Much of the performance advantage of Attoparsec is gained via
115+-- high-performance parsers such as 'I.takeWhile' and 'I.string'.
116+-- If you use complicated combinators that return lists of
117+-- characters, there is less performance difference between the two
118+-- libraries.
119+--
120+-- * Unlike Parsec 3, Attoparsec does not support being used as a
121+-- monad transformer.
122+--
123+-- * Attoparsec is specialised to deal only with strict 'Text'
124+-- input. Efficiency concerns rule out both lists and lazy text.
125+-- The usual use for lazy text would be to allow consumption of very
126+-- large input without a large footprint. For this need,
127+-- Attoparsec's incremental input provides an excellent substitute,
128+-- with much more control over when input takes place. If you must
129+-- use lazy text, see the 'Lazy' module, which feeds lazy chunks to
130+-- a regular parser.
131+--
132+-- * Parsec parsers can produce more helpful error messages than
133+-- Attoparsec parsers. This is a matter of focus: Attoparsec avoids
134+-- the extra book-keeping in favour of higher performance.
135+
136+-- $incremental
137+--
138+-- Attoparsec supports incremental input, meaning that you can feed it
139+-- a 'Text' that represents only part of the expected total amount
140+-- of data to parse. If your parser reaches the end of a fragment of
141+-- input and could consume more input, it will suspend parsing and
142+-- return a 'T.Partial' continuation.
143+--
144+-- Supplying the 'T.Partial' continuation with another string will
145+-- resume parsing at the point where it was suspended. You must be
146+-- prepared for the result of the resumed parse to be another
147+-- 'Partial' continuation.
148+--
149+-- To indicate that you have no more input, supply the 'Partial'
150+-- continuation with an 'T.empty' 'Text'.
151+--
152+-- Remember that some parsing combinators will not return a result
153+-- until they reach the end of input. They may thus cause 'T.Partial'
154+-- results to be returned.
155+--
156+-- If you do not need support for incremental input, consider using
157+-- the 'I.parseOnly' function to run your parser. It will never
158+-- prompt for more input.
159+
160+-- $performance
161+--
162+-- If you write an Attoparsec-based parser carefully, it can be
163+-- realistic to expect it to perform within a factor of 2 of a
164+-- hand-rolled C parser (measuring megabytes parsed per second).
165+--
166+-- To actually achieve high performance, there are a few guidelines
167+-- that it is useful to follow.
168+--
169+-- Use the 'Text'-oriented parsers whenever possible,
170+-- e.g. 'I.takeWhile1' instead of 'many1' 'I.anyChar'. There is
171+-- about a factor of 100 difference in performance between the two
172+-- kinds of parser.
173+--
174+-- For very simple character-testing predicates, write them by hand
175+-- instead of using 'I.inClass' or 'I.notInClass'. For instance, both
176+-- of these predicates test for an end-of-line character, but the
177+-- first is much faster than the second:
178+--
179+-- >endOfLine_fast c = c == '\r' || c == '\n'
180+-- >endOfLine_slow = inClass "\r\n"
181+--
182+-- Make active use of benchmarking and profiling tools to measure,
183+-- find the problems with, and improve the performance of your parser.
184+
185+-- | If a parser has returned a 'Partial' result, supply it with more
186+-- input.
187+feed :: Result r -> Text -> Result r
188+feed f@(T.Fail _ _ _) _ = f
189+feed (T.Partial k) d = k d
190+feed (T.Done bs r) d = T.Done (T.append bs d) r
191+{-# INLINE feed #-}
192+
193+-- | Run a parser and print its result to standard output.
194+parseTest :: (Show a) => I.Parser a -> Text -> IO ()
195+parseTest p s = print (parse p s)
196+
197+-- | Run a parser with an initial input string, and a monadic action
198+-- that can supply more input if needed.
199+parseWith :: Monad m =>
200+ (m Text)
201+ -- ^ An action that will be executed to provide the parser
202+ -- with more input, if necessary. The action must return an
203+ -- 'T.empty' string when there is no more input available.
204+ -> I.Parser a
205+ -> Text
206+ -- ^ Initial input for the parser.
207+ -> m (Result a)
208+parseWith refill p s = step $ parse p s
209+ where step (T.Partial k) = (step . k) =<< refill
210+ step r = return r
211+{-# INLINE parseWith #-}
212+
213+-- | Convert a 'Result' value to a 'Maybe' value. A 'Partial' result
214+-- is treated as failure.
215+maybeResult :: Result r -> Maybe r
216+maybeResult (T.Done _ r) = Just r
217+maybeResult _ = Nothing
218+
219+-- | Convert a 'Result' value to an 'Either' value. A 'Partial' result
220+-- is treated as failure.
221+eitherResult :: Result r -> Either String r
222+eitherResult (T.Done _ r) = Right r
223+eitherResult (T.Fail _ _ msg) = Left msg
224+eitherResult _ = Left "Result: incomplete input"
225+
226+-- | A predicate that matches either a carriage return @\'\\r\'@ or
227+-- newline @\'\\n\'@ character.
228+isEndOfLine :: Char -> Bool
229+isEndOfLine c = c == '\n' || c == '\r'
230+{-# INLINE isEndOfLine #-}
231+
232+-- | A predicate that matches either a space @\' \'@ or horizontal tab
233+-- @\'\\t\'@ character.
234+isHorizontalSpace :: Char -> Bool
235+isHorizontalSpace c = c == ' ' || c == '\t'
236+{-# INLINE isHorizontalSpace #-}
237+
238+-- | Parse and decode an unsigned hexadecimal number. The hex digits
239+-- @\'a\'@ through @\'f\'@ may be upper or lower case.
240+--
241+-- This parser does not accept a leading @\"0x\"@ string.
242+hexadecimal :: (Integral a, Bits a) => Parser a
243+hexadecimal = T.foldl' step 0 `fmap` takeWhile1 isHexDigit
244+ where
245+ isHexDigit c = (c >= '0' && c <= '9') ||
246+ (c >= 'a' && c <= 'f') ||
247+ (c >= 'A' && c <= 'F')
248+ step a c | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)
249+ | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)
250+ | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)
251+ where w = ord c
252+{-# SPECIALISE hexadecimal :: Parser Int #-}
253+{-# SPECIALISE hexadecimal :: Parser Int8 #-}
254+{-# SPECIALISE hexadecimal :: Parser Int16 #-}
255+{-# SPECIALISE hexadecimal :: Parser Int32 #-}
256+{-# SPECIALISE hexadecimal :: Parser Int64 #-}
257+{-# SPECIALISE hexadecimal :: Parser Integer #-}
258+{-# SPECIALISE hexadecimal :: Parser Word #-}
259+{-# SPECIALISE hexadecimal :: Parser Word8 #-}
260+{-# SPECIALISE hexadecimal :: Parser Word16 #-}
261+{-# SPECIALISE hexadecimal :: Parser Word32 #-}
262+{-# SPECIALISE hexadecimal :: Parser Word64 #-}
263+
264+-- | Parse and decode an unsigned decimal number.
265+decimal :: Integral a => Parser a
266+decimal = T.foldl' step 0 `fmap` takeWhile1 isDigit
267+ where step a c = a * 10 + fromIntegral (ord c - 48)
268+{-# SPECIALISE decimal :: Parser Int #-}
269+{-# SPECIALISE decimal :: Parser Int8 #-}
270+{-# SPECIALISE decimal :: Parser Int16 #-}
271+{-# SPECIALISE decimal :: Parser Int32 #-}
272+{-# SPECIALISE decimal :: Parser Int64 #-}
273+{-# SPECIALISE decimal :: Parser Integer #-}
274+{-# SPECIALISE decimal :: Parser Word #-}
275+{-# SPECIALISE decimal :: Parser Word8 #-}
276+{-# SPECIALISE decimal :: Parser Word16 #-}
277+{-# SPECIALISE decimal :: Parser Word32 #-}
278+{-# SPECIALISE decimal :: Parser Word64 #-}
279+
280+isDigit :: Char -> Bool
281+isDigit c = c >= '0' && c <= '9'
282+{-# INLINE isDigit #-}
283+
284+-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign
285+-- character.
286+signed :: Num a => Parser a -> Parser a
287+{-# SPECIALISE signed :: Parser Int -> Parser Int #-}
288+{-# SPECIALISE signed :: Parser Int8 -> Parser Int8 #-}
289+{-# SPECIALISE signed :: Parser Int16 -> Parser Int16 #-}
290+{-# SPECIALISE signed :: Parser Int32 -> Parser Int32 #-}
291+{-# SPECIALISE signed :: Parser Int64 -> Parser Int64 #-}
292+{-# SPECIALISE signed :: Parser Integer -> Parser Integer #-}
293+signed p = (negate <$> (I.char '-' *> p))
294+ <|> (I.char '+' *> p)
295+ <|> p
296+
297+-- | Parse a rational number.
298+--
299+-- This parser accepts an optional leading sign character, followed by
300+-- at least one decimal digit. The syntax similar to that accepted by
301+-- the 'read' function, with the exception that a trailing @\'.\'@ or
302+-- @\'e\'@ /not/ followed by a number is not consumed.
303+--
304+-- Examples with behaviour identical to 'read', if you feed an empty
305+-- continuation to the first result:
306+--
307+-- >rational "3" == Done 3.0 ""
308+-- >rational "3.1" == Done 3.1 ""
309+-- >rational "3e4" == Done 30000.0 ""
310+-- >rational "3.1e4" == Done 31000.0, ""
311+
312+-- Examples with behaviour identical to 'read':
313+--
314+-- >rational ".3" == Fail "input does not start with a digit"
315+-- >rational "e3" == Fail "input does not start with a digit"
316+--
317+-- Examples of differences from 'read':
318+--
319+-- >rational "3.foo" == Done 3.0 ".foo"
320+-- >rational "3e" == Done 3.0 "e"
321+--
322+-- This function does not accept string representations of \"NaN\" or
323+-- \"Infinity\".
324+rational :: Fractional a => Parser a
325+{-# SPECIALIZE rational :: Parser Double #-}
326+{-# SPECIALIZE rational :: Parser Float #-}
327+{-# SPECIALIZE rational :: Parser Rational #-}
328+rational = floaty $ \real frac fracDenom -> fromRational $
329+ real % 1 + frac % fracDenom
330+
331+-- | Parse a rational number.
332+--
333+-- The syntax accepted by this parser is the same as for 'rational'.
334+--
335+-- /Note/: This function is almost ten times faster than 'rational',
336+-- but is slightly less accurate.
337+--
338+-- The 'Double' type supports about 16 decimal places of accuracy.
339+-- For 94.2% of numbers, this function and 'rational' give identical
340+-- results, but for the remaining 5.8%, this function loses precision
341+-- around the 15th decimal place. For 0.001% of numbers, this
342+-- function will lose precision at the 13th or 14th decimal place.
343+--
344+-- This function does not accept string representations of \"NaN\" or
345+-- \"Infinity\".
346+double :: Parser Double
347+double = floaty asDouble
348+
349+asDouble :: Integer -> Integer -> Integer -> Double
350+asDouble real frac fracDenom =
351+ fromIntegral real + fromIntegral frac / fromIntegral fracDenom
352+{-# INLINE asDouble #-}
353+
354+-- | Parse a number, attempting to preserve both speed and precision.
355+--
356+-- The syntax accepted by this parser is the same as for 'rational'.
357+--
358+-- /Note/: This function is almost ten times faster than 'rational'.
359+-- On integral inputs, it gives perfectly accurate answers, and on
360+-- floating point inputs, it is slightly less accurate than
361+-- 'rational'.
362+--
363+-- This function does not accept string representations of \"NaN\" or
364+-- \"Infinity\".
365+number :: Parser Number
366+number = floaty $ \real frac fracDenom ->
367+ if frac == 0 && fracDenom == 0
368+ then I real
369+ else D (asDouble real frac fracDenom)
370+{-# INLINE number #-}
371+
372+data T = T !Integer !Int
373+
374+floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
375+{-# INLINE floaty #-}
376+floaty f = do
377+ !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>
378+ return True
379+ real <- decimal
380+ let tryFraction = do
381+ _ <- I.satisfy (=='.')
382+ ds <- I.takeWhile isDigit
383+ case I.parseOnly decimal ds of
384+ Right n -> return $ T n (T.length ds)
385+ _ -> fail "no digits after decimal"
386+ T fraction fracDigits <- tryFraction <|> return (T 0 0)
387+ let e c = c == 'e' || c == 'E'
388+ power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
389+ let n = if fracDigits == 0
390+ then if power == 0
391+ then fromIntegral real
392+ else fromIntegral real * (10 ^^ power)
393+ else if power == 0
394+ then f real fraction (10 ^ fracDigits)
395+ else f real fraction (10 ^ fracDigits) * (10 ^^ power)
396+ return $ if positive
397+ then n
398+ else -n
Data/Attoparsec/Text/FastSet.hsnew file+63
@@ -0,0 +1,63 @@
1+-----------------------------------------------------------------------------
2+-- |
3+-- Module : Data.Attoparsec.FastSet
4+-- Copyright : Felipe Lessa 2010, Bryan O'Sullivan 2008
5+-- License : BSD3
6+--
7+-- Maintainer : felipe.lessa@gmail.com
8+-- Stability : experimental
9+-- Portability : unknown
10+--
11+-- Fast set membership tests for 'Char' values. The set
12+-- representation is unboxed for efficiency. We test for
13+-- membership using a binary search.
14+--
15+-----------------------------------------------------------------------------
16+module Data.Attoparsec.Text.FastSet
17+ (
18+ -- * Data type
19+ FastSet
20+ -- * Construction
21+ , fromList
22+ , set
23+ -- * Lookup
24+ , member
25+ -- * Handy interface
26+ , charClass
27+ ) where
28+
29+import Data.List (sort)
30+import qualified Data.Array.Base as AB
31+import qualified Data.Array.Unboxed as A
32+import qualified Data.Text as T
33+
34+newtype FastSet = FastSet (A.UArray Int Char)
35+ deriving (Eq, Ord, Show)
36+
37+-- | Create a set.
38+set :: T.Text -> FastSet
39+set t = mkSet (T.length t) (sort $ T.unpack t)
40+
41+fromList :: [Char] -> FastSet
42+fromList cs = mkSet (length cs) (sort cs)
43+
44+mkSet :: Int -> [Char] -> FastSet
45+mkSet l = FastSet . A.listArray (0,l-1)
46+
47+-- | Check the set for membership.
48+member :: Char -> FastSet -> Bool
49+member c (FastSet a) = uncurry search (A.bounds a)
50+ where search lo hi
51+ | hi < lo = False
52+ | otherwise =
53+ let mid = (lo + hi) `div` 2
54+ in case compare c (AB.unsafeAt a mid) of
55+ GT -> search (mid + 1) hi
56+ LT -> search lo (mid - 1)
57+ _ -> True
58+
59+charClass :: String -> FastSet
60+charClass = fromList . go
61+ where go (a:'-':b:xs) = [a..b] ++ go xs
62+ go (x:xs) = x : go xs
63+ go _ = ""
Data/Attoparsec/Text/Internal.hsnew file+402
@@ -0,0 +1,402 @@
1+{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings, RecordWildCards #-}
2+-- |
3+-- Module : Data.Attoparsec.Text.Internal
4+-- Copyright : Bryan O'Sullivan 2011
5+-- License : BSD3
6+--
7+-- Maintainer : bos@serpentine.com
8+-- Stability : experimental
9+-- Portability : unknown
10+--
11+-- Simple, efficient parser combinators for 'T.Text' strings, loosely
12+-- based on the Parsec library.
13+
14+module Data.Attoparsec.Text.Internal
15+ (
16+ -- * Parser types
17+ Parser
18+ , Result
19+
20+ -- * Running parsers
21+ , parse
22+ , parseOnly
23+
24+ -- * Combinators
25+ , (<?>)
26+ , try
27+ , module Data.Attoparsec.Combinator
28+
29+ -- * Parsing individual characters
30+ , satisfy
31+ , satisfyWith
32+ , anyChar
33+ , skip
34+ , char
35+ , notChar
36+
37+ -- ** Character classes
38+ , inClass
39+ , notInClass
40+
41+ -- * Efficient string handling
42+ , skipWhile
43+ , string
44+ , stringTransform
45+ , take
46+ , takeWhile
47+ , takeWhile1
48+ , takeTill
49+
50+ -- ** Consume all remaining input
51+ , takeText
52+ , takeLazyText
53+
54+ -- * State observation and manipulation functions
55+ , endOfInput
56+ , atEnd
57+ , ensure
58+
59+ -- * Utilities
60+ , endOfLine
61+ ) where
62+
63+import Control.Applicative ((<|>), (<$>))
64+import Control.Monad (when)
65+import Data.Attoparsec.Combinator
66+import Data.Attoparsec.Internal.Types hiding (Parser, Input, Added, Failure, Success)
67+import Data.Text (Text)
68+import Prelude hiding (getChar, take, takeWhile)
69+import qualified Data.Attoparsec.Internal.Types as T
70+import qualified Data.Attoparsec.Text.FastSet as Set
71+import qualified Data.Text as T
72+import qualified Data.Text.Lazy as L
73+
74+type Parser a = T.Parser Text a
75+type Result a = IResult Text a
76+type Input = T.Input Text
77+type Added = T.Added Text
78+type Failure r = T.Failure Text r
79+type Success a r = T.Success Text a r
80+
81+-- | If at least @n@ characters of input are available, return the
82+-- current input, otherwise fail.
83+ensure :: Int -> Parser Text
84+ensure !n = T.Parser $ \i0 a0 m0 kf ks ->
85+ if T.length (unI i0) >= n
86+ then ks i0 a0 m0 (unI i0)
87+ else runParser (demandInput >> ensure n) i0 a0 m0 kf ks
88+
89+-- | Ask for input. If we receive any, pass it to a success
90+-- continuation, otherwise to a failure continuation.
91+prompt :: Input -> Added -> More
92+ -> (Input -> Added -> More -> Result r)
93+ -> (Input -> Added -> More -> Result r)
94+ -> Result r
95+prompt i0 a0 _m0 kf ks = Partial $ \s ->
96+ if T.null s
97+ then kf i0 a0 Complete
98+ else ks (I (unI i0 <> s)) (A (unA a0 <> s)) Incomplete
99+
100+-- | Immediately demand more input via a 'Partial' continuation
101+-- result.
102+demandInput :: Parser ()
103+demandInput = T.Parser $ \i0 a0 m0 kf ks ->
104+ if m0 == Complete
105+ then kf i0 a0 m0 ["demandInput"] "not enough input"
106+ else let kf' i a m = kf i a m ["demandInput"] "not enough input"
107+ ks' i a m = ks i a m ()
108+ in prompt i0 a0 m0 kf' ks'
109+
110+-- | This parser always succeeds. It returns 'True' if any input is
111+-- available either immediately or on demand, and 'False' if the end
112+-- of all input has been reached.
113+wantInput :: Parser Bool
114+wantInput = T.Parser $ \i0 a0 m0 _kf ks ->
115+ case () of
116+ _ | not (T.null (unI i0)) -> ks i0 a0 m0 True
117+ | m0 == Complete -> ks i0 a0 m0 False
118+ | otherwise -> let kf' i a m = ks i a m False
119+ ks' i a m = ks i a m True
120+ in prompt i0 a0 m0 kf' ks'
121+
122+get :: Parser Text
123+get = T.Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0)
124+
125+put :: Text -> Parser ()
126+put s = T.Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 ()
127+
128+-- | Attempt a parse, and if it fails, rewind the input so that no
129+-- input appears to have been consumed.
130+--
131+-- This combinator is provided for compatibility with Parsec.
132+-- Attoparsec parsers always backtrack on failure.
133+try :: Parser a -> Parser a
134+try p = p
135+{-# INLINE try #-}
136+
137+unsafeHead :: Text -> Char
138+unsafeHead = T.head
139+
140+unsafeTail :: Text -> Text
141+unsafeTail = T.tail
142+
143+unsafeTake :: Int -> Text -> Text
144+unsafeTake = T.take
145+
146+unsafeDrop :: Int -> Text -> Text
147+unsafeDrop = T.drop
148+
149+-- | The parser @satisfy p@ succeeds for any character for which the
150+-- predicate @p@ returns 'True'. Returns the character that is
151+-- actually parsed.
152+--
153+-- >digit = satisfy isDigit
154+-- > where isDigit c = c >= '0' && c <= '9'
155+satisfy :: (Char -> Bool) -> Parser Char
156+satisfy p = do
157+ s <- ensure 1
158+ let w = unsafeHead s
159+ if p w
160+ then put (unsafeTail s) >> return w
161+ else fail "satisfy"
162+
163+-- | The parser @skip p@ succeeds for any character for which the
164+-- predicate @p@ returns 'True'.
165+--
166+-- >skipDigit = skip isDigit
167+-- > where isDigit c = c >= '0' && c <= '9'
168+skip :: (Char -> Bool) -> Parser ()
169+skip p = do
170+ s <- ensure 1
171+ if p (unsafeHead s)
172+ then put (unsafeTail s)
173+ else fail "skip"
174+
175+-- | The parser @satisfyWith f p@ transforms a character, and succeeds
176+-- if the predicate @p@ returns 'True' on the transformed value. The
177+-- parser returns the transformed character that was parsed.
178+satisfyWith :: (Char -> a) -> (a -> Bool) -> Parser a
179+satisfyWith f p = do
180+ s <- ensure 1
181+ let c = f (unsafeHead s)
182+ if p c
183+ then put (unsafeTail s) >> return c
184+ else fail "satisfyWith"
185+
186+-- | Consume @n@ characters of input, but succeed only if the
187+-- predicate returns 'True'.
188+takeWith :: Int -> (Text -> Bool) -> Parser Text
189+takeWith n p = do
190+ s <- ensure n
191+ let h = unsafeTake n s
192+ t = unsafeDrop n s
193+ if p h
194+ then put t >> return h
195+ else fail "takeWith"
196+
197+-- | Consume exactly @n@ characters of input.
198+take :: Int -> Parser Text
199+take n = takeWith n (const True)
200+{-# INLINE take #-}
201+
202+-- | @string s@ parses a sequence of characters that identically match
203+-- @s@. Returns the parsed string (i.e. @s@). This parser consumes no
204+-- input if it fails (even if a partial match).
205+--
206+-- /Note/: The behaviour of this parser is different to that of the
207+-- similarly-named parser in Parsec, as this one is all-or-nothing.
208+-- To illustrate the difference, the following parser will fail under
209+-- Parsec given an input of @"for"@:
210+--
211+-- >string "foo" <|> string "for"
212+--
213+-- The reason for its failure is that that the first branch is a
214+-- partial match, and will consume the letters @\'f\'@ and @\'o\'@
215+-- before failing. In Attoparsec, the above parser will /succeed/ on
216+-- that input, because the failed first branch will consume nothing.
217+string :: Text -> Parser Text
218+string s = takeWith (T.length s) (==s)
219+{-# INLINE string #-}
220+
221+stringTransform :: (Text -> Text) -> Text
222+ -> Parser Text
223+stringTransform f s = takeWith (T.length s) ((==f s) . f)
224+{-# INLINE stringTransform #-}
225+
226+-- | Skip past input for as long as the predicate returns 'True'.
227+skipWhile :: (Char -> Bool) -> Parser ()
228+skipWhile p = go
229+ where
230+ go = do
231+ t <- T.dropWhile p <$> get
232+ put t
233+ when (T.null t) $ do
234+ input <- wantInput
235+ when input go
236+{-# INLINE skipWhile #-}
237+
238+-- | Consume input as long as the predicate returns 'False'
239+-- (i.e. until it returns 'True'), and return the consumed input.
240+--
241+-- This parser does not fail. It will return an empty string if the
242+-- predicate returns 'True' on the first character of input.
243+--
244+-- /Note/: Because this parser does not fail, do not use it with
245+-- combinators such as 'many', because such parsers loop until a
246+-- failure occurs. Careless use will thus result in an infinite loop.
247+takeTill :: (Char -> Bool) -> Parser Text
248+takeTill p = takeWhile (not . p)
249+{-# INLINE takeTill #-}
250+
251+-- | Consume input as long as the predicate returns 'True', and return
252+-- the consumed input.
253+--
254+-- This parser does not fail. It will return an empty string if the
255+-- predicate returns 'False' on the first character of input.
256+--
257+-- /Note/: Because this parser does not fail, do not use it with
258+-- combinators such as 'many', because such parsers loop until a
259+-- failure occurs. Careless use will thus result in an infinite loop.
260+takeWhile :: (Char -> Bool) -> Parser Text
261+takeWhile p = (T.concat . reverse) `fmap` go []
262+ where
263+ go acc = do
264+ (h,t) <- T.span p <$> get
265+ put t
266+ if T.null t
267+ then do
268+ input <- wantInput
269+ if input
270+ then go (h:acc)
271+ else return (h:acc)
272+ else return (h:acc)
273+
274+takeRest :: Parser [Text]
275+takeRest = go []
276+ where
277+ go acc = do
278+ input <- wantInput
279+ if input
280+ then do
281+ s <- get
282+ put T.empty
283+ go (s:acc)
284+ else return (reverse acc)
285+
286+-- | Consume all remaining input and return it as a single string.
287+takeText :: Parser Text
288+takeText = T.concat `fmap` takeRest
289+
290+-- | Consume all remaining input and return it as a single string.
291+takeLazyText :: Parser L.Text
292+takeLazyText = L.fromChunks `fmap` takeRest
293+
294+-- | Consume input as long as the predicate returns 'True', and return
295+-- the consumed input.
296+--
297+-- This parser requires the predicate to succeed on at least one
298+-- character of input: it will fail if the predicate never returns
299+-- 'True' or if there is no input left.
300+takeWhile1 :: (Char -> Bool) -> Parser Text
301+takeWhile1 p = do
302+ (`when` demandInput) =<< T.null <$> get
303+ (h,t) <- T.span p <$> get
304+ when (T.null h) $ fail "takeWhile1"
305+ put t
306+ if T.null t
307+ then (h<>) `fmap` takeWhile p
308+ else return h
309+
310+-- | Match any character in a set.
311+--
312+-- >vowel = inClass "aeiou"
313+--
314+-- Range notation is supported.
315+--
316+-- >halfAlphabet = inClass "a-nA-N"
317+--
318+-- To add a literal @\'-\'@ to a set, place it at the beginning or end
319+-- of the string.
320+inClass :: String -> Char -> Bool
321+inClass s = (`Set.member` mySet)
322+ where mySet = Set.charClass s
323+ {-# NOINLINE mySet #-}
324+{-# INLINE inClass #-}
325+
326+-- | Match any character not in a set.
327+notInClass :: String -> Char -> Bool
328+notInClass s = not . inClass s
329+{-# INLINE notInClass #-}
330+
331+-- | Match any character.
332+anyChar :: Parser Char
333+anyChar = satisfy $ const True
334+{-# INLINE anyChar #-}
335+
336+-- | Match a specific character.
337+char :: Char -> Parser Char
338+char c = satisfy (== c) <?> show c
339+{-# INLINE char #-}
340+
341+-- | Match any character except the given one.
342+notChar :: Char -> Parser Char
343+notChar c = satisfy (/= c) <?> "not " ++ show c
344+{-# INLINE notChar #-}
345+
346+-- | Match only if all input has been consumed.
347+endOfInput :: Parser ()
348+endOfInput = T.Parser $ \i0 a0 m0 kf ks ->
349+ if T.null (unI i0)
350+ then if m0 == Complete
351+ then ks i0 a0 m0 ()
352+ else let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $
353+ \ i2 a2 m2 -> ks i2 a2 m2 ()
354+ ks' i1 a1 m1 _ = addS i0 a0 m0 i1 a1 m1 $
355+ \ i2 a2 m2 -> kf i2 a2 m2 []
356+ "endOfInput"
357+ in runParser demandInput i0 a0 m0 kf' ks'
358+ else kf i0 a0 m0 [] "endOfInput"
359+
360+-- | Return an indication of whether the end of input has been
361+-- reached.
362+atEnd :: Parser Bool
363+atEnd = not <$> wantInput
364+{-# INLINE atEnd #-}
365+
366+-- | Match either a single newline character @\'\\n\'@, or a carriage
367+-- return followed by a newline character @\"\\r\\n\"@.
368+endOfLine :: Parser ()
369+endOfLine = (char '\n' >> return ()) <|> (string "\r\n" >> return ())
370+
371+--- | Name the parser, in case failure occurs.
372+(<?>) :: Parser a
373+ -> String -- ^ the name to use if parsing fails
374+ -> Parser a
375+p <?> msg0 = T.Parser $ \i0 a0 m0 kf ks ->
376+ let kf' i a m strs msg = kf i a m (msg0:strs) msg
377+ in runParser p i0 a0 m0 kf' ks
378+{-# INLINE (<?>) #-}
379+infix 0 <?>
380+
381+-- | Terminal failure continuation.
382+failK :: Failure a
383+failK i0 _a0 _m0 stack msg = Fail (unI i0) stack msg
384+{-# INLINE failK #-}
385+
386+-- | Terminal success continuation.
387+successK :: Success a a
388+successK i0 _a0 _m0 a = Done (unI i0) a
389+{-# INLINE successK #-}
390+
391+-- | Run a parser.
392+parse :: Parser a -> Text -> Result a
393+parse m s = runParser m (I s) (A T.empty) Incomplete failK successK
394+{-# INLINE parse #-}
395+
396+-- | Run a parser that cannot be resupplied via a 'Partial' result.
397+parseOnly :: Parser a -> Text -> Either String a
398+parseOnly m s = case runParser m (I s) (A T.empty) Complete failK successK of
399+ Fail _ _ err -> Left err
400+ Done _ a -> Right a
401+ _ -> error "parseOnly: impossible error!"
402+{-# INLINE parseOnly #-}
Data/Attoparsec/Text/Lazy.hsnew file+90
@@ -0,0 +1,90 @@
1+-- |
2+-- Module : Data.Attoparsec.Text.Lazy
3+-- Copyright : Bryan O'Sullivan 2011
4+-- License : BSD3
5+--
6+-- Maintainer : bos@serpentine.com
7+-- Stability : experimental
8+-- Portability : unknown
9+--
10+-- Simple, efficient combinator parsing for lazy 'Text'
11+-- strings, loosely based on the Parsec library.
12+--
13+-- This is essentially the same code as in the 'Data.Attoparsec.Text'
14+-- module, only with a 'parse' function that can consume a lazy
15+-- 'Text' incrementally, and a 'Result' type that does not allow
16+-- more input to be fed in. Think of this as suitable for use with a
17+-- lazily read file, e.g. via 'L.readFile' or 'L.hGetContents'.
18+--
19+-- Behind the scenes, strict 'T.Text' values are still used
20+-- internally to store parser input and manipulate it efficiently.
21+-- High-performance parsers such as 'string' still expect strict
22+-- 'T.Text' parameters.
23+
24+module Data.Attoparsec.Text.Lazy
25+ (
26+ Result(..)
27+ , module Data.Attoparsec.Text
28+ -- * Running parsers
29+ , parse
30+ , parseTest
31+ -- ** Result conversion
32+ , maybeResult
33+ , eitherResult
34+ ) where
35+
36+import Data.Text.Lazy.Internal (Text(..), chunk)
37+import qualified Data.Attoparsec.Internal.Types as T
38+import qualified Data.Attoparsec.Text as A
39+import qualified Data.Text as T
40+import Data.Attoparsec.Text hiding (IResult(..), Result, eitherResult,
41+ maybeResult, parse, parseWith, parseTest)
42+
43+-- | The result of a parse.
44+data Result r = Fail Text [String] String
45+ -- ^ The parse failed. The 'ByteString' is the input
46+ -- that had not yet been consumed when the failure
47+ -- occurred. The @[@'String'@]@ is a list of contexts
48+ -- in which the error occurred. The 'String' is the
49+ -- message describing the error, if any.
50+ | Done Text r
51+ -- ^ The parse succeeded. The 'ByteString' is the
52+ -- input that had not yet been consumed (if any) when
53+ -- the parse succeeded.
54+
55+instance Show r => Show (Result r) where
56+ show (Fail bs stk msg) =
57+ "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg
58+ show (Done bs r) = "Done " ++ show bs ++ " " ++ show r
59+
60+fmapR :: (a -> b) -> Result a -> Result b
61+fmapR _ (Fail st stk msg) = Fail st stk msg
62+fmapR f (Done bs r) = Done bs (f r)
63+
64+instance Functor Result where
65+ fmap = fmapR
66+
67+-- | Run a parser and return its result.
68+parse :: A.Parser a -> Text -> Result a
69+parse p s = case s of
70+ Chunk x xs -> go (A.parse p x) xs
71+ empty -> go (A.parse p T.empty) empty
72+ where
73+ go (T.Fail x stk msg) ys = Fail (chunk x ys) stk msg
74+ go (T.Done x r) ys = Done (chunk x ys) r
75+ go (T.Partial k) (Chunk y ys) = go (k y) ys
76+ go (T.Partial k) empty = go (k T.empty) empty
77+
78+-- | Run a parser and print its result to standard output.
79+parseTest :: (Show a) => A.Parser a -> Text -> IO ()
80+parseTest p s = print (parse p s)
81+
82+-- | Convert a 'Result' value to a 'Maybe' value.
83+maybeResult :: Result r -> Maybe r
84+maybeResult (Done _ r) = Just r
85+maybeResult _ = Nothing
86+
87+-- | Convert a 'Result' value to an 'Either' value.
88+eitherResult :: Result r -> Either String r
89+eitherResult (Done _ r) = Right r
90+eitherResult (Fail _ _ msg) = Left msg
Data/Attoparsec/Types.hsnew file+19
@@ -0,0 +1,19 @@
1+-- |
2+-- Module : Data.Attoparsec.Types
3+-- Copyright : Bryan O'Sullivan 2011
4+-- License : BSD3
5+--
6+-- Maintainer : bos@serpentine.com
7+-- Stability : experimental
8+-- Portability : unknown
9+--
10+-- Simple, efficient parser combinators for strings, loosely based on
11+-- the Parsec library.
12+
13+module Data.Attoparsec.Types
14+ (
15+ Parser
16+ , IResult(..)
17+ ) where
18+
19+import Data.Attoparsec.Internal.Types (Parser(..), IResult(..))
attoparsec.cabal+16−6
@@ -1,12 +1,12 @@
11name: attoparsec
2−version: 0.9.1.2
2+version: 0.10.0.0
33license: BSD3
44license-file: LICENSE
55category: Text, Parsing
66author: Bryan O'Sullivan <bos@serpentine.com>
77maintainer: Bryan O'Sullivan <bos@serpentine.com>
88stability: experimental
9−tested-with: GHC == 6.10.4, GHC == 6.12.3, GHC == 7.0.3
9+tested-with: GHC == 6.12.3, GHC == 7.0.3, GHC == 7.2.1
1010synopsis: Fast combinator parsing for bytestrings
1111cabal-version: >= 1.8
1212homepage: https://github.com/bos/attoparsec
@@ -36,21 +36,31 @@ Flag developer
3636 Default: False
3737
3838library
39− build-depends: base >= 3 && < 5,
39+ build-depends: array,
40+ base >= 3 && < 5,
4041 bytestring,
4142 containers,
42− deepseq
43+ deepseq,
44+ text >= 0.11.1.5
4345
4446 extensions: CPP
4547 exposed-modules: Data.Attoparsec
48+ Data.Attoparsec.ByteString
49+ Data.Attoparsec.ByteString.Char8
50+ Data.Attoparsec.ByteString.Lazy
4651 Data.Attoparsec.Char8
4752 Data.Attoparsec.Combinator
48− Data.Attoparsec.FastSet
4953 Data.Attoparsec.Lazy
5054 Data.Attoparsec.Number
55+ Data.Attoparsec.Text
56+ Data.Attoparsec.Text.Lazy
57+ Data.Attoparsec.Types
5158 Data.Attoparsec.Zepto
52− other-modules: Data.Attoparsec.Internal
59+ other-modules: Data.Attoparsec.ByteString.FastSet
60+ Data.Attoparsec.ByteString.Internal
5361 Data.Attoparsec.Internal.Types
62+ Data.Attoparsec.Text.FastSet
63+ Data.Attoparsec.Text.Internal
5464 ghc-options: -Wall
5565
5666 if flag(developer)
tests/QC.hs+14−12
@@ -1,20 +1,24 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# OPTIONS_GHC -fno-warn-orphans #-}
23module Main (main) where
34
5+import Control.Applicative ((<$>))
46import Prelude hiding (takeWhile)
5−import QCSupport
67import Test.Framework (defaultMain, testGroup)
78import Test.Framework.Providers.QuickCheck2 (testProperty)
8−import Test.QuickCheck hiding (NonEmpty)
9+import Test.QuickCheck
910import qualified Data.Attoparsec as P
1011import qualified Data.ByteString as B
12+import qualified Data.ByteString as S
13+import qualified Data.ByteString.Lazy as L
1114
12−-- Make sure that structures whose types claim they are non-empty
13−-- really are.
15+instance Arbitrary S.ByteString where
16+ arbitrary = S.pack <$> arbitrary
1417
15−nonEmptyList l = length (nonEmpty l) > 0
16− where types = l :: NonEmpty [Int]
17−nonEmptyBS l = B.length (nonEmpty l) > 0
18+instance Arbitrary L.ByteString where
19+ arbitrary = sized $ \n -> resize (round (sqrt (toEnum n :: Double)))
20+ ((L.fromChunks . map (S.pack . nonEmpty)) <$> arbitrary)
21+ where nonEmpty (NonEmpty a) = a
1822
1923-- Naming.
2024
@@ -40,10 +44,11 @@ anyWord8 s = maybeP P.anyWord8 s == if B.null s
4044 then Nothing
4145 else Just (B.head s)
4246
43−notWord8 w (NonEmpty s) = maybeP (P.notWord8 w) s == if v == w
47+notWord8 w (NonEmpty s) = maybeP (P.notWord8 w) bs == if v == w
4448 then Nothing
4549 else Just v
46− where v = B.head s
50+ where v = B.head bs
51+ bs = B.pack s
4752
4853string s = maybeP (P.string s) s == Just s
4954
@@ -87,8 +92,6 @@ main = defaultMain tests
8792
8893tests = [
8994 testGroup "fnord" [
90− testProperty "nonEmptyList" nonEmptyList,
91− testProperty "nonEmptyBS" nonEmptyBS,
9295 testProperty "satisfy" satisfy,
9396 testProperty "word8" word8,
9497 testProperty "notWord8" notWord8,
@@ -102,5 +105,4 @@ tests = [
102105 testProperty "takeTill" takeTill,
103106 testProperty "endOfInput" endOfInput
104107 ]
105−
106108 ]
tests/QCSupport.hsdeleted−39
@@ -1,39 +0,0 @@
1−{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
2−module QCSupport
3− (
4− NonEmpty(..)
5− ) where
6−
7−import Control.Applicative
8−import Data.Attoparsec
9−import Data.Word (Word8)
10−import Test.QuickCheck hiding (NonEmpty)
11−import qualified Data.ByteString as S
12−import qualified Data.ByteString.Lazy as L
13−
14−newtype NonEmpty a = NonEmpty { nonEmpty :: a }
15− deriving (Eq, Ord, Read, Show)
16−
17−instance Functor NonEmpty where
18− fmap f (NonEmpty a) = NonEmpty (f a)
19−
20−instance Applicative NonEmpty where
21− NonEmpty f <*> NonEmpty a = NonEmpty (f a)
22− pure a = NonEmpty a
23−
24−instance Arbitrary a => Arbitrary (NonEmpty [a]) where
25− arbitrary = NonEmpty <$> sized (\n -> choose (1,n+1) >>= vector)
26−
27−instance Arbitrary S.ByteString where
28− arbitrary = S.pack <$> arbitrary
29−
30−instance Arbitrary (NonEmpty S.ByteString) where
31− arbitrary = fmap S.pack <$> arbitrary
32−
33−instance Arbitrary L.ByteString where
34− arbitrary = sized $ \n -> resize (round (sqrt (toEnum n :: Double)))
35− ((L.fromChunks . map nonEmpty) <$> arbitrary)
36−
37−instance Arbitrary (NonEmpty L.ByteString) where
38− arbitrary = sized $ \n -> resize (round (sqrt (toEnum n :: Double)))
39− (fmap (L.fromChunks . map nonEmpty) <$> arbitrary)