100% compatibility with the BurntSushi tests established.
This commit is contained in:
parent
0d4cb356e9
commit
5782971bde
10
Makefile
10
Makefile
|
@ -1,9 +1,11 @@
|
||||||
all:
|
all: build
|
||||||
|
|
||||||
|
build:
|
||||||
@(cd cmd/toml-test-decoder; go build)
|
@(cd cmd/toml-test-decoder; go build)
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@(cd ast; go test)
|
@(cd ast; go test | grep -v ^PASS)
|
||||||
@(cd parse; go test)
|
@(cd parse; go test | grep -v ^PASS)
|
||||||
|
|
||||||
sushi-test:
|
sushi-test: build
|
||||||
@(cd cmd/toml-test-decoder; go build; ${GOPATH}/bin/toml-test ./toml-test-decoder)
|
@(cd cmd/toml-test-decoder; go build; ${GOPATH}/bin/toml-test ./toml-test-decoder)
|
||||||
|
|
51
ast/ast.go
51
ast/ast.go
|
@ -69,10 +69,10 @@ const (
|
||||||
TypeBoolean ValueType = "boolean"
|
TypeBoolean ValueType = "boolean"
|
||||||
|
|
||||||
// TypeOffsetDateTime identifies a date/time value, including timezone info (2019-06-18 10:32:15.173645362+0200).
|
// TypeOffsetDateTime identifies a date/time value, including timezone info (2019-06-18 10:32:15.173645362+0200).
|
||||||
TypeOffsetDateTime ValueType = "offset datetime"
|
TypeOffsetDateTime ValueType = "datetime"
|
||||||
|
|
||||||
// TypeLocalDateTime identifies a date/time value, without timezone info (2018-12-25 12:12:18.876772533).
|
// TypeLocalDateTime identifies a date/time value, without timezone info (2018-12-25 12:12:18.876772533).
|
||||||
TypeLocalDateTime ValueType = "datetime"
|
TypeLocalDateTime ValueType = "datetime-local"
|
||||||
|
|
||||||
// TypeLocalDate identifies a date value (2017-05-17).
|
// TypeLocalDate identifies a date value (2017-05-17).
|
||||||
TypeLocalDate ValueType = "date"
|
TypeLocalDate ValueType = "date"
|
||||||
|
@ -81,13 +81,18 @@ const (
|
||||||
TypeLocalTime ValueType = "time"
|
TypeLocalTime ValueType = "time"
|
||||||
|
|
||||||
// TypeArrayOfTables identifies an [[array.of.tables]].
|
// TypeArrayOfTables identifies an [[array.of.tables]].
|
||||||
TypeArrayOfTables ValueType = "arrayOfTables"
|
TypeArrayOfTables ValueType = "array-of-tables"
|
||||||
|
|
||||||
// TypeArray identifies ["an", "inline", "static", "array"].
|
// TypeArray identifies ["an", "inline", "static", "array"].
|
||||||
TypeArray ValueType = "array"
|
TypeArray ValueType = "array"
|
||||||
|
|
||||||
// TypeTable identifies an { "inline" = "table" } or [standard.table].
|
// TypeTable identifies an { "inline" = "table" } or [standard.table].
|
||||||
TypeTable ValueType = "table"
|
TypeTable ValueType = "table"
|
||||||
|
|
||||||
|
// TypeImplicitTable identifies an intermediate table that was created
|
||||||
|
// using a table definition that looks like [a.b.c.d] (where a, b and c
|
||||||
|
// would be implicit tables when they hadn't been created explicitly before).
|
||||||
|
TypeImplicitTable ValueType = "implicit-table"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetKeyValuePair is used to set a key and an accompanying value in the
|
// SetKeyValuePair is used to set a key and an accompanying value in the
|
||||||
|
@ -115,22 +120,30 @@ func (doc *Document) OpenTable(key Key) error {
|
||||||
doc.CurrentKey = nil
|
doc.CurrentKey = nil
|
||||||
doc.Current = doc.Root
|
doc.Current = doc.Root
|
||||||
// Go over all requested levels of the key. For all levels, except the last
|
// Go over all requested levels of the key. For all levels, except the last
|
||||||
// one, it is okay if a Table or TableArray already exists. For at least the
|
// one, it is okay if a Table, implicit Table or TableArray already exists.
|
||||||
// last level, no table or value must exist, because that would mean we are
|
// For at least the last level, no table or value must exist, or an implicit
|
||||||
// overwriting an existing key/value pair, which is not allowed.
|
// table must exist. Otherwise we are overwriting an existing value, which
|
||||||
|
// is not allowed.
|
||||||
node, lastKeyPart, err := doc.makeTablePath(key)
|
node, lastKeyPart, err := doc.makeTablePath(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid table: %s", err)
|
return fmt.Errorf("invalid table: %s", err)
|
||||||
}
|
}
|
||||||
// Check if the key is still free for use.
|
// Check if the key is already in use.
|
||||||
if existing, ok := node[lastKeyPart]; ok {
|
if existing, ok := node[lastKeyPart]; ok {
|
||||||
path := doc.formatKeyPath(key, len(key)-1)
|
// It is, but it is an implicit table. Upgrade it to an explicit and use it.
|
||||||
return fmt.Errorf("invalid table: %s value already exists at key %s", existing.Type, path)
|
if existing.Type == TypeImplicitTable {
|
||||||
|
existing.Type = TypeTable
|
||||||
|
node = existing.Data[0].(Table)
|
||||||
|
} else {
|
||||||
|
path := doc.formatKeyPath(key, len(key)-1)
|
||||||
|
return fmt.Errorf("invalid table: %s value already exists at key %s", existing.Type, path)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The subtable does not exist yet. Create the subtable.
|
||||||
|
subTable := make(Table)
|
||||||
|
node[lastKeyPart] = NewValue(TypeTable, subTable)
|
||||||
|
node = subTable
|
||||||
}
|
}
|
||||||
// The subtable does not exist yet. Create the subtable.
|
|
||||||
subTable := make(Table)
|
|
||||||
node[lastKeyPart] = NewValue(TypeTable, subTable)
|
|
||||||
node = subTable
|
|
||||||
|
|
||||||
// From here on, key/value pairs are added to the newly defined table.
|
// From here on, key/value pairs are added to the newly defined table.
|
||||||
doc.Current = node
|
doc.Current = node
|
||||||
|
@ -193,10 +206,10 @@ func (doc *Document) makeTablePath(key Key) (Table, string, error) {
|
||||||
}
|
}
|
||||||
if subValue, ok := node[keyPart]; ok {
|
if subValue, ok := node[keyPart]; ok {
|
||||||
// You cannot overwrite an already defined key, regardless its value.
|
// You cannot overwrite an already defined key, regardless its value.
|
||||||
// When a value already exists at the current key, this can only be a table
|
// When a value already exists at the current key, this can only be a table,
|
||||||
// or an array of tables. In case of an array of tables, the last created
|
// an implicit table or an array of tables. In case of an array of tables,
|
||||||
// table will be used.
|
// the table that was added last to the array will be used.
|
||||||
if subValue.Type == TypeTable {
|
if subValue.Type == TypeTable || subValue.Type == TypeImplicitTable {
|
||||||
// A table was found, traverse to that table.
|
// A table was found, traverse to that table.
|
||||||
node = subValue.Data[0].(Table)
|
node = subValue.Data[0].(Table)
|
||||||
} else if subValue.Type == TypeArrayOfTables {
|
} else if subValue.Type == TypeArrayOfTables {
|
||||||
|
@ -209,9 +222,9 @@ func (doc *Document) makeTablePath(key Key) (Table, string, error) {
|
||||||
return nil, "", fmt.Errorf("%s value already exists at key %s", subValue.Type, path)
|
return nil, "", fmt.Errorf("%s value already exists at key %s", subValue.Type, path)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The subtable does not exist yet. Create the subtable.
|
// The subtable does not exist yet. Create the subtable as an implicit table.
|
||||||
subTable := make(Table)
|
subTable := make(Table)
|
||||||
node[keyPart] = NewValue(TypeTable, subTable)
|
node[keyPart] = NewValue(TypeImplicitTable, subTable)
|
||||||
node = subTable
|
node = subTable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,9 +73,9 @@ func Test_ConstructExplicitTableAfterImplicitSubtable(t *testing.T) {
|
||||||
p := ast.NewDocument()
|
p := ast.NewDocument()
|
||||||
p.OpenTable(ast.NewKey("a", "b", "c"))
|
p.OpenTable(ast.NewKey("a", "b", "c"))
|
||||||
p.SetKeyValuePair(ast.NewKey("answer"), ast.NewValue(ast.TypeString, "42"))
|
p.SetKeyValuePair(ast.NewKey("answer"), ast.NewValue(ast.TypeString, "42"))
|
||||||
p.OpenTable(ast.NewKey("a"))
|
err := p.OpenTable(ast.NewKey("a"))
|
||||||
p.SetKeyValuePair(ast.NewKey("better"), ast.NewValue(ast.TypeString, "43"))
|
p.SetKeyValuePair(ast.NewKey("better"), ast.NewValue(ast.TypeString, "43"))
|
||||||
return nil, p
|
return err, p
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
`{"a": {"b": {"c": {"answer": "42"}}, "better": "43"}}`)
|
`{"a": {"b": {"c": {"answer": "42"}}, "better": "43"}}`)
|
||||||
|
|
|
@ -35,6 +35,8 @@ func (value Value) String() string {
|
||||||
values[i] = value.(*Value).String()
|
values[i] = value.(*Value).String()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("[%s]", strings.Join(values, ", "))
|
return fmt.Sprintf("[%s]", strings.Join(values, ", "))
|
||||||
|
case TypeImplicitTable:
|
||||||
|
fallthrough
|
||||||
case TypeTable:
|
case TypeTable:
|
||||||
pairs := value.Data[0].(Table)
|
pairs := value.Data[0].(Table)
|
||||||
keys := make([]string, len(pairs))
|
keys := make([]string, len(pairs))
|
||||||
|
|
|
@ -77,6 +77,8 @@ func makeSushi(value *ast.Value) string {
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf(`{"type": "array", "value": [%s]}`, strings.Join(values, ", "))
|
return fmt.Sprintf(`{"type": "array", "value": [%s]}`, strings.Join(values, ", "))
|
||||||
}
|
}
|
||||||
|
case ast.TypeImplicitTable:
|
||||||
|
fallthrough
|
||||||
case ast.TypeTable:
|
case ast.TypeTable:
|
||||||
pairs := value.Data[0].(ast.Table)
|
pairs := value.Data[0].(ast.Table)
|
||||||
keys := make([]string, len(pairs))
|
keys := make([]string, len(pairs))
|
||||||
|
|
|
@ -39,7 +39,7 @@ func TestArray(t *testing.T) {
|
||||||
{`x=[[1],['a']]`, `{"x": [[1], ["a"]]}`, ``},
|
{`x=[[1],['a']]`, `{"x": [[1], ["a"]]}`, ``},
|
||||||
{`x=[[[],[]],[]]`, `{"x": [[[], []], []]}`, ``},
|
{`x=[[[],[]],[]]`, `{"x": [[[], []], []]}`, ``},
|
||||||
{"x=[\r\n\r\n \t\n [\r\n\r\n\t [],[\t]],\t\n[]\t \t \n ]", `{"x": [[[], []], []]}`, ``},
|
{"x=[\r\n\r\n \t\n [\r\n\r\n\t [],[\t]],\t\n[]\t \t \n ]", `{"x": [[[], []], []]}`, ``},
|
||||||
{`x=[[1],'a']`, `{}`, `type mismatch in array of static arrays: found an item of type string at line 1, column 11`},
|
{`x=[[1],'a']`, `{}`, `type mismatch in array of arrays: found an item of type string at line 1, column 11`},
|
||||||
} {
|
} {
|
||||||
p := newParser()
|
p := newParser()
|
||||||
testParse(t, p, p.startDocument, test)
|
testParse(t, p, p.startDocument, test)
|
||||||
|
|
Loading…
Reference in New Issue