Fix key parsing in line tables (#311)
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: #282
This commit is contained in:
committed by
Thomas Pelletier
parent
e87c92d4f4
commit
bef0f57967
@@ -247,13 +247,13 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
|
|||||||
func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn {
|
func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn {
|
||||||
l.next()
|
l.next()
|
||||||
l.emit(tokenLeftCurlyBrace)
|
l.emit(tokenLeftCurlyBrace)
|
||||||
return l.lexRvalue
|
return l.lexVoid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
|
func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
|
||||||
l.next()
|
l.next()
|
||||||
l.emit(tokenRightCurlyBrace)
|
l.emit(tokenRightCurlyBrace)
|
||||||
return l.lexRvalue
|
return l.lexVoid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *tomlLexer) lexDate() tomlLexStateFn {
|
func (l *tomlLexer) lexDate() tomlLexStateFn {
|
||||||
|
|||||||
@@ -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) {
|
func BenchmarkLexer(b *testing.B) {
|
||||||
sample := `title = "Hugo: A Fast and Flexible Website Generator"
|
sample := `title = "Hugo: A Fast and Flexible Website Generator"
|
||||||
baseurl = "http://gohugo.io/"
|
baseurl = "http://gohugo.io/"
|
||||||
|
|||||||
@@ -360,12 +360,15 @@ Loop:
|
|||||||
}
|
}
|
||||||
key := p.getToken()
|
key := p.getToken()
|
||||||
p.assume(tokenEqual)
|
p.assume(tokenEqual)
|
||||||
value := p.parseRvalue()
|
|
||||||
tree.Set(key.val, value)
|
parsedKey, err := parseKey(key.val)
|
||||||
case tokenComma:
|
if err != nil {
|
||||||
if previous == nil {
|
p.raiseError(key, "invalid key: %s", err)
|
||||||
p.raiseError(follow, "inline table cannot start with a comma")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value := p.parseRvalue()
|
||||||
|
tree.SetPath(parsedKey, value)
|
||||||
|
case tokenComma:
|
||||||
if tokenIsComma(previous) {
|
if tokenIsComma(previous) {
|
||||||
p.raiseError(follow, "need field between two commas in inline table")
|
p.raiseError(follow, "need field between two commas in inline table")
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-1
@@ -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) {
|
func TestExampleInlineGroupInArray(t *testing.T) {
|
||||||
tree, err := Load(`points = [{ x = 1, y = 2 }]`)
|
tree, err := Load(`points = [{ x = 1, y = 2 }]`)
|
||||||
assertTree(t, tree, err, map[string]interface{}{
|
assertTree(t, tree, err, map[string]interface{}{
|
||||||
@@ -560,7 +587,7 @@ func TestInlineTableCommaExpected(t *testing.T) {
|
|||||||
|
|
||||||
func TestInlineTableCommaStart(t *testing.T) {
|
func TestInlineTableCommaStart(t *testing.T) {
|
||||||
_, err := Load("foo = {, hello = 53}")
|
_, 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())
|
t.Error("Bad error message:", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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) {
|
func TestDottedKeys(t *testing.T) {
|
||||||
tree, err := Load(`
|
tree, err := Load(`
|
||||||
name = "Orange"
|
name = "Orange"
|
||||||
|
|||||||
Reference in New Issue
Block a user