module Bookhound.Format.Parsers.Toml (toml, nil, integer, float, bool, string,
                     array, inlineTable) where

import Bookhound.Parser              (Parser, withError)
import Bookhound.ParserCombinators   (IsMatch (..), maybeWithin, within, (<#>),
                                      (<|>), (->>-), (|*), (|+), (|?))
import Bookhound.Parsers.Char        (dash, digit, dot, doubleQuote, equal,
                                      hashTag, letter, newLine, quote,
                                      spaceOrTab, underscore, whiteSpace)
import Bookhound.Parsers.Collections (listOf, mapOf)
import Bookhound.Parsers.Number      (double, hexInt, int, octInt)
import Bookhound.Parsers.String      (blankLine, blankLines, spacesOrTabs,
                                      spacing, withinDoubleQuotes, withinQuotes,
                                      withinSquareBrackets)

import Bookhound.Format.SyntaxTrees.Toml    (TableType (..), TomlExpression (..))

import qualified Bookhound.Parsers.DateTime as Dt

import qualified Data.Map   as Map
import           Data.Maybe (maybeToList)



toml :: Parser TomlExpression
toml :: Parser TomlExpression
toml = forall a b. Parser a -> Parser b -> Parser b
maybeWithin (((forall (f :: * -> *) a. Applicative f => a -> f a
pure forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Char
whiteSpace) forall a. Parser a -> Parser a -> Parser a
<|> Parser [Char]
comment) |+) Parser TomlExpression
topLevelTable



-- TODO: Add support for table arrays

nil :: Parser TomlExpression
nil :: Parser TomlExpression
nil = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Null"
  forall a b. (a -> b) -> a -> b
$ TomlExpression
TomlNull forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall a. IsMatch a => a -> Parser a
is [Char]
"null"

integer :: Parser TomlExpression
integer :: Parser TomlExpression
integer = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Integer"
  forall a b. (a -> b) -> a -> b
$ Integer -> TomlExpression
TomlInteger forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Parser Integer
hexInt forall a. Parser a -> Parser a -> Parser a
<|> Parser Integer
octInt forall a. Parser a -> Parser a -> Parser a
<|> Parser Integer
int)

float :: Parser TomlExpression
float :: Parser TomlExpression
float = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Float"
  forall a b. (a -> b) -> a -> b
$ Double -> TomlExpression
TomlFloat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Double
double

bool :: Parser TomlExpression
bool :: Parser TomlExpression
bool = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Bool"
  forall a b. (a -> b) -> a -> b
$ Bool -> TomlExpression
TomlBool forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Bool
True  forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall a. IsMatch a => a -> Parser a
is [Char]
"true"  forall a. Parser a -> Parser a -> Parser a
<|>
                Bool
False forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall a. IsMatch a => a -> Parser a
is [Char]
"false")


dateTime :: Parser TomlExpression
dateTime :: Parser TomlExpression
dateTime = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml DateTime"
  forall a b. (a -> b) -> a -> b
$ ZonedTime -> TomlExpression
TomlDateTime forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ZonedTime
Dt.dateTime

date :: Parser TomlExpression
date :: Parser TomlExpression
date = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Date"
  forall a b. (a -> b) -> a -> b
$ Day -> TomlExpression
TomlDate forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Day
Dt.date

time :: Parser TomlExpression
time :: Parser TomlExpression
time = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Time"
  forall a b. (a -> b) -> a -> b
$ TimeOfDay -> TomlExpression
TomlTime forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser TimeOfDay
Dt.time


string :: Parser TomlExpression
string :: Parser TomlExpression
string = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml String"
  forall a b. (a -> b) -> a -> b
$ [Char] -> TomlExpression
TomlString forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser [Char]
text
  where
    text :: Parser [Char]
text = forall a b. Parser a -> Parser b -> Parser b
within (Parser Char
doubleQuote forall a. Parser a -> Integer -> Parser [a]
<#> Integer
3) (forall {b}. Monoid b => Parser b -> Parser b
multiline (forall a. IsMatch a => Parser a -> Parser a
inverse Parser Char
doubleQuote |*)) forall a. Parser a -> Parser a -> Parser a
<|>
           forall a b. Parser a -> Parser b -> Parser b
within  (Parser Char
quote forall a. Parser a -> Integer -> Parser [a]
<#> Integer
3)      (forall {b}. Monoid b => Parser b -> Parser b
multiline (forall a. IsMatch a => Parser a -> Parser a
inverse Parser Char
quote |*))       forall a. Parser a -> Parser a -> Parser a
<|>
           forall b. Parser b -> Parser b
withinDoubleQuotes         (forall a. IsMatch a => Parser a -> Parser a
inverse Parser Char
doubleQuote |*)             forall a. Parser a -> Parser a -> Parser a
<|>
           forall b. Parser b -> Parser b
withinQuotes               (forall a. IsMatch a => Parser a -> Parser a
inverse Parser Char
quote       |*)

    multiline :: Parser b -> Parser b
multiline Parser b
parser = forall a. Monoid a => [a] -> a
mconcat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (((Parser [Char]
blankLine |?) forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall b. Parser b -> Parser b
line Parser b
parser) |*)

    line :: Parser b -> Parser b
line Parser b
parser = forall a. IsMatch a => a -> Parser a
is [Char]
"\\" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Parser Char
whiteSpace |*) forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser b
parser


array :: Parser TomlExpression
array :: Parser TomlExpression
array = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Array"
  forall a b. (a -> b) -> a -> b
$ [TomlExpression] -> TomlExpression
TomlArray forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Parser a -> Parser [a]
listOf (forall a b. Parser a -> Parser b -> Parser b
maybeWithin Parser [Char]
spacing Parser TomlExpression
tomlExpr)


