{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe #-}

-- |
-- Module      :  Text.Megaparsec.Common
-- Copyright   :  © 2018–present Megaparsec contributors
-- License     :  FreeBSD
--
-- Maintainer  :  Mark Karpov <markkarpov92@gmail.com>
-- Stability   :  experimental
-- Portability :  portable
--
-- Common token combinators. This module is not public, the functions from
-- it are re-exported in "Text.Megaparsec.Byte" and "Text.Megaparsec.Char".
--
-- @since 7.0.0
module Text.Megaparsec.Lexer
  ( -- * White space
    space,
    lexeme,
    symbol,
    symbol',
  )
where

import qualified Data.CaseInsensitive as CI
import Text.Megaparsec
import Text.Megaparsec.Common

----------------------------------------------------------------------------
-- White space

-- | @'space' sc lineComment blockComment@ produces a parser that can parse
-- white space in general. It's expected that you create such a parser once
-- and pass it to other functions in this module as needed (when you see
-- @spaceConsumer@ in documentation, usually it means that something like
-- 'space' is expected there).
--
-- @sc@ is used to parse blocks of space characters. You can use
-- 'Text.Megaparsec.Char.space1' from "Text.Megaparsec.Char" for this
-- purpose as well as your own parser (if you don't want to automatically
-- consume newlines, for example). Make sure that the parser does not
-- succeed on the empty input though. In an earlier version of the library
-- 'Text.Megaparsec.Char.spaceChar' was recommended, but now parsers based
-- on 'takeWhile1P' are preferred because of their speed.
--
-- @lineComment@ is used to parse line comments. You can use
-- @skipLineComment@ if you don't need anything special.
--
-- @blockComment@ is used to parse block (multi-line) comments. You can use
-- @skipBlockComment@ or @skipBlockCommentNested@ if you don't need anything
-- special.
--
-- If you don't want to allow a kind of comment, simply pass 'empty' which
-- will fail instantly when parsing of that sort of comment is attempted and
-- 'space' will just move on or finish depending on whether there is more
-- white space for it to consume.
space ::
  (MonadParsec e s m) =>
  -- | A parser for space characters which does not accept empty
  -- input (e.g. 'Text.Megaparsec.Char.space1')
  m () ->
  -- | A parser for a line comment (e.g. 'skipLineComment')
  m () ->
  -- | A parser for a block comment (e.g. 'skipBlockComment')
  m () ->
  m ()
space :: forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> m () -> m () -> m ()
space m ()
sp m ()
line m ()
block =
  forall (m :: * -> *) a. MonadPlus m => m a -> m ()
skipMany forall a b. (a -> b) -> a -> b
$
    forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice
      [forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
hidden m ()
sp, forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
hidden m ()
line, forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
hidden m ()
block]
{-# INLINEABLE space #-}

-- | This is a wrapper for lexemes. The typical usage is to supply the first
-- argument (parser that consumes white space, probably defined via 'space')
-- and use the resulting function to wrap parsers for every lexeme.
--
-- > lexeme  = L.lexeme spaceConsumer
-- > integer = lexeme L.decimal
lexeme ::
  (MonadParsec e s m) =>
  -- | How to consume white space after lexeme
  m () ->
  -- | How to parse actual lexeme
  m a ->
  m a
lexeme :: forall e s (m :: * -> *) a. MonadParsec e s m => m () -> m a -> m a
lexeme m ()
spc m a
p = m a
p forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* m ()
spc
{-# INLINEABLE lexeme #-}

-- | This is a helper to parse symbols, i.e. verbatim strings. You pass the
-- first argument (parser that consumes white space, probably defined via
-- 'space') and then you can use the resulting function to parse strings:
--
-- > symbol    = L.symbol spaceConsumer
-- >
-- > parens    = between (symbol "(") (symbol ")")
-- > braces    = between (symbol "{") (symbol "}")
-- > angles    = between (symbol "<") (symbol ">")
-- > brackets  = between (symbol "[") (symbol "]")
-- > semicolon = symbol ";"
-- > comma     = symbol ","
-- > colon     = symbol ":"
-- > dot       = symbol "."
symbol ::
  (MonadParsec e s m) =>
  -- | How to consume white space after lexeme
  m () ->
  -- | Symbol to parse
  Tokens s ->
  m (Tokens s)
symbol :: forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> Tokens s -> m (Tokens s)
symbol m ()
spc = forall e s (m :: * -> *) a. MonadParsec e s m => m () -> m a -> m a
lexeme m ()
spc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string
{-# INLINEABLE symbol #-}

-- | A case-insensitive version of 'symbol'. This may be helpful if you're
-- working with case-insensitive languages.
symbol' ::
  (MonadParsec e s m, CI.FoldCase (Tokens s)) =>
  -- | How to consume white space after lexeme
  m () ->
  -- | Symbol to parse (case-insensitive)
  Tokens s ->
  m (Tokens s)
symbol' :: forall e s (m :: * -> *).
(MonadParsec e s m, FoldCase (Tokens s)) =>
m () -> Tokens s -> m (Tokens s)
symbol' m ()
spc = forall e s (m :: * -> *) a. MonadParsec e s m => m () -> m a -> m a
lexeme m ()
spc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e s (m :: * -> *).
(MonadParsec e s m, FoldCase (Tokens s)) =>
Tokens s -> m (Tokens s)
string'
{-# INLINEABLE symbol' #-}