Skip to content

Commit

Permalink
Fix key parsing in line tables (pelletier#311)
Browse files Browse the repository at this point in the history
A bug was reported that indicated that inline tables did not fully support bare keys:
$ echo 'foo = { -bar => "buz"}' | ./tomljson
(1, 9): unexpected token type in inline table: Error

$ echo 'foo = { "whatever" = "buz"}' | ./tomljson
(1, 10): unexpected token type in inline table: String

echo 'foo = { _no = "buz"}' | ./tomljson
(1, 9): unexpected token type in inline table: Error

This change makes a couple of tweaks to to allow for all key variants in inline tables

Fixes: pelletier#282
  • Loading branch information
jonathanlloyd authored and pelletier committed Oct 21, 2019
1 parent e87c92d commit bef0f57
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 7 deletions.
4 changes: 2 additions & 2 deletions lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,13 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn {
l.next()
l.emit(tokenLeftCurlyBrace)
return l.lexRvalue
return l.lexVoid
}

func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
l.next()
l.emit(tokenRightCurlyBrace)
return l.lexRvalue
return l.lexVoid
}

func (l *tomlLexer) lexDate() tomlLexStateFn {
Expand Down
52 changes: 52 additions & 0 deletions lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,58 @@ func TestLexUnknownRvalue(t *testing.T) {
})
}

func TestLexInlineTableBareKey(t *testing.T) {
testFlow(t, `foo = { bar = "baz" }`, []token{
{Position{1, 1}, tokenKey, "foo"},
{Position{1, 5}, tokenEqual, "="},
{Position{1, 7}, tokenLeftCurlyBrace, "{"},
{Position{1, 9}, tokenKey, "bar"},
{Position{1, 13}, tokenEqual, "="},
{Position{1, 16}, tokenString, "baz"},
{Position{1, 21}, tokenRightCurlyBrace, "}"},
{Position{1, 22}, tokenEOF, ""},
})
}

func TestLexInlineTableBareKeyDash(t *testing.T) {
testFlow(t, `foo = { -bar = "baz" }`, []token{
{Position{1, 1}, tokenKey, "foo"},
{Position{1, 5}, tokenEqual, "="},
{Position{1, 7}, tokenLeftCurlyBrace, "{"},
{Position{1, 9}, tokenKey, "-bar"},
{Position{1, 14}, tokenEqual, "="},
{Position{1, 17}, tokenString, "baz"},
{Position{1, 22}, tokenRightCurlyBrace, "}"},
{Position{1, 23}, tokenEOF, ""},
})
}

func TestLexInlineTableBareKeyUnderscore(t *testing.T) {
testFlow(t, `foo = { _bar = "baz" }`, []token{
{Position{1, 1}, tokenKey, "foo"},
{Position{1, 5}, tokenEqual, "="},
{Position{1, 7}, tokenLeftCurlyBrace, "{"},
{Position{1, 9}, tokenKey, "_bar"},
{Position{1, 14}, tokenEqual, "="},
{Position{1, 17}, tokenString, "baz"},
{Position{1, 22}, tokenRightCurlyBrace, "}"},
{Position{1, 23}, tokenEOF, ""},
})
}

func TestLexInlineTableQuotedKey(t *testing.T) {
testFlow(t, `foo = { "bar" = "baz" }`, []token{
{Position{1, 1}, tokenKey, "foo"},
{Position{1, 5}, tokenEqual, "="},
{Position{1, 7}, tokenLeftCurlyBrace, "{"},
{Position{1, 9}, tokenKey, "\"bar\""},
{Position{1, 15}, tokenEqual, "="},
{Position{1, 18}, tokenString, "baz"},
{Position{1, 23}, tokenRightCurlyBrace, "}"},
{Position{1, 24}, tokenEOF, ""},
})
}

func BenchmarkLexer(b *testing.B) {
sample := `title = "Hugo: A Fast and Flexible Website Generator"
baseurl = "http://gohugo.io/"
Expand Down
11 changes: 7 additions & 4 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,15 @@ Loop:
}
key := p.getToken()
p.assume(tokenEqual)

parsedKey, err := parseKey(key.val)
if err != nil {
p.raiseError(key, "invalid key: %s", err)
}

value := p.parseRvalue()
tree.Set(key.val, value)
tree.SetPath(parsedKey, value)
case tokenComma:
if previous == nil {
p.raiseError(follow, "inline table cannot start with a comma")
}
if tokenIsComma(previous) {
p.raiseError(follow, "need field between two commas in inline table")
}
Expand Down
36 changes: 35 additions & 1 deletion parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,33 @@ point = { x = 1, y = 2 }`)
})
}

func TestInlineGroupBareKeysUnderscore(t *testing.T) {
tree, err := Load(`foo = { _bar = "buz" }`)
assertTree(t, tree, err, map[string]interface{}{
"foo": map[string]interface{}{
"_bar": "buz",
},
})
}

func TestInlineGroupBareKeysDash(t *testing.T) {
tree, err := Load(`foo = { -bar = "buz" }`)
assertTree(t, tree, err, map[string]interface{}{
"foo": map[string]interface{}{
"-bar": "buz",
},
})
}

func TestInlineGroupKeyQuoted(t *testing.T) {
tree, err := Load(`foo = { "bar" = "buz" }`)
assertTree(t, tree, err, map[string]interface{}{
"foo": map[string]interface{}{
"bar": "buz",
},
})
}

func TestExampleInlineGroupInArray(t *testing.T) {
tree, err := Load(`points = [{ x = 1, y = 2 }]`)
assertTree(t, tree, err, map[string]interface{}{
Expand Down Expand Up @@ -560,7 +587,7 @@ func TestInlineTableCommaExpected(t *testing.T) {

func TestInlineTableCommaStart(t *testing.T) {
_, err := Load("foo = {, hello = 53}")
if err.Error() != "(1, 8): inline table cannot start with a comma" {
if err.Error() != "(1, 8): unexpected token type in inline table: keys cannot contain , character" {
t.Error("Bad error message:", err.Error())
}
}
Expand Down Expand Up @@ -916,6 +943,13 @@ func TestMapKeyIsNum(t *testing.T) {
}
}

func TestInvalidKeyInlineTable(t *testing.T) {
_, err := Load("table={invalid..key = 1}")
if err.Error() != "(1, 8): invalid key: expecting key part after dot" {
t.Error("Bad error message:", err.Error())
}
}

func TestDottedKeys(t *testing.T) {
tree, err := Load(`
name = "Orange"
Expand Down

0 comments on commit bef0f57

Please sign in to comment.