{-# LANGUAGE CPP #-}
-- |
-- Module      : Streamly.Data.Parser
-- Copyright   : (c) 2020 Composewell Technologies
-- License     : BSD-3-Clause
-- Maintainer  : streamly@composewell.com
-- Stability   : pre-release
-- Portability : GHC
--
-- Fast, composable stream consumers with ability to terminate, backtrack and
-- fail, supporting stream fusion. Parsers are a natural extension of
-- "Streamly.Data.Fold". Parsers and folds can be interconverted.
--
-- Please refer to "Streamly.Internal.Data.Parser" for functions that have
-- not yet been released.
--
module Streamly.Data.Parser
    (
    -- * Setup
    -- | To execute the code examples provided in this module in ghci, please
    -- run the following commands first.
    --
    -- $setup

    -- * Overview
    -- $overview

    -- * Parser Type
      Parser

    -- -- * Downgrade to Fold
    -- , toFold

    -- * Parsers
    -- ** From Folds
    , fromFold

    -- ** Without Input
    -- , fromFoldMaybe
    , fromPure
    , fromEffect
    , die
    -- , dieM
    , peek
    , eof

    -- ** Element parsers

    -- All of these can be expressed in terms of either
    , one
    -- , oneEq
    -- , oneNotEq
    , oneOf
    , noneOf
    , satisfy
    -- , maybe
    -- , either

    -- ** Sequences
    , streamEqBy
    , listEqBy
    , listEq

    -- * Combinators
    -- Mapping on output
    -- , rmapM

    -- ** Mapping on input
    , lmap
    , lmapM

     -- * Map on output
    , rmapM

    -- ** Filtering
    , filter

    -- ** Look Ahead
    , lookAhead

    -- ** Tokenize by length
    -- , takeBetween
    , takeEQ
    -- , takeGE
    -- , takeP

    -- ** Tokenize by predicate
    -- , takeWhileP
    , takeWhile
    , takeWhile1
    , dropWhile
    -- , takeEndBy
    -- , takeEndByEsc
    -- , takeStartBy
    , wordBy

    -- ** Grouping
    , groupBy
    -- , groupByRolling
    -- , groupByRollingEither

    -- ** Framing
    -- , wordFramedBy
    , wordWithQuotes
    -- , wordProcessQuotes
    -- , wordKeepQuotes

    -- -- * Alternative
    -- , alt

    -- ** Splitting
    , many
    , some
    , manyTill

    -- ** De-interleaving
    , deintercalate
    )

where

import Streamly.Internal.Data.Parser
import Prelude hiding (dropWhile, takeWhile, filter)

#include "DocTestDataParser.hs"

-- $overview
--
-- Several combinators in this module can be many times faster than CPS based
-- parsers because of stream fusion. For example,
-- 'Streamly.Internal.Data.Parser.many' combinator in this module is much
-- faster than the 'Control.Applicative.many' combinator of
-- 'Control.Applicative.Alternative' type class used by CPS based parsers.
--
-- The use of 'Alternative' type class, in parsers has another drawback.
-- Alternative based parsers use plain Haskell lists to collect the results. In
-- a strict Monad like IO, the results are necessarily buffered before they can
-- be consumed.  This may not perform optimally in streaming applications
-- processing large amounts of data.  Equivalent combinators in this module can
-- consume the results of parsing using a 'Fold' or another parser, thus
-- providing a scalable and composable consumer.
--
-- Note that these parsers do not report the error context (e.g. line number or
-- column). This may be supported in future.
--
-- mtl instances are not provided. If the 'Parser' type is the top most layer
-- (which should be the case almost always) you can just use 'fromEffect' to
-- execute the lower layer monad effects.
--
-- == Performance Notes
--
-- The 'Parser' type represents a stream consumer by composing state as data
-- which enables stream fusion. Stream fusion generates a tight loop without
-- any constructor allocations between the stages, providing C like performance
-- for the loop. Stream fusion works when multiple functions are combined in a
-- pipeline statically. Therefore, the operations in this module must be
-- inlined and must not be used recursively to allow for stream fusion. Note
-- that operations like 'sequence', and 'asum' that compose pasrers using
-- recursion should be avoided with these parsers. You can use these with the
-- 'ParserK' module instead.
--
-- Using the 'Parser' type, parsing operations like 'one', 'splitWith' etc.
-- degrade quadratically (O(n^2)) when combined many times. If you need to
-- combine these operations, say more than 8 times in a single loop, then you
-- should consider using the continuation style parser type 'ParserK' instead.
-- Also, if you need to use these operations in a recursive loop you should use
-- 'ParserK' instead.
--
-- The 'ParserK' type represents a stream consumer by composing function calls,
-- therefore, a function call overhead is incurred at each composition. It is
-- quite fast in general but may be a few times slower than a fused parser.
-- However, it allows for scalable dynamic composition especially parsers can
-- be used in recursive calls. Using the 'ParserK' type operations like
-- 'splitWith' provide linear (O(n)) performance with respect to the number of
-- compositions..
--
-- 'Parser' and 'ParserK' types can be interconverted.