module Scanner.Attoparsec
( atto
, toAtto
)
where

import qualified Scanner
import Scanner.Internal (Scanner (Scanner))

import Data.Maybe
import qualified Data.ByteString as ByteString
import qualified Data.Attoparsec.ByteString as Atto

{-# INLINE atto #-}
-- | Convert attoparsec parser into a scanner
atto :: Atto.Parser a -> Scanner a
atto :: Parser a -> Scanner a
atto Parser a
p = (forall r. ByteString -> Next a r -> Result r) -> Scanner a
forall a.
(forall r. ByteString -> Next a r -> Result r) -> Scanner a
Scanner ((forall r. ByteString -> Next a r -> Result r) -> Scanner a)
-> (forall r. ByteString -> Next a r -> Result r) -> Scanner a
forall a b. (a -> b) -> a -> b
$ \ByteString
bs Next a r
next ->
  case Parser a -> ByteString -> Result a
forall a. Parser a -> ByteString -> Result a
Atto.parse Parser a
p ByteString
bs of
    Atto.Done ByteString
bs' a
r -> Next a r
next ByteString
bs' a
r
    Atto.Fail ByteString
bs' [String]
_ String
err -> ByteString -> String -> Result r
forall r. ByteString -> String -> Result r
Scanner.Fail ByteString
bs' String
err
    Atto.Partial ByteString -> Result a
cont -> (ByteString -> Result a) -> Next a r -> Result r
forall t r.
(ByteString -> IResult ByteString t)
-> (ByteString -> t -> Result r) -> Result r
slowPath ByteString -> Result a
cont Next a r
next
  where
  slowPath :: (ByteString -> IResult ByteString t)
-> (ByteString -> t -> Result r) -> Result r
slowPath ByteString -> IResult ByteString t
cont ByteString -> t -> Result r
next = (ByteString -> Result r) -> Result r
forall r. (ByteString -> Result r) -> Result r
Scanner.More ((ByteString -> Result r) -> Result r)
-> (ByteString -> Result r) -> Result r
forall a b. (a -> b) -> a -> b
$ \ByteString
bs ->
    case ByteString -> IResult ByteString t
cont ByteString
bs of
      Atto.Done ByteString
bs' t
r -> ByteString -> t -> Result r
next ByteString
bs' t
r
      Atto.Fail ByteString
bs' [String]
_ String
err -> ByteString -> String -> Result r
forall r. ByteString -> String -> Result r
Scanner.Fail ByteString
bs' String
err
      Atto.Partial ByteString -> IResult ByteString t
cont' -> (ByteString -> IResult ByteString t)
-> (ByteString -> t -> Result r) -> Result r
slowPath ByteString -> IResult ByteString t
cont' ByteString -> t -> Result r
next

-- | Convert scanner to attoparsec parser
--
-- @since 0.2
toAtto :: Scanner a -> Atto.Parser a
toAtto :: Scanner a -> Parser a
toAtto Scanner a
s = (ByteString -> Result a) -> Parser a
forall b. (ByteString -> Result b) -> Parser ByteString b
go (Scanner a -> ByteString -> Result a
forall r. Scanner r -> ByteString -> Result r
Scanner.scan Scanner a
s)
  where
  go :: (ByteString -> Result b) -> Parser ByteString b
go ByteString -> Result b
run = do
    ByteString
chunk <- ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe ByteString
ByteString.empty (Maybe ByteString -> ByteString)
-> Parser ByteString (Maybe ByteString)
-> Parser ByteString ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString (Maybe ByteString)
Atto.getChunk
    case ByteString -> Result b
run ByteString
chunk of
      Scanner.Done ByteString
bs b
r -> do
        ByteString
_ <- Int -> Parser ByteString ByteString
Atto.take (ByteString -> Int
ByteString.length ByteString
chunk Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
ByteString.length ByteString
bs)
        b -> Parser ByteString b
forall (m :: * -> *) a. Monad m => a -> m a
return b
r
      Scanner.Fail ByteString
bs String
msg -> do
        ByteString
_ <- Int -> Parser ByteString ByteString
Atto.take (ByteString -> Int
ByteString.length ByteString
chunk Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
ByteString.length ByteString
bs)
        String -> Parser ByteString b
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
msg
      Scanner.More ByteString -> Result b
next -> do
        ByteString
_ <- Int -> Parser ByteString ByteString
Atto.take (ByteString -> Int
ByteString.length ByteString
chunk)
        (ByteString -> Result b) -> Parser ByteString b
go ByteString -> Result b
next