packages feed

scanner-attoparsec-0.2: lib/Scanner/Attoparsec.hs

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 p = Scanner $ \bs next ->
  case Atto.parse p bs of
    Atto.Done bs' r -> next bs' r
    Atto.Fail bs' _ err -> Scanner.Fail bs' err
    Atto.Partial cont -> slowPath cont next
  where
  slowPath cont next = Scanner.More $ \bs ->
    case cont bs of
      Atto.Done bs' r -> next bs' r
      Atto.Fail bs' _ err -> Scanner.Fail bs' err
      Atto.Partial cont' -> slowPath cont' next

-- | Convert scanner to attoparsec parser
--
-- @since 0.2
toAtto :: Scanner a -> Atto.Parser a
toAtto s = go (Scanner.scan s)
  where
  go run = do
    chunk <- fromMaybe ByteString.empty <$> Atto.getChunk
    case run chunk of
      Scanner.Done bs r -> do
        _ <- Atto.take (ByteString.length chunk - ByteString.length bs)
        return r
      Scanner.Fail bs msg -> do
        _ <- Atto.take (ByteString.length chunk - ByteString.length bs)
        fail msg
      Scanner.More next -> do
        _ <- Atto.take (ByteString.length chunk)
        go next