@@ -159,9 +159,45 @@ take n = takeWith (max n 0) (const True)
159159-- before failing. In attoparsec, the above parser will /succeed/ on
160160-- that input, because the failed first branch will consume nothing.
161161string :: Text -> Parser Text
162−string s = takeWith (T.length s) (==s)
162+string s = string_ (stringSuspended id) id s
163163{-# INLINE string #-}
164164
165+string_ :: (forall r. Text -> Text -> Buffer -> Pos -> More
166+ -> Failure r -> Success Text r -> Result r)
167+ -> (Text -> Text)
168+ -> Text -> Parser Text
169+string_ suspended f s0 = T.Parser $ \t pos more lose succ ->
170+ let s = f s0
171+ ft = f (Buf.unbuffer t)
172+ in case T.commonPrefixes s ft of
173+ Nothing
174+ | T.null s -> succ t pos more T.empty
175+ | T.null ft -> suspended s s t pos more lose succ
176+ | otherwise -> lose t pos more [] "string"
177+ Just (pfx,ssfx,tsfx)
178+ | T.null ssfx -> succ t (pos + Pos (T.lengthWord16 pfx)) more pfx
179+ | not (T.null tsfx) -> lose t pos more [] "string"
180+ | otherwise -> suspended s ssfx t pos more lose succ
181+{-# INLINE string_ #-}
182+
183+stringSuspended :: (Text -> Text)
184+ -> Text -> Text -> Buffer -> Pos -> More
185+ -> Failure r
186+ -> Success Text r
187+ -> Result r
188+stringSuspended f s000 s0 t0 pos0 more0 lose0 succ0 =
189+ runParser (demandInput_ >>= go) t0 pos0 more0 lose0 succ0
190+ where
191+ go s' = T.Parser $ \t pos more lose succ ->
192+ let s = f s'
193+ in case T.commonPrefixes s0 s of
194+ Nothing -> lose t pos more [] "string"
195+ Just (_pfx,ssfx,tsfx)
196+ | T.null ssfx -> let l = Pos (T.lengthWord16 s000)
197+ in succ t (pos + l) more (substring pos l t)
198+ | T.null tsfx -> stringSuspended f s000 ssfx t pos more lose succ
199+ | otherwise -> lose t pos more [] "string"
200+
165201-- | Satisfy a literal string, ignoring case.
166202--
167203-- Note: this function is currently quite inefficient. Unicode case
@@ -487,6 +523,7 @@ match p = T.Parser $ \t pos more lose succ ->
487523 in runParser p t pos more lose succ'
488524
489525-- | Ensure that at least @n@ code points of input are available.
526+-- Returns the number of words consumed while traversing.
490527lengthAtLeast :: Pos -> Int -> Buffer -> Maybe Pos
491528lengthAtLeast pos n t = go 0 (fromPos pos)
492529 where go i !p