package toml

type tomlParser Peg {
    toml
}

TOML <- Expression (newline Expression)* newline? !. { _ = buffer }

Expression <- (
    <ws table ws comment? (wsnl keyval ws comment?)*> { p.SetTableString(begin, end) }
  / ws keyval ws comment?
  / ws comment?
  / ws
)

newline <- <[\r\n]+> { p.AddLineCount(end - begin) }

ws <- [ \t]*
wsnl <- (
    [ \t]
  / <[\r\n]> { p.AddLineCount(end - begin) }
)*

comment <- '#' <[\t -\0x10FFFF]*>

keyval <- key ws '=' ws val { p.AddKeyValue() }

key <- bareKey / quotedKey

bareKey <- <[0-9A-Za-z\-_]+> { p.SetKey(p.buffer, begin, end) }

quotedKey <- '"' <basicChar+> '"' { p.SetKey(p.buffer, begin-1, end+1) }

val <- (
    <datetime>    { p.SetTime(begin, end) }
  / <float>       { p.SetFloat64(begin, end) }
  / <integer>     { p.SetInt64(begin, end) }
  / <string>      { p.SetString(begin, end) }
  / <boolean>     { p.SetBool(begin, end) }
  / <array>       { p.SetArray(begin, end) }
  / inlineTable
)

table <- stdTable / arrayTable

stdTable <- '[' ws <tableKey> ws ']' { p.SetTable(p.buffer, begin, end) }

arrayTable <- '[[' ws <tableKey> ws ']]' { p.SetArrayTable(p.buffer, begin, end) }

inlineTable <- (
    '{' { p.StartInlineTable() }
    ws inlineTableKeyValues ws
    '}' { p.EndInlineTable() }
)

inlineTableKeyValues <- (keyval inlineTableValSep?)*

tableKey <- key (tableKeySep key)*

tableKeySep <- ws '.' ws

inlineTableValSep <- ws ',' ws

integer <- [\-+]? int
int <- [1-9] (digit / '_' digit)+ / digit

float <- integer (frac exp? / frac? exp)
frac <- '.' digit (digit / '_' digit)*
exp <- [eE] [\-+]? digit (digit / '_' digit)*

string <- (
    mlLiteralString
  / literalString
  / mlBasicString
  / basicString
)

basicString <- <'"' basicChar* '"'> { p.SetBasicString(p.buffer, begin, end) }

basicChar <- basicUnescaped / escaped
escaped <- escape ([btnfr"/\\] / 'u' hexQuad / 'U' hexQuad hexQuad)

basicUnescaped <- [ -!#-\[\]-\0x10FFFF]

escape <- '\\'

mlBasicString <- '"""' mlBasicBody '"""' { p.SetMultilineString() }

mlBasicBody <- (
    <basicChar / newline> { p.AddMultilineBasicBody(p.buffer, begin, end) }
  / escape newline wsnl
)*

literalString <- "'" <literalChar*> "'" { p.SetLiteralString(p.buffer, begin, end) }

literalChar <- [\t -&(-\0x10FFFF]

mlLiteralString <- "'''" <mlLiteralBody> "'''" { p.SetMultilineLiteralString(p.buffer, begin, end) }

mlLiteralBody <- (!"'''" (mlLiteralChar / newline))*

mlLiteralChar <- [\t -\0x10FFFF]

hexdigit <- [0-9A-Fa-f]
hexQuad <- hexdigit hexdigit hexdigit hexdigit

boolean <- 'true' / 'false'

dateFullYear <- digitQuad
dateMonth <- digitDual
dateMDay <- digitDual
timeHour <- digitDual
timeMinute <- digitDual
timeSecond <- digitDual
timeSecfrac <- '.' digit+
timeNumoffset <- [\-+] timeHour ':' timeMinute
timeOffset <- 'Z' / timeNumoffset
partialTime <- timeHour ':' timeMinute ':' timeSecond timeSecfrac?
fullDate <- dateFullYear '-' dateMonth '-' dateMDay
fullTime <- partialTime timeOffset
datetime <- (fullDate ('T' fullTime)?) / partialTime

digit <- [0-9]
digitDual <- digit digit
digitQuad <- digitDual digitDual

array <- (
    '[' { p.StartArray() }
    wsnl arrayValues? wsnl
    ']'
)

arrayValues <- (
    val { p.AddArrayVal() }
    (
        wsnl comment?
        wsnl arraySep
        wsnl comment?
        wsnl val { p.AddArrayVal() }
    )*
    wsnl arraySep?
    wsnl comment?
)

arraySep <- ','
