{- | A Parsec parser for the refSerialize monad. See package Parsec. all the functions have the same meaning -} module Data.RefSerialize.Parser( STR(..),StatR(..),(),(<|>),char,anyChar, string, upper, space, digit , sepBy, between, choice, option, notFollowedBy, many, manyTill, oneOf, noneOf , bool, try, Data.RefSerialize.Parser.empty, readContent , 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 StatR= StatR (Context, ByteString, ByteString) data STR a= STR(StatR-> Either Error (StatR , a) ) -- | monadic serialization & deserialization instance Monad STR where return x = STR (\s -> Right (s, x)) STR g >>= f = STR (\s -> case g s of Right (s', x)-> let STR fun = f x in case fun s' of left@(Left msg) -> left rigth-> rigth Left msg -> Left msg ) instance MonadPlus STR where mzero= STR (\(StatR (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 :: STR a -> STR a -> STR a parsecPlus (STR p1) (STR p2) = STR (\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 :: STR a -> String -> STR a label p msg = labels p [msg] labels :: STR a -> [String] -> STR a labels (STR p) msgs = STR (\state -> case (p state) of Left(Error reply) -> Left $ Error ( reply ++Prelude.concatMap ("\n in "++) msgs) other -> other ) ---- return n chars form the serialized data --takep :: Int -> STR ByteString --takep n= STR $ \(StatR(cs,s,v)) -> -- let (h,t)= Data.ByteString.Lazy.Char8.splitAt (fromIntegral n) s in h `seq` t `seq` Right(StatR(cs,t,v), h) -- char :: Char -> STR Char unexpectedEndOfInput= "unexpected end of input" char c= STR(\(StatR(cs,s,v)) -> if null s then Left (Error $ unexpectedEndOfInput) else if c== head s then Right(StatR(cs,tail s,v), c) else Left (Error ( "char "++ c:" not match " ++ '\"':unpack s++"\"" ))) anyChar = STR(\(StatR(cs,s,v)) -> if null s then Left (Error $ unexpectedEndOfInput) else Right(StatR(cs,tail s,v), head s)) satisfy bf= STR(\(StatR(cs,s,v)) -> let heads= head s in if null s then Left (Error $ unexpectedEndOfInput) else if bf heads then Right(StatR(cs,tail s,v), heads) else Left (Error ( "satisfy not matching condition in " ++ '\"':unpack s++"\"" ))) upper = STR(\(StatR(cs,s,v)) -> let heads= head s in if null s then Left (Error $ unexpectedEndOfInput) else if isUpper (head s) then Right(StatR(cs,tail s,v), head s) else Left (Error ( "upper not matching condition in " ++ '\"':unpack s++"\"" ))) space =STR(\(StatR(cs,s,v)) -> let heads= head s in if null s then Left (Error $ unexpectedEndOfInput) else if isSpace heads then Right(StatR(cs,tail s,v), heads) else Left (Error ( "expected space at the head of " ++ unpack s ))) digit1 l1 l2= STR(\(StatR(cs,s,v)) -> if null s then Left (Error $ unexpectedEndOfInput) else let c= head s in if c >= l1 && c <= l2 then Right(StatR(cs,tail s,v), c) else Left (Error ( "expected digit at the head of " ++ unpack s ))) empty = STR(\(StatR(cs,s,v)) -> if null s then Right(StatR(cs, s,v), ()) else Left (Error ( "expected empty list" ))) octDigit= digit1 '0' '7' digit= digit1 '0' '9' hexDigit= STR(\(StatR(cs,s,v)) -> if null s then Left (Error $ unexpectedEndOfInput) else let c= head s in if c >= '0' && c <= '9' || c >= 'a' && c<='f' || c >= 'A' && c <= 'F' then Right(StatR(cs,tail s,v), c) else Left (Error ( "expected space at the head of " ++ unpack s ))) oneOf xs= STR(\(StatR(cs,s,v)) -> if null s then Left (Error $ unexpectedEndOfInput) else let c= head s in if c `Prelude.elem` xs then Right(StatR(cs,tail s,v), c) else Left (Error ( "expected digit at the head of " ++ unpack s ))) noneOf xs= STR(\(StatR(cs,s,v)) -> if null s then Left (Error $ unexpectedEndOfInput) else let c= head s in if not $ c `Prelude.elem` xs then Right(StatR(cs,tail s,v), c) else Left (Error ( "expected digit at the head of " ++ unpack s ))) try p= do (cs,s,v)<- STR $ \(StatR(cs,s,v)) -> Right(StatR(cs, s,v), (cs,s,v)) r <- p STR(\(StatR _) -> Right(StatR(cs, s,v), r)) readContent= STR $ \(StatR(cs,s,v)) -> Right(StatR(cs,Data.ByteString.Lazy.Char8.empty,v), s) unexpected msg = STR (\state -> Left (Error $ msg++ "unexpected")) sepBy1,sepBy :: STR a -> STR sep -> STR [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 :: STR a -> STR [a] many p = many1 p <|> return [] many1 :: STR a -> STR [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 :: STR 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 :: STR String stringLiteral = lexeme ( do{ str <- between (char '"') (char '"' "end of string") (many stringChar) ; return (Prelude.foldr (maybe id (:)) "" str) } "literal string") -- stringChar :: STR (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 :: STR Char charControl = do{ char '^' ; code <- upper ; return (toEnum (fromEnum code - fromEnum 'A')) } -- charNum :: STR 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 :: STR (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 :: STR (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 -> STR Char -> STR 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)