{-# language MagicHash #-}
{-# language BlockArguments #-}
{-# language UnboxedTuples #-}
{-# language BangPatterns #-}
{-# language TypeApplications #-}
{-# language NegativeLiterals #-}
{-# language UnliftedFFITypes #-}
{-# language ScopedTypeVariables #-}
{-# language ForeignFunctionInterface #-}

-- | Note: @parsnip@ will still be assuming that the input is null terminated
-- even if you use these combinators.
module Text.Parsnip.Word8
( satisfy
, word8
, notWord8
, anyWord8
, while, whileSome
, till, tillSome, tillWord8
, skipWhile, skipWhileSome
, skipTill, skipTillSome, skipTillWord8
, previousWord8, previousWord8'
, nextWord8, nextWord8'
) where

import Data.ByteString (ByteString)
import Data.Word
import GHC.Prim
import GHC.Ptr
import GHC.Types
import GHC.Word
import Text.Parsnip.Internal.Parser
import Text.Parsnip.Internal.Private
import Text.Parsnip.Parser

--------------------------------------------------------------------------------
-- * Word8 parsers
--------------------------------------------------------------------------------

satisfy :: (Word8 -> Bool) -> Parser s Word8
satisfy :: forall s. (Word8 -> Bool) -> Parser s Word8
satisfy Word8 -> Bool
f = (Addr# -> State# s -> Result s Word8) -> Parser s Word8
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s -> case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p Int#
0# State# s
s of
  (# State# s
t, Word#
c #) -> if Int# -> Bool
isTrue# (Word#
0## Word# -> Word# -> Int#
`neWord#` Word#
c) Bool -> Bool -> Bool
&& Word8 -> Bool
f (Word# -> Word8
W8# Word#
c)
    then Word8 -> Addr# -> State# s -> Result s Word8
forall a s. a -> Addr# -> State# s -> Result s a
OK (Word# -> Word8
W8# Word#
c) (Addr# -> Int# -> Addr#
plusAddr# Addr#
p Int#
1#) State# s
t
    else Addr# -> State# s -> Result s Word8
forall s a. Addr# -> State# s -> Result s a
Fail Addr#
p State# s
t
{-# inline satisfy #-}

notWord8 :: Word8 -> Parser s Word8
notWord8 :: forall s. Word8 -> Parser s Word8
notWord8 Word8
0 = Parser s Word8
forall s. Parser s Word8
anyWord8
notWord8 (W8# Word#
c) = (Addr# -> State# s -> Result s Word8) -> Parser s Word8
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s -> case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p Int#
0# State# s
s of
  (# State# s
t, Word#
c' #) -> if Int# -> Bool
isTrue# (Word#
0## Word# -> Word# -> Int#
`neWord#` Word#
c') Bool -> Bool -> Bool
&& Int# -> Bool
isTrue# (Word#
c Word# -> Word# -> Int#
`neWord#` Word#
c')
    then Word8 -> Addr# -> State# s -> Result s Word8
forall a s. a -> Addr# -> State# s -> Result s a
OK (Word# -> Word8
W8# Word#
c') (Addr# -> Int# -> Addr#
plusAddr# Addr#
p Int#
1#) State# s
t
    else Addr# -> State# s -> Result s Word8
forall s a. Addr# -> State# s -> Result s a
Fail Addr#
p State# s
t
{-# inline notWord8 #-}

nextWord8 :: Parser s (Maybe Word8)
nextWord8 :: forall s. Parser s (Maybe Word8)
nextWord8 = (Addr# -> State# s -> Result s (Maybe Word8))
-> Parser s (Maybe Word8)
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s -> case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p Int#
0# State# s
s of
  (# State# s
t, Word#
c #) -> Maybe Word8 -> Addr# -> State# s -> Result s (Maybe Word8)
forall a s. a -> Addr# -> State# s -> Result s a
OK (if Int# -> Bool
isTrue# (Word#
0## Word# -> Word# -> Int#
`neWord#` Word#
c) then Word8 -> Maybe Word8
forall a. a -> Maybe a
Just (Word# -> Word8
W8# Word#
c) else Maybe Word8
forall a. Maybe a
Nothing) Addr#
p State# s
t
{-# inline nextWord8 #-}

nextWord8' :: Parser s Word8
nextWord8' :: forall s. Parser s Word8
nextWord8' = (Addr# -> State# s -> Result s Word8) -> Parser s Word8
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s -> case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p Int#
0# State# s
s of
  (# State# s
t, Word#
c #) -> if Int# -> Bool
isTrue# (Word#
0## Word# -> Word# -> Int#
`neWord#` Word#
c)
    then Word8 -> Addr# -> State# s -> Result s Word8
forall a s. a -> Addr# -> State# s -> Result s a
OK (Word# -> Word8
W8# Word#
c) Addr#
p State# s
t
    else Addr# -> State# s -> Result s Word8
forall s a. Addr# -> State# s -> Result s a
Fail Addr#
p State# s
t
{-# inline nextWord8' #-}

anyWord8 :: Parser s Word8
anyWord8 :: forall s. Parser s Word8
anyWord8 = (Addr# -> State# s -> Result s Word8) -> Parser s Word8
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s -> case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p Int#
0# State# s
s of
  (# State# s
t, Word#
c #) -> if Int# -> Bool
isTrue# (Word#
0## Word# -> Word# -> Int#
`neWord#` Word#
c)
    then Word8 -> Addr# -> State# s -> Result s Word8
forall a s. a -> Addr# -> State# s -> Result s a
OK (Word# -> Word8
W8# Word#
c) (Addr# -> Int# -> Addr#
plusAddr# Addr#
p Int#
1#) State# s
t
    else Addr# -> State# s -> Result s Word8
forall s a. Addr# -> State# s -> Result s a
Fail Addr#
p State# s
t
{-# inline anyWord8 #-}

scan :: (Word8 -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
scan :: forall s.
(Word8 -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
scan Word8 -> Bool
f = Addr# -> State# s -> (# State# s, Addr# #)
forall {s}. Addr# -> State# s -> (# State# s, Addr# #)
go where
  go :: Addr# -> State# s -> (# State# s, Addr# #)
go Addr#
p State# s
s = case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p Int#
0# State# s
s of
    (# State# s
t, Word#
c #) -> if Int# -> Bool
isTrue# (Word#
0## Word# -> Word# -> Int#
`neWord#` Word#
c) Bool -> Bool -> Bool
&& Word8 -> Bool
f (Word# -> Word8
W8# Word#
c)
      then (# State# s
t, Addr#
p #)
      else (Word8 -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
forall s.
(Word8 -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
scan Word8 -> Bool
f (Addr# -> Int# -> Addr#
plusAddr# Addr#
p Int#
1#) State# s
t
{-# inline scan #-}

skipWhile :: (Word8 -> Bool) -> Parser s ()
skipWhile :: forall s. (Word8 -> Bool) -> Parser s ()
skipWhile Word8 -> Bool
f = (Addr# -> State# s -> Result s ()) -> Parser s ()
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s -> case (Word8 -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
forall s.
(Word8 -> Bool) -> Addr# -> State# s -> (# State# s, Addr# #)
scan Word8 -> Bool
f Addr#
p State# s
s of
  (# State# s
t, Addr#
q #) -> () -> Addr# -> State# s -> Result s ()
forall a s. a -> Addr# -> State# s -> Result s a
OK () Addr#
q State# s
t
{-# inline [1] skipWhile #-}

{-# RULES
"skipWhile (x/=)" forall x.
  skipWhile (x `neWord8`) = skipTillWord8 x
"skipWhile (/=x)" forall x.
  skipWhile (`neWord8` x) = skipTillWord8 x
  #-}

skipTill :: (Word8 -> Bool) -> Parser s ()
skipTill :: forall s. (Word8 -> Bool) -> Parser s ()
skipTill Word8 -> Bool
p = (Word8 -> Bool) -> Parser s ()
forall s. (Word8 -> Bool) -> Parser s ()
skipWhile (Bool -> Bool
not (Bool -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Bool
p)
{-# inline [1] skipTill #-}

{-# RULES
"skipTill (x==)" forall x.
  skipTill (x `eqWord8`) = skipTillWord8 x
"skipWhile (==x)" forall x.
  skipWhile (`eqWord8` x) = skipTillWord8 x
  #-}

skipTillSome :: (Word8 -> Bool) -> Parser s ()
skipTillSome :: forall s. (Word8 -> Bool) -> Parser s ()
skipTillSome Word8 -> Bool
p = (Word8 -> Bool) -> Parser s ()
forall s. (Word8 -> Bool) -> Parser s ()
skipWhileSome (Bool -> Bool
not (Bool -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Bool
p)
{-# inline skipTillSome #-}

foreign import ccall "parsnip.h" strchr0 :: Addr# -> Char# -> IO (Ptr Word8) -- lazy reimport is lazy

skipTillWord8 :: Word8 -> Parser s ()
skipTillWord8 :: forall s. Word8 -> Parser s ()
skipTillWord8 (W8# Word#
c) = (Addr# -> State# s -> Result s ()) -> Parser s ()
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser ((Addr# -> State# s -> Result s ()) -> Parser s ())
-> (Addr# -> State# s -> Result s ()) -> Parser s ()
forall a b. (a -> b) -> a -> b
$ \Addr#
p State# s
s -> case IO (Ptr Word8) -> State# s -> (# State# s, Ptr Word8 #)
forall a s. IO a -> State# s -> (# State# s, a #)
io (Addr# -> Char# -> IO (Ptr Word8)
strchr0 Addr#
p (Int# -> Char#
chr# (Word# -> Int#
word2Int# Word#
c))) State# s
s of -- lazy cast is lazy
  (# State# s
t, Ptr Addr#
q #) -> () -> Addr# -> State# s -> Result s ()
forall a s. a -> Addr# -> State# s -> Result s a
OK () Addr#
q State# s
t
{-# inline skipTillWord8 #-}

skipWhileSome :: (Word8 -> Bool) -> Parser s ()
skipWhileSome :: forall s. (Word8 -> Bool) -> Parser s ()
skipWhileSome Word8 -> Bool
p = (Word8 -> Bool) -> Parser s Word8
forall s. (Word8 -> Bool) -> Parser s Word8
satisfy Word8 -> Bool
p Parser s Word8 -> Parser s () -> Parser s ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Word8 -> Bool) -> Parser s ()
forall s. (Word8 -> Bool) -> Parser s ()
skipWhile Word8 -> Bool
p
{-# inline skipWhileSome #-}

while :: KnownBase s => (Word8 -> Bool) -> Parser s ByteString
while :: forall s. KnownBase s => (Word8 -> Bool) -> Parser s ByteString
while Word8 -> Bool
f = Parser s () -> Parser s ByteString
forall s a. KnownBase s => Parser s a -> Parser s ByteString
snipping ((Word8 -> Bool) -> Parser s ()
forall s. (Word8 -> Bool) -> Parser s ()
skipWhile Word8 -> Bool
f)
{-# inline while #-}

till :: KnownBase s => (Word8 -> Bool) -> Parser s ByteString
till :: forall s. KnownBase s => (Word8 -> Bool) -> Parser s ByteString
till Word8 -> Bool
p = Parser s () -> Parser s ByteString
forall s a. KnownBase s => Parser s a -> Parser s ByteString
snipping ((Word8 -> Bool) -> Parser s ()
forall s. (Word8 -> Bool) -> Parser s ()
skipTill Word8 -> Bool
p)
{-# inline till #-}

tillWord8 :: KnownBase s => Word8 -> Parser s ByteString
tillWord8 :: forall s. KnownBase s => Word8 -> Parser s ByteString
tillWord8 Word8
c = Parser s () -> Parser s ByteString
forall s a. KnownBase s => Parser s a -> Parser s ByteString
snipping (Word8 -> Parser s ()
forall s. Word8 -> Parser s ()
skipTillWord8 Word8
c)
{-# inline tillWord8 #-}

whileSome :: KnownBase s => (Word8 -> Bool) -> Parser s ByteString
whileSome :: forall s. KnownBase s => (Word8 -> Bool) -> Parser s ByteString
whileSome Word8 -> Bool
p = Parser s () -> Parser s ByteString
forall s a. KnownBase s => Parser s a -> Parser s ByteString
snipping ((Word8 -> Bool) -> Parser s ()
forall s. (Word8 -> Bool) -> Parser s ()
skipWhileSome Word8 -> Bool
p)
{-# inline whileSome #-}

tillSome :: KnownBase s => (Word8 -> Bool) -> Parser s ByteString
tillSome :: forall s. KnownBase s => (Word8 -> Bool) -> Parser s ByteString
tillSome Word8 -> Bool
p = Parser s () -> Parser s ByteString
forall s a. KnownBase s => Parser s a -> Parser s ByteString
snipping ((Word8 -> Bool) -> Parser s ()
forall s. (Word8 -> Bool) -> Parser s ()
skipTillSome Word8 -> Bool
p)
{-# inline tillSome #-}

-- | Peek at the previous character. Always succeeds.
previousWord8 :: forall s. KnownBase s => Parser s (Maybe Word8)
previousWord8 :: forall s. KnownBase s => Parser s (Maybe Word8)
previousWord8 = case forall s. KnownBase s => Base s
reflectBase @s of
  !(Base Addr#
_ ForeignPtrContents
_ Addr#
l Addr#
_) -> (Addr# -> State# s -> Result s (Maybe Word8))
-> Parser s (Maybe Word8)
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s ->
    if Int# -> Bool
isTrue# (Addr# -> Addr# -> Int#
ltAddr# Addr#
l Addr#
p)
    then case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p (Int#
-1#) State# s
s of
      (# State# s
t, Word#
c #) -> Maybe Word8 -> Addr# -> State# s -> Result s (Maybe Word8)
forall a s. a -> Addr# -> State# s -> Result s a
OK (Word8 -> Maybe Word8
forall a. a -> Maybe a
Just (Word# -> Word8
W8# Word#
c)) Addr#
p State# s
t
    else Maybe Word8 -> Addr# -> State# s -> Result s (Maybe Word8)
forall a s. a -> Addr# -> State# s -> Result s a
OK Maybe Word8
forall a. Maybe a
Nothing Addr#
p State# s
s
{-# inline previousWord8 #-}

-- | Peek at the previous character. Fails if we're at the start of input.
previousWord8' :: forall s. KnownBase s => Parser s Word8
previousWord8' :: forall s. KnownBase s => Parser s Word8
previousWord8' = case forall s. KnownBase s => Base s
reflectBase @s of
  !(Base Addr#
_ ForeignPtrContents
_ Addr#
l Addr#
_) -> (Addr# -> State# s -> Result s Word8) -> Parser s Word8
forall s a. (Addr# -> State# s -> Result s a) -> Parser s a
Parser \Addr#
p State# s
s ->
    if Int# -> Bool
isTrue# (Addr# -> Addr# -> Int#
ltAddr# Addr#
l Addr#
p)
    then case Addr# -> Int# -> State# s -> (# State# s, Word# #)
forall d. Addr# -> Int# -> State# d -> (# State# d, Word# #)
readWord8OffAddr# Addr#
p (Int#
-1#) State# s
s of
      (# State# s
t, Word#
c #) -> Word8 -> Addr# -> State# s -> Result s Word8
forall a s. a -> Addr# -> State# s -> Result s a
OK (Word# -> Word8
W8# Word#
c) Addr#
p State# s
t
    else Addr# -> State# s -> Result s Word8
forall s a. Addr# -> State# s -> Result s a
Fail Addr#
p State# s
s
{-# inline previousWord8' #-}