{-# 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 :: forall (m :: * -> *) a b.
(MonadIO m, Unbox a) =>
Fold m a b -> ParserK (Array a) m b
fromFold = Parser a m b -> ParserK (Array a) m b
forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
Parser a m b -> ParserK (Array a) m b
Array.toParserK (Parser a m b -> ParserK (Array a) m b)
-> (Fold m a b -> Parser a m b)
-> Fold m a b
-> ParserK (Array a) m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fold m a b -> Parser a m b
forall (m :: * -> *) a b. Monad m => Fold m a b -> Parser a m b
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 :: forall (m :: * -> *) a b.
(MonadIO m, Unbox a) =>
Parser a m b -> ParserK (Array a) m b
fromParser = Parser a m b -> ParserK (Array a) m b
forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
Parser a m b -> ParserK (Array a) m b
Array.toParserK