bookhound-0.1.3.0: src/Parsers/Toml.hs
module Parsers.Toml (toml, nil, integer, float, bool, string,
array, inlineTable) where
import Parser(Parser)
import ParserCombinators (IsMatch(..), (<|>), (>>>), (<#>), (|?), (|*), (|+),
maybeWithin, within)
import Parsers.Number (double, hexInt, int, octInt)
import Parsers.String (blankLine, withinQuotes, withinDoubleQuotes,
spacesOrTabs, withinSquareBrackets, spacing, blankLines)
import Parsers.Char (quote, doubleQuote, whiteSpace, hashTag, newLine,
dot, digit, letter, underscore, dash, equal, spaceOrTab)
import SyntaxTrees.Toml (TomlExpression(..), TableType(..))
import Parsers.Collections (mapOf, listOf)
import qualified Parsers.DateTime as Dt
import qualified Data.Map as Map
import Data.Maybe (maybeToList)
toml :: Parser TomlExpression
toml = maybeWithin (((pure <$> whiteSpace) <|> comment) |+) topLevelTable
-- TODO: Add support for table arrays
nil :: Parser TomlExpression
nil = TomlNull <$ is "null"
integer :: Parser TomlExpression
integer = TomlInteger <$> (hexInt <|> octInt <|> int)
float :: Parser TomlExpression
float = TomlFloat <$> double
bool :: Parser TomlExpression
bool = TomlBool <$> (True <$ is "true" <|>
False <$ is "false")
dateTime :: Parser TomlExpression
dateTime = TomlDateTime <$> Dt.dateTime
date :: Parser TomlExpression
date = TomlDate <$> Dt.date
time :: Parser TomlExpression
time = TomlTime <$> Dt.time
string :: Parser TomlExpression
string = TomlString <$> text where
text = within (doubleQuote <#> 3) (multiline (inverse doubleQuote |*)) <|>
within (quote <#> 3) (multiline (inverse quote |*)) <|>
withinDoubleQuotes (inverse doubleQuote |*) <|>
withinQuotes (inverse quote |*)
multiline parser = mconcat <$> (((blankLine |?) *> line parser) |*)
line parser = is "\\" *> (whiteSpace |*) *> parser
array :: Parser TomlExpression
array = TomlArray <$> listOf (maybeWithin spacing tomlExpr)
key :: Parser String
key = keyParser >>> ((dot >>> keyParser) |*) where
keyParser = maybeWithin spacesOrTabs $ freeText <|>
withinDoubleQuotes (inverse doubleQuote |*) <|>
withinQuotes (inverse quote |*)
freeText = ((letter <|> digit <|> underscore <|> dash) |+)
inlineTable :: Parser TomlExpression
inlineTable = TomlTable Inline <$> mapOf equal key tomlExpr
topLevelTable :: Parser TomlExpression
topLevelTable = TomlTable TopLevel . Map.fromList <$> maybeWithin spacing tables where
tables = do xs <- keyValueSeqParser
ys <- (tableParser |*)
pure (ys ++ [("", TomlTable Standard . Map.fromList $ xs)])
tableParser = do k <- withinSquareBrackets key
v <- maybeWithin spacing standardTable
pure (k, v)
standardTable = TomlTable Standard . Map.fromList <$> keyValueSeqParser
keyValueSeqParser = do xs <- ((keyValueParser <* (blankLine *> (blankLines |?))) |*)
x <- (keyValueParser |?)
pure (xs ++ maybeToList x)
keyValueParser = do k <- key
maybeWithin spacesOrTabs equal
v <- tomlExpr
pure (k, v)
element :: Parser TomlExpression
element = dateTime <|> date <|> time <|> float <|>
integer <|> bool <|> nil <|> string
container :: Parser TomlExpression
container = array <|> inlineTable
comment :: Parser String
comment = hashTag *> (inverse newLine |+) <* newLine
tomlExpr :: Parser TomlExpression
tomlExpr = maybeWithin (((pure <$> spaceOrTab) <|> comment) |+) tomlValue where
tomlValue = element <|> container