{-|
Module:     Codec.Parser.ByteString
Copyright:  Jeremy List
License:    BSD-3
Maintainer: quick.dudley@gmail.com

'Phase's for processing bytestrings.
-}
module Codec.Phaser.ByteString (
  unpackBS,
  unpackLBS,
  parseFile_,
  parseHandle_
 ) where

import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.Word

import Control.Monad
import Control.Applicative
import System.IO (openFile,IOMode(ReadMode),Handle)

import Codec.Phaser.Core

-- | A 'Phase' which takes 'BS.ByteString's as input and yields their individual
-- bytes.
unpackBS :: (Monoid p) => Phase p BS.ByteString Word8 ()
unpackBS :: forall p. Monoid p => Phase p ByteString Word8 ()
unpackBS = (Phase p ByteString Word8 ()
forall {p}. Phase p ByteString Word8 ()
go Phase p ByteString Word8 ()
-> Phase p ByteString Word8 () -> Phase p ByteString Word8 ()
forall a b.
Phase p ByteString Word8 a
-> Phase p ByteString Word8 b -> Phase p ByteString Word8 b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Phase p ByteString Word8 ()
forall p. Monoid p => Phase p ByteString Word8 ()
unpackBS) Phase p ByteString Word8 ()
-> Phase p ByteString Word8 () -> Phase p ByteString Word8 ()
forall a.
Phase p ByteString Word8 a
-> Phase p ByteString Word8 a -> Phase p ByteString Word8 a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> () -> Phase p ByteString Word8 ()
forall a. a -> Phase p ByteString Word8 a
forall (m :: * -> *) a. Monad m => a -> m a
return () where
  go :: Phase p ByteString Word8 ()
go = Phase p ByteString Word8 ByteString
forall p i o. Phase p i o i
get Phase p ByteString Word8 ByteString
-> (ByteString -> Phase p ByteString Word8 ())
-> Phase p ByteString Word8 ()
forall a b.
Phase p ByteString Word8 a
-> (a -> Phase p ByteString Word8 b) -> Phase p ByteString Word8 b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Word8
 -> Phase p ByteString Word8 () -> Phase p ByteString Word8 ())
-> Phase p ByteString Word8 ()
-> ByteString
-> Phase p ByteString Word8 ()
forall a. (Word8 -> a -> a) -> a -> ByteString -> a
BS.foldr (\Word8
w Phase p ByteString Word8 ()
r -> Word8 -> Phase p ByteString Word8 ()
forall o p i. o -> Phase p i o ()
yield Word8
w Phase p ByteString Word8 ()
-> Phase p ByteString Word8 () -> Phase p ByteString Word8 ()
forall a b.
Phase p ByteString Word8 a
-> Phase p ByteString Word8 b -> Phase p ByteString Word8 b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Phase p ByteString Word8 ()
r) (() -> Phase p ByteString Word8 ()
forall a. a -> Phase p ByteString Word8 a
forall (m :: * -> *) a. Monad m => a -> m a
return ())

-- | A 'Phase' which takes lazy 'BL.ByteString's as input and yields their
-- individual bytes.
unpackLBS :: (Monoid p) => Phase p BL.ByteString Word8 ()
unpackLBS :: forall p. Monoid p => Phase p ByteString Word8 ()
unpackLBS = (Phase p ByteString Word8 ()
forall {p}. Phase p ByteString Word8 ()
go Phase p ByteString Word8 ()
-> Phase p ByteString Word8 () -> Phase p ByteString Word8 ()
forall a b.
Phase p ByteString Word8 a
-> Phase p ByteString Word8 b -> Phase p ByteString Word8 b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Phase p ByteString Word8 ()
forall p. Monoid p => Phase p ByteString Word8 ()
unpackLBS) Phase p ByteString Word8 ()
-> Phase p ByteString Word8 () -> Phase p ByteString Word8 ()
forall a.
Phase p ByteString Word8 a
-> Phase p ByteString Word8 a -> Phase p ByteString Word8 a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> () -> Phase p ByteString Word8 ()
forall a. a -> Phase p ByteString Word8 a
forall (m :: * -> *) a. Monad m => a -> m a
return () where
  go :: Phase p ByteString Word8 ()
