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(whitespaceChar) tab = a.Tab space = a.Space whitespaceChar = tab.Or(space) newline = a.Newline whitespace = 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(whitespace)) // 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(whitespaceChar.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() { }