module Text.TOML.Parser
( module Text.TOML.Value
, document
, keygroup
, keyval
, value
, Token
)where
import Control.Applicative
import qualified Data.ByteString.Char8 as B
import Data.Attoparsec.ByteString.Char8
import Data.Attoparsec.Combinator
import Data.Time.Format
import System.Locale
import Text.TOML.Value
type Token = Either [B.ByteString] (B.ByteString, TOMLV)
document :: Parser [Token]
document = smb *> many ekk <* endOfInput
where
smb = skipMany blank
ekk = (eitherP keygroup keyval) <* smb
keygroup :: Parser [B.ByteString]
keygroup = do
skipMany blank
between lbrace rbrace skey
where skey = keyg `sepBy` period
keyval :: Parser (B.ByteString, TOMLV)
keyval = do
k <- keyv
v <- equal *> value
return (k, v)
keyg = lexeme $ takeWhile1 $ notInClass " \t\n]."
keyv = lexeme $ takeWhile1 $ notInClass " \t\n="
value :: Parser TOMLV
value = (array <?> "array")
<|> (bool <?> "bool")
<|> (str <?> "string")
<|> (date <?> "date")
<|> (num <?> "number")
where
array = VArray <$> between lbrace rbrace (value `sepBy` comma)
bool = VBool <$> (true *> return True <|> false *> return False)
str = VString <$> between quote quote (many (notChar '"'))
num = do
n <- lexeme $ number
case n of
I n -> return $ VInteger n
D d -> return $ VDouble d
date = do
dstr <- takeTill (=='Z') <* zee
let mt = parseTime defaultTimeLocale (iso8601DateFormat (Just "%X")) (B.unpack dstr)
case mt of
Just t -> return (VDate t)
Nothing -> fail "parse date failed"
whatever p = p >> return ()
lexeme p = do { x <- p; many spc; return x }
spc = char ' ' <|> char '\t'
comment = whatever $ char '#' *> takeTill (=='\n')
line p = p *> (lexeme endOfLine)
blank = line $ lexeme $ (try comment) <|> return ()
zee = lexeme $ string "Z"
quote = lexeme $ string "\""
lbrace = lexeme $ string "["
rbrace = lexeme $ string "]"
comma = lexeme $ string ","
period = lexeme $ string "."
equal = lexeme $ string "="
true = lexeme $ string "true"
false = lexeme $ string "false"
between a b p = do { a; e <- p; b; return e }