@@ -20,31 +20,98 @@
21module Streamly.Internal.Data.Parser.ParserK.Types
21module Streamly.Internal.Data.Parser.ParserK.Types
23− Parser (..)
25+ , Parser (..)
29−import Control.Monad (MonadPlus(..), ap)
30import Control.Applicative (Alternative(..))
35import Control.Applicative (Alternative(..))
31−import Streamly.Internal.Data.Zipper (Zipper)
36+import Control.Exception (assert, Exception(..))
32−import qualified Streamly.Internal.Data.Zipper as Z
37+import Control.Monad (MonadPlus(..), ap)
33−
38+import Control.Monad.Catch (MonadCatch, MonadThrow(..), try)
34#if MIN_VERSION_base(4,9,0)
39#if MIN_VERSION_base(4,9,0)
35import qualified Control.Monad.Fail as Fail
40import qualified Control.Monad.Fail as Fail
42+#if !(MIN_VERSION_base(4,10,0))
43+import Data.Semigroup ((<>))
45+import Streamly.Internal.Data.Zipper (Zipper (..))
46+import Streamly.Internal.Data.SVar (defState)
47+import Prelude hiding (splitAt)
49+import qualified Streamly.Internal.Data.Zipper as Z
50+import qualified Streamly.Internal.Data.Parser.ParserD.Types as PD
51+import qualified Streamly.Internal.Data.Stream.StreamK as K
53+-- | The parse driver result. The driver may stop with a final result, pause
54+-- with a continuation to resume, or fail with an error.
60+ -- XXX we can use a "resume" and a "stop" continuations instead of Maybe.
61+ -- measure if that works any better.
62+ | Pause (Maybe a -> m (Driver m a r))
65+instance Functor m => Functor (Driver m a) where
66+ fmap f (Stop r) = Stop (f r)
67+ fmap f (Pause yld) = Pause (fmap (fmap f) . yld)
68+ fmap _ (Failed e) = Failed e
70+-- The parser's result.
75+ Done !b -- Done, no more input needed
76+ | Continue -- No result, need more input
77+ | Error !String -- Failed
79+instance Functor Parse where
80+ fmap f (Done b) = Done (f b)
81+ fmap _ Continue = Continue
82+ fmap _ (Error e) = Error e
84+-- | A continuation passing style parser representation. The parser is supplied
85+-- with a 'Zipper' with an initial input, and a continuation to consume the
86+-- parse result. The Zipper is threaded around as a state and maintains the
87+-- parser backtracking buffer.
38−newtype Parser m a b =
89+newtype Parser m a b = MkParser
39− MkParser { runParser :: forall r.
90+ { runParser :: forall r.
40− Zipper m a -> ((Zipper m a, Either String b) -> m r) -> m r }
91+ Zipper m a
92+ -> (Zipper m a -> Parse b -> m (Driver m a r))
96+-- | When there is no more input to feed, extract the result from the Parser.
100+extractParse :: MonadThrow m => (Maybe a -> m (Driver m a b)) -> m b
101+extractParse cont = do
105+ Pause _ -> error "Bug: extractParse got Pause"
106+ Failed e -> throwM $ PD.ParseError e
42−-- | Maps a function over the output of the fold.
108+-- | Maps a function over the output of the parser.
44instance Functor m => Functor (Parser m a) where
110instance Functor m => Functor (Parser m a) where
45 {-# INLINE fmap #-}
111 {-# INLINE fmap #-}
46− fmap f parser =
112+ fmap f parser = MkParser $ \zipper yieldk ->
47− MkParser $ \inp yieldk -> runParser parser inp (yieldk . fmap (fmap f))
113+ let yld z res = yieldk z (fmap f res)
114+ in runParser parser zipper yld
49-- | See 'Streamly.Internal.Data.Parser.yield'.
116-- | See 'Streamly.Internal.Data.Parser.yield'.
@@ -52,7 +119,7 @@ instance Functor m => Functor (Parser m a) where
53{-# INLINE yield #-}
120{-# INLINE yield #-}
54yield :: b -> Parser m a b
121yield :: b -> Parser m a b
55−yield b = MkParser (\inp yieldk -> yieldk (inp, Right b))
122+yield b = MkParser (\zipper yieldk -> yieldk zipper (Done b))
57-------------------------------------------------------------------------------
124-------------------------------------------------------------------------------
58-- Sequential applicative
125-- Sequential applicative
@@ -70,18 +137,19 @@ instance Monad m => Applicative (Parser m a) where
70 (<*>) = ap
137 (<*>) = ap
72 {-# INLINE (*>) #-}
139 {-# INLINE (*>) #-}
73− m1 *> m2 = MkParser $ \inp yieldk ->
140+ m1 *> m2 = MkParser $ \zipper yieldk ->
74− let yield1 (z, b) = case b of
75− Right _ -> runParser m2 z yieldk
141+ let yield1 z (Done _) = runParser m2 z yieldk
76− Left err -> runParser (die err) z yieldk
142+ yield1 z Continue = yieldk z Continue
143+ yield1 z (Error e) = yieldk z (Error e)
77− in runParser m1 inp yield1
144+ in runParser m1 zipper yield1
79 {-# INLINE (<*) #-}
146 {-# INLINE (<*) #-}
80− m1 <* m2 = MkParser $ \inp yieldk ->
147+ m1 <* m2 = MkParser $ \zipper yieldk ->
81− let yield1 (z, b) = case b of
148+ let
82− Right _ -> runParser m2 z (\(z1, _) -> yieldk (z1, b))
149+ yield1 z (Done b) = runParser m2 z $ \z1 _ -> yieldk z1 (Done b)
83− Left err -> runParser (die err) z yieldk
150+ yield1 z Continue = yieldk z Continue
151+ yield1 z (Error e) = yieldk z (Error e)
84− in runParser m1 inp yield1
152+ in runParser m1 zipper yield1
86-- | See 'Streamly.Internal.Data.Parser.die'.
154-- | See 'Streamly.Internal.Data.Parser.die'.
@@ -89,7 +157,7 @@ instance Monad m => Applicative (Parser m a) where
90{-# INLINE die #-}
158{-# INLINE die #-}
91die :: String -> Parser m a b
159die :: String -> Parser m a b
92−die err = MkParser (\z yieldk -> yieldk (z, Left err))
160+die err = MkParser (\z yieldk -> yieldk z (Error err))
94-- | Monad composition can be used for lookbehind parsers, we can make the
162-- | Monad composition can be used for lookbehind parsers, we can make the
95-- future parses depend on the previously parsed values.
163-- future parses depend on the previously parsed values.
@@ -138,11 +206,12 @@ instance Monad m => Monad (Parser m a) where
138 return = pure
206 return = pure
140 {-# INLINE (>>=) #-}
208 {-# INLINE (>>=) #-}
141− m >>= k = MkParser $ \inp yieldk ->
209+ m >>= k = MkParser $ \zipper yieldk ->
142− let yield1 (z, b) = case b of
210+ let
143− Right x -> runParser (k x) z yieldk
211+ yield1 z (Done b) = runParser (k b) z yieldk
144− Left err -> runParser (die err) z yieldk
212+ yield1 z Continue = yieldk z Continue
213+ yield1 z (Error e) = yieldk z (Error e)
145− in runParser m inp yield1
214+ in runParser m zipper yield1
147#if !(MIN_VERSION_base(4,13,0))
216#if !(MIN_VERSION_base(4,13,0))
148 -- This is redefined instead of just being Fail.fail to be
217 -- This is redefined instead of just being Fail.fail to be
@@ -175,11 +244,11 @@ instance Monad m => Alternative (Parser m a) where
175 empty = die "empty"
244 empty = die "empty"
177 {-# INLINE (<|>) #-}
246 {-# INLINE (<|>) #-}
178− m1 <|> m2 = MkParser $ \inp yieldk ->
247+ m1 <|> m2 = MkParser $ \zipper yieldk ->
179− let yield1 (z, b) = case b of
180− Right _ -> yieldk (Z.release z, b)
248+ let yield1 z (Done b) = yieldk (Z.release z) (Done b)
249+ yield1 z Continue = yieldk z Continue
181− Left _ -> runParser m2 (Z.restore z) yieldk
250+ yield1 z (Error _) = runParser m2 (Z.restore z) yieldk
182− in runParser m1 (Z.checkpoint inp) yield1
251+ in runParser m1 (Z.checkpoint zipper) yield1
184 -- some and many are implemented here instead of using default definitions
253 -- some and many are implemented here instead of using default definitions
185 -- so that we can use INLINE on them. It gives 50% performance improvement.
254 -- so that we can use INLINE on them. It gives 50% performance improvement.
@@ -211,3 +280,190 @@ instance Monad m => MonadPlus (Parser m a) where
212 {-# INLINE mplus #-}
281 {-# INLINE mplus #-}
213 mplus = (<|>)
282 mplus = (<|>)
284+-------------------------------------------------------------------------------
285+-- Parse driver for a Zipper
286+-------------------------------------------------------------------------------
288+-- Inlined definition. Without the inline "serially/parser/take" benchmark
289+-- degrades and splitParse does not fuse. Even using "inline" at the callsite
291+{-# INLINE splitAt #-}
292+splitAt :: Int -> [a] -> ([a],[a])
295+ | otherwise = splitAt' n ls
297+ splitAt' :: Int -> [a] -> ([a], [a])
298+ splitAt' _ [] = ([], [])
299+ splitAt' 1 (x:xs) = ([x], xs)
300+ splitAt' m (x:xs) = (x:xs', xs'')
302+ (xs', xs'') = splitAt' (m - 1) xs
304+-- | Parse a stream zipper using a direct style parser's @step@, @initial@ and
305+-- @extract@ functions.
307+{-# INLINE_NORMAL parse #-}
310+ => (s -> a -> m (PD.Step s b))
314+ -> (Zipper m a -> Parse b -> m (Driver m a r))
317+-- The case when no checkpoints exist
318+parse pstep initial extract (Zipper [] backward forward stream) cont =
320+ -- Stop if stream is nil
321+ [] -> goStream stream backward initial
322+ _ -> goBuf stream backward forward initial
326+ -- Pauses if no input was generated by the stream and returns a
327+ -- continuation. If the continuation is called with Nothing then it stops
328+ -- and returns the result.
329+ {-# INLINE goStream #-}
330+ goStream st back !acc =
331+ -- XXX We do not need to wrap the element in a stream we can process it
333+ let parseCont (Just x) = goStream (K.yield x) back acc
334+ parseCont Nothing = do
336+ r <- try $ extract pst
338+ Left (e :: PD.ParseError) ->
339+ cont Z.nil (Error (displayException e))
340+ Right b -> cont Z.nil (Done b)
341+ stop = return $ Pause parseCont
342+ single x = yieldk x K.nil
344+ acc1 <- acc >>= \b -> pstep b x
346+ PD.Partial 0 pst1 -> goStream r [] (return pst1)
347+ PD.Partial n pst1 -> do
348+ assert (n <= length (x:back)) (return ())
349+ let src0 = Prelude.take n (x:back)
350+ src = Prelude.reverse src0
351+ goBuf r [] src (return pst1)
352+ PD.Continue 0 pst1 -> goStream r (x:back) (return pst1)
353+ PD.Continue n pst1 -> do
354+ assert (n <= length (x:back)) (return ())
355+ let (src0, buf1) = splitAt n (x:back)
356+ src = Prelude.reverse src0
357+ goBuf r buf1 src (return pst1)
359+ assert (n <= length (x:back)) (return ())
360+ let (src0, buf1) = splitAt n (x:back)
361+ src = Prelude.reverse src0
362+ cont (Zipper [] buf1 src r) (Done b)
363+ PD.Error err -> cont (Zipper [] (x:back) [] r) (Error err)
364+ in K.foldStream defState yieldk single stop st
366+ goBuf s back [] !pst = goStream s back pst
367+ goBuf s back (x:xs) !pst = do
371+ PD.Partial 0 pst1 ->
372+ goBuf s [] xs (return pst1)
373+ PD.Partial n pst1 -> do
374+ assert (n <= length (x:back)) (return ())
375+ let src0 = Prelude.take n (x:back)
376+ src = Prelude.reverse src0
377+ goBuf s [] (src ++ xs) (return pst1)
378+ PD.Continue 0 pst1 -> goBuf s (x:back) xs (return pst1)
379+ PD.Continue n pst1 -> do
380+ assert (n <= length (x:back)) (return ())
381+ let (src0, buf1) = splitAt n (x:back)
382+ src = Prelude.reverse src0 ++ xs
383+ goBuf s buf1 src (return pst1)
385+ assert (n <= length (x:back)) (return ())
386+ let (src0, buf1) = splitAt n (x:back)
387+ src = Prelude.reverse src0 ++ xs
388+ cont (Zipper [] buf1 src s) (Done b)
389+ PD.Error err -> cont (Zipper [] (x:back) xs s) (Error err)
391+-- The case when checkpoints exist
392+-- XXX code duplication alert!
393+parse pstep initial extract (Zipper (cp:cps) backward forward stream) cont =
395+ [] -> goStream 0 stream backward initial
396+ _ -> goBuf 0 stream backward forward initial
400+ {-# INLINE goStream #-}
401+ goStream cnt st back !acc =
402+ let parseCont (Just x) = goStream cnt (K.yield x) back acc
403+ parseCont Nothing = do
405+ r <- try $ extract pst
407+ Left (e :: PD.ParseError) ->
408+ cont Z.nil (Error (displayException e))
409+ Right b -> cont Z.nil (Done b)
410+ stop = return $ Pause parseCont
411+ single x = yieldk x K.nil
413+ acc1 <- acc >>= \b -> pstep b x
416+ PD.Partial 0 pst1 ->
417+ goStream cnt1 r [] (return pst1)
418+ PD.Partial n pst1 -> do
419+ assert (n <= length (x:back)) (return ())
420+ let src0 = Prelude.take n (x:back)
421+ src = Prelude.reverse src0
422+ goBuf (cnt1 - n) r [] src (return pst1)
423+ PD.Continue 0 pst1 -> goStream cnt1 r (x:back) (return pst1)
424+ PD.Continue n pst1 -> do
425+ assert (n <= length (x:back)) (return ())
426+ let (src0, buf1) = splitAt n (x:back)
427+ src = Prelude.reverse src0
428+ assert (cnt1 - n >= 0) (return ())
429+ goBuf (cnt1 - n) r buf1 src (return pst1)
431+ assert (n <= length (x:back)) (return ())
432+ let (src0, buf1) = splitAt n (x:back)
433+ src = Prelude.reverse src0
434+ assert (cp + cnt1 - n >= 0) (return ())
435+ cont (Zipper (cp + cnt1 - n : cps) buf1 src r)
438+ cont (Zipper (cp + cnt1 : cps) (x:back) [] r)
440+ in K.foldStream defState yieldk single stop st
442+ goBuf cnt s back [] !pst = goStream cnt s back pst
443+ goBuf cnt s back (x:xs) !pst = do
448+ PD.Partial 0 pst1 ->
449+ goBuf cnt1 s [] xs (return pst1)
450+ PD.Partial n pst1 -> do
451+ assert (n <= length (x:back)) (return ())
452+ let src0 = Prelude.take n (x:back)
453+ src = Prelude.reverse src0
454+ goBuf (cnt1 - n) s [] (src ++ xs) (return pst1)
455+ PD.Continue 0 pst1 -> goBuf cnt1 s (x:back) xs (return pst1)
456+ PD.Continue n pst1 -> do
457+ assert (n <= length (x:back)) (return ())
458+ let (src0, buf1) = splitAt n (x:back)
459+ src = Prelude.reverse src0 ++ xs
460+ assert (cnt1 - n >= 0) (return ())
461+ goBuf (cnt1 - n) s buf1 src (return pst1)
463+ assert (n <= length (x:back)) (return ())
464+ let (src0, buf1) = splitAt n (x:back)
465+ src = Prelude.reverse src0 ++ xs
466+ assert (cp + cnt1 - n >= 0) (return ())
467+ cont (Zipper (cp + cnt1 - n : cps) buf1 src s) (Done b)
469+ cont (Zipper (cp + cnt1 : cps) (x:back) xs s) (Error err)