Rename group to table (#115)
* Rename Group to Table Fixes #45 * Change fmt.Errorf to errors.new for simple strings
This commit is contained in:
+6
-5
@@ -4,6 +4,7 @@ package toml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"unicode"
|
||||
)
|
||||
@@ -47,7 +48,7 @@ func parseKey(key string) ([]string, error) {
|
||||
} else {
|
||||
if !wasInQuotes {
|
||||
if buffer.Len() == 0 {
|
||||
return nil, fmt.Errorf("empty key group")
|
||||
return nil, errors.New("empty table key")
|
||||
}
|
||||
groups = append(groups, buffer.String())
|
||||
buffer.Reset()
|
||||
@@ -67,23 +68,23 @@ func parseKey(key string) ([]string, error) {
|
||||
return nil, fmt.Errorf("invalid bare character: %c", char)
|
||||
}
|
||||
if !inQuotes && expectDot {
|
||||
return nil, fmt.Errorf("what?")
|
||||
return nil, errors.New("what?")
|
||||
}
|
||||
buffer.WriteRune(char)
|
||||
expectDot = false
|
||||
}
|
||||
}
|
||||
if inQuotes {
|
||||
return nil, fmt.Errorf("mismatched quotes")
|
||||
return nil, errors.New("mismatched quotes")
|
||||
}
|
||||
if escapeNext {
|
||||
return nil, fmt.Errorf("unfinished escape sequence")
|
||||
return nil, errors.New("unfinished escape sequence")
|
||||
}
|
||||
if buffer.Len() > 0 {
|
||||
groups = append(groups, buffer.String())
|
||||
}
|
||||
if len(groups) == 0 {
|
||||
return nil, fmt.Errorf("empty key")
|
||||
return nil, errors.New("empty key")
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ func (l *tomlLexer) lexVoid() tomlLexStateFn {
|
||||
next := l.peek()
|
||||
switch next {
|
||||
case '[':
|
||||
return l.lexKeyGroup
|
||||
return l.lexTableKey
|
||||
case '#':
|
||||
return l.lexComment
|
||||
case '=':
|
||||
@@ -516,21 +516,21 @@ func (l *tomlLexer) lexString() tomlLexStateFn {
|
||||
return l.lexRvalue
|
||||
}
|
||||
|
||||
func (l *tomlLexer) lexKeyGroup() tomlLexStateFn {
|
||||
func (l *tomlLexer) lexTableKey() tomlLexStateFn {
|
||||
l.next()
|
||||
|
||||
if l.peek() == '[' {
|
||||
// token '[[' signifies an array of anonymous key groups
|
||||
// token '[[' signifies an array of tables
|
||||
l.next()
|
||||
l.emit(tokenDoubleLeftBracket)
|
||||
return l.lexInsideKeyGroupArray
|
||||
return l.lexInsideTableArrayKey
|
||||
}
|
||||
// vanilla key group
|
||||
// vanilla table key
|
||||
l.emit(tokenLeftBracket)
|
||||
return l.lexInsideKeyGroup
|
||||
return l.lexInsideTableKey
|
||||
}
|
||||
|
||||
func (l *tomlLexer) lexInsideKeyGroupArray() tomlLexStateFn {
|
||||
func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
|
||||
for r := l.peek(); r != eof; r = l.peek() {
|
||||
switch r {
|
||||
case ']':
|
||||
@@ -545,15 +545,15 @@ func (l *tomlLexer) lexInsideKeyGroupArray() tomlLexStateFn {
|
||||
l.emit(tokenDoubleRightBracket)
|
||||
return l.lexVoid
|
||||
case '[':
|
||||
return l.errorf("group name cannot contain ']'")
|
||||
return l.errorf("table array key cannot contain ']'")
|
||||
default:
|
||||
l.next()
|
||||
}
|
||||
}
|
||||
return l.errorf("unclosed key group array")
|
||||
return l.errorf("unclosed table array key")
|
||||
}
|
||||
|
||||
func (l *tomlLexer) lexInsideKeyGroup() tomlLexStateFn {
|
||||
func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
|
||||
for r := l.peek(); r != eof; r = l.peek() {
|
||||
switch r {
|
||||
case ']':
|
||||
@@ -564,12 +564,12 @@ func (l *tomlLexer) lexInsideKeyGroup() tomlLexStateFn {
|
||||
l.emit(tokenRightBracket)
|
||||
return l.lexVoid
|
||||
case '[':
|
||||
return l.errorf("group name cannot contain ']'")
|
||||
return l.errorf("table key cannot contain ']'")
|
||||
default:
|
||||
l.next()
|
||||
}
|
||||
}
|
||||
return l.errorf("unclosed key group")
|
||||
return l.errorf("unclosed table key")
|
||||
}
|
||||
|
||||
func (l *tomlLexer) lexRightBracket() tomlLexStateFn {
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ func TestNestedQuotedUnicodeKeyGroup(t *testing.T) {
|
||||
func TestUnclosedKeyGroup(t *testing.T) {
|
||||
testFlow(t, "[hello world", []token{
|
||||
{Position{1, 1}, tokenLeftBracket, "["},
|
||||
{Position{1, 2}, tokenError, "unclosed key group"},
|
||||
{Position{1, 2}, tokenError, "unclosed table key"},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
@@ -15,8 +16,8 @@ type tomlParser struct {
|
||||
flow chan token
|
||||
tree *TomlTree
|
||||
tokensBuffer []token
|
||||
currentGroup []string
|
||||
seenGroupKeys []string
|
||||
currentTable []string
|
||||
seenTableKeys []string
|
||||
}
|
||||
|
||||
type tomlParserStateFn func() tomlParserStateFn
|
||||
@@ -95,13 +96,13 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
|
||||
startToken := p.getToken() // discard the [[
|
||||
key := p.getToken()
|
||||
if key.typ != tokenKeyGroupArray {
|
||||
p.raiseError(key, "unexpected token %s, was expecting a key group array", key)
|
||||
p.raiseError(key, "unexpected token %s, was expecting a table array key", key)
|
||||
}
|
||||
|
||||
// get or create group array element at the indicated part in the path
|
||||
// get or create table array element at the indicated part in the path
|
||||
keys, err := parseKey(key.val)
|
||||
if err != nil {
|
||||
p.raiseError(key, "invalid group array key: %s", err)
|
||||
p.raiseError(key, "invalid table array key: %s", err)
|
||||
}
|
||||
p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries
|
||||
destTree := p.tree.GetPath(keys)
|
||||
@@ -111,32 +112,32 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
|
||||
} else if target, ok := destTree.([]*TomlTree); ok && target != nil {
|
||||
array = destTree.([]*TomlTree)
|
||||
} else {
|
||||
p.raiseError(key, "key %s is already assigned and not of type group array", key)
|
||||
p.raiseError(key, "key %s is already assigned and not of type table array", key)
|
||||
}
|
||||
p.currentGroup = keys
|
||||
p.currentTable = keys
|
||||
|
||||
// add a new tree to the end of the group array
|
||||
// add a new tree to the end of the table array
|
||||
newTree := newTomlTree()
|
||||
newTree.position = startToken.Position
|
||||
array = append(array, newTree)
|
||||
p.tree.SetPath(p.currentGroup, array)
|
||||
p.tree.SetPath(p.currentTable, array)
|
||||
|
||||
// remove all keys that were children of this group array
|
||||
// remove all keys that were children of this table array
|
||||
prefix := key.val + "."
|
||||
found := false
|
||||
for ii := 0; ii < len(p.seenGroupKeys); {
|
||||
groupKey := p.seenGroupKeys[ii]
|
||||
if strings.HasPrefix(groupKey, prefix) {
|
||||
p.seenGroupKeys = append(p.seenGroupKeys[:ii], p.seenGroupKeys[ii+1:]...)
|
||||
for ii := 0; ii < len(p.seenTableKeys); {
|
||||
tableKey := p.seenTableKeys[ii]
|
||||
if strings.HasPrefix(tableKey, prefix) {
|
||||
p.seenTableKeys = append(p.seenTableKeys[:ii], p.seenTableKeys[ii+1:]...)
|
||||
} else {
|
||||
found = (groupKey == key.val)
|
||||
found = (tableKey == key.val)
|
||||
ii++
|
||||
}
|
||||
}
|
||||
|
||||
// keep this key name from use by other kinds of assignments
|
||||
if !found {
|
||||
p.seenGroupKeys = append(p.seenGroupKeys, key.val)
|
||||
p.seenTableKeys = append(p.seenTableKeys, key.val)
|
||||
}
|
||||
|
||||
// move to next parser state
|
||||
@@ -148,24 +149,24 @@ func (p *tomlParser) parseGroup() tomlParserStateFn {
|
||||
startToken := p.getToken() // discard the [
|
||||
key := p.getToken()
|
||||
if key.typ != tokenKeyGroup {
|
||||
p.raiseError(key, "unexpected token %s, was expecting a key group", key)
|
||||
p.raiseError(key, "unexpected token %s, was expecting a table key", key)
|
||||
}
|
||||
for _, item := range p.seenGroupKeys {
|
||||
for _, item := range p.seenTableKeys {
|
||||
if item == key.val {
|
||||
p.raiseError(key, "duplicated tables")
|
||||
}
|
||||
}
|
||||
|
||||
p.seenGroupKeys = append(p.seenGroupKeys, key.val)
|
||||
p.seenTableKeys = append(p.seenTableKeys, key.val)
|
||||
keys, err := parseKey(key.val)
|
||||
if err != nil {
|
||||
p.raiseError(key, "invalid group array key: %s", err)
|
||||
p.raiseError(key, "invalid table array key: %s", err)
|
||||
}
|
||||
if err := p.tree.createSubTree(keys, startToken.Position); err != nil {
|
||||
p.raiseError(key, "%s", err)
|
||||
}
|
||||
p.assume(tokenRightBracket)
|
||||
p.currentGroup = keys
|
||||
p.currentTable = keys
|
||||
return p.parseStart
|
||||
}
|
||||
|
||||
@@ -174,26 +175,26 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
|
||||
p.assume(tokenEqual)
|
||||
|
||||
value := p.parseRvalue()
|
||||
var groupKey []string
|
||||
if len(p.currentGroup) > 0 {
|
||||
groupKey = p.currentGroup
|
||||
var tableKey []string
|
||||
if len(p.currentTable) > 0 {
|
||||
tableKey = p.currentTable
|
||||
} else {
|
||||
groupKey = []string{}
|
||||
tableKey = []string{}
|
||||
}
|
||||
|
||||
// find the group to assign, looking out for arrays of groups
|
||||
// find the table to assign, looking out for arrays of tables
|
||||
var targetNode *TomlTree
|
||||
switch node := p.tree.GetPath(groupKey).(type) {
|
||||
switch node := p.tree.GetPath(tableKey).(type) {
|
||||
case []*TomlTree:
|
||||
targetNode = node[len(node)-1]
|
||||
case *TomlTree:
|
||||
targetNode = node
|
||||
default:
|
||||
p.raiseError(key, "Unknown group type for path: %s",
|
||||
strings.Join(groupKey, "."))
|
||||
p.raiseError(key, "Unknown table type for path: %s",
|
||||
strings.Join(tableKey, "."))
|
||||
}
|
||||
|
||||
// assign value to the found group
|
||||
// assign value to the found table
|
||||
keyVals, err := parseKey(key.val)
|
||||
if err != nil {
|
||||
p.raiseError(key, "%s", err)
|
||||
@@ -203,7 +204,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
|
||||
}
|
||||
keyVal := keyVals[0]
|
||||
localKey := []string{keyVal}
|
||||
finalKey := append(groupKey, keyVal)
|
||||
finalKey := append(tableKey, keyVal)
|
||||
if targetNode.GetPath(localKey) != nil {
|
||||
p.raiseError(key, "The following key was defined twice: %s",
|
||||
strings.Join(finalKey, "."))
|
||||
@@ -224,7 +225,7 @@ var numberUnderscoreInvalidRegexp *regexp.Regexp
|
||||
|
||||
func cleanupNumberToken(value string) (string, error) {
|
||||
if numberUnderscoreInvalidRegexp.MatchString(value) {
|
||||
return "", fmt.Errorf("invalid use of _ in number")
|
||||
return "", errors.New("invalid use of _ in number")
|
||||
}
|
||||
cleanedVal := strings.Replace(value, "_", "", -1)
|
||||
return cleanedVal, nil
|
||||
@@ -380,8 +381,8 @@ func parseToml(flow chan token) *TomlTree {
|
||||
flow: flow,
|
||||
tree: result,
|
||||
tokensBuffer: make([]token, 0),
|
||||
currentGroup: make([]string, 0),
|
||||
seenGroupKeys: make([]string, 0),
|
||||
currentTable: make([]string, 0),
|
||||
seenTableKeys: make([]string, 0),
|
||||
}
|
||||
parser.run()
|
||||
return result
|
||||
|
||||
+6
-6
@@ -456,7 +456,7 @@ func TestDuplicateKeys(t *testing.T) {
|
||||
|
||||
func TestEmptyIntermediateTable(t *testing.T) {
|
||||
_, err := Load("[foo..bar]")
|
||||
if err.Error() != "(1, 2): invalid group array key: empty key group" {
|
||||
if err.Error() != "(1, 2): invalid table array key: empty table key" {
|
||||
t.Error("Bad error message:", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -580,12 +580,12 @@ func TestParseKeyGroupArray(t *testing.T) {
|
||||
|
||||
func TestParseKeyGroupArrayUnfinished(t *testing.T) {
|
||||
_, err := Load("[[foo.bar]\na = 42")
|
||||
if err.Error() != "(1, 10): was expecting token [[, but got unclosed key group array instead" {
|
||||
if err.Error() != "(1, 10): was expecting token [[, but got unclosed table array key instead" {
|
||||
t.Error("Bad error message:", err.Error())
|
||||
}
|
||||
|
||||
_, err = Load("[[foo.[bar]\na = 42")
|
||||
if err.Error() != "(1, 3): unexpected token group name cannot contain ']', was expecting a key group array" {
|
||||
if err.Error() != "(1, 3): unexpected token table array key cannot contain ']', was expecting a table array key" {
|
||||
t.Error("Bad error message:", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -753,13 +753,13 @@ func TestNestedTreePosition(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInvalidGroupArray(t *testing.T) {
|
||||
_, err := Load("[key#group]\nanswer = 42")
|
||||
_, err := Load("[table#key]\nanswer = 42")
|
||||
if err == nil {
|
||||
t.Error("Should error")
|
||||
}
|
||||
|
||||
_, err = Load("[foo.[bar]\na = 42")
|
||||
if err.Error() != "(1, 2): unexpected token group name cannot contain ']', was expecting a key group" {
|
||||
if err.Error() != "(1, 2): unexpected token table key cannot contain ']', was expecting a table key" {
|
||||
t.Error("Bad error message:", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -773,7 +773,7 @@ func TestDoubleEqual(t *testing.T) {
|
||||
|
||||
func TestGroupArrayReassign(t *testing.T) {
|
||||
_, err := Load("[hello]\n[[hello]]")
|
||||
if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type group array" {
|
||||
if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type table array" {
|
||||
t.Error("Bad error message:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func toTomlValue(item interface{}, indent int) string {
|
||||
}
|
||||
|
||||
// Recursive support function for ToString()
|
||||
// Outputs a tree, using the provided keyspace to prefix group names
|
||||
// Outputs a tree, using the provided keyspace to prefix table names
|
||||
func (t *TomlTree) toToml(indent, keyspace string) string {
|
||||
resultChunks := []string{}
|
||||
for k, v := range t.values {
|
||||
|
||||
@@ -2,9 +2,9 @@ package toml
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TestTomlTreeConversionToString(t *testing.T) {
|
||||
@@ -47,15 +47,14 @@ func TestTomlTreeConversionToStringKeysOrders(t *testing.T) {
|
||||
r := strings.NewReader(stringRepr)
|
||||
toml, err := LoadReader(r)
|
||||
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error:", err)
|
||||
}
|
||||
|
||||
assertTree(t, toml, err, map[string]interface{}{
|
||||
"foobar": true,
|
||||
"bar": "baz",
|
||||
"foo": 1,
|
||||
"bar": "baz",
|
||||
"foo": 1,
|
||||
"qux": map[string]interface{}{
|
||||
"foo": 1,
|
||||
"bar": "baz2",
|
||||
@@ -151,15 +150,15 @@ func TestTomlTreeConversionToMapWithArrayOfInlineTables(t *testing.T) {
|
||||
"params": map[string]interface{}{
|
||||
"language_tabs": []interface{}{
|
||||
map[string]interface{}{
|
||||
"key": "shell",
|
||||
"key": "shell",
|
||||
"name": "Shell",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key": "ruby",
|
||||
"key": "ruby",
|
||||
"name": "Ruby",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key": "python",
|
||||
"key": "python",
|
||||
"name": "Python",
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user