-- |
-- Module      :  Data.ByteString.Parser.Char8
-- License     :  CC0-1.0
--
-- Maintainer  :  mordae@anilinux.org
-- Stability   :  unstable
-- Portability :  non-portable (ghc)
--
-- This module provides a parser for ASCII 'ByteString'.
--
--   * If you\'d like to parse Unicode text, look instead at the
--     "Data.Text.Parser". Is is slower, but in a way more correct.
--
--   * If you\'d like to parse byte sequences, look instead at the
--     "Data.ByteString.Parser". It reuses the same 'Parser', but
--     provides functions working with 'Word8' instead of 'Char'.
--

module Data.ByteString.Parser.Char8
  ( Parser(..)
  , Result(..)
  , parseOnly

    -- * Characters
  , char
  , notChar
  , anyChar
  , satisfy
  , space
  , isSpace
  , skipSpace
  , peekChar

    -- * Strings
  , string
  , stringCI
  , Data.ByteString.Parser.Char8.take
  , scan
  , runScanner
  , inRange
  , notInRange
  , Data.ByteString.Parser.Char8.takeWhile
  , takeWhile1
  , takeTill
  , takeTill1

    -- * Numbers
  , signed
  , decimal
  , hexadecimal
  , octal
  , fractional

    -- * Combinators
  , provided
  , choice
  , branch
  , Data.ByteString.Parser.count
  , optional
  , eitherP
  , option
  , many
  , many1
  , manyTill
  , sepBy
  , sepBy1
  , wrap
  , match
  , label
  , unlabel
  , validate

    -- * End Of Input
  , takeByteString
  , peekByteString
  , endOfInput
  , atEnd

    -- * Position
  , offset
  , position
  , explain
  , Explanation(..)

    -- * Miscelaneous
    -- |
    -- These are all generic methods, but since I sometimes forget about them,
    -- it is nice to have them listed here for reference what writing parsers.
  , Control.Applicative.empty
  , pure
  , guard
  , when
  , unless
  , void
  )
