{-# LANGUAGE OverloadedStrings #-} module Data.Honeybee (parseBValue, BValue(..)) where import Control.Applicative import Data.Attoparsec.Combinator import Data.Attoparsec.ByteString.Char8 import qualified Data.Map as M data BValue = BInteger Integer | BString String | BList [BValue] | BDict (M.Map BValue BValue) deriving (Show, Eq, Ord) -- $setup -- >>> :set -XOverloadedStrings -- | Parse an integer -- -- >>> parseOnly parseInteger "i3e" -- Right (BInteger 3) parseInteger :: Parser BValue parseInteger = do char 'i' num <- many1 digit char 'e' return $ BInteger (read num) -- | Parse a string -- -- >>> parseOnly parseString "4:spam" -- Right (BString "spam") -- >>> parseOnly parseString "0:" -- Right (BString "") parseString :: Parser BValue parseString = do len <- many1 digit char ':' s <- count (read len) anyChar return $ BString s -- | Parse a list -- -- >>> parseOnly parseList "l4:spam4:eggse" -- Right (BList [BString "spam",BString "eggs"]) -- >>> parseOnly parseList "le" -- Right (BList []) parseList :: Parser BValue parseList = do char 'l' list <- many parseBValue char 'e' return $ BList list -- | Parse a dictionary -- -- >>> parseOnly parseDict "d3:cow3:moo4:spam4:eggse" -- Right (BDict (fromList [(BString "cow",BString "moo"),(BString "spam",BString "eggs")])) -- >>> parseOnly parseDict "d4:spaml1:a1:bee" -- Right (BDict (fromList [(BString "spam",BList [BString "a",BString "b"])])) -- >>> parseOnly parseDict "de" -- Right (BDict (fromList [])) parseDict :: Parser BValue parseDict = do char 'd' pairs <- many parseDictPair char 'e' return . BDict $ M.fromList pairs -- | Parse a dictionary key/value pair -- -- >>> parseOnly parseDictPair "3:cowi2e" -- Right (BString "cow",BInteger 2) -- >>> parseOnly parseDictPair "i10ei2e" -- Left "Failed reading: satisfyWith" parseDictPair :: Parser (BValue, BValue) parseDictPair = do key <- parseString value <- parseBValue return (key, value) -- | Parse any BEncoded value parseBValue :: Parser BValue parseBValue = parseInteger <|> parseString <|> parseList <|> parseDict