module Mongrel2.Tnetstring ( parseTnetstring1 , TValue(..) ) where import Data.Attoparsec import Data.Attoparsec.Char8 (decimal) import Data.ByteString (ByteString) import Data.Word (Word8) import Prelude hiding (take) isColon :: Word8 -> Bool isColon 0x3a = True isColon _ = False data TValue = TInteger Integer | TString ByteString | TBoolean Bool | TList [TValue] | TDictionary [(ByteString, TValue)] | TNull deriving (Show) subParse :: Parser a -> ByteString -> Parser a subParse p s = do let x = parseOnly p s case x of Left err -> error err Right x' -> return x' pString :: ByteString -> Parser TValue pString s = return $ TString s pInteger :: ByteString -> Parser TValue pInteger s = fmap TInteger $ subParse decimal s pBoolean :: ByteString -> Parser TValue pBoolean "false" = return $ TBoolean False pBoolean "true" = return $ TBoolean True pBoolean _ = error "Invalid boolean literal" pList :: ByteString -> Parser TValue pList s = fmap TList $ subParse (many parseTnetstring1) s pNull :: ByteString -> Parser TValue pNull _ = return TNull pDict :: ByteString -> Parser TValue pDict s = fmap TDictionary $ subParse (many parsePair) s where parsePair :: Parser (ByteString,TValue) parsePair = do k' <- parseTnetstring1 k'' <- case k' of TString k -> return k _ -> error "Dictionary keys may only be strings" v <- parseTnetstring1 return $ (k'', v) parseTnetstring1 :: Parser TValue parseTnetstring1 = do n <- decimal skip isColon middle <- take n ctyp <- anyWord8 value <- case ctyp of 0x2c -> pString middle 0x23 -> pInteger middle 0x21 -> pBoolean middle 0x7e -> pNull middle 0x5d -> pList middle 0x7d -> pDict middle _ -> error "Invalid type designation" return value