{-# LANGUAGE CPP #-}
-- |
-- Module      : Streamly.Data.Parser
-- Copyright   : (c) 2020 Composewell Technologies
-- License     : BSD-3-Clause
-- Maintainer  : streamly@composewell.com
-- Stability   : pre-release
-- Portability : GHC
--
-- Parsers are more powerful but less general than 'Streamly.Data.Fold.Fold's:
--
-- * folds cannot fail but parsers can fail and backtrack.
-- * folds can be composed as a Tee but parsers cannot.
-- * folds can be converted to parsers.
--
-- Streamly parsers support all operations offered by popular Haskell parser
-- libraries. Unlike other parser libraries, (1) streamly parsers can operate
-- on any Haskell type as input - not just bytes, (2) natively support
-- streaming, (3) and are faster.
--
-- == High Performance by Static Parser Fusion
--
-- Like folds, parsers are designed to utilize stream fusion, compiling to
-- efficient low-level code comparable to the speed of C. Parsers are suitable
-- for high-performance parsing of streams.
--
-- Operations in this module are designed to be composed statically rather than
-- dynamically. They are inlined to enable static fusion. More importantly,
-- they are not designed to be used recursively. Recursive use will break
-- fusion and lead to quadratic performance slowdown. For dynamic and
-- recursive compositions use the continuation passing style (CPS) operations
-- from the "Streamly.Data.ParserK" module. 'Parser' and
-- 'Streamly.Data.ParserK.ParserK' types are interconvertible.
--
-- == How to parse a stream?
--
-- Parser combinators can be used to create a pipeline of parsers such
-- that the next parser consumes the result of the previous parser.
-- Such a composed pipeline of parsers can then be driven by one of many parser
-- drivers available in the Stream and Array modules.
--
-- Use Streamly.Data.Stream.'Streamly.Data.Stream.parse' or
-- Streamly.Data.Stream.'Streamly.Data.Stream.parseBreak' to run a parser on an
-- input stream and return the parsed result.
--
-- Use Streamly.Data.Stream.'Streamly.Data.Stream.parseMany' or
-- Streamly.Data.Stream.'Streamly.Data.Stream.parseIterate' to transform an
-- input data stream to an output stream of parsed data elements using a
-- parser.
--
-- == Parser vs ParserK
--
-- There are two functionally equivalent parsing modules,
-- "Streamly.Data.Parser" (this module) and "Streamly.Data.ParserK". The latter
-- is a CPS based wrapper over the former, and can be used for parsing in
-- general. "Streamly.Data.Parser" enables stream fusion and where possible it should be
-- preferred over "Streamly.Data.ParserK" for high performance stream parsing
-- use cases. However, there are a few cases where this module is not
-- suitable and ParserK should be used instead. As a thumb rule, when recursion
-- or heavy nesting is needed use ParserK.
--
-- === Parser: suitable for non-recursive static fusion
--
-- The 'Parser' type is suitable only for non-recursive static fusion. It could
-- be problematic for recursive definitions. To enable static fusion, parser
-- combinators use strict pattern matching on arguments of type Parser. This
-- leads to infinte loop when a parser is defined recursively, due to strict
-- evaluation of the recursive call. For example, the following implementation
-- loops infinitely because of the recursive use of parser @p@ in the @*>@
-- combinator:
--
-- >>> import Streamly.Data.Parser (Parser)
-- >>> import qualified Streamly.Data.Fold as Fold
-- >>> import qualified Streamly.Data.Parser as Parser
-- >>> import qualified Streamly.Data.Stream as Stream
-- >>> import Control.Applicative ((<|>))
--
-- >>> :{
-- >>> p, p1, p2 :: Monad m => Parser Char m String
-- >>> p1 = Parser.satisfy (== '(') *> p
-- >>> p2 = Parser.fromFold Fold.toList
-- >>> p = p1 <|> p2
-- >>> :}
--
-- Another limitation of Parser type quadratic performance slowdown when too
-- many nested compositions are used. Especially Applicative, Monad,
-- Alternative instances, and sequenced parsing operations (e.g. nested 'one',
-- and 'splitWith') exhibit quadratic slowdown (O(n^2) complexity) when
-- combined @n@ times, roughly 8 or less sequenced parsers usually work fine.
-- READ THE DOCS OF APPLICATIVE, MONAD AND ALTERNATIVE INSTANCES.
--
-- === ParserK: suitable for recursive definitions
--
-- ParserK is suitable for recursive definitions:
--
-- >>> import Streamly.Data.ParserK (ParserK)
-- >>> import Streamly.Data.StreamK (toParserK)
-- >>> import qualified Streamly.Data.StreamK as StreamK
--
-- >>> :{
-- >>> p, p1, p2 :: Monad m => ParserK Char m String
-- >>> p1 = toParserK (Parser.satisfy (== '(')) *> p
-- >>> p2 = toParserK (Parser.fromFold Fold.toList)
-- >>> p = p1 <|> p2
-- >>> :}
--
-- >>> StreamK.parse p $ StreamK.fromStream $ Stream.fromList "hello"
-- Right "hello"
--
-- For this reason Applicative, Alternative or Monad compositions with
-- recursion cannot be used with the 'Parser' type. Alternative type class based
-- operations like 'asum' and Alternative based generic parser combinators use
-- recursion. Similarly, Applicative type class based operations like
-- 'Prelude.sequence' use recursion. Custom implementations of many such
-- operations are provided in this module (e.g. 'some', 'many'), and those
-- should be used instead.
--
-- == Parsers Galore!
--
-- Streamly provides all the parsing functionality provided by popular parsing
-- libraries, and much more with higher performance.
-- This module provides most of the elementary parsers and parser combinators.
-- Additionally,
--
-- * all the folds from the "Streamly.Data.Fold" module can be converted to
-- parsers using 'fromFold'.
-- * "Streamly.Unicode.Parser" module provides Char stream parsers.
-- * all the combinators from the
-- <https://hackage.haskell.org/package/parser-combinators parser-combinators>
-- package can be used with streamly ParserK.
-- * See "Streamly.Internal.Data.Parser" for many more unreleased but useful APIs.
--
-- == Generic Parser Combinators
--
-- With 'Streamly.Data.ParserK.ParserK' you can use the 'Applicative' and
-- 'Control.Applicative.Alternative' type class based generic parser
-- combinators from the
-- <https://hackage.haskell.org/package/parser-combinators parser-combinators>
-- library or similar. However, if available, we recommend that you use the
-- equivalent functionality from this module where performance and streaming
-- behavior matters.
-- Firstly, the combinators in this module are faster due to stream fusion.
-- Secondly, these are streaming in nature as the results can be passed
-- directly to other stream consumers (folds or parsers). The Alternative type
-- class based parsers would end up buffering all the results in lists before
-- they can be consumed.
--
-- == Error Reporting
--
-- There are two types of parser drivers available, @parse@ and @parseBreak@
-- drivers do not track stream position, whereas @parsePos@ and @parseBreakPos@
-- drivers track and report stream position information with slightly more
-- performance overhead.
--
-- When an error occurs the stream position is reported, in case of byte streams
-- or unboxed array streams this is the byte position, in case of generic
-- element parsers or generic array parsers this is the element position in the
-- stream.
--
-- These parsers do not report a case specific error context (e.g. line number
-- or column). If you need line number or column information you can read the
-- stream again (if it is immutable) and this count the lines to translate the
-- reported byte position to line number and column. More elaborate support for
-- building arbitrary and custom error context information is planned to be
-- added in future.
--
-- == Monad Transformer Stack
--
-- 'MonadTrans' instance is 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.
--
-- == Experimental APIs
--
-- 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

    -- * Parser Type
      Parser
    , ParseError(..)
    , ParseErrorPos(..)

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

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

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

    -- ** Single Elements

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

    -- ** Sequences
    , streamEqBy
    , listEqBy
    , listEq

    -- * Transformations
    -- Mapping on output
    -- , rmapM

    -- ** Map on input
    , lmap
    , lmapM

     -- ** Map on output
    , rmapM

    -- ** Filtering
    , filter

    -- ** Look Ahead
    , lookAhead

    -- * Tokenizing Combinators
    -- ** 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"