key :: Parser String
key :: Parser [Char]
key = Parser [Char]
keyParser forall a b.
(ToString a, ToString b) =>
Parser a -> Parser b -> Parser [Char]
->>- ((Parser Char
dot forall a b.
(ToString a, ToString b) =>
Parser a -> Parser b -> Parser [Char]
->>- Parser [Char]
keyParser) |*)
  where
    keyParser :: Parser [Char]
keyParser = forall a b. Parser a -> Parser b -> Parser b
maybeWithin Parser [Char]
spacesOrTabs forall a b. (a -> b) -> a -> b
$ Parser [Char]
freeText      forall a. Parser a -> Parser a -> Parser a
<|>
                forall b. Parser b -> Parser b
withinDoubleQuotes (forall a. IsMatch a => Parser a -> Parser a
inverse Parser Char
doubleQuote |*) forall a. Parser a -> Parser a -> Parser a
<|>
                forall b. Parser b -> Parser b
withinQuotes (forall a. IsMatch a => Parser a -> Parser a
inverse Parser Char
quote |*)

    freeText :: Parser [Char]
freeText = ((Parser Char
letter forall a. Parser a -> Parser a -> Parser a
<|> Parser Char
digit forall a. Parser a -> Parser a -> Parser a
<|> Parser Char
underscore forall a. Parser a -> Parser a -> Parser a
<|> Parser Char
dash) |+)


inlineTable :: Parser TomlExpression
inlineTable :: Parser TomlExpression
inlineTable = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Table"
  forall a b. (a -> b) -> a -> b
$ TableType -> Map [Char] TomlExpression -> TomlExpression
TomlTable TableType
Inline forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall b a c.
Ord b =>
Parser a -> Parser b -> Parser c -> Parser (Map b c)
mapOf Parser Char
equal Parser [Char]
key Parser TomlExpression
tomlExpr


topLevelTable :: Parser TomlExpression
topLevelTable :: Parser TomlExpression
topLevelTable = forall a. [Char] -> Parser a -> Parser a
withError [Char]
"Toml Table"
  forall a b. (a -> b) -> a -> b
$ TableType -> Map [Char] TomlExpression -> TomlExpression
TomlTable TableType
TopLevel forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b. Parser a -> Parser b -> Parser b
maybeWithin Parser [Char]
spacing Parser [([Char], TomlExpression)]
tables
  where
    tables :: Parser [([Char], TomlExpression)]
tables = do [([Char], TomlExpression)]
xs <- Parser [([Char], TomlExpression)]
keyValueSeqParser
                [([Char], TomlExpression)]
ys <- (Parser ([Char], TomlExpression)
tableParser |*)
                pure ([([Char], TomlExpression)]
ys forall a. Semigroup a => a -> a -> a
<> [([Char]
"", TableType -> Map [Char] TomlExpression -> TomlExpression
TomlTable TableType
Standard forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall a b. (a -> b) -> a -> b
$ [([Char], TomlExpression)]
xs)])

    tableParser :: Parser ([Char], TomlExpression)
tableParser = do [Char]
k <- forall b. Parser b -> Parser b
withinSquareBrackets Parser [Char]
key
                     TomlExpression
v <- forall a b. Parser a -> Parser b -> Parser b
maybeWithin Parser [Char]
spacing Parser TomlExpression
standardTable
                     pure ([Char]
k, TomlExpression
v)

    standardTable :: Parser TomlExpression
standardTable = TableType -> Map [Char] TomlExpression -> TomlExpression
TomlTable TableType
Standard forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser [([Char], TomlExpression)]
keyValueSeqParser


    keyValueSeqParser :: Parser [([Char], TomlExpression)]
keyValueSeqParser = do [([Char], TomlExpression)]
xs <- ((Parser ([Char], TomlExpression)
keyValueParser forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* (Parser [Char]
blankLine forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Parser [Char]
blankLines |?))) |*)
                           Maybe ([Char], TomlExpression)
x  <- (Parser ([Char], TomlExpression)
keyValueParser |?)
                           pure  ([([Char], TomlExpression)]
xs forall a. Semigroup a => a -> a -> a
<> forall a. Maybe a -> [a]
maybeToList Maybe ([Char], TomlExpression)
x)

    keyValueParser :: Parser ([Char], TomlExpression)
keyValueParser = do [Char]
k <- Parser [Char]
key
                        forall a b. Parser a -> Parser b -> Parser b
maybeWithin Parser [Char]
spacesOrTabs Parser Char
equal
                        TomlExpression
v <- Parser TomlExpression
tomlExpr
                        pure ([Char]
k, TomlExpression
v)



element :: Parser TomlExpression
element :: Parser TomlExpression
element = Parser TomlExpression
dateTime forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
date forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
time forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
float forall a. Parser a -> Parser a -> Parser a
<|>
          Parser TomlExpression
integer  forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
bool forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
nil  forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
string


container :: Parser TomlExpression
container :: Parser TomlExpression
container = Parser TomlExpression
array forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
inlineTable


comment :: Parser String
comment :: Parser [Char]
comment = Parser Char
hashTag forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (forall a. IsMatch a => Parser a -> Parser a
inverse Parser Char
newLine |+) forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser Char
newLine


tomlExpr :: Parser TomlExpression
tomlExpr :: Parser TomlExpression
tomlExpr = forall a b. Parser a -> Parser b -> Parser b
maybeWithin (((forall (f :: * -> *) a. Applicative f => a -> f a
pure forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Char
spaceOrTab) forall a. Parser a -> Parser a -> Parser a
<|> Parser [Char]
comment) |+) Parser TomlExpression
tomlValue
  where
    tomlValue :: Parser TomlExpression
tomlValue = Parser TomlExpression
element forall a. Parser a -> Parser a -> Parser a
<|> Parser TomlExpression
container