module Data.ByteString.Parser.Char8
( Parser(..)
, Result(..)
, parseOnly
, char
, notChar
, anyChar
, satisfy
, space
, isSpace
, skipSpace
, peekChar
, string
, stringCI
, Data.ByteString.Parser.Char8.take
, scan
, runScanner
, inRange
, notInRange
, Data.ByteString.Parser.Char8.takeWhile
, takeWhile1
, takeTill
, takeTill1
, signed
, decimal
, hexadecimal
, octal
, fractional
, provided
, choice
, branch
, Data.ByteString.Parser.count
, optional
, eitherP
, option
, many
, many1
, manyTill
, sepBy
, sepBy1
, wrap
, match
, label
, unlabel
, validate
, takeByteString
, peekByteString
, endOfInput
, atEnd
, offset
, position
, explain
, Explanation(..)
, 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
{-# 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
==)
{-# 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
/=)
{-# 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)
{-# 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
{-# 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
{-# 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
{-# 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')
{-# 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
{-# 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
{-# 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
{-# 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)
{-# 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
{-# 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)
{-# 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)
{-# 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)
{-# 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)
{-# 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)
{-# 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)
{-# 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
{-# 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
{-# 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
{-# 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
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
data Explanation
= Explanation
{ Explanation -> String
exSource :: String
, Explanation -> (Int, Int)
exSpanFrom :: (Int, Int)
, Explanation -> (Int, Int)
exSpanTo :: (Int, Int)
, Explanation -> String
exMessage :: String
}
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)
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)