diff --git a/ast.go b/ast.go index 554ab70..b07ab5f 100644 --- a/ast.go +++ b/ast.go @@ -10,33 +10,33 @@ import ( // item represents a TOML item. type item struct { - Type itemType + Type valueType Data []interface{} } // table represents a TOML table. type table map[string]*item -// itemType identifies the semantic role of a TOML item. -type itemType string +// valueType identifies the type of a TOML value. +type valueType string const ( - pString itemType = "string" // "various", 'types', """of""", '''strings''' - pInteger itemType = "integer" // 12345, 0xffee12a0, 0o0755, 0b101101011 - pFloat itemType = "float" // 10.1234, 143E-12, 43.28377e+4, +inf, -inf, nan - pBoolean itemType = "boolean" // true or false - pOffsetDateTime itemType = "offset datetime" // 2019-06-18 10:32:15.173645362+0200 - pLocalDateTime itemType = "datetime" // 2018-12-25 12:12:18.876772533 - pLocalDate itemType = "date" // 2017-05-17 - pLocalTime itemType = "time" // 23:01:22 - pArrayOfTables itemType = "array" // defined using an [[array.of.tables]] - pArray itemType = "static array" // defined using ["an", "inline", "array"] - pTable itemType = "table" // defined using { "inline" = "table" } or [standard.table] + tString valueType = "string" // "various", 'types', """of""", '''strings''' + tInteger valueType = "integer" // 12345, 0xffee12a0, 0o0755, 0b101101011 + tFloat valueType = "float" // 10.1234, 143E-12, 43.28377e+4, +inf, -inf, nan + tBoolean valueType = "boolean" // true or false + tOffsetDateTime valueType = "offset datetime" // 2019-06-18 10:32:15.173645362+0200 + tLocalDateTime valueType = "datetime" // 2018-12-25 12:12:18.876772533 + tLocalDate valueType = "date" // 2017-05-17 + tLocalTime valueType = "time" // 23:01:22 + tArrayOfTables valueType = "array" // defined using an [[array.of.tables]] + tArray valueType = "static array" // defined using ["an", "inline", "array"] + tTable valueType = "table" // defined using { "inline" = "table" } or [standard.table] ) // newItem instantiates a new item struct. -func newItem(itemType itemType, data ...interface{}) *item { - return &item{Type: itemType, Data: data} +func newItem(valueType valueType, data ...interface{}) *item { + return &item{Type: valueType, Data: data} } // 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 // methods of this 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) Current table // 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. subTable := make(table) - node[lastKeyPart] = newItem(pTable, subTable) + node[lastKeyPart] = newItem(tTable, subTable) node = subTable // 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 // existing value must be a table array. Other values are invalid. if existing, ok := node[lastKeyPart]; ok { - if existing.Type != pArrayOfTables { + if existing.Type != tArrayOfTables { path := t.formatKeyPath(key, len(key)-1) 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] subTable := make(table) tables := array.Data - tables = append(tables, newItem(pTable, subTable)) + tables = append(tables, newItem(tTable, subTable)) array.Data = tables node = subTable } else { // No value exists at the defined key path. Create a new table array. subTable := make(table) - node[lastKeyPart] = newItem(pArrayOfTables, newItem(pTable, subTable)) + node[lastKeyPart] = newItem(tArrayOfTables, newItem(tTable, subTable)) node = subTable } @@ -154,7 +153,7 @@ func (t *parser) makeTablePath(key []string) (table, string, error) { if subItem, ok := node[keyPart]; ok { // 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. - if subItem.Type != pTable { + if subItem.Type != tTable { path := t.formatKeyPath(key, i) 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 { // The subtable does not exist yet. Create the subtable. subTable := make(table) - node[keyPart] = newItem(pTable, subTable) + node[keyPart] = newItem(tTable, subTable) node = subTable } } @@ -202,30 +201,31 @@ func formatKeyName(key 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 { switch parseItem.Type { - case pString: + case tString: return fmt.Sprintf("%q", parseItem.Data[0]) - case pOffsetDateTime: + case tOffsetDateTime: 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") - case pLocalDate: + case tLocalDate: 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") - case pArrayOfTables: + case tArrayOfTables: fallthrough - case pArray: + case tArray: items := make([]string, len(parseItem.Data)) for i, value := range parseItem.Data { items[i] = value.(*item).String() } return fmt.Sprintf("[%s]", strings.Join(items, ", ")) - case pTable: + case tTable: pairs := parseItem.Data[0].(table) keys := make([]string, len(pairs)) i := 0 diff --git a/ast_test.go b/ast_test.go index 45883cb..50f5953 100644 --- a/ast_test.go +++ b/ast_test.go @@ -7,20 +7,20 @@ import ( func TestAST_ConstructStructure(t *testing.T) { testAST(t, func() (error, *parser) { p := newParser() - p.setKeyValuePair(newKey("ding"), newItem(pInteger, 10)) - p.setKeyValuePair(newKey("dong"), newItem(pString, "not a song")) + p.setKeyValuePair(newKey("ding"), newItem(tInteger, 10)) + p.setKeyValuePair(newKey("dong"), newItem(tString, "not a song")) p.openTable(newKey("key1", "key2 a")) - p.setKeyValuePair(newKey("dooh"), newItem(pBoolean, true)) - p.setKeyValuePair(newKey("dah"), newItem(pBoolean, false)) + p.setKeyValuePair(newKey("dooh"), newItem(tBoolean, true)) + p.setKeyValuePair(newKey("dah"), newItem(tBoolean, false)) p.openTable(newKey("key1", "key2 b")) - p.setKeyValuePair(newKey("dieh"), newItem(pFloat, 1.111)) - p.setKeyValuePair(newKey("duh"), newItem(pFloat, 1.18e-12)) - p.setKeyValuePair(newKey("foo", "bar"), newItem(pArrayOfTables, newItem(pInteger, 1), newItem(pInteger, 2))) + p.setKeyValuePair(newKey("dieh"), newItem(tFloat, 1.111)) + p.setKeyValuePair(newKey("duh"), newItem(tFloat, 1.18e-12)) + p.setKeyValuePair(newKey("foo", "bar"), newItem(tArrayOfTables, newItem(tInteger, 1), newItem(tInteger, 2))) 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.setKeyValuePair(newKey("b"), newItem(pFloat, 2.345)) - p.setKeyValuePair(newKey("c"), newItem(pString, "bingo!")) + p.setKeyValuePair(newKey("b"), newItem(tFloat, 2.345)) + p.setKeyValuePair(newKey("c"), newItem(tString, "bingo!")) p.openArrayOfTables(newKey("aaah", "table array")) return nil, p }, @@ -44,8 +44,8 @@ func TestAST_EmptyKeyForCreatingTablePath_Panics(t *testing.T) { func TestAST_StoreValueInRootTable(t *testing.T) { testAST(t, func() (error, *parser) { p := newParser() - p.setKeyValuePair(newKey("key1"), newItem(pString, "value1")) - return p.setKeyValuePair(newKey("key2"), newItem(pString, "value2")), p + p.setKeyValuePair(newKey("key1"), newItem(tString, "value1")) + return p.setKeyValuePair(newKey("key2"), newItem(tString, "value2")), p }, "", `{"key1": "value1", "key2": "value2"}`) @@ -54,7 +54,7 @@ func TestAST_StoreValueInRootTable(t *testing.T) { func TestAST_StoreValueWithMultipartKey_CreatesTableHierarchy(t *testing.T) { testAST(t, func() (error, *parser) { 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"}}}`) @@ -63,8 +63,8 @@ func TestAST_StoreValueWithMultipartKey_CreatesTableHierarchy(t *testing.T) { func TestAST_StoreDuplicateKeyInRootTable_ReturnsError(t *testing.T) { testAST(t, func() (error, *parser) { p := newParser() - p.setKeyValuePair(newKey("key"), newItem(pString, "value")) - return p.setKeyValuePair(newKey("key"), newItem(pInteger, 321)), p + p.setKeyValuePair(newKey("key"), newItem(tString, "value")) + return p.setKeyValuePair(newKey("key"), newItem(tInteger, 321)), p }, `invalid key/value pair: string item already exists at key [key]`, `{"key": "value"}`) @@ -74,7 +74,7 @@ func TestAST_StoreValueWithMultipartKey_UnderSubtable_CreatesTableHierarchy(t *t testAST(t, func() (error, *parser) { p := newParser() 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"}}}}}`) @@ -84,8 +84,8 @@ func TestAST_StoreKeyPathWherePathContainsNonTableAlready_ReturnsError(t *testin testAST(t, func() (error, *parser) { p := newParser() p.openTable(newKey("key1")) - p.setKeyValuePair(newKey("key2"), newItem(pInteger, 0)) - return p.setKeyValuePair(newKey("key2", "key3"), newItem(pString, "value")), p + p.setKeyValuePair(newKey("key2"), newItem(tInteger, 0)) + return p.setKeyValuePair(newKey("key2", "key3"), newItem(tString, "value")), p }, `invalid key/value pair: integer item already exists at key [key1->key2]`, `{"key1": {"key2": 0}}`) @@ -104,7 +104,7 @@ func TestAST_GivenExistingTableAtKey_CreatingTableAtSameKey_ReturnsError(t *test func TestAST_GivenExistingItemAtKey_CreatingTableAtSameKey_ReturnsError(t *testing.T) { testAST(t, func() (error, *parser) { p := newParser() - p.setKeyValuePair(newKey("key"), newItem(pString, "value")) + p.setKeyValuePair(newKey("key"), newItem(tString, "value")) return p.openTable(newKey("key")), p }, `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) { testAST(t, func() (error, *parser) { p := newParser() - p.setKeyValuePair(newKey("key"), newItem(pString, "value")) + p.setKeyValuePair(newKey("key"), newItem(tString, "value")) return p.openTable(newKey("key", "subkey")), p }, `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) { p := newParser() 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 }, `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) { p := newParser() p.openTable(newKey("deep", "table")) - p.setKeyValuePair(newKey("key1", "key2"), newItem(pInteger, 0)) - return p.setKeyValuePair(newKey("key1", "key2"), newItem(pBoolean, true)), p + p.setKeyValuePair(newKey("key1", "key2"), newItem(tInteger, 0)) + return p.setKeyValuePair(newKey("key1", "key2"), newItem(tBoolean, true)), p }, // 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(). @@ -149,8 +149,8 @@ func TestAST_FormattingOfQuotedPathPartInError(t *testing.T) { testAST(t, func() (error, *parser) { p := newParser() p.openTable(newKey("must be quoted")) - p.setKeyValuePair(newKey("this one too"), newItem(pInteger, 0)) - return p.setKeyValuePair(newKey("this one too"), newItem(pInteger, 0)), p + p.setKeyValuePair(newKey("this one too"), newItem(tInteger, 0)) + 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"]`, `{"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) { testAST(t, func() (error, *parser) { p := newParser() - p.Root["key"] = newItem(pString, "value") + p.Root["key"] = newItem(tString, "value") return p.openArrayOfTables(newKey("key")), p }, `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) { testAST(t, func() (error, *parser) { p := newParser() - p.Root["key"] = newItem(pString, "value") + p.Root["key"] = newItem(tString, "value") return p.openArrayOfTables(newKey("key", "subkey")), p }, `invalid table array: string item already exists at key [key]`, diff --git a/helpers_test.go b/helpers_test.go index 2d9c5b5..c64ab09 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -7,53 +7,6 @@ import ( "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) { err, p := code() if expectedError == "" { diff --git a/value_array.go b/value_array.go index 6ca0d62..53e13b0 100644 --- a/value_array.go +++ b/value_array.go @@ -45,7 +45,7 @@ func (t *parser) parseArray(p *parse.API) (*item, bool) { // Check for an empty array. if p.Accept(arrayClose) { - return newItem(pArray), true + return newItem(tArray), true } // 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. 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. diff --git a/value_boolean.go b/value_boolean.go index b906c38..fc954c0 100644 --- a/value_boolean.go +++ b/value_boolean.go @@ -4,8 +4,8 @@ import ( "git.makaay.nl/mauricem/go-parsekit/parse" ) -var falseItem = newItem(pBoolean, false) -var trueItem = newItem(pBoolean, true) +var falseItem = newItem(tBoolean, false) +var trueItem = newItem(tBoolean, true) // Booleans are just the tokens you're used to. Always lowercase. func (t *parser) parseBoolean(p *parse.API) (*item, bool) { diff --git a/value_datetime.go b/value_datetime.go index 93df40a..4666a25 100644 --- a/value_datetime.go +++ b/value_datetime.go @@ -66,10 +66,10 @@ var ( // The full date/time parse format, based on the above definitions. // The first token denotes the type of date/time value. // The rest of the tokens contain layout fragments for time.Parse(). - offsetDateTime = tok.Str(pOffsetDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok, tzTok)) - localDateTime = tok.Str(pLocalDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok)) - localDate = tok.Str(pLocalDate, dateTok) - localTime = tok.Str(pLocalTime, c.Seq(timeTok, microTok)) + offsetDateTime = tok.Str(tOffsetDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok, tzTok)) + localDateTime = tok.Str(tLocalDateTime, c.Seq(dateTok, tdelimTok, timeTok, microTok)) + localDate = tok.Str(tLocalDate, dateTok) + localTime = tok.Str(tLocalTime, c.Seq(timeTok, microTok)) 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. // Its type denotes the type of date/time value that it wraps. -func getDateTimeValueType(tokens *[]*tokenize.Token) itemType { - return (*tokens)[0].Type.(itemType) +func getDateTimeValueType(tokens *[]*tokenize.Token) valueType { + return (*tokens)[0].Type.(valueType) } // The rest of the tokens contain fragments that can be used with diff --git a/value_number.go b/value_number.go index f3d6248..e86e6ee 100644 --- a/value_number.go +++ b/value_number.go @@ -68,18 +68,18 @@ var ( func (t *parser) parseNumber(p *parse.API) (*item, bool) { switch { 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): - return newItem(pFloat, math.NaN()), true + return newItem(tFloat, math.NaN()), true case p.Accept(inf): 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): return t.parseIntegerStartingWithZero(p) 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: p.Expected("a number") return nil, false @@ -97,10 +97,10 @@ func (t *parser) parseIntegerStartingWithZero(p *parse.API) (*item, bool) { case p.Accept(binary): value, err = strconv.ParseInt(p.Result().Value(0).(string), 2, 64) default: - return newItem(pInteger, int64(0)), true + return newItem(tInteger, int64(0)), true } 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) return nil, false diff --git a/value_string.go b/value_string.go index eb34d7f..7d140db 100644 --- a/value_string.go +++ b/value_string.go @@ -59,7 +59,7 @@ func (t *parser) parseString(p *parse.API) (*item, bool) { p.Expected("a string value") } if ok { - return newItem(pString, value), ok + return newItem(tString, value), ok } return nil, false } diff --git a/value_table_test.go b/value_table_test.go index aff7efa..b61383c 100644 --- a/value_table_test.go +++ b/value_table_test.go @@ -5,21 +5,20 @@ import ( ) func TestTableKey(t *testing.T) { - for _, test := range []parseTest{ - {"", []string{`Error: unexpected end of file (expected a table) at start of file`}}, - {"[", []string{`Error: unexpected end of file (expected a key name) at line 1, column 2`}}, - {" \t [", []string{`Error: unexpected end of file (expected a key name) at line 1, column 5`}}, - {" \t [key", []string{`Error: unexpected end of file (expected closing ']' for table name) at line 1, column 8`}}, - {" \t [key.", []string{`Error: unexpected end of file (expected a key name) at line 1, column 9`}}, - {" \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]", []string{}}, - {" \t [key.'sub key' \t] \t ", []string{}}, - {" \t [key.'sub key' \t] \t \n", []string{}}, - {" \t [key.'sub key' \t]# with comment\n", []string{}}, - {" \t [key.'sub key' \t] \t # with comment\n", []string{}}, + for _, test := range []parseToASTTest{ + {"[", `{}`, `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 [key", `{}`, `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.'sub key'", `{}`, `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] \t ", `{"key": {"sub key": {}}}`, ``}, + {" \t [key.'sub key' \t] \t \n", `{"key": {"sub key": {}}}`, ``}, + {" \t [key.'sub key' \t]# with comment\n", `{"key": {"sub key": {}}}`, ``}, + {" \t [key.'sub key' \t] \t # with comment\n", `{"key": {"sub key": {}}}`, ``}, } { 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) { - for _, test := range []parseTest{ - {"[[", []string{`Error: 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 [[key", []string{`Error: 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.'sub key'", []string{`Error: 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]] \t ", []string{}}, - {" \t [[key.'sub key' \t]] \t \n", []string{}}, - {" \t [[key.'sub key' \t]]# with comment\n", []string{}}, - {" \t [[key.'sub key' \t]] \t # with comment\n", []string{}}, + for _, test := range []parseToASTTest{ + {"[[", `{}`, `unexpected end of file (expected a key name) at line 1, column 3`}, + {" \t [[", `{}`, `unexpected end of file (expected a key name) at line 1, column 6`}, + {" \t [[key", `{}`, `unexpected end of file (expected closing ']]' for array of tables name) at line 1, column 9`}, + {" \t [[key.", `{}`, `unexpected end of file (expected a key name) at line 1, column 10`}, + {" \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]]", `{"key": {"sub key": [{}]}}`, ``}, + {" \t [[key.'sub key' \t]] \t ", `{"key": {"sub key": [{}]}}`, ``}, + {" \t [[key.'sub key' \t]] \t \n", `{"key": {"sub key": [{}]}}`, ``}, + {" \t [[key.'sub key' \t]]# with comment\n", `{"key": {"sub key": [{}]}}`, ``}, + {" \t [[key.'sub key' \t]] \t # with comment\n", `{"key": {"sub key": [{}]}}`, ``}, } { p := newParser() - testParseHandler(t, p, p.startTable, test) + testParseToAST(t, p, p.startTable, test) } }