{-# LANGUAGE OverlappingInstances, TypeSynonymInstances #-} -- | Parse (simple) BERTs. module Data.BERT.Parser ( parseTerm ) where import Data.Char import Control.Applicative import Numeric import Text.ParserCombinators.Parsec hiding (many, optional, (<|>)) import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy.Char8 as C import Data.BERT.Types --instance Applicative (GenParser s a) where -- pure = return -- (<*>) = ap --instance Alternative (GenParser s a) where -- empty = mzero -- (<|>) = mplus -- | Parse a simple BERT (erlang) term from a string in the erlang -- grammar. Does not attempt to decompose complex terms. parseTerm :: String -> Either ParseError Term parseTerm = parse p_term "term" p_term :: Parser Term p_term = t <* spaces where t = IntTerm <$> p_num (readSigned readDec) <|> FloatTerm <$> p_num (readSigned readFloat) <|> AtomTerm <$> p_atom <|> TupleTerm <$> p_tuple <|> BytelistTerm . C.pack <$> p_string <|> ListTerm <$> p_list <|> BinaryTerm . B.pack <$> p_binary p_num which = do s <- getInput case which s of [(n, s')] -> n <$ setInput s' _ -> empty p_atom = unquoted <|> quoted where unquoted = many1 $ lower <|> oneOf ['_', '@'] quoted = quote >> many1 letter <* quote quote = char '\'' p_seq open close elem = between (open >> spaces) (spaces >> close) $ elem `sepBy` (spaces >> char ',' >> spaces) p_tuple = p_seq (char '{') (char '}') p_term p_list = p_seq (char '[') (char ']') p_term p_string = char '"' >> many strchar <* char '"' where strchar = noneOf ['\\', '"'] <|> (char '\\' >> anyChar) p_binary = string "<<" >> (bstr <|> bseq) <* string ">>" where bseq = (p_num readDec) `sepBy` (spaces >> char ',' >> spaces) bstr = map (fromIntegral . ord) <$> p_string