content: {-# LANGUAGE CPP #-}
  -- |
  -- Module      : Streamly.Data.ParserK
  -- Copyright   : (c) 2023 Composewell Technologies
  -- License     : BSD-3-Clause
  -- Maintainer  : streamly@composewell.com
  -- Stability   : pre-release
  -- Portability : GHC
  --
  -- See the general notes about parsing in the "Streamly.Data.Parser" module.
  -- This (ParserK) module implements a Continuation Passing Style (CPS) wrapper
  -- over the fused "Streamly.Data.Parser" module. It is a faster CPS parser than
  -- attoparsec.
  --
  -- The 'ParserK' type represents a stream-consumer as a composition of function
  -- calls, therefore, a function call overhead is incurred at each composition.
  -- It is reasonably fast in general but may be a few times slower than the
  -- fused 'Streamly.Data.Parser.Parser' type. However, unlike fused parsers, it
  -- allows for scalable dynamic composition, especially, 'ParserK' can be used
  -- in recursive calls. Operations like 'splitWith' on 'ParserK' type have
  -- linear (O(n)) performance with respect to the number of compositions.
  --
  -- 'ParserK' is preferred over the fused 'Streamly.Data.Parser.Parser' when
  -- extensive applicative, alternative and monadic composition is required, or
  -- when recursive or dynamic composition of parsers is required. 'ParserK' also
  -- allows efficient parsing of a stream of byte arrays, it can also break the
  -- input stream into a parse result and the remaining stream so that the stream
  -- can be parsed independently in segments.
  --
  -- == How to parse a stream?
  --
  -- All the fused parsers from the "Streamly.Data.Parser" module can be
  -- converted to the CPS ParserK, for use with different types of parser
  -- drivers, using
  -- the @toParserK@ combinators -
  -- Streamly.Data.Array.'Streamly.Data.Array.toParserK',
  -- Streamly.Data.StreamK.'Streamly.Data.StreamK.toParserK', and
  -- Streamly.Data.Array.Generic.'Streamly.Data.Array.Generic.toParserK'
  --
  -- To parse a stream of unboxed arrays, use
  -- Streamly.Data.Array.'Streamly.Data.Array.parse' for running the parser, this
  -- is the preferred and most efficient way to parse chunked input. The
  -- Streamly.Data.Array.'Streamly.Data.Array.parseBreak' function returns the
  -- remaining stream as well along with the parse result.
  --
  -- To parse a stream of boxed arrays, use
  -- Streamly.Data.Array.Generic.'Streamly.Data.Array.Generic.parse' or
  -- Streamly.Data.Array.Generic.'Streamly.Data.Array.Generic.parseBreak' to run
  -- the parser.
  --
  -- To parse a stream of individual elements, use
  -- Streamly.Data.StreamK.'Streamly.Data.StreamK.parse' and
  -- Streamly.Data.StreamK.'Streamly.Data.StreamK.parseBreak' to run the parser.
  --
  -- == Applicative  Composition
  --
  -- Applicative parsers are simpler but we cannot use lookbehind as we can in
  -- the monadic parsers.
  --
  -- If we have to parse "9a" or "a9" but not "99" or "aa" we can use the
  -- following Applicative, backtracking parser:
  --
  -- >>> -- parse p1 : p2 : []
  -- >>> token p1 p2 = ((:) <$> p1 <*> ((:) <$> p2 <*> pure []))
  -- >>> :{
  -- backtracking :: Monad m => ParserK Char m String
  -- backtracking = StreamK.toParserK $
  --     token (Parser.satisfy isDigit) (Parser.satisfy isAlpha) -- e.g. "9a"
  --     <|>
  --     token (Parser.satisfy isAlpha) (Parser.satisfy isDigit) -- e.g. "a9"
  -- :}
  --
  -- == Monadic Composition
  --
  -- Monad composition can be used to implement lookbehind parsers, we can dynamically
  -- compose new parsers based on the results of the previously parsed values.
  --
  -- In the previous example, we know that if the first parse resulted in a digit
  -- at the first place then the second parse is going to fail.  However, we
  -- waste that information and parse the first character again in the second
  -- parse only to know that it is not an alphabetic char.  By using lookbehind
  -- in a 'Monad' composition we can make dynamic decisions based on previously
  -- parsed information and avoid redundant work:
  --
  -- >>> data DigitOrAlpha = Digit Char | Alpha Char
  --
  -- >>> :{
  -- lookbehind :: Monad m => ParserK Char m String
  -- lookbehind = do
  --     x1 <- StreamK.toParserK $
  --              Digit <$> Parser.satisfy isDigit
  --          <|> Alpha <$> Parser.satisfy isAlpha
  --     -- Note: the parse depends on what we parsed already
  --     x2 <- StreamK.toParserK $
  --           case x1 of
  --              Digit _ -> Parser.satisfy isAlpha
  --              Alpha _ -> Parser.satisfy isDigit
  --     return $ case x1 of
  --         Digit x -> [x,x2]
  --         Alpha x -> [x,x2]
  -- :}
  --
  -- == Experimental APIs
  --
  -- Please refer to "Streamly.Internal.Data.ParserK" for functions that have
  -- not yet been released.
  --
  module Streamly.Data.ParserK
      (
      -- * Setup
      -- | To execute the code examples provided in this module in ghci, please
      -- run the following commands first.
      --
      -- $setup
  
      -- * Parser Type
        ParserK
  
      -- * Parsers
  
      -- -- ** Without Input
      , fromPure
      , fromEffect
      , die
  
      -- * Deprecated
      , fromFold
      , fromParser
      , adapt
      , adaptC
      , adaptCG
      )
  
  where
  
  import Control.Monad.IO.Class (MonadIO)
  import Streamly.Internal.Data.Fold (Fold)
  import Streamly.Internal.Data.Unbox (Unbox)
  import Streamly.Internal.Data.Array (Array)
  import qualified Streamly.Internal.Data.Parser as ParserD
  import qualified Streamly.Internal.Data.Array as Array
  
  import Streamly.Internal.Data.ParserK
  
  #include "DocTestDataParserK.hs"
  
  {-# DEPRECATED fromFold "Please use \"Array.toParserK . Parser.fromFold\" instead." #-}
  {-# INLINE fromFold #-}
  fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK (Array a) m b
  fromFold = Array.toParserK . ParserD.fromFold
  
  {-# DEPRECATED fromParser "Please use \"Array.toParserK\" instead." #-}
  {-# INLINE fromParser #-}
  fromParser ::
         (MonadIO m, Unbox a) => ParserD.Parser a m b -> ParserK (Array a) m b
  fromParser = Array.toParserK
  