content: {-|
  Module      : Parsley.Combinator
  Description : The parsing combinators
  License     : BSD-3-Clause
  Maintainer  : Jamie Willis
  Stability   : stable
  
  This module contains the classic parser combinator operations specific to parsers themselves, excluding
  those that consume input.
  
  @since 0.1.0.0
  -}
  module Parsley.Combinator (
      eof, more,
      someTill,
      try,
      lookAhead, notFollowedBy,
      line, col, pos
    ) where
  
  import Prelude hiding           ((*>))
  import Parsley.Alternative      (manyTill)
  import Parsley.Applicative      (void, (<:>), (*>), (<~>))
  import Parsley.Internal         (Parser)
  import Parsley.Char             (item)
  
  import qualified Parsley.Internal as Internal (try, lookAhead, notFollowedBy, line, col)
  
  {-|
  This combinator will attempt to parse a given parser. If it succeeds, the result is returned without
  having consumed any input. If it fails, however, any consumed input remains consumed.
  
  @since 0.1.0.0
  -}
  lookAhead :: Parser a -> Parser a
  lookAhead = Internal.lookAhead
  
  {-|
  This combinator will ensure that a given parser fails. If the parser does fail, a @()@ is returned
  and no input is consumed. If the parser succeeded, then this combinator will fail, however it will
  not consume any input.
  
  @since 0.1.0.0
  -}
  notFollowedBy :: Parser a -> Parser ()
  notFollowedBy = Internal.notFollowedBy
  
  {-|
  This combinator allows a parser to backtrack on failure, which is to say that it will
  not have consumed any input if it were to fail. This is important since @parsec@ semantics demand
  that the second branch of @(`Parsley.Alternative.<|>`)@ can only be taken if the first did not consume input on failure.
  
  Excessive use of `try` will reduce the efficiency of the parser and effect the generated error
  messages. It should only be used in one of two circumstances:
  
  * When two branches of a parser share a common leading prefix (in which case, it is often better
    to try and factor this out).
  * When a parser needs to be executed atomically (for example, tokens).
  
  @since 0.1.0.0
  -}
  try :: Parser a -> Parser a
  try = Internal.try
  
  {-|
  This parser succeeds only if there is no input left to consume, and fails without consuming input
  otherwise.
  
  @since 0.1.0.0
  -}
  eof :: Parser ()
  eof = notFollowedBy item
  
  {-|
  This parser succeeds if there is still input left to consume, and fails otherwise.
  
  @since 0.1.0.0
  -}
  more :: Parser ()
  more = lookAhead (void item)
  
  -- Composite Combinators
  {-|
  The combinator @someTill p end@ will try and parse @p@ as many times as possible (but at least once)
  so long as @end@ cannot be successfully parsed. It will return the results from the successful parses of @p@.
  
  @since 0.1.0.0
  -}
  someTill :: Parser a -> Parser b -> Parser [a]
  someTill p end = notFollowedBy end *> (p <:> manyTill p end)
  
  {-|
  The `line` combinator returns the current line number at this point in the parse. Line numbers
  start from 1.
  
  @since 1.0.1.0
  -}
  line :: Parser Int
  line = Internal.line
  
  {-|
  The `col` combinator returns the current column number at this point in the parse. Column numbers
  start from 1.
  
  @since 1.0.1.0
  -}
  col :: Parser Int
  col = Internal.col
  
  {-|
  The `pos` combinator returns the current line and column number at this point in the parse.
  
  @since 1.0.1.0
  -}
  pos :: Parser (Int, Int)
  pos = line <~> col
  