RefSerialize 0.2.7 → 0.2.8
raw patch · 6 files changed
+920/−737 lines, 6 filesdep +binarydep +bytestringdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: binary, bytestring
Dependency ranges changed: base
API changes (from Hackage documentation)
- Data.Parser: (<?>) :: ST a -> String -> ST a
- Data.Parser: (<|>) :: ST a -> ST a -> ST a
- Data.Parser: ST :: (Stat -> Either Error (Stat, a)) -> ST a
- Data.Parser: angles :: ST a -> ST a
- Data.Parser: anyChar :: ST Char
- Data.Parser: between :: (Monad m) => m a -> m a1 -> m b -> m b
- Data.Parser: bool :: ST Bool
- Data.Parser: braces :: ST a -> ST a
- Data.Parser: brackets :: ST a -> ST a
- Data.Parser: char :: Char -> ST Char
- Data.Parser: charLiteral :: ST Char
- Data.Parser: choice :: [ST a] -> ST a
- Data.Parser: colon :: ST [Char]
- Data.Parser: comma :: ST [Char]
- Data.Parser: commaSep :: ST a -> ST [a]
- Data.Parser: commaSep1 :: ST a -> ST [a]
- Data.Parser: data ST a
- Data.Parser: decimal :: ST Integer
- Data.Parser: digit :: ST Char
- Data.Parser: dot :: ST [Char]
- Data.Parser: float :: ST Double
- Data.Parser: hexadecimal :: ST Integer
- Data.Parser: instance Monad ST
- Data.Parser: instance MonadPlus ST
- Data.Parser: integer :: ST Integer
- Data.Parser: lexeme :: ST b -> ST b
- Data.Parser: many :: ST a -> ST [a]
- Data.Parser: natural :: ST Integer
- Data.Parser: naturalOrFloat :: ST (Either Integer Double)
- Data.Parser: notFollowedBy :: (Show t) => ST t -> ST ()
- Data.Parser: octal :: ST Integer
- Data.Parser: option :: a -> ST a -> ST a
- Data.Parser: parens :: ST a -> ST a
- Data.Parser: semi :: ST [Char]
- Data.Parser: semiSep :: ST a -> ST [a]
- Data.Parser: semiSep1 :: ST a -> ST [a]
- Data.Parser: sepBy :: ST a -> ST sep -> ST [a]
- Data.Parser: space :: ST Char
- Data.Parser: string :: [Char] -> ST [Char]
- Data.Parser: stringLiteral :: ST [Char]
- Data.Parser: symbol :: [Char] -> ST [Char]
- Data.Parser: upper :: ST Char
- Data.Parser: whiteSpace :: ST ()
- Data.RefSerialize: instance [overlap ok] (Serialize a) => Serialize (Maybe a)
- Data.RefSerialize: instance [overlap ok] (Serialize a) => Serialize [a]
- Data.RefSerialize: instance [overlap ok] Serialize ()
- Data.RefSerialize: instance [overlap ok] Serialize Bool
- Data.RefSerialize: instance [overlap ok] Serialize Char
- Data.RefSerialize: instance [overlap ok] Serialize Double
- Data.RefSerialize: instance [overlap ok] Serialize Float
- Data.RefSerialize: instance [overlap ok] Serialize Int
- Data.RefSerialize: instance [overlap ok] Serialize Integer
- Data.RefSerialize: instance [overlap ok] Serialize Ordering
- Data.RefSerialize: readSR :: (Read a) => ST a
- Data.RefSerialize: showSR :: (Show a) => a -> ST String
- Data.Serialize: Error :: String -> Error
- Data.Serialize: Stat :: (Context, String, String) -> Stat
- Data.Serialize: data Error
- Data.Serialize: data Stat
- Data.Serialize: numVar :: String -> Int
- Data.Serialize: type Context = Map Int (MFun, ShowF)
- Data.Serialize: type MFun = Char
- Data.Serialize: type ShowF = String
- Data.Serialize: type VarName = String
- Data.Serialize: varName :: a -> String
+ Data.RefSerialize: getContext :: ST (Context, ByteString)
+ Data.RefSerialize: insertChar :: Char -> ST ()
+ Data.RefSerialize: insertString :: ByteString -> ST ()
+ Data.RefSerialize: instance [overlap ok] (Show a, Read a) => Serialize a
+ Data.RefSerialize: instance [overlap ok] Serialize a => Serialize (Maybe a)
+ Data.RefSerialize: instance [overlap ok] Serialize a => Serialize [a]
+ Data.RefSerialize: newContext :: IO Context
+ Data.RefSerialize: readpBinary :: Binary a => ST a
+ Data.RefSerialize: readpText :: Read a => ST a
+ Data.RefSerialize: runRC :: (Context, ByteString) -> ST a -> ByteString -> a
+ Data.RefSerialize: showpBinary :: Binary a => a -> ST ()
+ Data.RefSerialize: showpText :: Show a => a -> ST ()
+ Data.RefSerialize: showps :: Serialize a => a -> ST ByteString
+ Data.RefSerialize: takep :: Int -> ST ByteString
+ Data.RefSerialize: type Context = HashTable Int (StableName MFun, MFun, ShowF)
+ Data.RefSerialize.Parser: (<?>) :: ST a -> String -> ST a
+ Data.RefSerialize.Parser: (<|>) :: ST a -> ST a -> ST a
+ Data.RefSerialize.Parser: ST :: (Stat -> Either Error (Stat, a)) -> ST a
+ Data.RefSerialize.Parser: angles :: ST a -> ST a
+ Data.RefSerialize.Parser: anyChar :: ST Char
+ Data.RefSerialize.Parser: between :: Monad m => m a -> m a1 -> m b -> m b
+ Data.RefSerialize.Parser: bool :: ST Bool
+ Data.RefSerialize.Parser: braces :: ST a -> ST a
+ Data.RefSerialize.Parser: brackets :: ST a -> ST a
+ Data.RefSerialize.Parser: char :: Char -> ST Char
+ Data.RefSerialize.Parser: charLiteral :: ST Char
+ Data.RefSerialize.Parser: choice :: [ST a] -> ST a
+ Data.RefSerialize.Parser: colon :: ST [Char]
+ Data.RefSerialize.Parser: comma :: ST [Char]
+ Data.RefSerialize.Parser: commaSep :: ST a -> ST [a]
+ Data.RefSerialize.Parser: commaSep1 :: ST a -> ST [a]
+ Data.RefSerialize.Parser: data ST a
+ Data.RefSerialize.Parser: decimal :: ST Integer
+ Data.RefSerialize.Parser: digit :: ST Char
+ Data.RefSerialize.Parser: dot :: ST [Char]
+ Data.RefSerialize.Parser: float :: ST Double
+ Data.RefSerialize.Parser: hexadecimal :: ST Integer
+ Data.RefSerialize.Parser: instance Monad ST
+ Data.RefSerialize.Parser: instance MonadPlus ST
+ Data.RefSerialize.Parser: integer :: ST Integer
+ Data.RefSerialize.Parser: lexeme :: ST b -> ST b
+ Data.RefSerialize.Parser: many :: ST a -> ST [a]
+ Data.RefSerialize.Parser: manyTill :: ST a1 -> ST a -> ST [a1]
+ Data.RefSerialize.Parser: natural :: ST Integer
+ Data.RefSerialize.Parser: naturalOrFloat :: ST (Either Integer Double)
+ Data.RefSerialize.Parser: noneOf :: [Char] -> ST Char
+ Data.RefSerialize.Parser: notFollowedBy :: Show t => ST t -> ST ()
+ Data.RefSerialize.Parser: octal :: ST Integer
+ Data.RefSerialize.Parser: oneOf :: [Char] -> ST Char
+ Data.RefSerialize.Parser: option :: a -> ST a -> ST a
+ Data.RefSerialize.Parser: parens :: ST a -> ST a
+ Data.RefSerialize.Parser: semi :: ST [Char]
+ Data.RefSerialize.Parser: semiSep :: ST a -> ST [a]
+ Data.RefSerialize.Parser: semiSep1 :: ST a -> ST [a]
+ Data.RefSerialize.Parser: sepBy :: ST a -> ST sep -> ST [a]
+ Data.RefSerialize.Parser: space :: ST Char
+ Data.RefSerialize.Parser: string :: [Char] -> ST [Char]
+ Data.RefSerialize.Parser: stringLiteral :: ST [Char]
+ Data.RefSerialize.Parser: symbol :: [Char] -> ST [Char]
+ Data.RefSerialize.Parser: upper :: ST Char
+ Data.RefSerialize.Parser: whiteSpace :: ST ()
+ Data.RefSerialize.Serialize: Error :: String -> Error
+ Data.RefSerialize.Serialize: Stat :: (Context, ByteString, ByteString) -> Stat
+ Data.RefSerialize.Serialize: data Error
+ Data.RefSerialize.Serialize: data Stat
+ Data.RefSerialize.Serialize: numVar :: String -> Int
+ Data.RefSerialize.Serialize: readContext :: ByteString -> ByteString -> (ByteString, ByteString)
+ Data.RefSerialize.Serialize: type Context = HashTable Int (StableName MFun, MFun, ShowF)
+ Data.RefSerialize.Serialize: type MFun = Char
+ Data.RefSerialize.Serialize: type ShowF = ByteString
+ Data.RefSerialize.Serialize: type VarName = String
- Data.RefSerialize: insertVar :: (a -> ST String) -> a -> ST String
+ Data.RefSerialize: insertVar :: (a -> ST ()) -> a -> ST ()
- Data.RefSerialize: rRead :: (Serialize c) => String -> c
+ Data.RefSerialize: rRead :: Serialize c => ByteString -> c
- Data.RefSerialize: rShow :: (Serialize c) => c -> String
+ Data.RefSerialize: rShow :: Serialize c => c -> ByteString
- Data.RefSerialize: readVar :: (Serialize c) => ST c -> ST c
+ Data.RefSerialize: readVar :: Serialize c => ST c -> ST c
- Data.RefSerialize: readp :: (Serialize c) => ST c
+ Data.RefSerialize: readp :: Serialize c => ST c
- Data.RefSerialize: rreadp :: (Serialize c) => ST c
+ Data.RefSerialize: rreadp :: Serialize c => ST c
- Data.RefSerialize: rshowp :: (Serialize c) => c -> ST String
+ Data.RefSerialize: rshowp :: Serialize c => c -> ST ()
- Data.RefSerialize: runR :: ST a -> String -> a
+ Data.RefSerialize: runR :: ST a -> ByteString -> a
- Data.RefSerialize: runW :: ST String -> String
+ Data.RefSerialize: runW :: ST () -> ByteString
- Data.RefSerialize: showHexp :: (Num a, Integral a) => a -> ST String
+ Data.RefSerialize: showHexp :: (Num a, Integral a) => a -> ST ()
- Data.RefSerialize: showp :: (Serialize c) => c -> ST String
+ Data.RefSerialize: showp :: Serialize c => c -> ST ()
- Data.RefSerialize: varName :: a -> String
+ Data.RefSerialize: varName :: a -> [Char]
Files
- Data/Parser.hs +0/−428
- Data/RefSerialize.hs +399/−240
- Data/RefSerialize/Parser.hs +428/−0
- Data/RefSerialize/Serialize.hs +72/−0
- Data/Serialize.hs +0/−49
- RefSerialize.cabal +21/−20
− Data/Parser.hs
@@ -1,428 +0,0 @@-{- | A Parsec parser for the refSerialize monad. See package Parsec. all the functions have the same meaning--}-module Data.Parser( ST(..),(<?>),(<|>),char,anyChar, string, upper, space, digit- , sepBy, between, choice, option, notFollowedBy, many- , bool-- , charLiteral -- :: ST Char- , stringLiteral -- :: ST String- , natural -- :: ST Integer- , integer -- :: ST Integer- , float -- :: ST Double- , naturalOrFloat -- :: ST (Either Integer Double)- , decimal -- :: ST Integer- , hexadecimal -- :: ST Integer- , octal -- :: ST Integer-- , symbol -- :: String -> ST String- , lexeme -- :: forall a. ST a -> ST a- , whiteSpace -- :: ST ()-- , parens -- :: forall a. ST a -> ST a- , braces -- :: forall a. ST a -> ST a- , angles -- :: forall a. ST a -> ST a- , brackets -- :: forall a. ST a -> ST a- -- "squares" is deprecated-- , semi -- :: ST String- , comma -- :: ST String- , colon -- :: ST String- , dot -- :: ST String- , semiSep -- :: forall a . ST a -> ST [a]- , semiSep1 -- :: forall a . ST a -> ST [a]- , commaSep -- :: forall a . ST a -> ST [a]- , commaSep1 -- :: forall a . ST a -> ST [a]---- ) where--import Control.Monad-import Data.Char(isUpper,isSpace,digitToInt)-import qualified Data.Map as M-import Data.Serialize---data ST a= ST(Stat-> Either Error (Stat , a) )---- | monadic serialization & deserialization-instance Monad ST where- return x = ST (\s -> Right (s, x))- ST g >>= f = ST (\s ->-- case g s of- Right (s', x)->- let- ST fun = f x- in case fun s' of- left@(Left msg) -> left- rigth-> rigth-- Left msg -> Left msg-- )--instance MonadPlus ST where- mzero= ST (\(Stat (a,b,c)) -> Left $ Error "an error occurred")- mplus p1 p2 = parsecPlus p1 p2--infixr 1 <|>-(<|>) = parsecPlus-infix 0 <?>--p <?> msg = label p msg--parsecPlus :: ST a -> ST a -> ST a-parsecPlus (ST p1) (ST p2)- = ST (\state ->- case (p1 state) of- Left (Error s) -> case (p2 state) of- Left (Error s') -> Left $ Error ( s++ "\n"++ s')- consumed-> consumed- other -> other- )----label :: ST a -> String -> ST a-label p msg- = labels p [msg]--labels :: ST a -> [String] -> ST a-labels (ST p) msgs- = ST (\state ->- case (p state) of- Left(Error reply) -> Left $ Error ( reply ++concatMap ("\n in "++) msgs)-- other -> other- )--char :: Char -> ST Char--char c= ST(\(Stat(cs,s,v)) ->- if null s then Left (Error $ "unexpected end of input")- else if c== head s then Right(Stat(cs,tail s,v), c)- else Left (Error ( "char "++ c:" not match " ++ '\"':s++"\"" )))---anyChar = ST(\(Stat(cs,s,v)) ->- if null s then Left (Error $ "unexpected end of input")- else Right(Stat(cs,tail s,v), head s))--satisfy bf= ST(\(Stat(cs,s,v)) -> let heads= head s in- if null s then Left (Error $ "unexpected end of input")- else if bf heads then Right(Stat(cs,tail s,v), heads)- else Left (Error ( "satisfy not matching condition in " ++ '\"':s++"\"" )))---upper = ST(\(Stat(cs,s,v)) -> let heads= head s in- if null s then Left (Error $ "unexpected end of input")- else if isUpper (head s) then Right(Stat(cs,tail s,v), head s)- else Left (Error ( "upper not matching condition in " ++ '\"':s++"\"" )))---space =ST(\(Stat(cs,s,v)) -> let heads= head s in- if null s then Left (Error $ "unexpected end of input")- else if isSpace heads then Right(Stat(cs,tail s,v), heads)- else Left (Error ( "expected space at the head of " ++ s )))---digit1 l1 l2= ST(\(Stat(cs,s,v)) -> let c= head s in if c >= l1 && c <= l2 then Right(Stat(cs,tail s,v), c)- else Left (Error ( "expected digit at the head of " ++ s )))--empty = ST(\(Stat(cs,s,v)) -> if null s then Right(Stat(cs, s,v), ())- else Left (Error ( "expected empty list" )))--octDigit= digit1 '0' '7'--digit= digit1 '0' '9'--hexDigit= ST(\(Stat(cs,s,v)) -> let c= head s in if c >= '0' && c <= '9' || c >= 'a' && c<='f' || c >= 'A' && c <= 'F' then Right(Stat(cs,tail s,v), c)- else Left (Error ( "expected space at the head of " ++ s )))--oneOf xs= ST(\(Stat(cs,s,v)) -> let c= head s in if c `elem` xs then Right(Stat(cs,tail s,v), c)- else Left (Error ( "expected digit at the head of " ++ s )))--noneOf xs= ST(\(Stat(cs,s,v)) -> let c= head s in if not $ c `elem` xs then Right(Stat(cs,tail s,v), c)- else Left (Error ( "expected digit at the head of " ++ s )))--try p= p--unexpected msg- = ST (\state -> Left (Error $ msg++ "unexpected"))--sepBy1,sepBy :: ST a -> ST sep -> ST [a]-sepBy p sep = sepBy1 p sep <|> return []-sepBy1 p sep = do{ x <- p- ; xs <- many (sep >> p)- ; return (x:xs)- }- <?> "sepBy "-between open close p- = do{ open; x <- p; close; return x }--choice ps = foldr (<|>) mzero ps <?> "choice "--option x p = p <|> return x---notFollowedBy p = try (do{ c <- p; unexpected (show [c]) }- <|> return ()- )-- <?> "notFollowedBy "--skipMany1 p = do{ p; skipMany p }--skipMany p = scan- where- scan = do{ p; scan } <|> return ()---manyTill p end = scan- where- scan = do{ end; return [] }- <|>- do{ x <- p; xs <- scan; return (x:xs) }---string ""= return ""-string ys@(x:xs)= do- char x- string xs- return ys- <?> "string "++ys---bool = lexeme ( do{ symbol "True" ; return True} <|> do{ symbol "False" ; return False}) <?> "Bool"--many :: ST a -> ST [a]-many p = many1 p <|> return []-many1 :: ST a -> ST [a]-many1 p = do {a <- p; as <- many p; return (a:as)}-----from Token.hs--------------------------------------------------------------- Bracketing-------------------------------------------------------------parens p = between (symbol "(") (symbol ")") p <?> "parens "-braces p = between (symbol "{") (symbol "}") p <?> "braces "-angles p = between (symbol "<") (symbol ">") p <?> "angles "-brackets p = between (symbol "[") (symbol "]") p <?> "brackets "--semi = symbol ";"-comma = symbol ","-dot = symbol "."-colon = symbol ":"--commaSep p = sepBy p comma-semiSep p = sepBy p semi--commaSep1 p = sepBy1 p comma-semiSep1 p = sepBy1 p semi----------------------------------------------------------------- Chars & Strings--------------------------------------------------------------- charLiteral :: ST Char-charLiteral = lexeme (between (char '\'')- (char '\'' <?> "end of character")- characterChar )- <?> "character"--characterChar = charLetter <|> charEscape- <?> "literal character"--charEscape = do{ char '\\'; escapeCode }-charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))------ stringLiteral :: ST String-stringLiteral = lexeme (- do{ str <- between (char '"')- (char '"' <?> "end of string")- (many stringChar)- ; return (foldr (maybe id (:)) "" str)- }- <?> "literal string")---- stringChar :: ST (Maybe Char)-stringChar = do{ c <- stringLetter; return (Just c) }- <|> stringEscape- <?> "string character"--stringLetter = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))--stringEscape = do{ char '\\'- ; do{ escapeGap ; return Nothing }- <|> do{ escapeEmpty; return Nothing }- <|> do{ esc <- escapeCode; return (Just esc) }- }--escapeEmpty = char '&'-escapeGap = do{ many1 space- ; char '\\' <?> "end of string gap"- }------ escape codes-escapeCode = charEsc <|> charNum <|> charAscii <|> charControl- <?> "escape code"---- charControl :: ST Char-charControl = do{ char '^'- ; code <- upper- ; return (toEnum (fromEnum code - fromEnum 'A'))- }---- charNum :: ST Char-charNum = do{ code <- decimal- <|> do{ char 'o'; number 8 octDigit }- <|> do{ char 'x'; number 16 hexDigit }- ; return (toEnum (fromInteger code))- }--charEsc = choice (map parseEsc escMap)- where- parseEsc (c,code) = do{ char c; return code }--charAscii = choice (map parseAscii asciiMap)- where- parseAscii (asc,code) = try (do{ string asc; return code })----- escape code tables-escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")-asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)--ascii2codes = ["BS","HT","LF","VT","FF","CR","SO","SI","EM",- "FS","GS","RS","US","SP"]-ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK","BEL",- "DLE","DC1","DC2","DC3","DC4","NAK","SYN","ETB",- "CAN","SUB","ESC","DEL"]--ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI',- '\EM','\FS','\GS','\RS','\US','\SP']-ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK',- '\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK',- '\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']----------------------------------------------------------------- Numbers--------------------------------------------------------------- naturalOrFloat :: ST (Either Integer Double)-naturalOrFloat = lexeme (natFloat) <?> "number"--float = lexeme floating <?> "float"-integer = lexeme int <?> "integer"-natural = lexeme nat <?> "natural"----- floats-floating = do{ n <- decimal- ; fractExponent n- }---natFloat = do{ char '0'- ; zeroNumFloat- }- <|> decimalFloat--zeroNumFloat = do{ n <- hexadecimal <|> octal- ; return (Left n)- }- <|> decimalFloat- <|> fractFloat 0- <|> return (Left 0)--decimalFloat = do{ n <- decimal- ; option (Left n)- (fractFloat n)- }--fractFloat n = do{ f <- fractExponent n- ; return (Right f)- }--fractExponent n = do{ fract <- fraction- ; expo <- option 1.0 exponent'- ; return ((fromInteger n + fract)*expo)- }- <|>- do{ expo <- exponent'- ; return ((fromInteger n)*expo)- }--fraction = do{ char '.'- ; digits <- many1 digit <?> "fraction"- ; return (foldr op 0.0 digits)- }- <?> "fraction"- where- op d f = (f + fromIntegral (digitToInt d))/10.0--exponent' = do{ oneOf "eE"- ; f <- sign- ; e <- decimal <?> "exponent"- ; return (power (f e))- }- <?> "exponent"- where- power e | e < 0 = 1.0/power(-e)- | otherwise = fromInteger (10^e)----- integers and naturals-int = do{ f <- lexeme sign- ; n <- nat- ; return (f n)- }---- sign :: ST (Integer -> Integer)-sign = (char '-' >> return negate)- <|> (char '+' >> return id)- <|> return id--nat = zeroNumber <|> decimal--zeroNumber = do{ char '0'- ; hexadecimal <|> octal <|> decimal <|> return 0- }- <?> ""--decimal = number 10 digit-hexadecimal = do{ oneOf "xX"; number 16 hexDigit }-octal = do{ oneOf "oO"; number 8 octDigit }--- -- number :: Integer -> ST Char -> ST Integer-number base baseDigit- = do{ digits <- many1 baseDigit- ; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits- ; seq n (return n)- }----------------------------------------------------------------- White space & symbols-------------------------------------------------------------symbol name- = lexeme (string name) <?> "symbol"--lexeme p- = do{ x <- p; whiteSpace ; return x }-----whiteSpace-whiteSpace = skipMany (simpleSpace <?> "")---simpleSpace = skipMany1 (satisfy isSpace)--
Data/RefSerialize.hs view
@@ -1,4 +1,9 @@-{-# OPTIONS -fglasgow-exts -XOverlappingInstances #-}+{-# OPTIONS -XOverlappingInstances+ -XTypeSynonymInstances+ -XFlexibleInstances+ -XUndecidableInstances+ -XOverloadedStrings+ #-} ----------------------------------------------------------------------------- --@@ -10,158 +15,178 @@ -- Stability : experimental --- | Read, Show and Data.Binary do not check for repeated references to the same address.--- As a result, the data is duplicated when seri<alized. This is a waste of space in the filesystem--- and also a waste of serialization time. but the worst consequence is that, when the serialized data is read,--- it allocates multiple copies for the same object when referenced multiple times. Because multiple referenced--- data is very typical in a pure language such is Haskell, this means that the resulting data loose the beatiful--- economy of space and processing time that referential transparency permits.------ Here comes a brief tutorial:------ @runW applies showp, the serialization parser of the instance Int for the RefSerialize class------ Data.RefSerialize>let x= 5 :: Int--- Data.RefSerialize>runW $ showp x--- "5"------ every instance of Read and Show is an instance of RefSerialize. for how to construct showp and readp parsers, see the demo.hs------ rshowp is derived from showp, it labels the serialized data with a variable name------ Data.RefSerialize>runW $ rshowp x--- " v8 where {v8= 5; }"------ Data.RefSerialize>runW $ rshowp [2::Int,3::Int]--- " v6 where {v6= [ v9, v10]; v9= 2; v10= 3; }"------ while showp does a normal show serialization------ Data.RefSerialize>runW $ showp [x,x]--- "[5, 5]"------ rshowp variables are serialized memory references: no piece of data that point to the same addrees is serialized but one time------ Data.RefSerialize>runW $ rshowp [x,x]--- " v9 where {v6= 5; v9= [ v6, v6]; }"------------ "this happens recursively"------ Data.RefSerialize>let xs= [x,x] in str = runW $ rshowp [xs,xs]--- Data.RefSerialize>str--- " v8 where {v8= [ v10, v10]; v9= 5; v10= [ v9, v9]; }"------ the rshowp serialized data is read with rreadp. The showp serialized data is read by readp------ Data.RefSerialize>let xss= runR rreadp str :: [[Int]]--- Data.RefSerialize>print xss--- [[5,5],[5,5]]------ this is the deserialized data------ the deserialized data keep the references!! pointers are restored! That is the whole point!------ Data.RefSerialize>varName xss !! 0 == varName xss !! 1--- True--------- rShow= runW rshowp--- rRead= runR rreadp------ Data.RefSerialize>rShow x--- " v11 where {v11= 5; }"--------- In the definition of a referencing parser non referencing parsers can be used and viceversa. Use a referencing parser--- when the piece of data is being referenced many times inside the serialized data.------ by default the referencing parser is constructed by:--------- rshowp= insertVar showp--- rreadp= readVar readp--- but this can be redefined. See for example the instance of [] in RefSerialize.hs------ This is an example of a showp parser for a simple data structure.------ data S= S Int Int deriving ( Show, Eq)------ instance Serialize S where--- showp (S x y)= do--- xs <- rshowp x -- rshowp parsers can be inside showp parser--- ys <- rshowp y--- return $ "S "++xs++" "++ys------------ readp = do--- symbol "S" -- I included a (almost) complete Parsec for deserialization--- x <- rreadp--- y <- rreadp--- return $ S x y------ there is a mix between referencing and no referencing parser here:------ Data.RefSerialize>putStrLn $ runW $ showp $ S x x--- S v23 v23 where {v23= 5; }@+{- | Read, Show and Data.Binary do not check for repeated references to the same address.+ As a result, the data is duplicated when serialized. This is a waste of space in the filesystem+ and also a waste of serialization time. but the worst consequence is that, when the serialized data is read,+ it allocates multiple copies for the same object when referenced multiple times. Because multiple referenced+ data is very typical in a pure language such is Haskell, this means that the resulting data loose the beatiful+ economy of space and processing time that referential transparency permits. + This package leverages Show, Read and Data.Binary instances while it permits textual as well as binary serialization+ keeping internal references. + Here comes a brief tutorial: + @runW applies showp, the serialization parser of the instance Int for the RefSerialize class + Data.RefSerialize>let x= 5 :: Int+ Data.RefSerialize>runW $ showp x+ "5" + every instance of Read and Show is an instance of RefSerialize. for how to construct showp and readp parsers, see the demo.hs + rshowp is derived from showp, it labels the serialized data with a variable name + Data.RefSerialize>runW $ rshowp x+ " v8 where {v8= 5; }"++ Data.RefSerialize>runW $ rshowp [2::Int,3::Int]+ " v6 where {v6= [ v9, v10]; v9= 2; v10= 3; }"++ while showp does a normal show serialization++ Data.RefSerialize>runW $ showp [x,x]+ "[5, 5]"++ rshowp variables are serialized memory references: no piece of data that point to the same addrees is serialized but one time++ Data.RefSerialize>runW $ rshowp [x,x]+ " v9 where {v6= 5; v9= [ v6, v6]; }"++++ "this happens recursively"++ Data.RefSerialize>let xs= [x,x] in str = runW $ rshowp [xs,xs]+ Data.RefSerialize>str+ " v8 where {v8= [ v10, v10]; v9= 5; v10= [ v9, v9]; }"++ the rshowp serialized data is read with rreadp. The showp serialized data is read by readp++ Data.RefSerialize>let xss= runR rreadp str :: [[Int]]+ Data.RefSerialize>print xss+ [[5,5],[5,5]]++ this is the deserialized data++ the deserialized data keep the references!! pointers are restored! That is the whole point!++ Data.RefSerialize>varName xss !! 0 == varName xss !! 1+ True+++ rShow= runW rshowp+ rRead= runR rreadp++ Data.RefSerialize>rShow x+ " v11 where {v11= 5; }"+++ In the definition of a referencing parser non referencing parsers can be used and viceversa. Use a referencing parser+ when the piece of data is being referenced many times inside the serialized data.++ by default the referencing parser is constructed by:+++ rshowp= insertVar showp+ rreadp= readVar readp+ but this can be redefined. See for example the instance of [] in RefSerialize.hs++ This is an example of a showp parser for a simple data structure.++ data S= S Int Int deriving ( Show, Eq)++ instance Serialize S where+ showp (S x y)= do+-- insertString "S"+ rshowp x -- rshowp parsers can be inside showp parser+ rshowp y+++ readp = do+ symbol "S" -- I included a (almost) complete Parsec for deserialization+ x <- rreadp+ y <- rreadp+ return $ S x y++ there is a mix between referencing and no referencing parser here:++ Data.RefSerialize>putStrLn $ runW $ showp $ S x x+ S v23 v23 where {v23= 5; }@++-}+++++ module Data.RefSerialize (- module Data.Parser+ module Data.RefSerialize.Parser ,Serialize( showp- ,readp-- ,rshowp-- ,rreadp-- )- ,showSR- ,readSR+ )+ ,Context+ ,newContext+ ,rshowp+ ,rreadp+ ,showps+ ,showpText+ ,readpText+ ,takep+ ,showpBinary+ ,readpBinary+ ,insertString+ ,insertChar ,rShow ,rRead ,insertVar ,readVar ,varName ,runR+ ,runRC ,runW+ ,readHexp ,showHexp+ ,getContext+ ) where-import qualified Data.Map as M-import Data.Serialize-import Data.Parser++import Data.RefSerialize.Serialize+import Data.RefSerialize.Parser import Unsafe.Coerce import Data.Char(isAlpha, isSpace, isAlphaNum) import Numeric(readHex,showHex)-import Data.Map+import Data.ByteString.Lazy.Char8 as B+--import Data.ByteString(breakSubstring)+import Debug.Trace+import Data.Binary+import System.IO.Unsafe+import qualified Data.Map as M -class Serialize c where-- showp :: c -> ST String -- ^ shows the content of a expression, must be defined bu the user+newContext :: IO Context+newContext = Data.RefSerialize.Serialize.empty - readp :: ST c -- ^ read the content of a expression, must be user defined+class Serialize c where+ showp :: c -> ST () -- ^ shows the content of a expression, must be defined bu the user+ readp :: ST c -- ^ read the content of a expression, must be user defined - rshowp :: c -> ST String -- ^ insert a reference (a variable in the where section). @rshowp = insertVar showp @ -- default definition+-- | insert a reference (a variable in the where section). - rshowp = insertVar showp+-- @rshowp = insertVar showp @+rshowp :: Serialize c => c -> ST ()+rshowp = insertVar showp - rreadp :: ST c -- ^ read a variable in the where section (to use for deserializing rshowp output). @rreadp = readVar readp@ -- default definition- rreadp = readVar readp+ -- | read a variable in the where section (to use for deserializing rshowp output). + -- @rreadp = readVar readp@+rreadp :: Serialize c => ST c+rreadp = readVar readp {- #ifdef Axioms@@ -181,70 +206,99 @@ } #endif -}++++-- | return the serialized list of variable values+-- useful for delayed deserialzation of expresions, in case of dynamic variables were deserialization+-- is done when needed, once the type is known with `runRC`++getContext :: ST (Context, ByteString)+getContext = ST(\(Stat(c,s,v)) -> Right (Stat (c,s,v), (c,v)))+ -- | use the rshowp parser to serialize the object -- @ rShow c= runW $ rshowp c@-rShow :: Serialize c => c -> String-rShow c= runW $ rshowp c+rShow :: Serialize c => c -> ByteString+rShow c= runW $ showp c -- | deserialize trough the rreadp parser -- @ rRead str= runR rreadp $ str@-rRead :: Serialize c => String -> c-rRead str= runR rreadp $ str+rRead :: Serialize c => ByteString -> c+rRead str= runR readp $ str readHexp :: (Num a, Integral a) => ST a readHexp = ST(\(Stat(c,s,v)) ->- let l= readHex s- in if Prelude.null l then Left . Error $ "not readable: " ++ s- else let ((x,str2):_)= l- in Right(Stat(c,dropWhile isSpace str2,v),x) )- <?> "readHexp "--- |if a is an instance of Read, readSR can be used as the readp method+ let us= unpack s+ l= readHex us+ in if Prelude.null l then Left . Error $ "not readable: " ++ us+ else let ((x,str2):_)= l+ in Right(Stat(c, pack $ Prelude.dropWhile isSpace str2,v),x) )+ <?> "readHexp "++++showHexp :: (Num a,Integral a) => a -> ST ()+showHexp var= ST(\(Stat(c,s,v)) -> Right(Stat(c, s `append` " " `append` (pack $ showHex var ""),v),())) <?> "showHexp "++-- |if a is an instance of Show, showpText can be used as the showp method -- the drawback is that the data inside is not inspected for common references -- so it is recommended to create your own readp method for your complex data structures-readSR :: Read a => ST a-readSR = ST(\(Stat(c,s,v)) ->- let l= readsPrec 1 s- in if Prelude.null l then Left . Error $ "not readable: " ++ s- else let ((x,str2):_)= l- in Right(Stat(c,dropWhile isSpace str2,v),x) )- <?> "readp: readsPrec "+showpText :: Show a => a -> ST ()+showpText var= ST(\(Stat(c,s,v)) -> Right(Stat(c, s `append` (snoc (pack $ show var) ' ') ,v),())) <?> "showp: show " +-- |if a is an instance of Read, readpText can be used as the readp method+-- the drawback is that the data inside is not inspected for common references+-- so it is recommended to create your own readp method for your complex data structures+readpText :: Read a => ST a+readpText = ST(\(Stat(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(Stat(c, pack $ Prelude.dropWhile isSpace str2,v),x) )+ <?> "readp: readsPrec " ---readSR = ST(\(Stat(c,s,v)) -> let ((x,str2):_)= readsPrec 1 s in Right(Stat(c,str2,v),x) ) -- | deserialize the string with the parser-runR:: ST a -> String -> a-runR (ST f) str=- let (struct, vars)= readContext "where " str- in case f (Stat(M.empty,struct,vars) ) of- Right (Stat _, a) -> a- Left (Error s) -> error s--showHexp :: (Num a,Integral a) => a -> ST String-showHexp var= ST(\(Stat(c,s,v)) -> Right(Stat(c,s,v),showHex var "")) <?> "showHexp "+runR:: ST a -> ByteString -> a+runR p str=unsafePerformIO $ do+ c <- newContext+ let (struct, vars)= readContext whereSep str+ return $ runRC (c, vars) p struct --- |if a is an instance of Show, showSR can be used as the showp method--- the drawback is that the data inside is not inspected for common references--- so it is recommended to create your own readp method for your complex data structures-showSR :: Show a => a -> ST String-showSR var= ST(\(Stat(c,s,v)) -> Right(Stat(c,s,v),show var)) <?> "showp: show "+-- | read an expression with the variables definedd in a context passed as parameter.+runRC :: (Context, ByteString) -> ST a -> ByteString -> a+runRC (c,vars) (ST f) struct=+ case f (Stat(c,struct,vars) ) of+ Right (Stat _, a) -> a+ Left (Error s) -> error s +whereSep= "\r\nwhere{\r\n " -- | serialize x with the parser-runW :: ST String -> String-runW (ST f) = case f (Stat(M.empty,"","")) of- Right (Stat (c,_,_), str) ->- let scontext= M.assocs c- show1 c= concatMap (\(n,(_,v))->"v"++ show n++"= "++v++"; ") scontext- vars= show1 c- strContext= if Prelude.null vars then "" else " where {"++vars ++ "}"+runW :: ST () -> ByteString+runW (ST f) = unsafePerformIO $ do+ c <- newContext+ return $ case f (Stat(c,"","")) of+ Right (Stat (c,str,_), _) ->+ let scontext= assocs c+ vars= B.concat $ Prelude.map (\(n,(_,_,v))->"v" `append` (pack $ show n) `append` "= " `append` v `append` ";\r\n ") scontext - in str ++ strContext+ strContext= if Prelude.null scontext then "" else whereSep `append` vars `append` "\r\n}" + in str `append` strContext+ Left (Error s) -> error s +-- | output the string of the serialized variable+showps :: Serialize a => a -> ST ByteString+showps x= ST(\(Stat(c,s,v))->+ let+ ST f= showp x+ Right (Stat (c',str,_), _) = f (Stat(c,"",v)) + in Right(Stat(c',s ,v), str)) @@ -256,85 +310,175 @@ -- runW (insertVar showp) [(1::Int) ,1] -> [v1.v1] where { v1=1}@ -- This is useful when the object is referenced many times -insertVar :: (a -> ST String) -> a -> ST String+insertVar :: (a -> ST ()) -> a -> ST () insertVar parser x= ST(\(Stat(c,s,v))-> let mf = trytofindEntireObject x c in case mf of- Just var -> Right(Stat(c,s,v),var)+ Just var -> Right(Stat(c,s `append` " " `append` var,v),()) Nothing -> let ST f= parser x- Right (Stat (c',_,_), str) = f (Stat(c,s,v))+ Right (Stat (c',str,_), _) = f (Stat(c,"",v)) - in Right(Stat(addc str c',s,v), ' ':varname))+ in Right(Stat(addc str c',s `append` (cons ' ' varname) ,v), ())) where- addc str c= M.insert ( hash) (unsafeCoerce x, str) c- hash = hasht x- varname= "v" ++ show hash+ addc str c= insert ( hash) (st,unsafeCoerce x, str) c+ (hash,st) = hasht x+ varname= pack$ "v" ++ show hash trytofindEntireObject x c=- case M.lookup hash c of+ case Data.RefSerialize.Serialize.lookup hash c of Nothing -> Nothing Just _ -> Just varname +-- | inform if the expression iwas already referenced and return @Right varname@+-- otherwise, add the expresion to the context and giive it a name and return @Left varname@+-- The varname is not added to the serialized expression. The user must serialize it+-- This is usefu for expressions that admit different syntax depending or recursiviity, such are lists +isInVars :: (a -> ST ()) -> a -> ST (Either ByteString ByteString)+isInVars parser x= ST(\(Stat(c,s,v))->+ let mf = trytofindEntireObject x c in+ case mf of+ Just var -> Right(Stat(c,s,v),Right var)+ Nothing ->+ let+ ST f= parser x+ Right (Stat (c',str,_), _) = f (Stat(c,"",v))++ in Right(Stat(addc str c',s ,v), Left varname))+ where+ addc str c= insert ( hash) (st,unsafeCoerce x, str) c+ (hash,st) = hasht x+ varname= pack$ "v" ++ show hash++ trytofindEntireObject x c=+ case Data.RefSerialize.Serialize.lookup hash c of+ Nothing -> Nothing+ Just _ -> Just varname+++ -- | deserialize a variable serialized with insertVar. Memory references are restored readVar :: Serialize c => ST c -> ST c-readVar parser= ST(\(Stat(c,s,v))->- let- s1= dropWhile isSpace s- (var, str2) = span isAlphaNum s1+readVar (ST f)= ST(\(Stat(c,s,v))->+ let+ s1= B.dropWhile isSpace s+ (var, str2) = B.span isAlphaNum s1+ str3= B.dropWhile isSpace str2+ nvar= numVar $ unpack var - in case trytofindEntireObject (numVar var) c of+ in if B.null var then Left (Error "expected variable name" )+ else+ case trytofindEntireObject nvar c of - Just (x,_) -> Right(Stat(c,str2,v),unsafeCoerce x)+ Just (_,x,_) -> Right(Stat(c,str3,v),unsafeCoerce x) Nothing -> let- (_, rest)= readContext (var++"= ") v- ST f= parser- in case f (Stat(c,rest,v)) --`debug` ("s="++s++"var="++var++"rest="++rest )- of+ (_, rest)= readContext (var `append` "= ") v++ in if B.null rest then Left (Error ( "RedSerialize: readVar: " ++ unpack var ++ "value not found" ))+ else case f (Stat(c,rest,v)) of+ Right (Stat(c',s',v'),x) ->- let c''= M.insert (numVar var) (unsafeCoerce x, "") c'- in Right (Stat(c'',str2,v),x)+ let c''= insert nvar ( undefined, unsafeCoerce x, "") c'+ in Right (Stat(c'', str3,v),x) err -> err) where trytofindEntireObject x c=- case M.lookup x c of+ case Data.RefSerialize.Serialize.lookup x c of Nothing -> Nothing justx -> justx --- -------------Instances+-- | Write a String in the serialized output with an added whitespace. Deserializable with `symbol`+insertString :: ByteString -> ST ()+insertString s1= ST(\(Stat(c,s,v)) -> Right(Stat(c, s `append` ( snoc s1 ' '),v),())) +-- | Write a char in the serialized output (no spaces)+insertChar :: Char -> ST()+insertChar car= ST(\(Stat(c,s,v)) -> Right(Stat(c, snoc s car,v),()))+-- +-- -------------Instances+ instance Serialize String where- showp = showSR- readp = readSR+ showp = showpText+ readp = readpText + instance Serialize a => Serialize [a] where- showp []= return "[]"+ showp []= insertString "[]" showp (x:xs)= do- s1<- rshowp x- sn<- mapM f xs- return $ "["++ s1++ concat sn ++"]"+ insertChar '['+ rshowp x+ mapM f xs+ insertString "]" where- f x= do str <- rshowp (x:: a)- return $ ", "++str+ f :: Serialize a => a -> ST ()+ f x= do+ insertChar ','+ rshowp x - readp = (brackets $ commaSep $ rreadp) <?> "rreadp:: [] " + readp = (brackets . commaSep $ rreadp) <?> "readp:: [] " +{-+instance Serialize a => Serialize [a] where+ showp xs= showpl [] xs+ where+ showpl res []= bracketdisp $ Prelude.reverse res+ showpl res xs= do+ is <- isInVars showp xs+ case is of+ Right v ->parensdisp (Prelude.reverse res) v+ Left v -> showpl (v:res) xs + parensdisp xs t= do+ insertChar '('+ disp ':' xs+ insertChar ':'+ insertString t+ insertString ")" + bracketdisp []= insertString "[]"+ bracketdisp xs= do+ insertChar '['+ disp ',' xs+ insertString "]" + disp sep (x:xs)= do+ insertString x+ mapM f xs+ where++ f x= do+ insertChar sep+ insertString x++ readp= choice [bracketsscan, parensscan] <?> "readp:: [] "+ where+ bracketsscan= (brackets . commaSep $ rreadp) <?> "readp:: [] "+ parensscan=parens $ do+ xs <- many(rreadp >>= \x -> symbol ":" >> return x)+ end <- rreadp+ return $ xs ++ end+++-}+++ instance (Serialize a, Serialize b) => Serialize (a, b) where showp (x, y)= do- sx <- rshowp x- sy <- rshowp y- return $ "("++ sx ++ "," ++ sy ++ ")"+ insertString "("+ rshowp x+ insertString ","+ rshowp y+ insertString ")" + readp = parens (do x <- rreadp comma@@ -344,11 +488,15 @@ instance (Serialize a, Serialize b, Serialize c) => Serialize (a, b,c) where showp (x, y, z)= do- sx <- rshowp x- sy <- rshowp y- sz <- rshowp z- return $ "("++ sx ++ "," ++ sy ++"," ++ sz ++ ")"+ insertString "("+ rshowp x+ insertString ","+ rshowp y+ insertString ","+ rshowp z+ insertString ")" + readp = parens (do x <- rreadp comma@@ -360,12 +508,17 @@ instance (Serialize a, Serialize b, Serialize c, Serialize d) => Serialize (a, b,c, d) where showp (x, y, z, t)= do- sx <- rshowp x- sy <- rshowp y- sz <- rshowp z- st <- rshowp t- return $ "("++ sx ++ "," ++ sy ++"," ++ sz ++ "," ++ st ++ ")"+ insertString "("+ rshowp x+ insertString ","+ rshowp y+ insertString ","+ rshowp z+ insertString ","+ rshowp t+ insertString ")" + readp = parens (do x <- rreadp comma@@ -377,26 +530,36 @@ return (x,y,z,t)) <?> "rreadp:: (,,,) " -instance (Serialize a, Ord a, Serialize b) => Serialize (Map a b) where+instance (Serialize a, Ord a, Serialize b) => Serialize (M.Map a b) where showp m= showp $ M.toList m readp= do- list <- readp :: ST [(a,b)]+ list <- readp -- :: ST [(a,b)] return $ M.fromList list instance Serialize a => Serialize (Maybe a) where- showp Nothing = return "Nothing"- showp (Just x) = showp x >>= \sx -> return $ "Just " ++ sx+ showp Nothing = insertString "Nothing"+ showp (Just x) =do+ insertString "Just"+ showp x+ readp = choice [rNothing, rJust] where rNothing = symbol "Nothing" >> return Nothing- rJust = symbol "Just" >> readp >>= \x -> return $ Just x+ rJust = do+ symbol "Just"+ x <- readp+ return $ Just x instance (Serialize a, Serialize b) => Serialize (Either a b) where- showp (Left x) = rshowp x >>= \sx -> return $ "Left " ++ sx+ showp (Left x) = do+ insertString "Left"+ rshowp x - showp (Right x) = rshowp x >>= \sx -> return $ "Right " ++ sx+ showp (Right x) = do+ insertString "Right"+ rshowp x readp = choice [rLeft, rRight] where rLeft = symbol "Left" >> rreadp >>= \x -> return $ Left x@@ -405,44 +568,40 @@ --instance Serialize Bool where- showp = showSR- readp = readSR--instance Serialize Char where- showp = showSR- readp = readSR--instance Serialize Double where- showp = showSR- readp = readSR--instance Serialize Float where- showp = showSR- readp = readSR--instance Serialize Int where- showp = showSR- readp = readSR+-- binary serialization -instance Serialize Integer where- showp = showSR- readp = readSR--instance Serialize Ordering where- showp = showSR- readp = readSR--instance Serialize () where- showp = showSR- readp = readSR+binPrefix= "Bin "+binPrefixSp= append (pack binPrefix) " " +-- | serialize a variable which has a Binary instance+showpBinary :: Binary a => a -> ST ()+showpBinary x = do+ let s = encode x+ let n = pack . show $ B.length s+ insertString $ binPrefixSp `append` n `append` " " `append` s +-- | deserialize a variable serialized by `showpBinary`+readpBinary :: Binary a => ST a+readpBinary = do+ symbol binPrefix+ n <- integer+ str <- takep $ fromIntegral n+ let x = decode str+ return x +-- return n chars form the serialized data+takep :: Int -> ST ByteString+takep n= take1 "" n+ where+ take1 s 0= return s+ take1 s n= anyChar >>= \x -> take1 (snoc s x) (n-1) +-- | defualt instances +instance (Show a, Read a )=> Serialize a where+ showp= showpText+ readp= readpText
+ Data/RefSerialize/Parser.hs view
@@ -0,0 +1,428 @@+{- | A Parsec parser for the refSerialize monad. See package Parsec. all the functions have the same meaning+-}+module Data.RefSerialize.Parser( ST(..),(<?>),(<|>),char,anyChar, string, upper, space, digit+ , sepBy, between, choice, option, notFollowedBy, many, manyTill, oneOf, noneOf+ , bool++ , charLiteral -- :: ST Char+ , stringLiteral -- :: ST String+ , natural -- :: ST Integer+ , integer -- :: ST Integer+ , float -- :: ST Double+ , naturalOrFloat -- :: ST (Either Integer Double)+ , decimal -- :: ST Integer+ , hexadecimal -- :: ST Integer+ , octal -- :: ST Integer++ , symbol -- :: String -> ST String+ , lexeme -- :: forall a. ST a -> ST a+ , whiteSpace -- :: ST ()++ , parens -- :: forall a. ST a -> ST a+ , braces -- :: forall a. ST a -> ST a+ , angles -- :: forall a. ST a -> ST a+ , brackets -- :: forall a. ST a -> ST a+ -- "squares" is deprecated++ , semi -- :: ST String+ , comma -- :: ST String+ , colon -- :: ST String+ , dot -- :: ST String+ , semiSep -- :: forall a . ST a -> ST [a]+ , semiSep1 -- :: forall a . ST a -> ST [a]+ , commaSep -- :: forall a . ST a -> ST [a]+ , commaSep1 -- :: forall a . ST a -> ST [a]+++ ) where+import Prelude hiding(head,tail, null)+import Control.Monad+import Data.Char(isUpper,isSpace,digitToInt)+import qualified Data.Map as M+import Data.RefSerialize.Serialize+import Data.ByteString.Lazy.Char8+++data ST a= ST(Stat-> Either Error (Stat , a) )++-- | monadic serialization & deserialization+instance Monad ST where+ return x = ST (\s -> Right (s, x))+ ST g >>= f = ST (\s ->++ case g s of+ Right (s', x)->+ let+ ST fun = f x+ in case fun s' of+ left@(Left msg) -> left+ rigth-> rigth++ Left msg -> Left msg++ )++instance MonadPlus ST where+ mzero= ST (\(Stat (a,b,c)) -> Left $ Error "an error occurred")+ mplus p1 p2 = parsecPlus p1 p2++infixr 1 <|>+(<|>) = parsecPlus+infix 0 <?>++p <?> msg = label p msg++parsecPlus :: ST a -> ST a -> ST a+parsecPlus (ST p1) (ST p2)+ = ST (\state ->+ case (p1 state) of+ Left (Error s) -> case (p2 state) of+ Left (Error s') -> Left $ Error ( s++ "\n"++ s')+ consumed-> consumed+ other -> other+ )+++label :: ST a -> String -> ST a+label p msg+ = labels p [msg]++labels :: ST a -> [String] -> ST a+labels (ST p) msgs+ = ST (\state ->+ case (p state) of+ Left(Error reply) -> Left $ Error ( reply ++Prelude.concatMap ("\n in "++) msgs)++ other -> other+ )++char :: Char -> ST Char++unexpectedEndOfInput= "unexpected end of input"+char c= ST(\(Stat(cs,s,v)) ->+ if null s then Left (Error $ unexpectedEndOfInput)+ else if c== head s then Right(Stat(cs,tail s,v), c)+ else Left (Error ( "char "++ c:" not match " ++ '\"':unpack s++"\"" )))+++anyChar = ST(\(Stat(cs,s,v)) ->+ if null s then Left (Error $ unexpectedEndOfInput)+ else Right(Stat(cs,tail s,v), head s))++satisfy bf= ST(\(Stat(cs,s,v)) -> let heads= head s in+ if null s then Left (Error $ unexpectedEndOfInput)+ else if bf heads then Right(Stat(cs,tail s,v), heads)+ else Left (Error ( "satisfy not matching condition in " ++ '\"':unpack s++"\"" )))+++upper = ST(\(Stat(cs,s,v)) -> let heads= head s in+ if null s then Left (Error $ unexpectedEndOfInput)+ else if isUpper (head s) then Right(Stat(cs,tail s,v), head s)+ else Left (Error ( "upper not matching condition in " ++ '\"':unpack s++"\"" )))+++space =ST(\(Stat(cs,s,v)) -> let heads= head s in+ if null s then Left (Error $ unexpectedEndOfInput)+ else if isSpace heads then Right(Stat(cs,tail s,v), heads)+ else Left (Error ( "expected space at the head of " ++ unpack s )))+++digit1 l1 l2= ST(\(Stat(cs,s,v)) -> let c= head s in if c >= l1 && c <= l2 then Right(Stat(cs,tail s,v), c)+ else Left (Error ( "expected digit at the head of " ++ unpack s )))++empty = ST(\(Stat(cs,s,v)) -> if null s then Right(Stat(cs, s,v), ())+ else Left (Error ( "expected empty list" )))++octDigit= digit1 '0' '7'++digit= digit1 '0' '9'++hexDigit= ST(\(Stat(cs,s,v)) -> let c= head s in if c >= '0' && c <= '9' || c >= 'a' && c<='f' || c >= 'A' && c <= 'F' then Right(Stat(cs,tail s,v), c)+ else Left (Error ( "expected space at the head of " ++ unpack s )))++oneOf xs= ST(\(Stat(cs,s,v)) -> let c= head s in if c `Prelude.elem` xs then Right(Stat(cs,tail s,v), c)+ else Left (Error ( "expected digit at the head of " ++ unpack s )))++noneOf xs= ST(\(Stat(cs,s,v)) -> let c= head s in if not $ c `Prelude.elem` xs then Right(Stat(cs,tail s,v), c)+ else Left (Error ( "expected digit at the head of " ++ unpack s )))++try p= p++unexpected msg+ = ST (\state -> Left (Error $ msg++ "unexpected"))++sepBy1,sepBy :: ST a -> ST sep -> ST [a]+sepBy p sep = sepBy1 p sep <|> return []+sepBy1 p sep = do{ x <- p+ ; xs <- many (sep >> p)+ ; return (x:xs)+ }+ <?> "sepBy "+between open close p+ = do{ open; x <- p; close; return x }++choice ps = Prelude.foldr (<|>) mzero ps <?> "choice "++option x p = p <|> return x+++notFollowedBy p = try (do{ c <- p; unexpected (show [c]) }+ <|> return ()+ )++ <?> "notFollowedBy "++skipMany1 p = do{ p; skipMany p }++skipMany p = scan+ where+ scan = do{ p; scan } <|> return ()+++manyTill p end = scan+ where+ scan = do{ end; return [] }+ <|>+ do{ x <- p; xs <- scan; return (x:xs) }+++string ""= return ""+string ys@(x:xs)= do+ char x+ string xs+ return ys+ <?> "string "++ys+++bool = lexeme ( do{ symbol "True" ; return True} <|> do{ symbol "False" ; return False}) <?> "Bool"++many :: ST a -> ST [a]+many p = many1 p <|> return []+many1 :: ST a -> ST [a]+many1 p = do {a <- p; as <- many p; return (a:as)}+++--from Token.hs+-----------------------------------------------------------+-- Bracketing+-----------------------------------------------------------+parens p = between (symbol "(") (symbol ")") p <?> "parens "+braces p = between (symbol "{") (symbol "}") p <?> "braces "+angles p = between (symbol "<") (symbol ">") p <?> "angles "+brackets p = between (symbol "[") (symbol "]") p <?> "brackets "++semi = symbol ";"+comma = symbol ","+dot = symbol "."+colon = symbol ":"++commaSep p = sepBy p comma+semiSep p = sepBy p semi++commaSep1 p = sepBy1 p comma+semiSep1 p = sepBy1 p semi+++-----------------------------------------------------------+-- Chars & Strings+-----------------------------------------------------------+-- charLiteral :: ST Char+charLiteral = lexeme (between (char '\'')+ (char '\'' <?> "end of character")+ characterChar )+ <?> "character"++characterChar = charLetter <|> charEscape+ <?> "literal character"++charEscape = do{ char '\\'; escapeCode }+charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))++++-- stringLiteral :: ST String+stringLiteral = lexeme (+ do{ str <- between (char '"')+ (char '"' <?> "end of string")+ (many stringChar)+ ; return (Prelude.foldr (maybe id (:)) "" str)+ }+ <?> "literal string")++-- stringChar :: ST (Maybe Char)+stringChar = do{ c <- stringLetter; return (Just c) }+ <|> stringEscape+ <?> "string character"++stringLetter = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))++stringEscape = do{ char '\\'+ ; do{ escapeGap ; return Nothing }+ <|> do{ escapeEmpty; return Nothing }+ <|> do{ esc <- escapeCode; return (Just esc) }+ }++escapeEmpty = char '&'+escapeGap = do{ many1 space+ ; char '\\' <?> "end of string gap"+ }++++-- escape codes+escapeCode = charEsc <|> charNum <|> charAscii <|> charControl+ <?> "escape code"++-- charControl :: ST Char+charControl = do{ char '^'+ ; code <- upper+ ; return (toEnum (fromEnum code - fromEnum 'A'))+ }++-- charNum :: ST Char+charNum = do{ code <- decimal+ <|> do{ char 'o'; number 8 octDigit }+ <|> do{ char 'x'; number 16 hexDigit }+ ; return (toEnum (fromInteger code))+ }++charEsc = choice (Prelude.map parseEsc escMap)+ where+ parseEsc (c,code) = do{ char c; return code }++charAscii = choice (Prelude.map parseAscii asciiMap)+ where+ parseAscii (asc,code) = try (do{ string asc; return code })+++-- escape code tables+escMap = Prelude.zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")+asciiMap = Prelude.zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)++ascii2codes = ["BS","HT","LF","VT","FF","CR","SO","SI","EM",+ "FS","GS","RS","US","SP"]+ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK","BEL",+ "DLE","DC1","DC2","DC3","DC4","NAK","SYN","ETB",+ "CAN","SUB","ESC","DEL"]++ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI',+ '\EM','\FS','\GS','\RS','\US','\SP']+ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK',+ '\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK',+ '\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']+++-----------------------------------------------------------+-- Numbers+-----------------------------------------------------------+-- naturalOrFloat :: ST (Either Integer Double)+naturalOrFloat = lexeme (natFloat) <?> "number"++float = lexeme floating <?> "float"+integer = lexeme int <?> "integer"+natural = lexeme nat <?> "natural"+++-- floats+floating = do{ n <- decimal+ ; fractExponent n+ }+++natFloat = do{ char '0'+ ; zeroNumFloat+ }+ <|> decimalFloat++zeroNumFloat = do{ n <- hexadecimal <|> octal+ ; return (Left n)+ }+ <|> decimalFloat+ <|> fractFloat 0+ <|> return (Left 0)++decimalFloat = do{ n <- decimal+ ; option (Left n)+ (fractFloat n)+ }++fractFloat n = do{ f <- fractExponent n+ ; return (Right f)+ }++fractExponent n = do{ fract <- fraction+ ; expo <- option 1.0 exponent'+ ; return ((fromInteger n + fract)*expo)+ }+ <|>+ do{ expo <- exponent'+ ; return ((fromInteger n)*expo)+ }++fraction = do{ char '.'+ ; digits <- many1 digit <?> "fraction"+ ; return (Prelude.foldr op 0.0 digits)+ }+ <?> "fraction"+ where+ op d f = (f + fromIntegral (digitToInt d))/10.0++exponent' = do{ oneOf "eE"+ ; f <- sign+ ; e <- decimal <?> "exponent"+ ; return (power (f e))+ }+ <?> "exponent"+ where+ power e | e < 0 = 1.0/power(-e)+ | otherwise = fromInteger (10^e)+++-- integers and naturals+int = do{ f <- lexeme sign+ ; n <- nat+ ; return (f n)+ }++-- sign :: ST (Integer -> Integer)+sign = (char '-' >> return negate)+ <|> (char '+' >> return id)+ <|> return id++nat = zeroNumber <|> decimal++zeroNumber = do{ char '0'+ ; hexadecimal <|> octal <|> decimal <|> return 0+ }+ <?> ""++decimal = number 10 digit+hexadecimal = do{ oneOf "xX"; number 16 hexDigit }+octal = do{ oneOf "oO"; number 8 octDigit }+++ -- number :: Integer -> ST Char -> ST Integer+number base baseDigit+ = do{ digits <- many1 baseDigit+ ; let n = Prelude.foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits+ ; seq n (return n)+ }+++-----------------------------------------------------------+-- White space & symbols+-----------------------------------------------------------+symbol name+ = lexeme (string name) <?> "symbol"++lexeme p+ = do{ x <- p; whiteSpace ; return x }+++--whiteSpace+whiteSpace = skipMany (simpleSpace <?> "")+++simpleSpace = skipMany1 (satisfy isSpace)++
+ Data/RefSerialize/Serialize.hs view
@@ -0,0 +1,72 @@+{-# OPTIONS -XOverlappingInstances+ -XTypeSynonymInstances+ -XFlexibleInstances+ -XUndecidableInstances+ -XOverloadedStrings+ -XNoMonomorphismRestriction+ #-}+module Data.RefSerialize.Serialize where+import GHC.Exts+import Unsafe.Coerce+import Data.List(isPrefixOf,insertBy,elem)+import Data.Char(isAlpha,isAlphaNum,isSpace,isUpper)++import System.Mem.StableName+import System.IO.Unsafe+import Control.Monad (MonadPlus(..))+import Data.ByteString.Lazy.Char8 as B+import qualified Data.HashTable as HT+import Data.List(sortBy)+import Data.Ord+++type MFun= Char -- usafeCoherced to char to store simply the address of the function+type VarName = String+type ShowF= ByteString+type Context = HT.HashTable Int ( StableName MFun, MFun,ShowF)++data Error= Error String+data Stat= Stat (Context, ByteString, ByteString)+++-- HT to map+empty = HT.new (==) HT.hashInt++assocs = sortBy (comparing fst) . unsafePerformIO . HT.toList++insert k v ht= unsafePerformIO $ HT.insert ht k v >> return ht++lookup k ht= unsafePerformIO $ HT.lookup ht k++toList = unsafePerformIO . HT.toList++fromList = unsafePerformIO . HT.fromList HT.hashInt+++readContext :: ByteString -> ByteString -> (ByteString, ByteString)+readContext pattern str= readContext1 (pack "") str where++ readContext1 :: ByteString -> ByteString -> (ByteString, ByteString)+ readContext1 s str| B.null str = (s, pack "")+ | pattern `B.isPrefixOf` str = (s, B.drop n str)+ | otherwise= readContext1 (snoc s (B.head str)) (B.tail str)+ where n= fromIntegral $ B.length pattern+++hasht x= unsafePerformIO $ do+ st <- makeStableName $! x+ return (hashStableName st,unsafeCoerce st)++-- ! two variables that point to the same address will have identical varname (derived from import System.Mem.StableName)varName:: a -> String+varName x= "v"++ (show . hash) x+ where hash x= let (ht,_)= hasht x in ht+++++numVar :: String -> Int+numVar "" = error "refSerialize: numVar: null variable"+numVar var= read $ Prelude.tail var+++
− Data/Serialize.hs
@@ -1,49 +0,0 @@-{-# OPTIONS -fglasgow-exts #-}-module Data.Serialize where-import GHC.Exts-import Unsafe.Coerce-import Data.List(isPrefixOf,insertBy,elem)-import Data.Char(isAlpha,isAlphaNum,isSpace,isUpper)-import qualified Data.Map as M-import System.Mem.StableName-import System.IO.Unsafe-import Control.Monad (MonadPlus(..))--import Debug.Trace--debug a b= trace b a----type MFun= Char -- usafeCoherced to char to store simply the address of the function-type VarName = String-type ShowF= String-type Context = M.Map Int (MFun,ShowF)--data Error= Error String-data Stat= Stat (Context, String, String)----readContext pattern str= readContext1 "" str where- readContext1 s str| null str = (s,"")- | pattern `isPrefixOf` str = (s,drop n str)- | otherwise= readContext1 (s++[head str]) (tail str)- where n= length pattern----hasht x= (hashStableName . unsafePerformIO . makeStableName) x---- ! two variables that point to the same address will have identical varname (derived from import System.Mem.StableName)-varName:: a -> String-varName x= "v"++ (show . hasht) x-----numVar :: String -> Int-numVar var= read $ tail var---
RefSerialize.cabal view
@@ -1,5 +1,5 @@ name: RefSerialize-version: 0.2.7+version: 0.2.8 synopsis: Write to and read from Strings maintaining internal memory references description: Read, Show and Data.Binary do not check for internal data references to the same address.@@ -27,32 +27,33 @@ . in this release: .- * bug in 0.2.5 corrected: empty lists were written with two indirections (insertVar . insertVar). That caused an error in readp+ * Serialization instance now includes an internal wiriter .- * bug in 0.2.6 corrected for lists+ * Solved a criitical bug only appearing in structures with many references, when StableNames started to be+ freed by the gartbage colllector before serialization was completed, which gave erroneous references .- * removed the problematic instance (Show a, Read a) => Serialize a+ * Bug in 0.2.5 fixed: empty lists were written with two indirections (insertVar . insertVar). That caused an error in readp .+ * Bug in 0.2.6 fixed for lists+ . * Added instances for standard datatypes. More "deeper" instances favouring more variable usage .- * instance of Serialize [a] changed- .- To do:- .- -derived instances for Data.Binary- .- -serialization to/from ByteStings+ * Instance of Serialize [a] changed+ .+ * Derived Serialize instances for Data.Binary instances: readpBinary, showpBinary+ .+ *- Serialization now is to/from ByteStings -category: Parsing, Data, Database-license: BSD3-license-file: LICENSE-author: Alberto Gómez Corona-maintainer: agocorona@gmail.com-Tested-With: GHC == 6.8.2+category: Parsing, Data, Database+license: BSD3+license-file: LICENSE+author: Alberto Gómez Corona+maintainer: agocorona@gmail.com+Tested-With: GHC == 6.8.2 Build-Type: Simple-build-Depends: base >=3 && <4,containers-Cabal-Version: >= 1.2+build-Depends: binary,bytestring, base >=4 && <5,containers -exposed-modules: Data.RefSerialize, Data.Parser, Data.Serialize++exposed-modules: Data.RefSerialize, Data.RefSerialize.Parser, Data.RefSerialize.Serialize ghc-options: -O2