Inline tables
This commit is contained in:
@@ -222,8 +222,9 @@ func (p *parser) parseVal(b []byte) (ast.Node, []byte, error) {
|
||||
b, err := p.parseValArray(&node, b)
|
||||
return node, b, err
|
||||
case '{':
|
||||
// TODO
|
||||
//return p.parseInlineTable(b)
|
||||
node.Kind = ast.InlineTable
|
||||
b, err := p.parseInlineTable(&node, b)
|
||||
return node, b, err
|
||||
default:
|
||||
// TODO
|
||||
//return p.parseIntOrFloatOrDateTime(b)
|
||||
@@ -240,38 +241,39 @@ func (p *parser) parseLiteralString(b []byte) ([]byte, []byte, error) {
|
||||
return v[1 : len(v)-1], rest, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseInlineTable(b []byte) ([]byte, error) {
|
||||
func (p *parser) parseInlineTable(node *ast.Node, b []byte) ([]byte, error) {
|
||||
//inline-table = inline-table-open [ inline-table-keyvals ] inline-table-close
|
||||
//inline-table-open = %x7B ws ; {
|
||||
//inline-table-close = ws %x7D ; }
|
||||
//inline-table-sep = ws %x2C ws ; , Comma
|
||||
//inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ]
|
||||
|
||||
// TODO
|
||||
//b = b[1:]
|
||||
//
|
||||
//first := true
|
||||
//var err error
|
||||
//for len(b) > 0 {
|
||||
// b = p.parseWhitespace(b)
|
||||
// if b[0] == '}' {
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// if !first {
|
||||
// b, err = expect(',', b)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// b = p.parseWhitespace(b)
|
||||
// }
|
||||
// b, err = p.parseKeyval(b)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// first = false
|
||||
//}
|
||||
b = b[1:]
|
||||
|
||||
first := true
|
||||
var err error
|
||||
for len(b) > 0 {
|
||||
b = p.parseWhitespace(b)
|
||||
if b[0] == '}' {
|
||||
break
|
||||
}
|
||||
|
||||
if !first {
|
||||
b, err = expect(',', b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = p.parseWhitespace(b)
|
||||
}
|
||||
var kv ast.Node
|
||||
kv, b, err = p.parseKeyval(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node.Children = append(node.Children, kv)
|
||||
|
||||
first = false
|
||||
}
|
||||
|
||||
return expect('}', b)
|
||||
}
|
||||
|
||||
@@ -98,6 +98,40 @@ func TestParser_AST(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "inline table",
|
||||
input: `name = { first = "Tom", last = "Preston-Werner" }`,
|
||||
ast: ast.Root{
|
||||
ast.Node{
|
||||
Kind: ast.KeyValue,
|
||||
Children: []ast.Node{
|
||||
{
|
||||
Kind: ast.Key,
|
||||
Data: []byte(`name`),
|
||||
},
|
||||
{
|
||||
Kind: ast.InlineTable,
|
||||
Children: []ast.Node{
|
||||
{
|
||||
Kind: ast.KeyValue,
|
||||
Children: []ast.Node{
|
||||
{Kind: ast.Key, Data: []byte(`first`)},
|
||||
{Kind: ast.String, Data: []byte(`Tom`)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Kind: ast.KeyValue,
|
||||
Children: []ast.Node{
|
||||
{Kind: ast.Key, Data: []byte(`last`)},
|
||||
{Kind: ast.String, Data: []byte(`Preston-Werner`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, e := range examples {
|
||||
|
||||
@@ -80,6 +80,8 @@ func unmarshalValue(x target, node *ast.Node) error {
|
||||
return unmarshalString(x, node)
|
||||
case ast.Array:
|
||||
return unmarshalArray(x, node)
|
||||
case ast.InlineTable:
|
||||
return unmarshalInlineTable(x, node)
|
||||
default:
|
||||
panic(fmt.Errorf("unhandled unmarshalValue kind %s", node.Kind))
|
||||
}
|
||||
@@ -87,10 +89,21 @@ func unmarshalValue(x target, node *ast.Node) error {
|
||||
|
||||
func unmarshalString(x target, node *ast.Node) error {
|
||||
assertNode(ast.String, node)
|
||||
|
||||
return x.setString(string(node.Data))
|
||||
}
|
||||
|
||||
func unmarshalInlineTable(x target, node *ast.Node) error {
|
||||
assertNode(ast.InlineTable, node)
|
||||
|
||||
for _, kv := range node.Children {
|
||||
err := unmarshalKeyValue(x, &kv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalArray(x target, node *ast.Node) error {
|
||||
assertNode(ast.Array, node)
|
||||
|
||||
|
||||
@@ -137,6 +137,62 @@ func TestFromAst_Table(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestFromAst_InlineTable(t *testing.T) {
|
||||
t.Run("one level of strings", func(t *testing.T) {
|
||||
// name = { first = "Tom", last = "Preston-Werner" }
|
||||
|
||||
root := ast.Root{
|
||||
ast.Node{
|
||||
Kind: ast.KeyValue,
|
||||
Children: []ast.Node{
|
||||
{
|
||||
Kind: ast.Key,
|
||||
Data: []byte(`Name`)},
|
||||
{
|
||||
Kind: ast.InlineTable,
|
||||
Children: []ast.Node{
|
||||
{
|
||||
Kind: ast.KeyValue,
|
||||
Children: []ast.Node{
|
||||
{Kind: ast.Key, Data: []byte(`First`)},
|
||||
{Kind: ast.String, Data: []byte(`Tom`)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Kind: ast.KeyValue,
|
||||
Children: []ast.Node{
|
||||
{Kind: ast.Key, Data: []byte(`Last`)},
|
||||
{Kind: ast.String, Data: []byte(`Preston-Werner`)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type Name struct {
|
||||
First string
|
||||
Last string
|
||||
}
|
||||
|
||||
type Doc struct {
|
||||
Name Name
|
||||
}
|
||||
|
||||
x := Doc{}
|
||||
err := fromAst(root, &x)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, Doc{
|
||||
Name: Name{
|
||||
First: "Tom",
|
||||
Last: "Preston-Werner",
|
||||
},
|
||||
}, x)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestFromAst_Slice(t *testing.T) {
|
||||
t.Run("slice of string", func(t *testing.T) {
|
||||
root := ast.Root{
|
||||
|
||||
Reference in New Issue
Block a user