where
  import Prelude hiding (null, length, splitAt, take)

  import Control.Applicative
  import Control.Monad

  import Data.Maybe
  import Data.Word
  import Data.List qualified as List
  import GHC.Base (unsafeChr)

  import Data.ByteString as BS
  import Data.ByteString.Unsafe as BS

  import Snack.Combinators

  import Data.ByteString.Parser ( Parser(..), Result(..), parseOnly
                                , string, count, match, label, unlabel
                                , validate, branch
                                , takeByteString, peekByteString
                                , endOfInput, atEnd, offset
                                )

  import Data.ByteString.Lex.Fractional qualified as LF
  import Data.ByteString.Lex.Integral qualified as LI


  -- |
  -- Accepts a single, matching ASCII character.
  --
  {-# INLINE CONLIKE char #-}
  char :: Char -> Parser Char
  char :: Char -> Parser Char
char Char
c = String -> Parser Char -> Parser Char
forall a. String -> Parser a -> Parser a
label (Char -> String
forall a. Show a => a -> String
show Char
c) (Parser Char -> Parser Char) -> Parser Char -> Parser Char
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Parser Char
satisfy (Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==)


  -- |
  -- Accepts a single, differing ASCII character.
  --
  {-# INLINE CONLIKE notChar #-}
  notChar :: Char -> Parser Char
  notChar :: Char -> Parser Char
notChar Char
c = (Char -> Bool) -> Parser Char
satisfy (Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=)


  -- |
  -- Accepts a single character.
  --
  {-# INLINE anyChar #-}
  anyChar :: Parser Char
  anyChar :: Parser Char
anyChar = (ByteString -> Result Char) -> Parser Char
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    if ByteString -> Bool
null ByteString
inp
       then [String] -> ByteString -> Result Char
forall a. [String] -> ByteString -> Result a
Failure [String
"any character"] ByteString
inp
       else Char -> ByteString -> Result Char
forall a. a -> ByteString -> Result a
Success (Word8 -> Char
w2c (ByteString -> Word8
unsafeHead ByteString
inp)) (ByteString -> ByteString
unsafeTail ByteString
inp)


  -- |
  -- Accepts a single character matching the predicate.
  --
  {-# INLINE CONLIKE satisfy #-}
  satisfy :: (Char -> Bool) -> Parser Char
  satisfy :: (Char -> Bool) -> Parser Char
satisfy Char -> Bool
isOk = (ByteString -> Result Char) -> Parser Char
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    if ByteString -> Bool
null ByteString
inp
       then [String] -> ByteString -> Result Char
forall a. [String] -> ByteString -> Result a
Failure [String
"more input"] ByteString
inp
       else let c :: Char
c = Word8 -> Char
w2c (ByteString -> Word8
unsafeHead ByteString
inp)
             in if Char -> Bool
isOk Char
c
                   then Char -> ByteString -> Result Char
forall a. a -> ByteString -> Result a
Success Char
c (ByteString -> ByteString
unsafeTail ByteString
inp)
                   else [String] -> ByteString -> Result Char
forall a. [String] -> ByteString -> Result a
Failure [] ByteString
inp


  -- |
  -- Accepts a single ASCII white space character.
  -- See 'isSpace' for details.
  --
  {-# INLINE space #-}
  space :: Parser Char
  space :: Parser Char
space = String -> Parser Char -> Parser Char
forall a. String -> Parser a -> Parser a
label String
"space" (Parser Char -> Parser Char) -> Parser Char -> Parser Char
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Parser Char
satisfy Char -> Bool
isSpace


  -- |
  -- Accepts multiple ASCII white space characters.
  -- See 'isSpace' for details.
  --
  {-# INLINE skipSpace #-}
  skipSpace :: Parser ()
  skipSpace :: Parser ()
skipSpace = Parser ByteString -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Parser ByteString -> Parser ()) -> Parser ByteString -> Parser ()
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Parser ByteString
Data.ByteString.Parser.Char8.takeWhile Char -> Bool
isSpace


  -- |
  -- True for any of the @[' ', '\\t', '\\n', '\\v', '\\f', '\\r']@ characters.
  --
  -- Please note that "Data.Text.Parser" re-exports 'Data.Char.isString', that
  -- considers more unicode codepoints, making it significantly slower.
  --
  {-# INLINE isSpace #-}
  isSpace :: Char -> Bool
  isSpace :: Char -> Bool
isSpace Char
c = (Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ') Bool -> Bool -> Bool
|| (Char
'\t' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\r')


  -- |
  -- Peeks ahead, but does not consume.
  --
  -- Be careful, peeking behind end of the input fails.
  -- You might want to check using 'atEnd' beforehand.
  --
  {-# INLINE peekChar #-}
  peekChar :: Parser Char
  peekChar :: Parser Char
peekChar = (ByteString -> Result Char) -> Parser Char
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    if ByteString -> Bool
null ByteString
inp
       then [String] -> ByteString -> Result Char
forall a. [String] -> ByteString -> Result a
Failure [String
"more input"] ByteString
inp
       else Char -> ByteString -> Result Char
forall a. a -> ByteString -> Result a
Success (Word8 -> Char
w2c (ByteString -> Word8
unsafeHead ByteString
inp)) ByteString
inp


  -- |
  -- Accepts a matching string.
  -- Matching is performed in a case-insensitive manner under ASCII.
  --
  {-# INLINE CONLIKE stringCI #-}
  stringCI :: ByteString -> Parser ByteString
  stringCI :: ByteString -> Parser ByteString
stringCI ByteString
str = (ByteString -> Result ByteString) -> Parser ByteString
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    let (ByteString
pfx, ByteString
sfx) = Int -> ByteString -> (ByteString, ByteString)
splitAt (ByteString -> Int
length ByteString
str) ByteString
inp
     in case ByteString -> ByteString
toCaseFold ByteString
pfx ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString -> ByteString
toCaseFold ByteString
str of
          Bool
True -> ByteString -> ByteString -> Result ByteString
forall a. a -> ByteString -> Result a
Success ByteString
pfx ByteString
sfx
          Bool
False -> [String] -> ByteString -> Result ByteString
forall a. [String] -> ByteString -> Result a
Failure [ByteString -> String
forall a. Show a => a -> String
show ByteString
str] ByteString
inp


  -- |
  -- Perform simple ASCII case folding.
  --
  {-# INLINE toCaseFold #-}
  toCaseFold :: ByteString -> ByteString
  toCaseFold :: ByteString -> ByteString
toCaseFold = (Word8 -> Word8) -> ByteString -> ByteString
BS.map Word8 -> Word8
forall p. (Ord p, Num p) => p -> p
foldCase
    where foldCase :: p -> p
foldCase p
w | p
65 p -> p -> Bool
forall a. Ord a => a -> a -> Bool
<= p
w Bool -> Bool -> Bool
&& p
w p -> p -> Bool
forall a. Ord a => a -> a -> Bool
<= p
90 = p
w p -> p -> p
forall a. Num a => a -> a -> a
+ p
32
          foldCase p
w = p
w


  -- |
  -- Accepts given number of bytes.
  -- Fails when not enough bytes are available.
  --
  {-# INLINE CONLIKE take #-}
  take :: Int -> Parser ByteString
  take :: Int -> Parser ByteString
take Int
n = (ByteString -> Result ByteString) -> Parser ByteString
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> ByteString -> Int
length ByteString
inp
       then [String] -> ByteString -> Result ByteString
forall a. [String] -> ByteString -> Result a
Failure [Int -> String
forall a. Show a => a -> String
show Int
n String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" more bytes"] ByteString
inp
       else ByteString -> ByteString -> Result ByteString
forall a. a -> ByteString -> Result a
Success (Int -> ByteString -> ByteString
unsafeTake Int
n ByteString
inp) (Int -> ByteString -> ByteString
unsafeDrop Int
n ByteString
inp)


  -- |
  -- Scans ahead statefully and then accepts whatever bytes the scanner liked.
  -- Scanner returns 'Nothing' to mark end of the acceptable extent.
  --
  {-# INLINE CONLIKE scan #-}
  scan :: s -> (s -> Char -> Maybe s) -> Parser ByteString
  scan :: s -> (s -> Char -> Maybe s) -> Parser ByteString
scan s
state s -> Char -> Maybe s
scanner = (ByteString, s) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, s) -> ByteString)
-> Parser (ByteString, s) -> Parser ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> s -> (s -> Char -> Maybe s) -> Parser (ByteString, s)
forall s. s -> (s -> Char -> Maybe s) -> Parser (ByteString, s)
runScanner s
state s -> Char -> Maybe s
scanner


  -- |
  -- Like 'scan', but also returns the final scanner state.
  --
  {-# INLINE CONLIKE runScanner #-}
  runScanner :: s -> (s -> Char -> Maybe s) -> Parser (ByteString, s)
  runScanner :: s -> (s -> Char -> Maybe s) -> Parser (ByteString, s)
runScanner s
state s -> Char -> Maybe s
scanner = (ByteString -> Result (ByteString, s)) -> Parser (ByteString, s)
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp -> ByteString -> s -> Int -> Result (ByteString, s)
loop ByteString
inp s
state Int
0
    where
      loop :: ByteString -> s -> Int -> Result (ByteString, s)
loop ByteString
inp !s
st !Int
n =
        case Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteString -> Int
length ByteString
inp of
          Bool
True -> (ByteString, s) -> ByteString -> Result (ByteString, s)
forall a. a -> ByteString -> Result a
Success (ByteString
inp, s
st) ByteString
forall a. Monoid a => a
mempty
          Bool
False ->
            case ByteString -> Int -> Word8
unsafeIndex ByteString
inp Int
n of
              Word8
w ->
                case s -> Char -> Maybe s
scanner s
st (Word8 -> Char
w2c Word8
w) of
                  Maybe s
Nothing -> (ByteString, s) -> ByteString -> Result (ByteString, s)
forall a. a -> ByteString -> Result a
Success (Int -> ByteString -> ByteString
unsafeTake Int
n ByteString
inp, s
st) (Int -> ByteString -> ByteString
unsafeDrop Int
n ByteString
inp)
                  Just s
st' -> ByteString -> s -> Int -> Result (ByteString, s)
loop ByteString
inp s
st' (Int -> Int
forall a. Enum a => a -> a
succ Int
n)


  -- |
  -- Efficiently consume as long as the input characters match the predicate.
  -- An inverse of 'takeTill'.
  --
  {-# INLINE CONLIKE takeWhile #-}
  takeWhile :: (Char -> Bool) -> Parser ByteString
  takeWhile :: (Char -> Bool) -> Parser ByteString
takeWhile Char -> Bool
test = (Char -> Bool) -> Parser ByteString
takeTill (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
test)


  -- |
  -- Like 'Data.ByteString.Parser.Char8.takeWhile',
  -- but requires at least a single character.
  --
  {-# INLINE CONLIKE takeWhile1 #-}
  takeWhile1 :: (Char -> Bool) -> Parser ByteString
  takeWhile1 :: (Char -> Bool) -> Parser ByteString
takeWhile1 Char -> Bool
test = (Char -> Bool) -> Parser ByteString
Data.ByteString.Parser.Char8.takeWhile Char -> Bool
test Parser ByteString -> (ByteString -> Bool) -> Parser ByteString
forall (m :: * -> *) a.
(Alternative m, Monad m) =>
m a -> (a -> Bool) -> m a
`provided` (Bool -> Bool
not (Bool -> Bool) -> (ByteString -> Bool) -> ByteString -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Bool
null)


  -- |
  -- Efficiently consume until a character matching the predicate is found.
  -- An inverse of 'Data.ByteString.Parser.Char8.takeWhile'.
  --
  {-# INLINE CONLIKE takeTill #-}
  takeTill :: (Char -> Bool) -> Parser ByteString
  takeTill :: (Char -> Bool) -> Parser ByteString
takeTill Char -> Bool
test = (ByteString -> Result ByteString) -> Parser ByteString
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    let n :: Int
n = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe (ByteString -> Int
length ByteString
inp) (Maybe Int -> Int) -> Maybe Int -> Int
forall a b. (a -> b) -> a -> b
$ (Word8 -> Bool) -> ByteString -> Maybe Int
findIndex (Char -> Bool
test (Char -> Bool) -> (Word8 -> Char) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Char
w2c) ByteString
inp
     in ByteString -> ByteString -> Result ByteString
forall a. a -> ByteString -> Result a
Success (Int -> ByteString -> ByteString
unsafeTake Int
n ByteString
inp) (Int -> ByteString -> ByteString
unsafeDrop Int
n ByteString
inp)


  -- |
  -- Same as 'takeTill', but requires at least a single character.
  --
  {-# INLINE CONLIKE takeTill1 #-}
  takeTill1 :: (Char -> Bool) -> Parser ByteString
  takeTill1 :: (Char -> Bool) -> Parser ByteString
takeTill1 Char -> Bool
test = (Char -> Bool) -> Parser ByteString
Data.ByteString.Parser.Char8.takeTill Char -> Bool
test Parser ByteString -> (ByteString -> Bool) -> Parser ByteString
forall (m :: * -> *) a.
(Alternative m, Monad m) =>
m a -> (a -> Bool) -> m a
`provided` (Bool -> Bool
not (Bool -> Bool) -> (ByteString -> Bool) -> ByteString -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Bool
null)


  -- |
  -- Accepts optional @\'+\'@ or @\'-\'@ character and then applies it to
  -- the following parser result.
  --
  {-# INLINE signed #-}
  signed :: (Num a) => Parser a -> Parser a
  signed :: Parser a -> Parser a
signed Parser a
runNumber = (Char -> Parser Char
char Char
'-' Parser Char -> Parser a -> Parser a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (a -> a) -> Parser a -> Parser a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Num a => a -> a
negate Parser a
runNumber)
                 Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Parser Char
char Char
'+' Parser Char -> Parser a -> Parser a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser a
runNumber)
                 Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Parser a
runNumber)


  -- |
  -- Accepts an integral number in the decimal format.
  --
  {-# INLINE decimal #-}
  decimal :: (Integral a) => Parser a
  decimal :: Parser a
decimal = (ByteString -> Result a) -> Parser a
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    case ByteString -> Maybe (a, ByteString)
forall a. Integral a => ByteString -> Maybe (a, ByteString)
LI.readDecimal ByteString
inp of
      Just (a
res, ByteString
more) -> a -> ByteString -> Result a
forall a. a -> ByteString -> Result a
Success a
res ByteString
more
      Maybe (a, ByteString)
Nothing -> [String] -> ByteString -> Result a
forall a. [String] -> ByteString -> Result a
Failure [String
"decimal"] ByteString
inp


  -- |
  -- Accepts an integral number in the hexadecimal format in either case.
  -- Does not look for @0x@ or similar prefixes.
  --
  {-# INLINE hexadecimal #-}
  hexadecimal :: (Integral a) => Parser a
  hexadecimal :: Parser a
hexadecimal = (ByteString -> Result a) -> Parser a
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    case ByteString -> Maybe (a, ByteString)
forall a. Integral a => ByteString -> Maybe (a, ByteString)
LI.readHexadecimal ByteString
inp of
      Just (a
res, ByteString
more) -> a -> ByteString -> Result a
forall a. a -> ByteString -> Result a
Success a
res ByteString
more
      Maybe (a, ByteString)
Nothing -> [String] -> ByteString -> Result a
forall a. [String] -> ByteString -> Result a
Failure [String
"hexadecimal"] ByteString
inp


  -- |
  -- Accepts an integral number in the octal format.
  --
  {-# INLINE octal #-}
  octal :: (Integral a) => Parser a
  octal :: Parser a
octal = (ByteString -> Result a) -> Parser a
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    case ByteString -> Maybe (a, ByteString)
forall a. Integral a => ByteString -> Maybe (a, ByteString)
LI.readOctal ByteString
inp of
      Just (a
res, ByteString
more) -> a -> ByteString -> Result a
forall a. a -> ByteString -> Result a
Success a
res ByteString
more
      Maybe (a, ByteString)
Nothing -> [String] -> ByteString -> Result a
forall a. [String] -> ByteString -> Result a
Failure [String
"octal"] ByteString
inp


  -- |
  -- Accepts a fractional number as a decimal optinally followed by a colon
  -- and the fractional part. Does not support exponentiation.
  --
  {-# INLINE fractional #-}
  fractional :: (Fractional a) => Parser a
  fractional :: Parser a
fractional = (ByteString -> Result a) -> Parser a
forall a. (ByteString -> Result a) -> Parser a
Parser \ByteString
inp ->
    case ByteString -> Maybe (a, ByteString)
forall a. Fractional a => ByteString -> Maybe (a, ByteString)
LF.readDecimal ByteString
inp of
      Just (a
res, ByteString
more) -> a -> ByteString -> Result a
forall a. a -> ByteString -> Result a
Success a
res ByteString
more
      Maybe (a, ByteString)
Nothing -> [String] -> ByteString -> Result a
forall a. [String] -> ByteString -> Result a
Failure [String
"fractional"] ByteString
inp


  {-# INLINE w2c #-}
  w2c :: Word8 -> Char
  w2c :: Word8 -> Char
w2c = Int -> Char
unsafeChr (Int -> Char) -> (Word8 -> Int) -> Word8 -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral


  -- |
  -- Determine @(line, column)@ from the original input and the remainder.
  --
  -- Counts line feed characters leading to the 'offset', so only use it
  -- on your slow path. For example when describing parsing errors.
  --
  position :: ByteString -> ByteString -> (Int, Int)
  position :: ByteString -> ByteString -> (Int, Int)
position ByteString
inp ByteString
more = (Int -> Int
forall a. Enum a => a -> a
succ Int
line, Int -> Int
forall a. Enum a => a -> a
succ Int
column)
    where
      column :: Int
column = ByteString -> Int
length ByteString
lastLine
      lastLine :: ByteString
lastLine = (Word8 -> Bool) -> ByteString -> ByteString
takeWhileEnd (Word8
10 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/=) ByteString
leader
      line :: Int
line = Word8 -> ByteString -> Int
BS.count Word8
10 ByteString
leader
      leader :: ByteString
leader = Int -> ByteString -> ByteString
dropEnd (ByteString -> Int
length ByteString
more) ByteString
inp


  -- |
  -- More precise 'Result' description produced by 'explain'.
  --
  data Explanation
    = Explanation
      { Explanation -> String
exSource       :: String
        -- ^ Name of the source file.
      , Explanation -> (Int, Int)
exSpanFrom     :: (Int, Int)
        -- ^ Line and column where the problem starts.
      , Explanation -> (Int, Int)
exSpanTo       :: (Int, Int)
        -- ^ Line and column where the problem ends.
      , Explanation -> String
exMessage      :: String
        -- ^ Message associated with the problem.
      }
    deriving (Explanation -> Explanation -> Bool
(Explanation -> Explanation -> Bool)
-> (Explanation -> Explanation -> Bool) -> Eq Explanation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Explanation -> Explanation -> Bool
$c/= :: Explanation -> Explanation -> Bool
== :: Explanation -> Explanation -> Bool
$c== :: Explanation -> Explanation -> Bool
Eq, Int -> Explanation -> String -> String
[Explanation] -> String -> String
Explanation -> String
(Int -> Explanation -> String -> String)
-> (Explanation -> String)
-> ([Explanation] -> String -> String)
-> Show Explanation
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [Explanation] -> String -> String
$cshowList :: [Explanation] -> String -> String
show :: Explanation -> String
$cshow :: Explanation -> String
showsPrec :: Int -> Explanation -> String -> String
$cshowsPrec :: Int -> Explanation -> String -> String
Show)


  -- |
  -- Process the result for showing it to the user.
  --
  explain :: String -> ByteString -> Result a -> Explanation
  explain :: String -> ByteString -> Result a -> Explanation
explain String
src ByteString
inp (Success a
_ ByteString
more) =
    Explanation :: String -> (Int, Int) -> (Int, Int) -> String -> Explanation
Explanation { exSource :: String
exSource   = String
src
                , exSpanFrom :: (Int, Int)
exSpanFrom = (Int, Int)
pos
                , exSpanTo :: (Int, Int)
exSpanTo   = (Int, Int)
pos
                , exMessage :: String
exMessage  = String
"Parsed successfully up to this point."
                }
      where
        pos :: (Int, Int)
pos = ByteString -> ByteString -> (Int, Int)
position ByteString
inp ByteString
more


  explain String
src ByteString
inp (Failure [String]
expected ByteString
more) =
    Explanation :: String -> (Int, Int) -> (Int, Int) -> String -> Explanation
Explanation { exSource :: String
exSource   = String
src
                , exSpanFrom :: (Int, Int)
exSpanFrom = (Int, Int)
pos
                , exSpanTo :: (Int, Int)
exSpanTo   = (Int, Int)
pos
                , exMessage :: String
exMessage =
                    case [String]
expected of
                      [] -> String
"Unexpected input."
                      [String]
ex -> String
"Expected " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
List.intercalate String
", " [String]
ex String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"."
                }
      where
        pos :: (Int, Int)
pos = ByteString -> ByteString -> (Int, Int)
position ByteString
inp ByteString
more

  explain String
src ByteString
inp (Error String
reason ByteString
more Int
len) =
    Explanation :: String -> (Int, Int) -> (Int, Int) -> String -> Explanation
Explanation { exSource :: String
exSource   = String
src
                , exSpanFrom :: (Int, Int)
exSpanFrom = (Int, Int)
from
                , exSpanTo :: (Int, Int)
exSpanTo   = (Int, Int)
to
                , exMessage :: String
exMessage  = String
reason
                }
      where
        from :: (Int, Int)
from = ByteString -> ByteString -> (Int, Int)
position ByteString
inp ByteString
more
        to :: (Int, Int)
to   = ByteString -> ByteString -> (Int, Int)
position ByteString
inp (Int -> ByteString -> ByteString
BS.drop Int
len ByteString
more)


-- vim:set ft=haskell sw=2 ts=2 et: