Update vendored toml. Adds support for inline tables

This commit is contained in:
Wim 2017-03-25 19:13:47 +01:00
parent 2f68519b3c
commit be15cc8a36
6 changed files with 224 additions and 85 deletions

View File

@ -30,3 +30,12 @@ enable=true
[[gateway.out]] [[gateway.out]]
account="mattermost.work" account="mattermost.work"
channel="off-topic" channel="off-topic"
#simpler config possible since v0.10.2
#[[gateway]]
#name="gateway2"
#enable=true
#inout = [
# { account="irc.freenode", channel="#testing", options={key="channelkey"}},
# { account="mattermost.work", channel="off-topic" },
#]

View File

@ -4,7 +4,7 @@ files via reflection. There is also support for delaying decoding with
the Primitive type, and querying the set of keys in a TOML document with the the Primitive type, and querying the set of keys in a TOML document with the
MetaData type. MetaData type.
The specification implemented: https://github.com/mojombo/toml The specification implemented: https://github.com/toml-lang/toml
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
whether a file is a valid TOML document. It can also be used to print the whether a file is a valid TOML document. It can also be used to print the

View File

@ -241,7 +241,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
func (enc *Encoder) eTable(key Key, rv reflect.Value) { func (enc *Encoder) eTable(key Key, rv reflect.Value) {
panicIfInvalidKey(key) panicIfInvalidKey(key)
if len(key) == 1 { if len(key) == 1 {
// Output an extra new line between top-level tables. // Output an extra newline between top-level tables.
// (The newline isn't written if nothing else has been written though.) // (The newline isn't written if nothing else has been written though.)
enc.newline() enc.newline()
} }

View File

@ -30,10 +30,13 @@ const (
itemArrayTableEnd itemArrayTableEnd
itemKeyStart itemKeyStart
itemCommentStart itemCommentStart
itemInlineTableStart
itemInlineTableEnd
) )
const ( const (
eof = 0 eof = 0
comma = ','
tableStart = '[' tableStart = '['
tableEnd = ']' tableEnd = ']'
arrayTableStart = '[' arrayTableStart = '['
@ -42,12 +45,13 @@ const (
keySep = '=' keySep = '='
arrayStart = '[' arrayStart = '['
arrayEnd = ']' arrayEnd = ']'
arrayValTerm = ','
commentStart = '#' commentStart = '#'
stringStart = '"' stringStart = '"'
stringEnd = '"' stringEnd = '"'
rawStringStart = '\'' rawStringStart = '\''
rawStringEnd = '\'' rawStringEnd = '\''
inlineTableStart = '{'
inlineTableEnd = '}'
) )
type stateFn func(lx *lexer) stateFn type stateFn func(lx *lexer) stateFn
@ -56,11 +60,18 @@ type lexer struct {
input string input string
start int start int
pos int pos int
width int
line int line int
state stateFn state stateFn
items chan item items chan item
// Allow for backing up up to three runes.
// This is necessary because TOML contains 3-rune tokens (""" and ''').
prevWidths [3]int
nprev int // how many of prevWidths are in use
// If we emit an eof, we can still back up, but it is not OK to call
// next again.
atEOF bool
// A stack of state functions used to maintain context. // A stack of state functions used to maintain context.
// The idea is to reuse parts of the state machine in various places. // The idea is to reuse parts of the state machine in various places.
// For example, values can appear at the top level or within arbitrarily // For example, values can appear at the top level or within arbitrarily
@ -88,7 +99,7 @@ func (lx *lexer) nextItem() item {
func lex(input string) *lexer { func lex(input string) *lexer {
lx := &lexer{ lx := &lexer{
input: input + "\n", input: input,
state: lexTop, state: lexTop,
line: 1, line: 1,
items: make(chan item, 10), items: make(chan item, 10),
@ -103,7 +114,7 @@ func (lx *lexer) push(state stateFn) {
func (lx *lexer) pop() stateFn { func (lx *lexer) pop() stateFn {
if len(lx.stack) == 0 { if len(lx.stack) == 0 {
return lx.errorf("BUG in lexer: no states to pop.") return lx.errorf("BUG in lexer: no states to pop")
} }
last := lx.stack[len(lx.stack)-1] last := lx.stack[len(lx.stack)-1]
lx.stack = lx.stack[0 : len(lx.stack)-1] lx.stack = lx.stack[0 : len(lx.stack)-1]
@ -125,16 +136,25 @@ func (lx *lexer) emitTrim(typ itemType) {
} }
func (lx *lexer) next() (r rune) { func (lx *lexer) next() (r rune) {
if lx.atEOF {
panic("next called after EOF")
}
if lx.pos >= len(lx.input) { if lx.pos >= len(lx.input) {
lx.width = 0 lx.atEOF = true
return eof return eof
} }
if lx.input[lx.pos] == '\n' { if lx.input[lx.pos] == '\n' {
lx.line++ lx.line++
} }
r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:]) lx.prevWidths[2] = lx.prevWidths[1]
lx.pos += lx.width lx.prevWidths[1] = lx.prevWidths[0]
if lx.nprev < 3 {
lx.nprev++
}
r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
lx.prevWidths[0] = w
lx.pos += w
return r return r
} }
@ -143,9 +163,20 @@ func (lx *lexer) ignore() {
lx.start = lx.pos lx.start = lx.pos
} }
// backup steps back one rune. Can be called only once per call of next. // backup steps back one rune. Can be called only twice between calls to next.
func (lx *lexer) backup() { func (lx *lexer) backup() {
lx.pos -= lx.width if lx.atEOF {
lx.atEOF = false
return
}
if lx.nprev < 1 {
panic("backed up too far")
}
w := lx.prevWidths[0]
lx.prevWidths[0] = lx.prevWidths[1]
lx.prevWidths[1] = lx.prevWidths[2]
lx.nprev--
lx.pos -= w
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' { if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
lx.line-- lx.line--
} }
@ -182,7 +213,7 @@ func (lx *lexer) skip(pred func(rune) bool) {
// errorf stops all lexing by emitting an error and returning `nil`. // errorf stops all lexing by emitting an error and returning `nil`.
// Note that any value that is a character is escaped if it's a special // Note that any value that is a character is escaped if it's a special
// character (new lines, tabs, etc.). // character (newlines, tabs, etc.).
func (lx *lexer) errorf(format string, values ...interface{}) stateFn { func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
lx.items <- item{ lx.items <- item{
itemError, itemError,
@ -198,7 +229,6 @@ func lexTop(lx *lexer) stateFn {
if isWhitespace(r) || isNL(r) { if isWhitespace(r) || isNL(r) {
return lexSkip(lx, lexTop) return lexSkip(lx, lexTop)
} }
switch r { switch r {
case commentStart: case commentStart:
lx.push(lexTop) lx.push(lexTop)
@ -207,7 +237,7 @@ func lexTop(lx *lexer) stateFn {
return lexTableStart return lexTableStart
case eof: case eof:
if lx.pos > lx.start { if lx.pos > lx.start {
return lx.errorf("Unexpected EOF.") return lx.errorf("unexpected EOF")
} }
lx.emit(itemEOF) lx.emit(itemEOF)
return nil return nil
@ -222,12 +252,12 @@ func lexTop(lx *lexer) stateFn {
// lexTopEnd is entered whenever a top-level item has been consumed. (A value // lexTopEnd is entered whenever a top-level item has been consumed. (A value
// or a table.) It must see only whitespace, and will turn back to lexTop // or a table.) It must see only whitespace, and will turn back to lexTop
// upon a new line. If it sees EOF, it will quit the lexer successfully. // upon a newline. If it sees EOF, it will quit the lexer successfully.
func lexTopEnd(lx *lexer) stateFn { func lexTopEnd(lx *lexer) stateFn {
r := lx.next() r := lx.next()
switch { switch {
case r == commentStart: case r == commentStart:
// a comment will read to a new line for us. // a comment will read to a newline for us.
lx.push(lexTop) lx.push(lexTop)
return lexCommentStart return lexCommentStart
case isWhitespace(r): case isWhitespace(r):
@ -236,11 +266,11 @@ func lexTopEnd(lx *lexer) stateFn {
lx.ignore() lx.ignore()
return lexTop return lexTop
case r == eof: case r == eof:
lx.ignore() lx.emit(itemEOF)
return lexTop return nil
} }
return lx.errorf("Expected a top-level item to end with a new line, "+ return lx.errorf("expected a top-level item to end with a newline, "+
"comment or EOF, but got %q instead.", r) "comment, or EOF, but got %q instead", r)
} }
// lexTable lexes the beginning of a table. Namely, it makes sure that // lexTable lexes the beginning of a table. Namely, it makes sure that
@ -267,8 +297,8 @@ func lexTableEnd(lx *lexer) stateFn {
func lexArrayTableEnd(lx *lexer) stateFn { func lexArrayTableEnd(lx *lexer) stateFn {
if r := lx.next(); r != arrayTableEnd { if r := lx.next(); r != arrayTableEnd {
return lx.errorf("Expected end of table array name delimiter %q, "+ return lx.errorf("expected end of table array name delimiter %q, "+
"but got %q instead.", arrayTableEnd, r) "but got %q instead", arrayTableEnd, r)
} }
lx.emit(itemArrayTableEnd) lx.emit(itemArrayTableEnd)
return lexTopEnd return lexTopEnd
@ -278,11 +308,11 @@ func lexTableNameStart(lx *lexer) stateFn {
lx.skip(isWhitespace) lx.skip(isWhitespace)
switch r := lx.peek(); { switch r := lx.peek(); {
case r == tableEnd || r == eof: case r == tableEnd || r == eof:
return lx.errorf("Unexpected end of table name. (Table names cannot " + return lx.errorf("unexpected end of table name " +
"be empty.)") "(table names cannot be empty)")
case r == tableSep: case r == tableSep:
return lx.errorf("Unexpected table separator. (Table names cannot " + return lx.errorf("unexpected table separator " +
"be empty.)") "(table names cannot be empty)")
case r == stringStart || r == rawStringStart: case r == stringStart || r == rawStringStart:
lx.ignore() lx.ignore()
lx.push(lexTableNameEnd) lx.push(lexTableNameEnd)
@ -317,8 +347,8 @@ func lexTableNameEnd(lx *lexer) stateFn {
case r == tableEnd: case r == tableEnd:
return lx.pop() return lx.pop()
default: default:
return lx.errorf("Expected '.' or ']' to end table name, but got %q "+ return lx.errorf("expected '.' or ']' to end table name, "+
"instead.", r) "but got %q instead", r)
} }
} }
@ -328,7 +358,7 @@ func lexKeyStart(lx *lexer) stateFn {
r := lx.peek() r := lx.peek()
switch { switch {
case r == keySep: case r == keySep:
return lx.errorf("Unexpected key separator %q.", keySep) return lx.errorf("unexpected key separator %q", keySep)
case isWhitespace(r) || isNL(r): case isWhitespace(r) || isNL(r):
lx.next() lx.next()
return lexSkip(lx, lexKeyStart) return lexSkip(lx, lexKeyStart)
@ -359,7 +389,7 @@ func lexBareKey(lx *lexer) stateFn {
lx.emit(itemText) lx.emit(itemText)
return lexKeyEnd return lexKeyEnd
default: default:
return lx.errorf("Bare keys cannot contain %q.", r) return lx.errorf("bare keys cannot contain %q", r)
} }
} }
@ -372,7 +402,7 @@ func lexKeyEnd(lx *lexer) stateFn {
case isWhitespace(r): case isWhitespace(r):
return lexSkip(lx, lexKeyEnd) return lexSkip(lx, lexKeyEnd)
default: default:
return lx.errorf("Expected key separator %q, but got %q instead.", return lx.errorf("expected key separator %q, but got %q instead",
keySep, r) keySep, r)
} }
} }
@ -381,9 +411,8 @@ func lexKeyEnd(lx *lexer) stateFn {
// lexValue will ignore whitespace. // lexValue will ignore whitespace.
// After a value is lexed, the last state on the next is popped and returned. // After a value is lexed, the last state on the next is popped and returned.
func lexValue(lx *lexer) stateFn { func lexValue(lx *lexer) stateFn {
// We allow whitespace to precede a value, but NOT new lines. // We allow whitespace to precede a value, but NOT newlines.
// In array syntax, the array states are responsible for ignoring new // In array syntax, the array states are responsible for ignoring newlines.
// lines.
r := lx.next() r := lx.next()
switch { switch {
case isWhitespace(r): case isWhitespace(r):
@ -397,6 +426,10 @@ func lexValue(lx *lexer) stateFn {
lx.ignore() lx.ignore()
lx.emit(itemArray) lx.emit(itemArray)
return lexArrayValue return lexArrayValue
case inlineTableStart:
lx.ignore()
lx.emit(itemInlineTableStart)
return lexInlineTableValue
case stringStart: case stringStart:
if lx.accept(stringStart) { if lx.accept(stringStart) {
if lx.accept(stringStart) { if lx.accept(stringStart) {
@ -420,7 +453,7 @@ func lexValue(lx *lexer) stateFn {
case '+', '-': case '+', '-':
return lexNumberStart return lexNumberStart
case '.': // special error case, be kind to users case '.': // special error case, be kind to users
return lx.errorf("Floats must start with a digit, not '.'.") return lx.errorf("floats must start with a digit, not '.'")
} }
if unicode.IsLetter(r) { if unicode.IsLetter(r) {
// Be permissive here; lexBool will give a nice error if the // Be permissive here; lexBool will give a nice error if the
@ -430,11 +463,11 @@ func lexValue(lx *lexer) stateFn {
lx.backup() lx.backup()
return lexBool return lexBool
} }
return lx.errorf("Expected value but found %q instead.", r) return lx.errorf("expected value but found %q instead", r)
} }
// lexArrayValue consumes one value in an array. It assumes that '[' or ',' // lexArrayValue consumes one value in an array. It assumes that '[' or ','
// have already been consumed. All whitespace and new lines are ignored. // have already been consumed. All whitespace and newlines are ignored.
func lexArrayValue(lx *lexer) stateFn { func lexArrayValue(lx *lexer) stateFn {
r := lx.next() r := lx.next()
switch { switch {
@ -443,10 +476,11 @@ func lexArrayValue(lx *lexer) stateFn {
case r == commentStart: case r == commentStart:
lx.push(lexArrayValue) lx.push(lexArrayValue)
return lexCommentStart return lexCommentStart
case r == arrayValTerm: case r == comma:
return lx.errorf("Unexpected array value terminator %q.", return lx.errorf("unexpected comma")
arrayValTerm)
case r == arrayEnd: case r == arrayEnd:
// NOTE(caleb): The spec isn't clear about whether you can have
// a trailing comma or not, so we'll allow it.
return lexArrayEnd return lexArrayEnd
} }
@ -455,8 +489,9 @@ func lexArrayValue(lx *lexer) stateFn {
return lexValue return lexValue
} }
// lexArrayValueEnd consumes the cruft between values of an array. Namely, // lexArrayValueEnd consumes everything between the end of an array value and
// it ignores whitespace and expects either a ',' or a ']'. // the next value (or the end of the array): it ignores whitespace and newlines
// and expects either a ',' or a ']'.
func lexArrayValueEnd(lx *lexer) stateFn { func lexArrayValueEnd(lx *lexer) stateFn {
r := lx.next() r := lx.next()
switch { switch {
@ -465,31 +500,88 @@ func lexArrayValueEnd(lx *lexer) stateFn {
case r == commentStart: case r == commentStart:
lx.push(lexArrayValueEnd) lx.push(lexArrayValueEnd)
return lexCommentStart return lexCommentStart
case r == arrayValTerm: case r == comma:
lx.ignore() lx.ignore()
return lexArrayValue // move on to the next value return lexArrayValue // move on to the next value
case r == arrayEnd: case r == arrayEnd:
return lexArrayEnd return lexArrayEnd
} }
return lx.errorf("Expected an array value terminator %q or an array "+ return lx.errorf(
"terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r) "expected a comma or array terminator %q, but got %q instead",
arrayEnd, r,
)
} }
// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has // lexArrayEnd finishes the lexing of an array.
// just been consumed. // It assumes that a ']' has just been consumed.
func lexArrayEnd(lx *lexer) stateFn { func lexArrayEnd(lx *lexer) stateFn {
lx.ignore() lx.ignore()
lx.emit(itemArrayEnd) lx.emit(itemArrayEnd)
return lx.pop() return lx.pop()
} }
// lexInlineTableValue consumes one key/value pair in an inline table.
// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
func lexInlineTableValue(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValue)
case isNL(r):
return lx.errorf("newlines not allowed within inline tables")
case r == commentStart:
lx.push(lexInlineTableValue)
return lexCommentStart
case r == comma:
return lx.errorf("unexpected comma")
case r == inlineTableEnd:
return lexInlineTableEnd
}
lx.backup()
lx.push(lexInlineTableValueEnd)
return lexKeyStart
}
// lexInlineTableValueEnd consumes everything between the end of an inline table
// key/value pair and the next pair (or the end of the table):
// it ignores whitespace and expects either a ',' or a '}'.
func lexInlineTableValueEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValueEnd)
case isNL(r):
return lx.errorf("newlines not allowed within inline tables")
case r == commentStart:
lx.push(lexInlineTableValueEnd)
return lexCommentStart
case r == comma:
lx.ignore()
return lexInlineTableValue
case r == inlineTableEnd:
return lexInlineTableEnd
}
return lx.errorf("expected a comma or an inline table terminator %q, "+
"but got %q instead", inlineTableEnd, r)
}
// lexInlineTableEnd finishes the lexing of an inline table.
// It assumes that a '}' has just been consumed.
func lexInlineTableEnd(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemInlineTableEnd)
return lx.pop()
}
// lexString consumes the inner contents of a string. It assumes that the // lexString consumes the inner contents of a string. It assumes that the
// beginning '"' has already been consumed and ignored. // beginning '"' has already been consumed and ignored.
func lexString(lx *lexer) stateFn { func lexString(lx *lexer) stateFn {
r := lx.next() r := lx.next()
switch { switch {
case r == eof:
return lx.errorf("unexpected EOF")
case isNL(r): case isNL(r):
return lx.errorf("Strings cannot contain new lines.") return lx.errorf("strings cannot contain newlines")
case r == '\\': case r == '\\':
lx.push(lexString) lx.push(lexString)
return lexStringEscape return lexStringEscape
@ -506,11 +598,12 @@ func lexString(lx *lexer) stateFn {
// lexMultilineString consumes the inner contents of a string. It assumes that // lexMultilineString consumes the inner contents of a string. It assumes that
// the beginning '"""' has already been consumed and ignored. // the beginning '"""' has already been consumed and ignored.
func lexMultilineString(lx *lexer) stateFn { func lexMultilineString(lx *lexer) stateFn {
r := lx.next() switch lx.next() {
switch { case eof:
case r == '\\': return lx.errorf("unexpected EOF")
case '\\':
return lexMultilineStringEscape return lexMultilineStringEscape
case r == stringEnd: case stringEnd:
if lx.accept(stringEnd) { if lx.accept(stringEnd) {
if lx.accept(stringEnd) { if lx.accept(stringEnd) {
lx.backup() lx.backup()
@ -534,8 +627,10 @@ func lexMultilineString(lx *lexer) stateFn {
func lexRawString(lx *lexer) stateFn { func lexRawString(lx *lexer) stateFn {
r := lx.next() r := lx.next()
switch { switch {
case r == eof:
return lx.errorf("unexpected EOF")
case isNL(r): case isNL(r):
return lx.errorf("Strings cannot contain new lines.") return lx.errorf("strings cannot contain newlines")
case r == rawStringEnd: case r == rawStringEnd:
lx.backup() lx.backup()
lx.emit(itemRawString) lx.emit(itemRawString)
@ -547,12 +642,13 @@ func lexRawString(lx *lexer) stateFn {
} }
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such // lexMultilineRawString consumes a raw string. Nothing can be escaped in such
// a string. It assumes that the beginning "'" has already been consumed and // a string. It assumes that the beginning "'''" has already been consumed and
// ignored. // ignored.
func lexMultilineRawString(lx *lexer) stateFn { func lexMultilineRawString(lx *lexer) stateFn {
r := lx.next() switch lx.next() {
switch { case eof:
case r == rawStringEnd: return lx.errorf("unexpected EOF")
case rawStringEnd:
if lx.accept(rawStringEnd) { if lx.accept(rawStringEnd) {
if lx.accept(rawStringEnd) { if lx.accept(rawStringEnd) {
lx.backup() lx.backup()
@ -605,10 +701,9 @@ func lexStringEscape(lx *lexer) stateFn {
case 'U': case 'U':
return lexLongUnicodeEscape return lexLongUnicodeEscape
} }
return lx.errorf("Invalid escape character %q. Only the following "+ return lx.errorf("invalid escape character %q; only the following "+
"escape characters are allowed: "+ "escape characters are allowed: "+
"\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+ `\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
"\\uXXXX and \\UXXXXXXXX.", r)
} }
func lexShortUnicodeEscape(lx *lexer) stateFn { func lexShortUnicodeEscape(lx *lexer) stateFn {
@ -616,8 +711,8 @@ func lexShortUnicodeEscape(lx *lexer) stateFn {
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
r = lx.next() r = lx.next()
if !isHexadecimal(r) { if !isHexadecimal(r) {
return lx.errorf("Expected four hexadecimal digits after '\\u', "+ return lx.errorf(`expected four hexadecimal digits after '\u', `+
"but got '%s' instead.", lx.current()) "but got %q instead", lx.current())
} }
} }
return lx.pop() return lx.pop()
@ -628,8 +723,8 @@ func lexLongUnicodeEscape(lx *lexer) stateFn {
for i := 0; i < 8; i++ { for i := 0; i < 8; i++ {
r = lx.next() r = lx.next()
if !isHexadecimal(r) { if !isHexadecimal(r) {
return lx.errorf("Expected eight hexadecimal digits after '\\U', "+ return lx.errorf(`expected eight hexadecimal digits after '\U', `+
"but got '%s' instead.", lx.current()) "but got %q instead", lx.current())
} }
} }
return lx.pop() return lx.pop()
@ -647,9 +742,9 @@ func lexNumberOrDateStart(lx *lexer) stateFn {
case 'e', 'E': case 'e', 'E':
return lexFloat return lexFloat
case '.': case '.':
return lx.errorf("Floats must start with a digit, not '.'.") return lx.errorf("floats must start with a digit, not '.'")
} }
return lx.errorf("Expected a digit but got %q.", r) return lx.errorf("expected a digit but got %q", r)
} }
// lexNumberOrDate consumes either an integer, float or datetime. // lexNumberOrDate consumes either an integer, float or datetime.
@ -697,9 +792,9 @@ func lexNumberStart(lx *lexer) stateFn {
r := lx.next() r := lx.next()
if !isDigit(r) { if !isDigit(r) {
if r == '.' { if r == '.' {
return lx.errorf("Floats must start with a digit, not '.'.") return lx.errorf("floats must start with a digit, not '.'")
} }
return lx.errorf("Expected a digit but got %q.", r) return lx.errorf("expected a digit but got %q", r)
} }
return lexNumber return lexNumber
} }
@ -757,7 +852,7 @@ func lexBool(lx *lexer) stateFn {
lx.emit(itemBool) lx.emit(itemBool)
return lx.pop() return lx.pop()
} }
return lx.errorf("Expected value but found %q instead.", s) return lx.errorf("expected value but found %q instead", s)
} }
// lexCommentStart begins the lexing of a comment. It will emit // lexCommentStart begins the lexing of a comment. It will emit
@ -769,7 +864,7 @@ func lexCommentStart(lx *lexer) stateFn {
} }
// lexComment lexes an entire comment. It assumes that '#' has been consumed. // lexComment lexes an entire comment. It assumes that '#' has been consumed.
// It will consume *up to* the first new line character, and pass control // It will consume *up to* the first newline character, and pass control
// back to the last state on the stack. // back to the last state on the stack.
func lexComment(lx *lexer) stateFn { func lexComment(lx *lexer) stateFn {
r := lx.peek() r := lx.peek()

View File

@ -269,6 +269,41 @@ func (p *parser) value(it item) (interface{}, tomlType) {
types = append(types, typ) types = append(types, typ)
} }
return array, p.typeOfArray(types) return array, p.typeOfArray(types)
case itemInlineTableStart:
var (
hash = make(map[string]interface{})
outerContext = p.context
outerKey = p.currentKey
)
p.context = append(p.context, p.currentKey)
p.currentKey = ""
for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
if it.typ != itemKeyStart {
p.bug("Expected key start but instead found %q, around line %d",
it.val, p.approxLine)
}
if it.typ == itemCommentStart {
p.expect(itemText)
continue
}
// retrieve key
k := p.next()
p.approxLine = k.line
kname := p.keyString(k)
// retrieve value
p.currentKey = kname
val, typ := p.value(p.next())
// make sure we keep metadata up to date
p.setType(kname, typ)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
hash[kname] = val
}
p.context = outerContext
p.currentKey = outerKey
return hash, tomlHash
} }
p.bug("Unexpected value type: %s", it.typ) p.bug("Unexpected value type: %s", it.typ)
panic("unreachable") panic("unreachable")

2
vendor/manifest vendored
View File

@ -5,7 +5,7 @@
"importpath": "github.com/BurntSushi/toml", "importpath": "github.com/BurntSushi/toml",
"repository": "https://github.com/BurntSushi/toml", "repository": "https://github.com/BurntSushi/toml",
"vcs": "git", "vcs": "git",
"revision": "99064174e013895bbd9b025c31100bd1d9b590ca", "revision": "d94612f9fc140360834f9742158c70b5c5b5535b",
"branch": "master", "branch": "master",
"notests": true "notests": true
}, },