go = Phase p ByteString Word8 ByteString
forall p i o. Phase p i o i
get Phase p ByteString Word8 ByteString
-> (ByteString -> Phase p ByteString Word8 ())
-> Phase p ByteString Word8 ()
forall a b.
Phase p ByteString Word8 a
-> (a -> Phase p ByteString Word8 b) -> Phase p ByteString Word8 b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Word8
 -> Phase p ByteString Word8 () -> Phase p ByteString Word8 ())
-> Phase p ByteString Word8 ()
-> ByteString
-> Phase p ByteString Word8 ()
forall a. (Word8 -> a -> a) -> a -> ByteString -> a
BL.foldr (\Word8
w Phase p ByteString Word8 ()
r -> Word8 -> Phase p ByteString Word8 ()
forall o p i. o -> Phase p i o ()
yield Word8
w Phase p ByteString Word8 ()
-> Phase p ByteString Word8 () -> Phase p ByteString Word8 ()
forall a b.
Phase p ByteString Word8 a
-> Phase p ByteString Word8 b -> Phase p ByteString Word8 b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Phase p ByteString Word8 ()
r) (() -> Phase p ByteString Word8 ()
forall a. a -> Phase p ByteString Word8 a
forall (m :: * -> *) a. Monad m => a -> m a
return ())


-- | Run a parser on input from a file. Input is provided as bytes, if
-- characters are needed: a decoding phase such as
-- 'Codec.Phaser.UTF8.utf8_stream' or 'latin1' may be used. Counter type
-- agnostic version.
parseFile_ :: (Monoid p,PhaserType s) => p -> s p Word8 o a -> FilePath ->
  IO (Either [(p,[String])] [a])
parseFile_ :: forall p (s :: * -> * -> * -> * -> *) o a.
(Monoid p, PhaserType s) =>
p -> s p Word8 o a -> FilePath -> IO (Either [(p, [FilePath])] [a])
parseFile_ p
p s p Word8 o a
c FilePath
n = FilePath -> IOMode -> IO Handle
openFile FilePath
n IOMode
ReadMode IO Handle
-> (Handle -> IO (Either [(p, [FilePath])] [a]))
-> IO (Either [(p, [FilePath])] [a])
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= p -> s p Word8 o a -> Handle -> IO (Either [(p, [FilePath])] [a])
forall p (s :: * -> * -> * -> * -> *) o a.
(Monoid p, PhaserType s) =>
p -> s p Word8 o a -> Handle -> IO (Either [(p, [FilePath])] [a])
parseHandle_ p
p s p Word8 o a
c

-- | Run a parser from the contents of a 'Handle'. Input is provided as bytes.
parseHandle_ :: (Monoid p,PhaserType s) => p -> s p Word8 o a -> Handle ->
  IO (Either [(p,[String])] [a])
parseHandle_ :: forall p (s :: * -> * -> * -> * -> *) o a.
(Monoid p, PhaserType s) =>
p -> s p Word8 o a -> Handle -> IO (Either [(p, [FilePath])] [a])
parseHandle_ p
p s p Word8 o a
c Handle
h = do
  ByteString
d <- Handle -> IO ByteString
BL.hGetContents Handle
h
  Either [(p, [FilePath])] [a] -> IO (Either [(p, [FilePath])] [a])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either [(p, [FilePath])] [a] -> IO (Either [(p, [FilePath])] [a]))
-> Either [(p, [FilePath])] [a]
-> IO (Either [(p, [FilePath])] [a])
forall a b. (a -> b) -> a -> b
$ p
-> Automaton p ByteString o a
-> [ByteString]
-> Either [(p, [FilePath])] [a]
forall p (s :: * -> * -> * -> * -> *) i o a.
(Monoid p, PhaserType s) =>
p -> s p i o a -> [i] -> Either [(p, [FilePath])] [a]
parse_ p
p (Phase p ByteString Word8 ()
forall p. Monoid p => Phase p ByteString Word8 ()
unpackBS Phase p ByteString Word8 ()
-> s p Word8 o a -> Automaton p ByteString o a
forall p (s :: * -> * -> * -> * -> *) (d :: * -> * -> * -> * -> *)
       b c x t a.
(Monoid p, PhaserType s, PhaserType d) =>
s p b c x -> d p c t a -> Automaton p b t a
>># s p Word8 o a
c) (ByteString -> [ByteString]
BL.toChunks ByteString
d)