{-#LANGUAGE ExistentialQuantification, OverloadedStrings, TypeSynonymInstances, FlexibleInstances #-}
module Transient.Parse where
import Transient.Internals
import Data.String
import Data.Typeable
import Control.Applicative
import Data.Char
import Data.Monoid
import System.IO.Unsafe
import Control.Monad
import Control.Monad.State
import qualified Data.ByteString.Lazy.Char8 as BS
setParseStream :: (Typeable str,IsString str) => IO str -> TransIO ()
setParseStream iox= setState $ ParseContext iox ""
setParseString :: (Typeable str,IsString str) => str -> TransIO ()
setParseString x = setState $ ParseContext (error "end of parse string") x
data ParseContext str = IsString str => ParseContext (IO str) str deriving Typeable
string :: BS.ByteString -> TransIO BS.ByteString
string s=withData $ \str -> do
let len= BS.length s
ret@(s',_) = BS.splitAt len str
if s == s'
then return ret
else empty
manyTill p end = scan
where
scan = do{ end; return [] }
<|>
do{ x <- p; xs <- scan; return (x:xs) }
dropSpaces= parse $ \str ->((),BS.dropWhile isSpace str)
dropChar= parse $ \r -> ((), BS.tail r)
endline c= c== '\r' || c =='\n'
parseString= do
dropSpaces
tTakeWhile (not . isSpace)
tTakeWhile :: (Char -> Bool) -> TransIO BS.ByteString
tTakeWhile cond= parse (BS.span cond)
tTakeWhile' :: (Char -> Bool) -> TransIO BS.ByteString
tTakeWhile' cond= parse ((\(h,t) -> (h, if BS.null t then t else BS.tail t)) . BS.span cond)
tTake n= parse ( BS.splitAt n)
tChar= parse $ \s -> (BS.head s,BS.tail s)
parse :: (BS.ByteString -> (b, BS.ByteString)) -> TransIO b
parse split= withData $ \str ->
if str== mempty then empty
else return $ split str
withData :: (BS.ByteString -> TransIO (a,BS.ByteString)) -> TransIO a
withData parser= Transient $ do
ParseContext readMore s <- getData `onNothing` error "parser: no context"
let loop = unsafeInterleaveIO $ do
r <- readMore
(r <>) `liftM` loop
str <- liftIO $ (s <> ) `liftM` loop
mr <- runTrans $ parser str
case mr of
Nothing -> return Nothing
Just (v,str') -> do
setData $ ParseContext readMore str'
return $ Just v
giveData= noTrans $ do
ParseContext readMore s <- getData `onNothing` error "parser: no context"
:: StateIO (ParseContext BS.ByteString)
let loop = unsafeInterleaveIO $ do
r <- readMore
(r <>) `liftM` loop
liftIO $ (s <> ) `liftM` loop