222 lines
6.7 KiB
Go
222 lines
6.7 KiB
Go
package parse2
|
|
|
|
import "git.makaay.nl/mauricem/go-parsekit/tokenize"
|
|
|
|
var (
|
|
c, a, m, tok = tokenize.C, tokenize.A, tokenize.M, tokenize.T
|
|
|
|
// Overall Structure
|
|
|
|
toml = c.Seq(expression, c.ZeroOrMore(newline.Then(expression)))
|
|
|
|
expression = c.Any(
|
|
c.Seq(ws, comment.Optional()),
|
|
c.Seq(ws, keyval, ws, comment.Optional()),
|
|
c.Seq(ws, table, ws, comment.Optional()))
|
|
|
|
// ABNF definitions
|
|
|
|
alpha = a.Letter
|
|
digit = a.Digit
|
|
|
|
// Whitespace, Newline
|
|
|
|
ws = c.ZeroOrMore(wschar)
|
|
tab = a.Tab
|
|
space = a.Space
|
|
wschar = tab.Or(space)
|
|
|
|
newline = a.Newline
|
|
|
|
wsOrNewline = ws.Or(newline)
|
|
|
|
// Comment
|
|
|
|
comment = commentStartSymbol.Then(c.ZeroOrMore(nonEOL))
|
|
|
|
commentStartSymbol = a.Hash
|
|
nonEOL = c.Any(a.Rune(0x09), printableASCII, nonASCII)
|
|
printableASCII = a.RuneRange(0x20, 0x7E)
|
|
nonASCII = a.RuneRange(0x80, 0xD7FF).Or(a.RuneRange(0xE000, 0x10FFFF))
|
|
|
|
// Key-Value Pairs
|
|
|
|
keyval = c.Seq(key, keyvalSep, val)
|
|
|
|
key = simpleKey.Or(dottedKey)
|
|
simpleKey = quotedKey.Or(unquotedKey)
|
|
|
|
unquotedKey = c.OneOrMore(c.Any(alpha, digit, minus, underscore))
|
|
quotedKey = basicString.Or(literalString)
|
|
dottedKey = c.Seq(simpleKey, c.OneOrMore(dotSep.Then(simpleKey)))
|
|
|
|
dotSep = c.Seq(ws, a.Dot, ws)
|
|
keyvalSep = c.Seq(ws, a.Equal, ws)
|
|
|
|
val = c.Any(string, boolean, array, inlineTable, dateTime, float, integer)
|
|
|
|
// String
|
|
|
|
string = c.Any(mlBasicString, basicString, mlLiteralString, literalString)
|
|
|
|
// Basic String
|
|
|
|
basicString = c.Seq(quotationMark, c.ZeroOrMore(basicChar), quotationMark)
|
|
|
|
quotationMark = a.DoubleQuote
|
|
|
|
basicChar = escaped.Or(basicUnescaped)
|
|
basicUnescaped = c.Any(printableASCII.Except(quotationMark.Or(escape)), nonASCII)
|
|
escaped = escape.Then(escapeSeqChar)
|
|
|
|
escape = a.Backslash
|
|
escapeSeqChar = c.Any(
|
|
a.Runes('"', '\\', 'b', 'f', 'n', 'r', 't'),
|
|
a.Rune('u').Then(a.HexDigit.Times(4)),
|
|
a.Rune('U').Then(a.HexDigit.Times(8)))
|
|
|
|
// Multiline Basic String
|
|
|
|
mlBasicString = c.Seq(mlBasicStringDelim, mlBasicBody, mlBasicStringDelim)
|
|
|
|
mlBasicStringDelim = quotationMark.Times(3)
|
|
|
|
mlBasicBody = c.ZeroOrMore(c.Any(mlBasicChar, newline, mlBasicBodyConcat))
|
|
mlBasicChar = mlBasicUnescaped.Or(escaped)
|
|
mlBasicUnescaped = c.Any(printableASCII.Except(a.Backslash), nonASCII)
|
|
mlBasicBodyConcat = c.Seq(escape, ws, newline, c.ZeroOrMore(wsOrNewline))
|
|
|
|
// Literal String
|
|
|
|
literalString = c.Seq(apostrophe, c.ZeroOrMore(literalChar), apostrophe)
|
|
|
|
apostrophe = a.SingleQuote
|
|
|
|
literalChar = c.Any(a.Tab, printableASCII.Except(apostrophe), nonASCII)
|
|
|
|
// Multiline Literal String
|
|
|
|
mlLiteralString = c.Seq(mlLiteralStringDelim, mlLiteralBody, mlLiteralStringDelim)
|
|
|
|
mlLiteralStringDelim = apostrophe.Times(3)
|
|
|
|
mlLiteralBody = c.ZeroOrMore(mlLiteralChar.Or(newline))
|
|
mlLiteralChar = c.Any(a.Tab, printableASCII, nonASCII)
|
|
|
|
// Integer
|
|
|
|
integer = c.Any(decInt, hexInt, octInt, binInt)
|
|
|
|
minus = a.Minus
|
|
plus = a.Plus
|
|
underscore = a.Underscore
|
|
|
|
decInt = c.Optional(plus.Or(minus)).Then(unsignedDecInt)
|
|
unsignedDecInt = c.Any(digit, digit1to9.Then(c.OneOrMore(intDigitOrUnderscoreIntDigit)))
|
|
digit1to9 = a.DigitNotZero
|
|
intDigitOrUnderscoreIntDigit = c.Any(digit, underscore.Then(digit))
|
|
|
|
hexInt = c.Seq(hexPrefix, hexDigit, c.ZeroOrMore(hexDigitOrUnderscoreHexDigit))
|
|
hexPrefix = a.Zero.Then(a.Rune('x'))
|
|
hexDigit = a.HexDigit
|
|
hexDigitOrUnderscoreHexDigit = c.Any(hexDigit, underscore.Then(hexDigit))
|
|
|
|
octInt = c.Seq(octPrefix, digit0to7, c.ZeroOrMore(octDigitOrUnderscoreOctDigit))
|
|
octPrefix = a.Zero.Then(a.Rune('o'))
|
|
digit0to7 = a.RuneRange('0', '7')
|
|
octDigitOrUnderscoreOctDigit = c.Any(digit0to7, underscore.Then(digit0to7))
|
|
|
|
binInt = c.Seq(binPrefix, digit0to1, c.ZeroOrMore(binDigitOrUnderscoreBinDigit))
|
|
binPrefix = a.Zero.Then(a.Rune('b'))
|
|
digit0to1 = a.Runes('0', '1')
|
|
binDigitOrUnderscoreBinDigit = c.Any(digit0to1, underscore.Then(digit0to1))
|
|
|
|
// Float
|
|
|
|
float = standardFloat.Or(specialFloat)
|
|
|
|
standardFloat = c.Seq(floatIntPart, exp.Or(frac.Then(c.Optional(exp))))
|
|
floatIntPart = decInt
|
|
exp = a.StrNoCase("e").Then(floatIntPart)
|
|
frac = c.Seq(decimalPoint, zeroPrefixableInt)
|
|
decimalPoint = a.Dot
|
|
zeroPrefixableInt = c.Seq(digit, c.ZeroOrMore(intDigitOrUnderscoreIntDigit))
|
|
|
|
specialFloat = c.Optional(plus.Or(minus)).Then(inf.Or(nan))
|
|
inf = a.Str("inf")
|
|
nan = a.Str("nan")
|
|
|
|
// Boolean
|
|
|
|
boolean = boolTrue.Or(boolFalse)
|
|
|
|
boolTrue = a.Str("true")
|
|
boolFalse = a.Str("false")
|
|
|
|
// Date and time (as defined in RFC 3339)
|
|
|
|
dateTime = c.Any(offsetDateTime, localDateTime, localDate, localTime)
|
|
|
|
offsetDateTime = c.Seq(fullDate, timeDelim, fullTime)
|
|
localDateTime = c.Seq(fullDate, timeDelim, partialTime)
|
|
localDate = fullDate
|
|
localTime = partialTime
|
|
|
|
dateFullYear = digit.Times(4)
|
|
dateMonth = digit.Times(2)
|
|
dateMday = digit.Times(2)
|
|
timeDelim = a.Runes('T', 't', ' ')
|
|
timeHour = digit.Times(2)
|
|
timeMinute = digit.Times(2)
|
|
timeSecond = digit.Times(2)
|
|
timeSecfrac = a.Dot.Then(c.OneOrMore(digit))
|
|
timeNumOffset = c.Seq(plus.Or(minus), timeHour, a.Colon, timeMinute)
|
|
timeOffset = c.Any(a.Runes('Z', 'z'), timeNumOffset)
|
|
partialTime = c.Seq(timeHour, a.Colon, timeMinute, a.Colon, timeSecond, timeSecfrac.Optional())
|
|
fullTime = c.Seq(partialTime, timeOffset)
|
|
fullDate = c.Seq(dateFullYear, minus, dateMonth, minus, dateMday)
|
|
|
|
// Array
|
|
|
|
array = c.Seq(arrayOpen, arrayvalues.Optional(), wsCommentNewline, arrayClose)
|
|
|
|
arrayOpen = a.SquareOpen
|
|
arrayClose = a.SquareClose
|
|
arrayvalues = c.Seq(arrayValue, c.ZeroOrMore(c.Seq(arraySep, arrayValue)), arraySep.Optional())
|
|
arraySep = ws.Then(a.Comma)
|
|
arrayValue = wsCommentNewline.Then(val)
|
|
wsCommentNewline = c.ZeroOrMore(wschar.Or(comment.Optional().Then(newline)))
|
|
|
|
// Table
|
|
|
|
table = stdTable.Or(arrayTable)
|
|
|
|
// Standard Table
|
|
|
|
stdTable = c.Seq(stdTableOpen, key, stdTableClose)
|
|
|
|
stdTableOpen = a.SquareOpen.Then(ws)
|
|
stdTableClose = ws.Then(a.SquareClose)
|
|
|
|
// Inline Table
|
|
|
|
inlineTable = c.Seq(inlineTableOpen, inlineTableKeyvals, inlineTableClose)
|
|
|
|
inlineTableOpen = a.CurlyOpen.Then(ws)
|
|
inlineTableClose = ws.Then(a.CurlyClose)
|
|
inlineTableKeyvals = c.Seq(inlineTableKeyval, c.ZeroOrMore(c.Seq(inlineTableSep, inlineTableKeyval)))
|
|
inlineTableKeyval = c.Seq(key, keyvalSep, val)
|
|
inlineTableSep = c.Seq(ws, a.Comma, ws)
|
|
|
|
// Array Table
|
|
|
|
arrayTable = c.Seq(arrayTableOpen, key, arrayTableClose)
|
|
|
|
arrayTableOpen = a.SquareOpen.Times(2).Then(ws)
|
|
arrayTableClose = ws.Then(a.SquareClose.Times(2))
|
|
)
|
|
|
|
func init() {
|
|
|
|
}
|