git.iko.soy/typeable/attoparsec
on master help sign in
Rework string for ByteString to fail early (gh-97)
633e189Bryan O'Sullivan
Data/Attoparsec/ByteString/Internal.hs+29−1
@@ -170,9 +170,37 @@ take n = takeWith n (const True)
170-- before failing. In attoparsec, the above parser will /succeed/ on
170-- before failing. In attoparsec, the above parser will /succeed/ on
171-- that input, because the failed first branch will consume nothing.
171-- that input, because the failed first branch will consume nothing.
172string :: ByteString -> Parser ByteString
172string :: ByteString -> Parser ByteString
173+string s = T.Parser $ \t pos more lose succ ->
173−string s = takeWith (B.length s) (==s)
174+ let n = B.length s
175+ in if lengthAtLeast pos n t
176+ then if s == substring pos (Pos n) t
177+ then succ t (pos + Pos n) more s
178+ else lose t pos more [] "string"
179+ else let t' = Buf.unsafeDrop (fromPos pos) t
180+ in if t' `B.isPrefixOf` s
181+ then stringSuspended s (B.drop (B.length t') s)
182+ t pos more lose succ
183+ else lose t pos more [] "string"
174{-# INLINE string #-}
184{-# INLINE string #-}
175
185
186+stringSuspended :: ByteString -> ByteString -> Buffer -> Pos -> More
187+ -> Failure r
188+ -> Success ByteString r
189+ -> Result r
190+stringSuspended s0 s t pos more lose succ =
191+ runParser (demandInput_ >>= go) t pos more lose succ
192+ where go s' = T.Parser $ \t' pos' more' lose' succ' ->
193+ let m = B.length s
194+ n = B.length s'
195+ in if n >= m
196+ then if B.unsafeTake m s' == s
197+ then succ' t' (pos' + Pos (B.length s0)) more' s0
198+ else lose' t' pos' more' [] "string"
199+ else if s' == B.unsafeTake n s
200+ then stringSuspended s0 (B.unsafeDrop n s)
201+ t' pos' more' lose' succ'
202+ else lose' t' pos' more' [] "string"
203+
176stringTransform :: (ByteString -> ByteString) -> ByteString
204stringTransform :: (ByteString -> ByteString) -> ByteString
177 -> Parser ByteString
205 -> Parser ByteString
178stringTransform f s = takeWith (B.length s) ((==f s) . f)
206stringTransform f s = takeWith (B.length s) ((==f s) . f)
Data/Attoparsec/Internal.hs+17−3
@@ -15,6 +15,7 @@ module Data.Attoparsec.Internal
15 ( compareResults
15 ( compareResults
16 , prompt
16 , prompt
17 , demandInput
17 , demandInput
18+ , demandInput_
18 , wantInput
19 , wantInput
19 , endOfInput
20 , endOfInput
20 , atEnd
21 , atEnd
@@ -40,8 +41,8 @@ compareResults (Done t0 r0) (Done t1 r1) =
40compareResults (Partial _) (Partial _) = Nothing
41compareResults (Partial _) (Partial _) = Nothing
41compareResults _ _ = Just False
42compareResults _ _ = Just False
42
43
43−-- | Ask for input. If we receive any, pass it to a success
44+-- | Ask for input. If we receive any, pass the augmented input to a
44−-- continuation, otherwise to a failure continuation.
45+-- success continuation, otherwise to a failure continuation.
45prompt :: Chunk t
46prompt :: Chunk t
46 => State t -> Pos -> More
47 => State t -> Pos -> More
47 -> (State t -> Pos -> More -> IResult t r)
48 -> (State t -> Pos -> More -> IResult t r)
@@ -68,12 +69,25 @@ demandInput :: Chunk t => Parser t ()
68demandInput = Parser $ \t pos more lose succ ->
69demandInput = Parser $ \t pos more lose succ ->
69 case more of
70 case more of
70 Complete -> lose t pos more [] "not enough input"
71 Complete -> lose t pos more [] "not enough input"
71− _ -> let lose' t' pos' more' = lose t' pos' more' [] "not enough input"
72+ _ -> let lose' _ pos' more' = lose t pos' more' [] "not enough input"
72 succ' t' pos' more' = succ t' pos' more' ()
73 succ' t' pos' more' = succ t' pos' more' ()
73 in prompt t pos more lose' succ'
74 in prompt t pos more lose' succ'
74{-# SPECIALIZE demandInput :: Parser ByteString () #-}
75{-# SPECIALIZE demandInput :: Parser ByteString () #-}
75{-# SPECIALIZE demandInput :: Parser Text () #-}
76{-# SPECIALIZE demandInput :: Parser Text () #-}
76
77
78+-- | Immediately demand more input via a 'Partial' continuation
79+-- result. Return the new input.
80+demandInput_ :: Chunk t => Parser t t
81+demandInput_ = Parser $ \t pos more lose succ ->
82+ case more of
83+ Complete -> lose t pos more [] "not enough input"
84+ _ -> Partial $ \s ->
85+ if nullChunk s
86+ then lose t pos Complete [] "not enough input"
87+ else succ (pappendChunk t s) pos more s
88+{-# SPECIALIZE demandInput_ :: Parser ByteString ByteString #-}
89+{-# SPECIALIZE demandInput_ :: Parser Text Text #-}
90+
77-- | This parser always succeeds. It returns 'True' if any input is
91-- | This parser always succeeds. It returns 'True' if any input is
78-- available either immediately or on demand, and 'False' if the end
92-- available either immediately or on demand, and 'False' if the end
79-- of all input has been reached.
93-- of all input has been reached.