module Data.RefSerialize
(
module Data.RefSerialize.Parser
,Serialize(
showp
,readp
)
,rshowp
,rreadp
,showps
,rshowps
,runR
,runW
,showpText
,readpText
,showpBinary
,readpBinary
,insertString
,insertChar
,rShow
,rRead
,insertVar
,addrHash
,readVar
,takep
,readHexp
,showHexp
,Context
,getRContext
,getWContext
,newContext
,showContext
,runRC
,runWC
)
where
import Data.RefSerialize.Serialize
import Data.RefSerialize.Parser
import Unsafe.Coerce
import Data.Char(isAlpha, isSpace, isAlphaNum)
import Numeric(readHex,showHex)
import Data.ByteString.Lazy.Char8 as B
import Debug.Trace
import Data.Binary
import System.IO.Unsafe
import qualified Data.Map as M
import Data.Monoid
import Data.Maybe
newContext :: IO Context
newContext = Data.RefSerialize.Serialize.empty
class Serialize c where
showp :: c -> STW ()
readp :: STR c
rshowp :: Serialize c => c -> STW ()
rshowp = insertVar showp
rreadp :: Serialize c => STR c
rreadp = readVar readp
getRContext :: STR (Context, ByteString)
getRContext = STR(\(StatR(c,s,v)) -> Right (StatR (c,s,v), (c,v)))
getWContext :: STW (Context, ByteString)
getWContext = STW(\(StatW(c,s,v)) -> (StatW (c,s,v), (c,"")))
rShow :: Serialize c => c -> ByteString
rShow c= runW $ showp c
rRead :: Serialize c => ByteString -> c
rRead str= runR readp $ str
readHexp :: (Num a, Integral a) => STR a
readHexp = STR(\(StatR(c,s,v)) ->
let us= unpack s
l= readHex us
in if Prelude.null l then Left . Error $ "readHexp: not readable: " ++ us
else let ((x,str2):_)= l
in Right(StatR(c, pack $ Prelude.dropWhile isSpace str2,v),x) )
<?> "readHexp "
showHexp :: (Num a,Integral a,Show a) => a -> STW ()
showHexp var= STW(\(StatW(c,s,v)) -> (StatW(c, mappend s [Expr (pack $ showHex var "")],v),()))
showpText :: Show a => a -> STW ()
showpText var= STW(\(StatW(c,s,v)) -> (StatW(c, s `mappend` [Expr $ snoc (pack $ show var) ' '] ,v),()))
readpText :: Read a => STR a
readpText = STR(\(StatR(c,s,v)) ->
let us= unpack s
l= readsPrec 1 us
in if Prelude.null l then Left . Error $ "not readable: " ++ us
else let ((x,str2):_)= l
in Right(StatR(c, pack $ Prelude.dropWhile isSpace str2,v),x) )
<?> "readpText: readsPrec "
runR:: STR a -> ByteString -> a
runR p str=unsafePerformIO $ do
c <- newContext
let (struct, vars)= readContext whereSep str
return $ runRC (c, vars) p struct
runRC :: (Context, ByteString) -> STR a -> ByteString -> a
runRC (c,vars) (STR f) struct=
case f (StatR(c,struct,vars) ) of
Right (StatR _, a) -> a
Left (Error s) -> error s
whereSep= "\r\nwhere{\r\n "
runW :: STW () -> ByteString
runW f = unsafePerformIO $ do
c <- newContext
return $ runWC (c,"") f `append` showContext c True
runWC :: (Context, ByteString) -> STW () -> ByteString
runWC (c,vars) (STW f) =
let
(StatW(c',str,_), _) = f (StatW(c,[],vars))
in showExpr str c'
showContext :: Context -> Bool -> ByteString
showContext c False=
let scontext= assocs c
in B.concat $ Prelude.map (\(n,(_,_,v,_))->"v" `append` (pack $ show n) `append` "= " `append` showExpr v c `append` ";\r\n ") scontext
showContext c True=
let vars= showContext c False
in if B.null vars then "" else whereSep `append` vars `append` "\r\n}"
showExpr :: [ShowF] -> Context -> ByteString
showExpr [] _ = B.empty
showExpr (Expr s:xs) c = s `mappend` (cons ' ' $ showExpr xs c)
showExpr ex@(Var v:xs) c=
case Data.RefSerialize.Serialize.lookup v c of
Nothing -> error $ "showp: not found first variable in "++ show ex
Just (_,_,exp,1) -> delete v c `seq` showExpr exp c `mappend` (cons ' ' $ showExpr xs c)
Just (_,_,exp,n) -> pack ('v':show v) `mappend` (cons ' ' $ showExpr xs c)
showps :: Serialize a => a -> STW ByteString
showps x= STW(\(StatW(c,s,v))->
let
STW f= showp x
(StatW (c',str,_), _) = f (StatW(c,[],v))
in (StatW(c',s ,v), showExpr str c'))
rshowps x= STW(\(StatW(c,s,v))->
let
STW f= rshowp x
(StatW (c',str,_), _) = f (StatW(c,[],v))
in (StatW(c',s ,v), showExpr str c'))
insertVar :: (a -> STW ()) -> a -> STW ()
insertVar parser x= STW(\(StatW(c,s,v))->
let mf = x `seq`findVar x c in
case mf of
True -> (StatW(c,s `mappend` [Var hash],v),())
False ->
let
STW f= parser x
(StatW (c',str,_), _) = f (StatW(c,[],v))
in (StatW(addc str c',s `mappend` [Var hash] ,v), ()))
where
addc str c= insert ( hash) (st,unsafeCoerce x, str,1) c
(hash,st) = hasht x
findVar x c=
case Data.RefSerialize.Serialize.lookup hash c of
Nothing -> False
Just (x,y,z,n) -> insert hash (x,y,z,n+1) c `seq` True
isInVars :: (a -> STW ()) -> a -> STW (Either ByteString ByteString)
isInVars parser x= STW(\(StatW(c,s,v))->
let mf = trytofindEntireObject x c in
case mf of
Just var -> (StatW(c,s,v),Right var)
Nothing ->
let
STW f= parser x
(StatW (c',str,_), _) = f (StatW(c,[],v))
in (StatW(addc str c',s ,v), Left varname))
where
addc str c= insert ( hash) (st,unsafeCoerce x, str,1) c
(hash,st) = hasht x
varname= pack$ "v" ++ show hash
trytofindEntireObject x c=
case Data.RefSerialize.Serialize.lookup hash c of
Nothing -> Nothing
Just(x,y,z,n) -> insert hash (x,y,z,n+1) c `seq` Just varname
readVar :: Serialize c => STR c -> STR c
readVar (STR f)= STR(\stat@(StatR(c,s,v))->
let
s1= B.dropWhile isSpace s
(var, str2) = B.span isAlphaNum s1
str3= B.dropWhile isSpace str2
mnvar= numVar $ unpack var
nvar= fromJust mnvar
in if isNothing mnvar then f stat
else
case trytofindEntireObject nvar c of
Just (_,x,_,_) -> Right(StatR(c,str3,v),unsafeCoerce x)
Nothing ->
let
(_, rest)= readContext (var `append` "= ") v
in if B.null rest then Left (Error ( "RedSerialize: readVar: " ++ unpack var ++ "value not found" ))
else case f (StatR(c,rest,v)) of
Right (StatR(c',s',v'),x) ->
let c''= insert nvar ( undefined, unsafeCoerce x, [],0) c'
in Right (StatR(c'', str3,v),x)
err -> err)
where
trytofindEntireObject x c=
case Data.RefSerialize.Serialize.lookup x c of
Nothing -> Nothing
justx -> justx
insertString :: ByteString -> STW ()
insertString s1= STW(\(StatW(c,s,v)) -> (StatW(c, s `mappend` [ Expr s1 ],v),()))
insertChar :: Char -> STW()
insertChar car= STW(\(StatW(c, s,v)) -> (StatW(c, s `mappend` [Expr $ pack [car]],v),()))
instance Serialize a => Serialize [a] where
showp []= insertString "[]"
showp (x:xs)= do
insertChar '['
rshowp x
mapM f xs
insertString "]"
where
f :: Serialize a => a -> STW ()
f x= do
insertChar ','
rshowp x
readp = (brackets . commaSep $ rreadp) <?> "readp:: [] "
instance Serialize String where
showp = showpText
readp = readpText
instance (Serialize a, Serialize b) => Serialize (a, b) where
showp (x, y)= do
insertString "("
rshowp x
insertString ","
rshowp y
insertString ")"
readp = parens (do
x <- rreadp
comma
y <- rreadp
return (x,y))
<?> "rreadp:: (,) "
instance (Serialize a, Serialize b, Serialize c) => Serialize (a, b,c) where
showp (x, y, z)= do
insertString "("
rshowp x
insertString ","
rshowp y
insertString ","
rshowp z
insertString ")"
readp = parens (do
x <- rreadp
comma
y <- rreadp
comma
z <- rreadp
return (x,y,z))
<?> "rreadp:: (,,) "
instance (Serialize a, Serialize b, Serialize c, Serialize d) => Serialize (a, b,c, d) where
showp (x, y, z, t)= do
insertString "("
rshowp x
insertString ","
rshowp y
insertString ","
rshowp z
insertString ","
rshowp t
insertString ")"
readp = parens (do
x <- rreadp
comma
y <- rreadp
comma
z <- rreadp
comma
t <- rreadp
return (x,y,z,t))
<?> "rreadp:: (,,,) "
instance (Serialize a, Ord a, Serialize b) => Serialize (M.Map a b) where
showp m= showp $ M.toList m
readp= do
list <- readp
return $ M.fromList list
instance Serialize a => Serialize (Maybe a) where
showp Nothing = insertString "Nothing"
showp (Just x) =do
insertString "Just"
showp x
readp = choice [rNothing, rJust] where
rNothing = symbol "Nothing" >> return Nothing
rJust = do
symbol "Just"
x <- readp
return $ Just x
instance (Serialize a, Serialize b) => Serialize (Either a b) where
showp (Left x) = do
insertString "Left"
rshowp x
showp (Right x) = do
insertString "Right"
rshowp x
readp = choice [rLeft, rRight] where
rLeft = symbol "Left" >> rreadp >>= \x -> return $ Left x
rRight = symbol "Right" >> rreadp >>= \x -> return $ Right x
binPrefix= "Bin "
binPrefixSp= append (pack binPrefix) " "
showpBinary :: Binary a => a -> STW ()
showpBinary x = do
let s = encode x
let n = pack . show $ B.length s
insertString $ binPrefixSp `append` n `append` " " `append` s
readpBinary :: Binary a => STR a
readpBinary = do
symbol binPrefix
n <- integer
str <- takep (fromIntegral n)
let x = decode str
return x
takep n=STR(\(StatR(c,s,v)) ->
let (x,r)= B.splitAt n s
in Right(StatR(c, r,v),x) )
<?> "takep "