diff --git a/conf/lex.go b/conf/lex.go index 5566ef92..5334bb39 100644 --- a/conf/lex.go +++ b/conf/lex.go @@ -248,7 +248,7 @@ func lexTopValueEnd(lx *lexer) stateFn { } // lexKeyStart consumes a key name up until the first non-whitespace character. -// lexKeyStart will ignore whitespace. +// lexKeyStart will ignore whitespace. It will also eat enclosing quotes. func lexKeyStart(lx *lexer) stateFn { r := lx.peek() switch { @@ -257,12 +257,27 @@ func lexKeyStart(lx *lexer) stateFn { case isWhitespace(r) || isNL(r): lx.next() return lexSkip(lx, lexKeyStart) + case r == sqStringStart || r == dqStringStart: + lx.next() + return lexSkip(lx, lexQuotedKey) } lx.ignore() lx.next() return lexKey } +// lexQuotedKey consumes the text of a key between quotes. +func lexQuotedKey(lx *lexer) stateFn { + r := lx.peek() + if r == sqStringEnd || r == dqStringEnd { + lx.emit(itemKey) + lx.next() + return lexSkip(lx, lexKeyEnd) + } + lx.next() + return lexQuotedKey +} + // lexKey consumes the text of a key. Assumes that the first character (which // is not whitespace) has already been consumed. func lexKey(lx *lexer) stateFn { diff --git a/conf/lex_test.go b/conf/lex_test.go index 13ee8372..0a891fba 100644 --- a/conf/lex_test.go +++ b/conf/lex_test.go @@ -246,6 +246,32 @@ func TestNestedMaps(t *testing.T) { expect(t, lx, expectedItems) } +func TestQuotedKeys(t *testing.T) { + expectedItems := []item{ + {itemKey, "foo", 1}, + {itemInteger, "123", 1}, + {itemEOF, "", 1}, + } + lx := lex("foo : 123") + expect(t, lx, expectedItems) + lx = lex("'foo' : 123") + expect(t, lx, expectedItems) + lx = lex("\"foo\" : 123") + expect(t, lx, expectedItems) +} + +func TestQuotedKeysWithSpace(t *testing.T) { + expectedItems := []item{ + {itemKey, " foo", 1}, + {itemInteger, "123", 1}, + {itemEOF, "", 1}, + } + lx := lex("' foo' : 123") + expect(t, lx, expectedItems) + lx = lex("\" foo\" : 123") + expect(t, lx, expectedItems) +} + func TestColonKeySep(t *testing.T) { expectedItems := []item{ {itemKey, "foo", 1},