Cleaning up test code.

This commit is contained in:
Maurice Makaay 2019-06-26 06:39:41 +00:00
parent c536dd1243
commit 608e68c207
9 changed files with 101 additions and 149 deletions

64
ast.go
View File

@ -10,33 +10,33 @@ import (
// item represents a TOML item. // item represents a TOML item.
type item struct { type item struct {
Type itemType Type valueType
Data []interface{} Data []interface{}
} }
// table represents a TOML table. // table represents a TOML table.
type table map[string]*item type table map[string]*item
// itemType identifies the semantic role of a TOML item. // valueType identifies the type of a TOML value.
type itemType string type valueType string
const ( const (
pString itemType = "string" // "various", 'types', """of""", '''strings''' tString valueType = "string" // "various", 'types', """of""", '''strings'''
pInteger itemType = "integer" // 12345, 0xffee12a0, 0o0755, 0b101101011 tInteger valueType = "integer" // 12345, 0xffee12a0, 0o0755, 0b101101011
pFloat itemType = "float" // 10.1234, 143E-12, 43.28377e+4, +inf, -inf, nan tFloat valueType = "float" // 10.1234, 143E-12, 43.28377e+4, +inf, -inf, nan
pBoolean itemType = "boolean" // true or false tBoolean valueType = "boolean" // true or false
pOffsetDateTime itemType = "offset datetime" // 2019-06-18 10:32:15.173645362+0200 tOffsetDateTime valueType = "offset datetime" // 2019-06-18 10:32:15.173645362+0200
pLocalDateTime itemType = "datetime" // 2018-12-25 12:12:18.876772533 tLocalDateTime valueType = "datetime" // 2018-12-25 12:12:18.876772533
pLocalDate itemType = "date" // 2017-05-17 tLocalDate valueType = "date" // 2017-05-17
pLocalTime itemType = "time" // 23:01:22 tLocalTime valueType = "time" // 23:01:22
pArrayOfTables itemType = "array" // defined using an [[array.of.tables]] tArrayOfTables valueType = "array" // defined using an [[array.of.tables]]
pArray itemType = "static array" // defined using ["an", "inline", "array"] tArray valueType = "static array" // defined using ["an", "inline", "array"]
pTable itemType = "table" // defined using { "inline" = "table" } or [standard.table] tTable valueType = "table" // defined using { "inline" = "table" } or [standard.table]
) )
// newItem instantiates a new item struct. // newItem instantiates a new item struct.
func newItem(itemType itemType, data ...interface{}) *item { func newItem(valueType valueType, data ...interface{}) *item {
return &item{Type: itemType, Data: data} return &item{Type: valueType, Data: data}
} }
// newKey instantiates a new key. // newKey instantiates a new key.
@ -47,7 +47,6 @@ func newKey(key ...string) []string {
// parser holds the state for the TOML parser. All parsing functions are // parser holds the state for the TOML parser. All parsing functions are
// methods of this struct. // methods of this struct.
type parser struct { type parser struct {
Items []*item // a buffer for holding parsed items
Root table // the root-level TOML table (each TOML doc is implicitly a table) Root table // the root-level TOML table (each TOML doc is implicitly a table)
Current table // the currently active TOML table Current table // the currently active TOML table
CurrentKey []string // the key for the currently active TOML table CurrentKey []string // the key for the currently active TOML table
@ -93,7 +92,7 @@ func (t *parser) openTable(key []string) error {
} }
// The subtable does not exist yet. Create the subtable. // The subtable does not exist yet. Create the subtable.
subTable := make(table) subTable := make(table)
node[lastKeyPart] = newItem(pTable, subTable) node[lastKeyPart] = newItem(tTable, subTable)
node = 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.
@ -118,7 +117,7 @@ func (t *parser) openArrayOfTables(key []string) error {
// At the last key position, there must be either no value yet, or the // At the last key position, there must be either no value yet, or the
// existing value must be a table array. Other values are invalid. // existing value must be a table array. Other values are invalid.
if existing, ok := node[lastKeyPart]; ok { if existing, ok := node[lastKeyPart]; ok {
if existing.Type != pArrayOfTables { if existing.Type != tArrayOfTables {
path := t.formatKeyPath(key, len(key)-1) path := t.formatKeyPath(key, len(key)-1)
return fmt.Errorf("invalid table array: %s item already exists at key %s", existing.Type, path) return fmt.Errorf("invalid table array: %s item already exists at key %s", existing.Type, path)
} }
@ -126,13 +125,13 @@ func (t *parser) openArrayOfTables(key []string) error {
array := node[lastKeyPart] array := node[lastKeyPart]
subTable := make(table) subTable := make(table)
tables := array.Data tables := array.Data
tables = append(tables, newItem(pTable, subTable)) tables = append(tables, newItem(tTable, subTable))
array.Data = tables array.Data = tables
node = subTable node = subTable
} else { } else {
// No value exists at the defined key path. Create a new table array. // No value exists at the defined key path. Create a new table array.
subTable := make(table) subTable := make(table)
node[lastKeyPart] = newItem(pArrayOfTables, newItem(pTable, subTable)) node[lastKeyPart] = newItem(tArrayOfTables, newItem(tTable, subTable))
node = subTable node = subTable
} }
@ -154,7 +153,7 @@ func (t *parser) makeTablePath(key []string) (table, string, error) {
if subItem, ok := node[keyPart]; ok { if subItem, 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.
if subItem.Type != pTable { if subItem.Type != tTable {
path := t.formatKeyPath(key, i) path := t.formatKeyPath(key, i)
return nil, "", fmt.Errorf("%s item already exists at key %s", subItem.Type, path) return nil, "", fmt.Errorf("%s item already exists at key %s", subItem.Type, path)
} }
@ -163,7 +162,7 @@ func (t *parser) makeTablePath(key []string) (table, string, error) {
} else { } else {
// The subtable does not exist yet. Create the subtable. // The subtable does not exist yet. Create the subtable.
subTable := make(table) subTable := make(table)
node[keyPart] = newItem(pTable, subTable) node[keyPart] = newItem(tTable, subTable)
node = subTable node = subTable
} }
} }
@ -202,30 +201,31 @@ func formatKeyName(key string) string {
} }
func (t table) String() string { func (t table) String() string {
return newItem(pTable, t).String() return newItem(tTable, t).String()
} }
// String() produces a JSON-like (but not JSON) string representation of the value.
func (parseItem item) String() string { func (parseItem item) String() string {
switch parseItem.Type { switch parseItem.Type {
case pString: case tString:
return fmt.Sprintf("%q", parseItem.Data[0]) return fmt.Sprintf("%q", parseItem.Data[0])
case pOffsetDateTime: case tOffsetDateTime:
return parseItem.Data[0].(time.Time).Format(time.RFC3339Nano) return parseItem.Data[0].(time.Time).Format(time.RFC3339Nano)
case pLocalDateTime: case tLocalDateTime:
return parseItem.Data[0].(time.Time).Format("2006-01-02 15:04:05.999999999") return parseItem.Data[0].(time.Time).Format("2006-01-02 15:04:05.999999999")
case pLocalDate: case tLocalDate:
return parseItem.Data[0].(time.Time).Format("2006-01-02") return parseItem.Data[0].(time.Time).Format("2006-01-02")
case pLocalTime: case tLocalTime:
return parseItem.Data[0].(time.Time).Format("15:04:05.999999999") return parseItem.Data[0].(time.Time).Format("15:04:05.999999999")
case pArrayOfTables: case tArrayOfTables:
fallthrough fallthrough
case pArray: case tArray:
items := make([]string, len(parseItem.Data)) items := make([]string, len(parseItem.Data))
for i, value := range parseItem.Data { for i, value := range parseItem.Data {
items[i] = value.(*item).String() items[i] = value.(*item).String()
} }
return fmt.Sprintf("[%s]", strings.Join(items, ", ")) return fmt.Sprintf("[%s]", strings.Join(items, ", "))
case pTable: case tTable:
pairs := parseItem.Data[0].(table) pairs := parseItem.Data[0].(table)
keys := make([]string, len(pairs)) keys := make([]string, len(pairs))
i := 0 i := 0

View File

@ -7,20 +7,20 @@ import (
func TestAST_ConstructStructure(t *testing.T) { func TestAST_ConstructStructure(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.setKeyValuePair(newKey("ding"), newItem(pInteger, 10)) p.setKeyValuePair(newKey("ding"), newItem(tInteger, 10))
p.setKeyValuePair(newKey("dong"), newItem(pString, "not a song")) p.setKeyValuePair(newKey("dong"), newItem(tString, "not a song"))
p.openTable(newKey("key1", "key2 a")) p.openTable(newKey("key1", "key2 a"))
p.setKeyValuePair(newKey("dooh"), newItem(pBoolean, true)) p.setKeyValuePair(newKey("dooh"), newItem(tBoolean, true))
p.setKeyValuePair(newKey("dah"), newItem(pBoolean, false)) p.setKeyValuePair(newKey("dah"), newItem(tBoolean, false))
p.openTable(newKey("key1", "key2 b")) p.openTable(newKey("key1", "key2 b"))
p.setKeyValuePair(newKey("dieh"), newItem(pFloat, 1.111)) p.setKeyValuePair(newKey("dieh"), newItem(tFloat, 1.111))
p.setKeyValuePair(newKey("duh"), newItem(pFloat, 1.18e-12)) p.setKeyValuePair(newKey("duh"), newItem(tFloat, 1.18e-12))
p.setKeyValuePair(newKey("foo", "bar"), newItem(pArrayOfTables, newItem(pInteger, 1), newItem(pInteger, 2))) p.setKeyValuePair(newKey("foo", "bar"), newItem(tArrayOfTables, newItem(tInteger, 1), newItem(tInteger, 2)))
p.openArrayOfTables(newKey("aaah", "table array")) p.openArrayOfTables(newKey("aaah", "table array"))
p.setKeyValuePair(newKey("a"), newItem(pFloat, 1.234)) p.setKeyValuePair(newKey("a"), newItem(tFloat, 1.234))
p.openArrayOfTables(newKey("aaah", "table array")) p.openArrayOfTables(newKey("aaah", "table array"))
p.setKeyValuePair(newKey("b"), newItem(pFloat, 2.345)) p.setKeyValuePair(newKey("b"), newItem(tFloat, 2.345))
p.setKeyValuePair(newKey("c"), newItem(pString, "bingo!")) p.setKeyValuePair(newKey("c"), newItem(tString, "bingo!"))
p.openArrayOfTables(newKey("aaah", "table array")) p.openArrayOfTables(newKey("aaah", "table array"))
return nil, p return nil, p
}, },
@ -44,8 +44,8 @@ func TestAST_EmptyKeyForCreatingTablePath_Panics(t *testing.T) {
func TestAST_StoreValueInRootTable(t *testing.T) { func TestAST_StoreValueInRootTable(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.setKeyValuePair(newKey("key1"), newItem(pString, "value1")) p.setKeyValuePair(newKey("key1"), newItem(tString, "value1"))
return p.setKeyValuePair(newKey("key2"), newItem(pString, "value2")), p return p.setKeyValuePair(newKey("key2"), newItem(tString, "value2")), p
}, },
"", "",
`{"key1": "value1", "key2": "value2"}`) `{"key1": "value1", "key2": "value2"}`)
@ -54,7 +54,7 @@ func TestAST_StoreValueInRootTable(t *testing.T) {
func TestAST_StoreValueWithMultipartKey_CreatesTableHierarchy(t *testing.T) { func TestAST_StoreValueWithMultipartKey_CreatesTableHierarchy(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
return p.setKeyValuePair(newKey("key1", "key2", "key3"), newItem(pString, "value")), p return p.setKeyValuePair(newKey("key1", "key2", "key3"), newItem(tString, "value")), p
}, },
"", "",
`{"key1": {"key2": {"key3": "value"}}}`) `{"key1": {"key2": {"key3": "value"}}}`)
@ -63,8 +63,8 @@ func TestAST_StoreValueWithMultipartKey_CreatesTableHierarchy(t *testing.T) {
func TestAST_StoreDuplicateKeyInRootTable_ReturnsError(t *testing.T) { func TestAST_StoreDuplicateKeyInRootTable_ReturnsError(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.setKeyValuePair(newKey("key"), newItem(pString, "value")) p.setKeyValuePair(newKey("key"), newItem(tString, "value"))
return p.setKeyValuePair(newKey("key"), newItem(pInteger, 321)), p return p.setKeyValuePair(newKey("key"), newItem(tInteger, 321)), p
}, },
`invalid key/value pair: string item already exists at key [key]`, `invalid key/value pair: string item already exists at key [key]`,
`{"key": "value"}`) `{"key": "value"}`)
@ -74,7 +74,7 @@ func TestAST_StoreValueWithMultipartKey_UnderSubtable_CreatesTableHierarchy(t *t
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.openTable(newKey("tablekey1", "tablekey2")) p.openTable(newKey("tablekey1", "tablekey2"))
return p.setKeyValuePair(newKey("valuekey1", "valuekey2", "valuekey3"), newItem(pString, "value")), p return p.setKeyValuePair(newKey("valuekey1", "valuekey2", "valuekey3"), newItem(tString, "value")), p
}, },
"", "",
`{"tablekey1": {"tablekey2": {"valuekey1": {"valuekey2": {"valuekey3": "value"}}}}}`) `{"tablekey1": {"tablekey2": {"valuekey1": {"valuekey2": {"valuekey3": "value"}}}}}`)
@ -84,8 +84,8 @@ func TestAST_StoreKeyPathWherePathContainsNonTableAlready_ReturnsError(t *testin
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.openTable(newKey("key1")) p.openTable(newKey("key1"))
p.setKeyValuePair(newKey("key2"), newItem(pInteger, 0)) p.setKeyValuePair(newKey("key2"), newItem(tInteger, 0))
return p.setKeyValuePair(newKey("key2", "key3"), newItem(pString, "value")), p return p.setKeyValuePair(newKey("key2", "key3"), newItem(tString, "value")), p
}, },
`invalid key/value pair: integer item already exists at key [key1->key2]`, `invalid key/value pair: integer item already exists at key [key1->key2]`,
`{"key1": {"key2": 0}}`) `{"key1": {"key2": 0}}`)
@ -104,7 +104,7 @@ func TestAST_GivenExistingTableAtKey_CreatingTableAtSameKey_ReturnsError(t *test
func TestAST_GivenExistingItemAtKey_CreatingTableAtSameKey_ReturnsError(t *testing.T) { func TestAST_GivenExistingItemAtKey_CreatingTableAtSameKey_ReturnsError(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.setKeyValuePair(newKey("key"), newItem(pString, "value")) p.setKeyValuePair(newKey("key"), newItem(tString, "value"))
return p.openTable(newKey("key")), p return p.openTable(newKey("key")), p
}, },
`invalid table: string item already exists at key [key]`, `invalid table: string item already exists at key [key]`,
@ -114,7 +114,7 @@ func TestAST_GivenExistingItemAtKey_CreatingTableAtSameKey_ReturnsError(t *testi
func TestAST_GivenExistingItemInKeyPath_CreatingTable_ReturnsError(t *testing.T) { func TestAST_GivenExistingItemInKeyPath_CreatingTable_ReturnsError(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.setKeyValuePair(newKey("key"), newItem(pString, "value")) p.setKeyValuePair(newKey("key"), newItem(tString, "value"))
return p.openTable(newKey("key", "subkey")), p return p.openTable(newKey("key", "subkey")), p
}, },
`invalid table: string item already exists at key [key]`, `invalid table: string item already exists at key [key]`,
@ -125,7 +125,7 @@ func TestAST_GivenExistingItemAtDeepKey_CreatingTableAtSameKey_ReturnsError(t *t
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.openTable(newKey("deep", "table")) p.openTable(newKey("deep", "table"))
p.setKeyValuePair(newKey("key"), newItem(pInteger, 0)) p.setKeyValuePair(newKey("key"), newItem(tInteger, 0))
return p.openTable(newKey("deep", "table", "key")), p return p.openTable(newKey("deep", "table", "key")), p
}, },
`invalid table: integer item already exists at key [deep->table->key]`, `invalid table: integer item already exists at key [deep->table->key]`,
@ -136,8 +136,8 @@ func TestAST_GivenExistingItemAtDeepKeyFromSubTable_CreatingTableAtSameKey_Retur
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.openTable(newKey("deep", "table")) p.openTable(newKey("deep", "table"))
p.setKeyValuePair(newKey("key1", "key2"), newItem(pInteger, 0)) p.setKeyValuePair(newKey("key1", "key2"), newItem(tInteger, 0))
return p.setKeyValuePair(newKey("key1", "key2"), newItem(pBoolean, true)), p return p.setKeyValuePair(newKey("key1", "key2"), newItem(tBoolean, true)), p
}, },
// This test mainly tests the formatting of [deep->table->key1->key2], being a concatenation // This test mainly tests the formatting of [deep->table->key1->key2], being a concatenation
// of the currently active table plus the multipart key for setKeyValuePair(). // of the currently active table plus the multipart key for setKeyValuePair().
@ -149,8 +149,8 @@ func TestAST_FormattingOfQuotedPathPartInError(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.openTable(newKey("must be quoted")) p.openTable(newKey("must be quoted"))
p.setKeyValuePair(newKey("this one too"), newItem(pInteger, 0)) p.setKeyValuePair(newKey("this one too"), newItem(tInteger, 0))
return p.setKeyValuePair(newKey("this one too"), newItem(pInteger, 0)), p return p.setKeyValuePair(newKey("this one too"), newItem(tInteger, 0)), p
}, },
`invalid key/value pair: integer item already exists at key ["must be quoted"->"this one too"]`, `invalid key/value pair: integer item already exists at key ["must be quoted"->"this one too"]`,
`{"must be quoted": {"this one too": 0}}`) `{"must be quoted": {"this one too": 0}}`)
@ -159,7 +159,7 @@ func TestAST_FormattingOfQuotedPathPartInError(t *testing.T) {
func TestAST_GivenExistingItemAtKey_CreatingArrayOfTablesAtSameKey_ReturnsError(t *testing.T) { func TestAST_GivenExistingItemAtKey_CreatingArrayOfTablesAtSameKey_ReturnsError(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.Root["key"] = newItem(pString, "value") p.Root["key"] = newItem(tString, "value")
return p.openArrayOfTables(newKey("key")), p return p.openArrayOfTables(newKey("key")), p
}, },
`invalid table array: string item already exists at key [key]`, `invalid table array: string item already exists at key [key]`,
@ -169,7 +169,7 @@ func TestAST_GivenExistingItemAtKey_CreatingArrayOfTablesAtSameKey_ReturnsError(
func TestAST_GivenExistingItemInKeyPath_CreatingArrayOfTables_ReturnsError(t *testing.T) { func TestAST_GivenExistingItemInKeyPath_CreatingArrayOfTables_ReturnsError(t *testing.T) {
testAST(t, func() (error, *parser) { testAST(t, func() (error, *parser) {
p := newParser() p := newParser()
p.Root["key"] = newItem(pString, "value") p.Root["key"] = newItem(tString, "value")
return p.openArrayOfTables(newKey("key", "subkey")), p return p.openArrayOfTables(newKey("key", "subkey")), p
}, },
`invalid table array: string item already exists at key [key]`, `invalid table array: string item already exists at key [key]`,

View File

@ -7,53 +7,6 @@ import (
"git.makaay.nl/mauricem/go-parsekit/parse" "git.makaay.nl/mauricem/go-parsekit/parse"
) )
type statesT struct {
name string
in string
out interface{}
err string
}
type parseTest struct {
input interface{}
expected []string
}
func testParseHandler(t *testing.T, p *parser, handler parse.Handler, test parseTest) {
var err error
defer func() {
recovered := recover()
results := []string{}
for _, item := range p.Items {
results = append(results, item.String())
}
if err != nil {
results = append(results, fmt.Sprintf("Error: %s", err))
}
if recovered != nil {
results = append(results, fmt.Sprintf("Panic: %s", recovered.(string)))
}
for i, e := range test.expected {
if i > len(results)-1 {
t.Errorf("No result at index %d for input %q, expected: %s", i, test.input, e)
continue
}
r := results[i]
if e != r {
t.Errorf("Unexpected result at index %d for input %q:\nexpected: %s\nactual: %s\n", i, test.input, e, r)
}
}
if len(results) > len(test.expected) {
t.Errorf("Got more results than expected for input %q, surplus result(s):\n", test.input)
for i := len(test.expected); i < len(results); i++ {
t.Errorf("[%d] %s", i, results[i])
}
}
}()
err = parse.New(handler)(test.input)
}
func testAST(t *testing.T, code func() (error, *parser), expectedError string, expectedData string) { func testAST(t *testing.T, code func() (error, *parser), expectedError string, expectedData string) {
err, p := code() err, p := code()
if expectedError == "" { if expectedError == "" {

View File

@ -45,7 +45,7 @@ func (t *parser) parseArray(p *parse.API) (*item, bool) {
// Check for an empty array. // Check for an empty array.
if p.Accept(arrayClose) { if p.Accept(arrayClose) {
return newItem(pArray), true return newItem(tArray), true
} }
// Not an empty array, parse the array items. // Not an empty array, parse the array items.
@ -68,7 +68,7 @@ func (t *parser) parseArray(p *parse.API) (*item, bool) {
// Check for the end of the array. // Check for the end of the array.
if p.Accept(arrayClose) { if p.Accept(arrayClose) {
return newItem(pArray, items...), true return newItem(tArray, items...), true
} }
// Not the end of the array? Then we should find an array separator. // Not the end of the array? Then we should find an array separator.

View File

@ -4,8 +4,8 @@ import (
"git.makaay.nl/mauricem/go-parsekit/parse" "git.makaay.nl/mauricem/go-parsekit/parse"
) )
var falseItem = newItem(pBoolean, false) var falseItem = newItem(tBoolean, false)
var trueItem = newItem(pBoolean, true) var trueItem = newItem(tBoolean, true)
// Booleans are just the tokens you're used to. Always lowercase. // Booleans are just the tokens you're used to. Always lowercase.
func (t *parser) parseBoolean(p *parse.API) (*item, bool) { func (t *parser) parseBoolean(p *parse.API) (*item, bool) {

View File

@ -66,10 +66,10 @@ var (
// The full date/time parse format, based on the above definitions. // The full date/time parse format, based on the above definitions.
// The first token denotes the type of date/time value. // The first token denotes the type of date/time value.
// The rest of the tokens contain layout fragments for time.Parse(). // The rest of the tokens contain layout fragments for time.Parse().
offsetDateTime = tok.Str(pOffsetDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok, tzTok)) offsetDateTime = tok.Str(tOffsetDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok, tzTok))
localDateTime = tok.Str(pLocalDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok)) localDateTime = tok.Str(tLocalDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok))
localDate = tok.Str(pLocalDate, dateTok) localDate = tok.Str(tLocalDate, dateTok)
localTime = tok.Str(pLocalTime, c.Seq(timeTok, microTok)) localTime = tok.Str(tLocalTime, c.Seq(timeTok, microTok))
datetime = c.Any(offsetDateTime, localDateTime, localDate, localTime) datetime = c.Any(offsetDateTime, localDateTime, localDate, localTime)
) )
@ -91,8 +91,8 @@ func (t *parser) parseDateTime(p *parse.API) (*item, bool) {
// The first token is a token that wraps the complete date/time input. // The first token is a token that wraps the complete date/time input.
// Its type denotes the type of date/time value that it wraps. // Its type denotes the type of date/time value that it wraps.
func getDateTimeValueType(tokens *[]*tokenize.Token) itemType { func getDateTimeValueType(tokens *[]*tokenize.Token) valueType {
return (*tokens)[0].Type.(itemType) return (*tokens)[0].Type.(valueType)
} }
// The rest of the tokens contain fragments that can be used with // The rest of the tokens contain fragments that can be used with

View File

@ -68,18 +68,18 @@ var (
func (t *parser) parseNumber(p *parse.API) (*item, bool) { func (t *parser) parseNumber(p *parse.API) (*item, bool) {
switch { switch {
case p.Accept(tok.Float64(nil, float)): case p.Accept(tok.Float64(nil, float)):
return newItem(pFloat, p.Result().Value(0).(float64)), true return newItem(tFloat, p.Result().Value(0).(float64)), true
case p.Accept(nan): case p.Accept(nan):
return newItem(pFloat, math.NaN()), true return newItem(tFloat, math.NaN()), true
case p.Accept(inf): case p.Accept(inf):
if p.Result().Rune(0) == '-' { if p.Result().Rune(0) == '-' {
return newItem(pFloat, math.Inf(-1)), true return newItem(tFloat, math.Inf(-1)), true
} }
return newItem(pFloat, math.Inf(+1)), true return newItem(tFloat, math.Inf(+1)), true
case p.Accept(a.Zero): case p.Accept(a.Zero):
return t.parseIntegerStartingWithZero(p) return t.parseIntegerStartingWithZero(p)
case p.Accept(tok.Int64(nil, integer)): case p.Accept(tok.Int64(nil, integer)):
return newItem(pInteger, p.Result().Value(0).(int64)), true return newItem(tInteger, p.Result().Value(0).(int64)), true
default: default:
p.Expected("a number") p.Expected("a number")
return nil, false return nil, false
@ -97,10 +97,10 @@ func (t *parser) parseIntegerStartingWithZero(p *parse.API) (*item, bool) {
case p.Accept(binary): case p.Accept(binary):
value, err = strconv.ParseInt(p.Result().Value(0).(string), 2, 64) value, err = strconv.ParseInt(p.Result().Value(0).(string), 2, 64)
default: default:
return newItem(pInteger, int64(0)), true return newItem(tInteger, int64(0)), true
} }
if err == nil { if err == nil {
return newItem(pInteger, value), true return newItem(tInteger, value), true
} }
p.Error("invalid integer value 0%s: %s", p.Result().String(), err) p.Error("invalid integer value 0%s: %s", p.Result().String(), err)
return nil, false return nil, false

View File

@ -59,7 +59,7 @@ func (t *parser) parseString(p *parse.API) (*item, bool) {
p.Expected("a string value") p.Expected("a string value")
} }
if ok { if ok {
return newItem(pString, value), ok return newItem(tString, value), ok
} }
return nil, false return nil, false
} }

View File

@ -5,21 +5,20 @@ import (
) )
func TestTableKey(t *testing.T) { func TestTableKey(t *testing.T) {
for _, test := range []parseTest{ for _, test := range []parseToASTTest{
{"", []string{`Error: unexpected end of file (expected a table) at start of file`}}, {"[", `{}`, `unexpected end of file (expected a key name) at line 1, column 2`},
{"[", []string{`Error: unexpected end of file (expected a key name) at line 1, column 2`}}, {" \t [", `{}`, `unexpected end of file (expected a key name) at line 1, column 5`},
{" \t [", []string{`Error: unexpected end of file (expected a key name) at line 1, column 5`}}, {" \t [key", `{}`, `unexpected end of file (expected closing ']' for table name) at line 1, column 8`},
{" \t [key", []string{`Error: unexpected end of file (expected closing ']' for table name) at line 1, column 8`}}, {" \t [key.", `{}`, `unexpected end of file (expected a key name) at line 1, column 9`},
{" \t [key.", []string{`Error: unexpected end of file (expected a key name) at line 1, column 9`}}, {" \t [key.'sub key'", `{}`, `unexpected end of file (expected closing ']' for table name) at line 1, column 18`},
{" \t [key.'sub key'", []string{`Error: unexpected end of file (expected closing ']' for table name) at line 1, column 18`}}, {" \t [key.'sub key' \t]", `{"key": {"sub key": {}}}`, ``},
{" \t [key.'sub key' \t]", []string{}}, {" \t [key.'sub key' \t] \t ", `{"key": {"sub key": {}}}`, ``},
{" \t [key.'sub key' \t] \t ", []string{}}, {" \t [key.'sub key' \t] \t \n", `{"key": {"sub key": {}}}`, ``},
{" \t [key.'sub key' \t] \t \n", []string{}}, {" \t [key.'sub key' \t]# with comment\n", `{"key": {"sub key": {}}}`, ``},
{" \t [key.'sub key' \t]# with comment\n", []string{}}, {" \t [key.'sub key' \t] \t # with comment\n", `{"key": {"sub key": {}}}`, ``},
{" \t [key.'sub key' \t] \t # with comment\n", []string{}},
} { } {
p := newParser() p := newParser()
testParseHandler(t, p, p.startTable, test) testParseToAST(t, p, p.startTable, test)
} }
} }
@ -43,20 +42,20 @@ func TestTable(t *testing.T) {
} }
func TestArrayOfTableKey(t *testing.T) { func TestArrayOfTableKey(t *testing.T) {
for _, test := range []parseTest{ for _, test := range []parseToASTTest{
{"[[", []string{`Error: unexpected end of file (expected a key name) at line 1, column 3`}}, {"[[", `{}`, `unexpected end of file (expected a key name) at line 1, column 3`},
{" \t [[", []string{`Error: unexpected end of file (expected a key name) at line 1, column 6`}}, {" \t [[", `{}`, `unexpected end of file (expected a key name) at line 1, column 6`},
{" \t [[key", []string{`Error: unexpected end of file (expected closing ']]' for array of tables name) at line 1, column 9`}}, {" \t [[key", `{}`, `unexpected end of file (expected closing ']]' for array of tables name) at line 1, column 9`},
{" \t [[key.", []string{`Error: unexpected end of file (expected a key name) at line 1, column 10`}}, {" \t [[key.", `{}`, `unexpected end of file (expected a key name) at line 1, column 10`},
{" \t [[key.'sub key'", []string{`Error: unexpected end of file (expected closing ']]' for array of tables name) at line 1, column 19`}}, {" \t [[key.'sub key'", `{}`, `unexpected end of file (expected closing ']]' for array of tables name) at line 1, column 19`},
{" \t [[key.'sub key' \t]]", []string{}}, {" \t [[key.'sub key' \t]]", `{"key": {"sub key": [{}]}}`, ``},
{" \t [[key.'sub key' \t]] \t ", []string{}}, {" \t [[key.'sub key' \t]] \t ", `{"key": {"sub key": [{}]}}`, ``},
{" \t [[key.'sub key' \t]] \t \n", []string{}}, {" \t [[key.'sub key' \t]] \t \n", `{"key": {"sub key": [{}]}}`, ``},
{" \t [[key.'sub key' \t]]# with comment\n", []string{}}, {" \t [[key.'sub key' \t]]# with comment\n", `{"key": {"sub key": [{}]}}`, ``},
{" \t [[key.'sub key' \t]] \t # with comment\n", []string{}}, {" \t [[key.'sub key' \t]] \t # with comment\n", `{"key": {"sub key": [{}]}}`, ``},
} { } {
p := newParser() p := newParser()
testParseHandler(t, p, p.startTable, test) testParseToAST(t, p, p.startTable, test)
} }
} }