{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE FlexibleInstances #-}

{-|
Parser supporting a custom reader environment, custom error types and an 'Int'
state. A common use case of the `Int` state is to keep track of column numbers
to implement indentation-sensitive parsers.
-}

module FlatParse.Stateful (

  -- * Parser types
    FP.Parser.ParserT(..)
  , FP.Parser.Parser, FP.Parser.ParserIO, FP.Parser.ParserST

  -- * Running parsers
  , Result(..)
  , runParser
  , runParserUtf8
  , runParserIO
  , runParserST

  -- ** Primitive result types
  , type FP.Parser.Res#
  , pattern FP.Parser.OK#, pattern FP.Parser.Err#, pattern FP.Parser.Fail#
  , type FP.Parser.ResI#

  -- * Embedding `ST` operations
  , liftST

  -- * Environment operations
  , ask
  , local

  -- * State operations
  , get
  , put
  , modify

  -- * UTF conversion
  , Common.strToUtf8
  , Common.utf8ToStr

  -- * Character predicates
  , Common.isDigit
  , Common.isLatinLetter
  , Common.isGreekLetter

  -- * Parsers
  -- ** Bytewise
  , FP.Base.eof
  , FP.Base.take
  , FP.Base.take#
  , FP.Base.takeUnsafe#
  , FP.Base.takeRest
  , FP.Base.skip
  , FP.Base.skip#
  , FP.Base.skipBack
  , FP.Base.skipBack#
  , FP.Base.atSkip#
  , FP.Base.atSkipUnsafe#

  , FP.Bytes.bytes
  , FP.Bytes.bytesUnsafe
  , byteString
  , anyCString
  , anyVarintProtobuf

  -- ** Combinators
  , (FP.Parser.<|>)
  , FP.Base.branch
  , FP.Base.notFollowedBy
  , FP.Base.chainl
  , FP.Base.chainr
  , FP.Base.lookahead
  , FP.Base.ensure
  , FP.Base.ensure#
  , FP.Base.withEnsure
  , FP.Base.withEnsure1
  , FP.Base.withEnsure#
  , FP.Base.isolate
  , FP.Base.isolate#
  , FP.Base.isolateUnsafe#
  , FP.Switch.switch
  , FP.Switch.switchWithPost
  , FP.Switch.rawSwitchWithPost
  , Control.Applicative.many
  , FP.Base.skipMany
  , Control.Applicative.some
  , FP.Base.skipSome

  -- ** Errors and failures
  , Control.Applicative.empty
  , FP.Base.failed
  , FP.Base.try
  , FP.Base.err
  , FP.Base.fails
  , FP.Base.cut
  , FP.Base.cutting
  , FP.Base.optional
  , FP.Base.optional_
  , FP.Base.withOption

  -- ** Positions
  , FlatParse.Common.Position.Pos(..)
  , FlatParse.Common.Position.endPos
  , FlatParse.Common.Position.addrToPos#
  , FlatParse.Common.Position.posToAddr#
  , FlatParse.Common.Position.Span(..)
  , FlatParse.Common.Position.unsafeSlice
  , getPos
  , setPos
  , spanOf
  , withSpan
  , byteStringOf
  , withByteString
  , inSpan
  , Basic.validPos
  , Basic.posLineCols
  , Basic.mkPos

  -- ** Text
  -- *** UTF-8
  , FP.Text.char, FP.Text.string
  , FP.Text.anyChar, FP.Text.skipAnyChar
  , FP.Text.satisfy, FP.Text.skipSatisfy
  , FP.Text.fusedSatisfy, FP.Text.skipFusedSatisfy
  , FP.Text.takeLine
  , FP.Text.takeRestString
  , Basic.linesUtf8

  -- *** ASCII
  , FP.Text.anyAsciiChar, FP.Text.skipAnyAsciiChar
  , FP.Text.satisfyAscii, FP.Text.skipSatisfyAscii

  -- *** ASCII-encoded numbers
  , FP.Text.anyAsciiDecimalWord
  , FP.Text.anyAsciiDecimalInt
  , FP.Text.anyAsciiDecimalInteger
  , FP.Text.anyAsciiHexWord
  , FP.Text.anyAsciiHexInt

  -- ** Machine integers
  , module FP.Integers

  -- ** Debugging parsers
  , FP.Text.traceLine
  , FP.Text.traceRest

  -- * Unsafe
  , unsafeSpanToByteString

  -- ** IO
  , unsafeLiftIO

  -- ** Parsers
  , module FP.Addr
  , anyCStringUnsafe

  ) where


import qualified FlatParse.Basic as Basic
import FlatParse.Stateful.Parser
import FlatParse.Stateful.Base
import FlatParse.Stateful.Integers
import FlatParse.Stateful.Addr
import FlatParse.Common.Position
import qualified FlatParse.Common.Assorted as Common
import qualified FlatParse.Common.Numbers  as Common

import qualified FlatParse.Stateful.Parser as FP.Parser
import qualified FlatParse.Stateful.Base as FP.Base
import qualified FlatParse.Stateful.Integers as FP.Integers
import qualified FlatParse.Stateful.Bytes as FP.Bytes
import qualified FlatParse.Stateful.Text as FP.Text
import qualified FlatParse.Stateful.Switch as FP.Switch
import qualified FlatParse.Stateful.Addr as FP.Addr

import qualified Control.Applicative
import GHC.IO (IO(..))
import GHC.Exts
import GHC.ForeignPtr
import GHC.ST (ST(..))
import System.IO.Unsafe

import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Unsafe as B

--------------------------------------------------------------------------------

-- | Higher-level boxed data type for parsing results.
data Result e a =
    OK a Int !(B.ByteString)  -- ^ Contains return value, last `Int` state, unconsumed input.
  | Fail                      -- ^ Recoverable-by-default failure.
  | Err !e                    -- ^ Unrecoverble-by-default error.
  deriving Int -> Result e a -> ShowS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall e a. (Show a, Show e) => Int -> Result e a -> ShowS
forall e a. (Show a, Show e) => [Result e a] -> ShowS
forall e a. (Show a, Show e) => Result e a -> String
showList :: [Result e a] -> ShowS
$cshowList :: forall e a. (Show a, Show e) => [Result e a] -> ShowS
show :: Result e a -> String
$cshow :: forall e a. (Show a, Show e) => Result e a -> String
showsPrec :: Int -> Result e a -> ShowS
$cshowsPrec :: forall e a. (Show a, Show e) => Int -> Result e a -> ShowS
Show

instance Functor (Result e) where
  fmap :: forall a b. (a -> b) -> Result e a -> Result e b
fmap a -> b
f (OK a
a Int
s ByteString
n) = let !b :: b
b = a -> b
f a
a in forall e a. a -> Int -> ByteString -> Result e a
OK b
b Int
s ByteString
n
  fmap a -> b
f Result e a
r          = unsafeCoerce# :: forall a b. a -> b
unsafeCoerce# Result e a
r
  {-# inline fmap #-}
  <$ :: forall a b. a -> Result e b -> Result e a
(<$) a
a (OK b
_ Int
s ByteString
n) = forall e a. a -> Int -> ByteString -> Result e a
OK a
a Int
s ByteString
n
  (<$) a
_ Result e b
r          = unsafeCoerce# :: forall a b. a -> b
unsafeCoerce# Result e b
r
  {-# inline (<$) #-}

-- | Embed an IO action in a 'ParserT'. This is slightly safer than 'unsafePerformIO' because
-- it will sequenced correctly with respect to the surrounding actions, and its execution is guaranteed.
unsafeLiftIO :: IO a -> ParserT st r e a
unsafeLiftIO :: forall a (st :: ZeroBitType) r e. IO a -> ParserT st r e a
unsafeLiftIO IO a
io = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st ->
                   let !a :: a
a = forall a. IO a -> a
unsafePerformIO IO a
io
                   in forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st a
a Addr#
s Int#
n
{-# inline unsafeLiftIO #-}

--------------------------------------------------------------------------------

-- | Run a pure parser. The `Int` argument is the initial state.
runParser :: Parser r e a -> r -> Int -> B.ByteString -> Result e a
runParser :: forall r e a. Parser r e a -> r -> Int -> ByteString -> Result e a
runParser (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> PureMode -> Res# PureMode e a
f) !r
r (I# Int#
n) b :: ByteString
b@(B.PS (ForeignPtr Addr#
_ ForeignPtrContents
fp) Int
_ (I# Int#
len)) = forall a. IO a -> a
unsafeDupablePerformIO forall a b. (a -> b) -> a -> b
$
  forall a. ByteString -> (CString -> IO a) -> IO a
B.unsafeUseAsCString ByteString
b \(Ptr Addr#
buf) -> do
    let end :: Addr#
end = Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
len
    forall (f :: * -> *) a. Applicative f => a -> f a
pure case ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> PureMode -> Res# PureMode e a
f ForeignPtrContents
fp r
r Addr#
end Addr#
buf Int#
n forall {k} (a :: k). Proxy# a
proxy# of
      OK# PureMode
_st a
a Addr#
s Int#
n' -> let offset :: Int#
offset = Addr# -> Addr# -> Int#
minusAddr# Addr#
s Addr#
buf
                        in forall e a. a -> Int -> ByteString -> Result e a
OK a
a (Int# -> Int
I# Int#
n') (Int -> ByteString -> ByteString
B.drop (Int# -> Int
I# Int#
offset) ByteString
b)

      Err# PureMode
_st e
e ->  forall e a. e -> Result e a
Err e
e
      Fail# PureMode
_st  ->  forall e a. Result e a
Fail
{-# noinline runParser #-}
-- We mark this as noinline to allow power users to safely do unsafe state token coercions.
-- Details are discussed in https://github.com/AndrasKovacs/flatparse/pull/34#issuecomment-1326999390

-- | Run a parser on a 'String', converting it to the corresponding UTF-8 bytes.
--   The `Int` argument is the initial state.
--
-- Reminder: @OverloadedStrings@ for 'B.ByteString' does not yield a valid UTF-8
-- encoding! For non-ASCII 'B.ByteString' literal input, use this wrapper or
-- convert your input using `strToUtf8`.
runParserUtf8 :: Parser r e a -> r -> Int -> String -> Result e a
runParserUtf8 :: forall r e a. Parser r e a -> r -> Int -> String -> Result e a
runParserUtf8 Parser r e a
pa r
r !Int
n String
s = forall r e a. Parser r e a -> r -> Int -> ByteString -> Result e a
runParser Parser r e a
pa r
r Int
n (String -> ByteString
Common.strToUtf8 String
s)

-- | Run an `ST`-based parser. The `Int` argument is the initial state.
runParserST :: (forall s. ParserST s r e a) -> r -> Int -> B.ByteString -> Result e a
runParserST :: forall r e a.
(forall s. ParserST s r e a)
-> r -> Int -> ByteString -> Result e a
runParserST forall s. ParserST s r e a
pst !r
r Int
i ByteString
buf = forall a. IO a -> a
unsafeDupablePerformIO (forall r e a.
ParserIO r e a -> r -> Int -> ByteString -> IO (Result e a)
runParserIO forall s. ParserST s r e a
pst r
r Int
i ByteString
buf)
{-# inlinable runParserST #-}

-- | Run an `IO`-based parser. The `Int` argument is the initial state.
runParserIO :: ParserIO r e a -> r -> Int -> B.ByteString -> IO (Result e a)
runParserIO :: forall r e a.
ParserIO r e a -> r -> Int -> ByteString -> IO (Result e a)
runParserIO (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e a
f) !r
r (I# Int#
n) b :: ByteString
b@(B.PS (ForeignPtr Addr#
_ ForeignPtrContents
fp) Int
_ (I# Int#
len)) = do
  forall a. ByteString -> (CString -> IO a) -> IO a
B.unsafeUseAsCString ByteString
b \(Ptr Addr#
buf) -> do
    let end :: Addr#
end = Addr# -> Int# -> Addr#
plusAddr# Addr#
buf Int#
len
    forall a. (IOMode -> (# IOMode, a #)) -> IO a
IO \IOMode
st -> case ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e a
f ForeignPtrContents
fp r
r Addr#
end Addr#
buf Int#
n IOMode
st of
      OK# IOMode
rw' a
a Addr#
s Int#
n' ->  let offset :: Int#
offset = Addr# -> Addr# -> Int#
minusAddr# Addr#
s Addr#
buf
                         in (# IOMode
rw', forall e a. a -> Int -> ByteString -> Result e a
OK a
a (Int# -> Int
I# Int#
n') (Int -> ByteString -> ByteString
B.drop (Int# -> Int
I# Int#
offset) ByteString
b) #)

      Err# IOMode
rw' e
e ->  (# IOMode
rw', forall e a. e -> Result e a
Err e
e #)
      Fail# IOMode
rw'  ->  (# IOMode
rw', forall e a. Result e a
Fail #)
{-# inlinable runParserIO #-}

--------------------------------------------------------------------------------

-- | Run an `ST` action in a `ParserST`.
liftST :: ST s a -> ParserST s r e a
liftST :: forall s a r e. ST s a -> ParserST s r e a
liftST (ST STRep s a
f) = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n STMode s
st -> case STRep s a
f STMode s
st of
  (# STMode s
st, a
a #) -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# STMode s
st a
a Addr#
s Int#
n
{-# inline liftST #-}

--------------------------------------------------------------------------------

-- | Query the `Int` state.
get :: ParserT st r e Int
get :: forall (st :: ZeroBitType) r e. ParserT st r e Int
get = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st (Int# -> Int
I# Int#
n) Addr#
s Int#
n
{-# inline get #-}

-- | Write the `Int` state.
put :: Int -> ParserT st r e ()
put :: forall (st :: ZeroBitType) r e. Int -> ParserT st r e ()
put (I# Int#
n) = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
_ st
st -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st () Addr#
s Int#
n
{-# inline put #-}

-- | Modify the `Int` state.
modify :: (Int -> Int) -> ParserT st r e ()
modify :: forall (st :: ZeroBitType) r e. (Int -> Int) -> ParserT st r e ()
modify Int -> Int
f = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st ->
  case Int -> Int
f (Int# -> Int
I# Int#
n) of
    I# Int#
n -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st () Addr#
s Int#
n
{-# inline modify #-}

-- | Query the environment.
ask :: ParserT st r e r
ask :: forall (st :: ZeroBitType) r e. ParserT st r e r
ask = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st r
r Addr#
s Int#
n
{-# inline ask #-}

-- | Run a parser in a modified environment.
local :: (r -> r) -> ParserT st r e a -> ParserT st r e a
local :: forall r (st :: ZeroBitType) e a.
(r -> r) -> ParserT st r e a -> ParserT st r e a
local r -> r
f (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
g) = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> let !r' :: r
r' = r -> r
f r
r in ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
g ForeignPtrContents
fp r
r' Addr#
eob Addr#
s Int#
n st
st
{-# inline local #-}

--------------------------------------------------------------------------------

-- | Parse a given `B.ByteString`. If the bytestring is statically known, consider using 'bytes' instead.
byteString :: B.ByteString -> ParserT st r e ()
byteString :: forall (st :: ZeroBitType) r e. ByteString -> ParserT st r e ()
byteString (B.PS (ForeignPtr Addr#
bs ForeignPtrContents
fcontent) Int
_ (I# Int#
len)) =

  let go64 :: Addr# -> Addr# -> Addr# -> Int# -> State# RealWorld -> Res# (State# RealWorld) e ()
      go64 :: forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go64 Addr#
bs Addr#
bsend Addr#
s Int#
n IOMode
rw =
        let bs' :: Addr#
bs' = Addr# -> Int# -> Addr#
plusAddr# Addr#
bs Int#
8# in
        case Addr# -> Addr# -> Int#
gtAddr# Addr#
bs' Addr#
bsend of
          Int#
1# -> forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go8 Addr#
bs Addr#
bsend Addr#
s Int#
n IOMode
rw
#if MIN_VERSION_base(4,17,0)
          _  -> case eqWord64# (indexWord64OffAddr# bs 0#) (indexWord64OffAddr# s 0#) of
#else
          Int#
_  -> case Word# -> Word# -> Int#
eqWord# (Addr# -> Int# -> Word#
indexWord64OffAddr# Addr#
bs Int#
0#) (Addr# -> Int# -> Word#
indexWord64OffAddr# Addr#
s Int#
0#) of
#endif
            Int#
1# -> forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go64 Addr#
bs' Addr#
bsend (Addr# -> Int# -> Addr#
plusAddr# Addr#
s Int#
8#) Int#
n IOMode
rw
            Int#
_  -> forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# IOMode
rw

      go8 :: Addr# -> Addr# -> Addr# -> Int# -> State# RealWorld -> Res# (State# RealWorld) e ()
      go8 :: forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go8 Addr#
bs Addr#
bsend Addr#
s Int#
n IOMode
rw = case Addr# -> Addr# -> Int#
ltAddr# Addr#
bs Addr#
bsend of
#if MIN_VERSION_base(4,16,0)
        Int#
1# -> case Word8# -> Word8# -> Int#
eqWord8# (Addr# -> Int# -> Word8#
indexWord8OffAddr# Addr#
bs Int#
0#) (Addr# -> Int# -> Word8#
indexWord8OffAddr# Addr#
s Int#
0#) of
#else
        1# -> case eqWord# (indexWord8OffAddr# bs 0#) (indexWord8OffAddr# s 0#) of
#endif
          Int#
1# -> forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go8 (Addr# -> Int# -> Addr#
plusAddr# Addr#
bs Int#
1#) Addr#
bsend (Addr# -> Int# -> Addr#
plusAddr# Addr#
s Int#
1#) Int#
n IOMode
rw
          Int#
_  -> forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# IOMode
rw
        Int#
_  -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# IOMode
rw () Addr#
s Int#
n

      go :: Addr# -> Addr# -> Addr# -> Int# -> State# RealWorld -> Res# (State# RealWorld) e ()
      go :: forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go Addr#
bs Addr#
bsend Addr#
s Int#
n IOMode
rw = case forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go64 Addr#
bs Addr#
bsend Addr#
s Int#
n IOMode
rw of
        (# IOMode
rw', ResI# e ()
res #) -> case touch# :: forall a. a -> IOMode -> IOMode
touch# ForeignPtrContents
fcontent IOMode
rw' of
          IOMode
rw'' -> (# IOMode
rw'', ResI# e ()
res #)

  in forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st ->
      case Int#
len Int# -> Int# -> Int#
<=# Addr# -> Addr# -> Int#
minusAddr# Addr#
eob Addr#
s of
           Int#
1# -> case forall o. (IOMode -> o) -> o
runRW# (forall e.
Addr# -> Addr# -> Addr# -> Int# -> IOMode -> Res# IOMode e ()
go Addr#
bs (Addr# -> Int# -> Addr#
plusAddr# Addr#
bs Int#
len) Addr#
s Int#
n) of
             (# IOMode
rw, ResI# e ()
a #) -> (# st
st, ResI# e ()
a #)
           Int#
_  -> forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
{-# inline byteString #-}

--------------------------------------------------------------------------------

-- | Get the current position in the input.
getPos :: ParserT st r e Pos
getPos :: forall (st :: ZeroBitType) r e. ParserT st r e Pos
getPos = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st (Addr# -> Addr# -> Pos
addrToPos# Addr#
eob Addr#
s) Addr#
s Int#
n
{-# inline getPos #-}

-- | Set the input position.
--
-- Warning: this can result in crashes if the position points outside the
-- current buffer. It is always safe to 'setPos' values which came from 'getPos'
-- with the current input.
setPos :: Pos -> ParserT st r e ()
setPos :: forall (st :: ZeroBitType) r e. Pos -> ParserT st r e ()
setPos Pos
s = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
_ Int#
n st
st -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st () (Addr# -> Pos -> Addr#
posToAddr# Addr#
eob Pos
s) Int#
n
{-# inline setPos #-}

-- | Return the consumed span of a parser. Use `withSpan` if possible for better efficiency.
spanOf :: ParserT st r e a -> ParserT st r e Span
spanOf :: forall (st :: ZeroBitType) r e a.
ParserT st r e a -> ParserT st r e Span
spanOf (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f) = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> case ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f ForeignPtrContents
fp r
r Addr#
eob Addr#
s Int#
n st
st of
  OK# st
st' a
a Addr#
s' Int#
n -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st' (Pos -> Pos -> Span
Span (Addr# -> Addr# -> Pos
addrToPos# Addr#
eob Addr#
s) (Addr# -> Addr# -> Pos
addrToPos# Addr#
eob Addr#
s')) Addr#
s' Int#
n
  Res# st e a
x              -> unsafeCoerce# :: forall a b. a -> b
unsafeCoerce# Res# st e a
x
{-# inline spanOf #-}

-- | Bind the result together with the span of the result. CPS'd version of `spanOf`
--   for better unboxing.
withSpan :: ParserT st r e a -> (a -> Span -> ParserT st r e b) -> ParserT st r e b
withSpan :: forall (st :: ZeroBitType) r e a b.
ParserT st r e a
-> (a -> Span -> ParserT st r e b) -> ParserT st r e b
withSpan (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f) a -> Span -> ParserT st r e b
g = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> case ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f ForeignPtrContents
fp r
r Addr#
eob Addr#
s Int#
n st
st of
  OK# st
st' a
a Addr#
s' Int#
n -> forall (st :: ZeroBitType) r e a.
ParserT st r e a
-> ForeignPtrContents
-> r
-> Addr#
-> Addr#
-> Int#
-> st
-> Res# st e a
runParserT# (a -> Span -> ParserT st r e b
g a
a (Pos -> Pos -> Span
Span (Addr# -> Addr# -> Pos
addrToPos# Addr#
eob Addr#
s) (Addr# -> Addr# -> Pos
addrToPos# Addr#
eob Addr#
s'))) ForeignPtrContents
fp r
r Addr#
eob Addr#
s' Int#
n st
st'
  Res# st e a
x              -> unsafeCoerce# :: forall a b. a -> b
unsafeCoerce# Res# st e a
x
{-# inline withSpan #-}

-- | Return the `B.ByteString` consumed by a parser. Note: it's more efficient to use `spanOf` and
--   `withSpan` instead.
byteStringOf :: ParserT st r e a -> ParserT st r e B.ByteString
byteStringOf :: forall (st :: ZeroBitType) r e a.
ParserT st r e a -> ParserT st r e ByteString
byteStringOf (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f) = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> case ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f ForeignPtrContents
fp r
r Addr#
eob Addr#
s Int#
n st
st of
  OK# st
st' a
a Addr#
s' Int#
n -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st' (ForeignPtr Word8 -> Int -> Int -> ByteString
B.PS (forall a. Addr# -> ForeignPtrContents -> ForeignPtr a
ForeignPtr Addr#
s ForeignPtrContents
fp) Int
0 (Int# -> Int
I# (Addr# -> Addr# -> Int#
minusAddr# Addr#
s' Addr#
s))) Addr#
s' Int#
n
  Res# st e a
x              -> unsafeCoerce# :: forall a b. a -> b
unsafeCoerce# Res# st e a
x
{-# inline byteStringOf #-}

-- | CPS'd version of `byteStringOf`. Can be more efficient, because the result is more eagerly unboxed
--   by GHC. It's more efficient to use `spanOf` or `withSpan` instead.
withByteString :: ParserT st r e a -> (a -> B.ByteString -> ParserT st r e b) -> ParserT st r e b
withByteString :: forall (st :: ZeroBitType) r e a b.
ParserT st r e a
-> (a -> ByteString -> ParserT st r e b) -> ParserT st r e b
withByteString (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f) a -> ByteString -> ParserT st r e b
g = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> case ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f ForeignPtrContents
fp r
r Addr#
eob Addr#
s Int#
n st
st of
  OK# st
st' a
a Addr#
s' Int#
n -> forall (st :: ZeroBitType) r e a.
ParserT st r e a
-> ForeignPtrContents
-> r
-> Addr#
-> Addr#
-> Int#
-> st
-> Res# st e a
runParserT# (a -> ByteString -> ParserT st r e b
g a
a (ForeignPtr Word8 -> Int -> Int -> ByteString
B.PS (forall a. Addr# -> ForeignPtrContents -> ForeignPtr a
ForeignPtr Addr#
s ForeignPtrContents
fp) Int
0 (Int# -> Int
I# (Addr# -> Addr# -> Int#
minusAddr# Addr#
s' Addr#
s)))) ForeignPtrContents
fp r
r Addr#
eob Addr#
s' Int#
n st
st'
  Res# st e a
x              -> unsafeCoerce# :: forall a b. a -> b
unsafeCoerce# Res# st e a
x
{-# inline withByteString #-}

-- | Run a parser in a given input 'Span'.
--
-- The input position and the parser state is restored after the parser is
-- finished, so 'inSpan' does not consume input and has no side effect.
--
-- Warning: this operation may crash if the given span points outside the
-- current parsing buffer. It's always safe to use 'inSpan' if the 'Span' comes
-- from a previous 'withSpan' or 'spanOf' call on the current input.
inSpan :: Span -> ParserT st r e a -> ParserT st r e a
inSpan :: forall (st :: ZeroBitType) r e a.
Span -> ParserT st r e a -> ParserT st r e a
inSpan (Span Pos
s Pos
eob) (ParserT ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f) = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob' Addr#
s' Int#
n' st
st ->
  case ForeignPtrContents
-> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a
f ForeignPtrContents
fp r
r (Addr# -> Pos -> Addr#
posToAddr# Addr#
eob' Pos
eob) (Addr# -> Pos -> Addr#
posToAddr# Addr#
eob' Pos
s) Int#
n' st
st of
    OK# st
st' a
a Addr#
_ Int#
_ -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st' a
a Addr#
s' Int#
n'
    Res# st e a
x             -> unsafeCoerce# :: forall a b. a -> b
unsafeCoerce# Res# st e a
x
{-# inline inSpan #-}

--------------------------------------------------------------------------------

-- | Create a 'B.ByteString' from a 'Span'.
--
-- The result is invalid if the 'Span' points outside the current buffer, or if
-- the 'Span' start is greater than the end position.
unsafeSpanToByteString :: Span -> ParserT st r e B.ByteString
unsafeSpanToByteString :: forall (st :: ZeroBitType) r e. Span -> ParserT st r e ByteString
unsafeSpanToByteString (Span Pos
l Pos
r) =
  forall (st :: ZeroBitType) r e a.
ParserT st r e a -> ParserT st r e a
lookahead (forall (st :: ZeroBitType) r e. Pos -> ParserT st r e ()
setPos Pos
l forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (st :: ZeroBitType) r e a.
ParserT st r e a -> ParserT st r e ByteString
byteStringOf (forall (st :: ZeroBitType) r e. Pos -> ParserT st r e ()
setPos Pos
r))
{-# inline unsafeSpanToByteString #-}

--------------------------------------------------------------------------------

-- | Read a null-terminated bytestring (a C-style string).
--
-- Consumes the null terminator.
anyCString :: ParserT st r e B.ByteString
anyCString :: forall (st :: ZeroBitType) r e. ParserT st r e ByteString
anyCString = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st -> forall {p :: ZeroBitType} {e}.
ForeignPtrContents
-> Addr# -> Addr# -> Int# -> p -> Res# p e ByteString
go' ForeignPtrContents
fp Addr#
eob Addr#
s Int#
n st
st
  where
    go' :: ForeignPtrContents
-> Addr# -> Addr# -> Int# -> p -> Res# p e ByteString
go' ForeignPtrContents
fp Addr#
eob Addr#
s0 Int#
n p
st = forall {e}. Int# -> Addr# -> Int# -> Res# p e ByteString
go Int#
0# Addr#
s0 Int#
n
      where
        go :: Int# -> Addr# -> Int# -> Res# p e ByteString
go Int#
n# Addr#
s Int#
n = case Addr# -> Addr# -> Int#
eqAddr# Addr#
eob Addr#
s of
          Int#
1# -> forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# p
st
          Int#
_  ->
            let s' :: Addr#
s' = Addr# -> Int# -> Addr#
plusAddr# Addr#
s Int#
1#
#if MIN_VERSION_base(4,16,0)
            -- TODO below is a candidate for improving with ExtendedLiterals!
            in  case Word8# -> Word8# -> Int#
eqWord8# (Addr# -> Int# -> Word8#
indexWord8OffAddr# Addr#
s Int#
0#) (Word# -> Word8#
wordToWord8# Word#
0##) of
#else
            in  case eqWord# (indexWord8OffAddr# s 0#) 0## of
#endif
                  Int#
1# -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# p
st (ForeignPtr Word8 -> Int -> Int -> ByteString
B.PS (forall a. Addr# -> ForeignPtrContents -> ForeignPtr a
ForeignPtr Addr#
s0 ForeignPtrContents
fp) Int
0 (Int# -> Int
I# Int#
n#)) Addr#
s' Int#
n
                  Int#
_  -> Int# -> Addr# -> Int# -> Res# p e ByteString
go (Int#
n# Int# -> Int# -> Int#
+# Int#
1#) Addr#
s' Int#
n
{-# inline anyCString #-}

-- | Read a null-terminated bytestring (a C-style string), where the bytestring
--   is known to be null-terminated somewhere in the input.
--
-- Highly unsafe. Unless you have a guarantee that the string will be null
-- terminated before the input ends, use 'anyCString' instead. Honestly, I'm not
-- sure if this is a good function to define. But here it is.
--
-- Fails on GHC versions older than 9.0, since we make use of the
-- 'cstringLength#' primop introduced in GHC 9.0, and we aren't very useful
-- without it.
--
-- Consumes the null terminator.
anyCStringUnsafe :: ParserT st r e B.ByteString
{-# inline anyCStringUnsafe #-}
#if MIN_VERSION_base(4,15,0)
anyCStringUnsafe :: forall (st :: ZeroBitType) r e. ParserT st r e ByteString
anyCStringUnsafe = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st ->
  case Addr# -> Addr# -> Int#
eqAddr# Addr#
eob Addr#
s of
    Int#
1# -> forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
    Int#
_  -> let n# :: Int#
n#  = Addr# -> Int#
cstringLength# Addr#
s
              s'# :: Addr#
s'# = Addr# -> Int# -> Addr#
plusAddr# Addr#
s (Int#
n# Int# -> Int# -> Int#
+# Int#
1#)
           in forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st (ForeignPtr Word8 -> Int -> Int -> ByteString
B.PS (forall a. Addr# -> ForeignPtrContents -> ForeignPtr a
ForeignPtr Addr#
s ForeignPtrContents
fp) Int
0 (Int# -> Int
I# Int#
n#)) Addr#
s'# Int#
n
#else
anyCStringUnsafe = error "Flatparse.Stateful.anyCStringUnsafe: requires GHC 9.0 / base-4.15, not available on this compiler"
#endif

-- | Read a protobuf-style varint into a positive 'Int'.
--
-- protobuf-style varints are byte-aligned. For each byte, the lower 7 bits are
-- data and the MSB indicates if there are further bytes. Once fully parsed, the
-- 7-bit payloads are concatenated and interpreted as a little-endian unsigned
-- integer.
--
-- Fails if the varint exceeds the positive 'Int' range.
--
-- Really, these are varnats. They also match with the LEB128 varint encoding.
--
-- protobuf encodes negatives in unsigned integers using zigzag encoding. See
-- the @fromZigzag@ family of functions for this functionality.
--
-- Further reading:
-- https://developers.google.com/protocol-buffers/docs/encoding#varints
anyVarintProtobuf :: ParserT st r e Int
anyVarintProtobuf :: forall (st :: ZeroBitType) r e. ParserT st r e Int
anyVarintProtobuf = forall (st :: ZeroBitType) r e a.
(ForeignPtrContents
 -> r -> Addr# -> Addr# -> Int# -> st -> Res# st e a)
-> ParserT st r e a
ParserT \ForeignPtrContents
fp !r
r Addr#
eob Addr#
s Int#
n st
st ->
    case Addr# -> Addr# -> (# (# #) | (# Int#, Addr#, Int# #) #)
Common.anyVarintProtobuf# Addr#
eob Addr#
s of
      (# (##) | #) -> forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st
      (# | (# Int#
w#, Addr#
s#, Int#
bits# #) #) ->
        case Int#
bits# Int# -> Int# -> Int#
># Int#
63# of
          Int#
0# -> forall (st :: ZeroBitType) a e.
st -> a -> Addr# -> Int# -> Res# st e a
OK# st
st (Int# -> Int
I# Int#
w#) Addr#
s# Int#
n
          Int#
_  -> forall (st :: ZeroBitType) e a. st -> Res# st e a
Fail# st
st -- overflow
{-# inline anyVarintProtobuf #-}