Added Position Support to TomlTree
TomlDocument provides an optional TOML processing path where position informaiton is stored alongside a TomlTree. * Added Position struct * Revised TomlTree to contain position data * Added tomlValue to bind positions to values * Revised parser to emit position data * Revised token to use new Position struct * Added tests for new functionality * Bugfixed table array duplicate key handling * Applied gofmt to all code
This commit is contained in:
@@ -22,7 +22,7 @@ type parserStateFn func(*parser) parserStateFn
|
||||
|
||||
// Formats and panics an error message based on a token
|
||||
func (p *parser) raiseError(tok *token, msg string, args ...interface{}) {
|
||||
panic(tok.Pos() + ": " + fmt.Sprintf(msg, args...))
|
||||
panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...))
|
||||
}
|
||||
|
||||
func (p *parser) run() {
|
||||
@@ -47,10 +47,10 @@ func (p *parser) peek() *token {
|
||||
func (p *parser) assume(typ tokenType) {
|
||||
tok := p.getToken()
|
||||
if tok == nil {
|
||||
p.raiseError(tok, "was expecting token %s, but token stream is empty", tok.typ)
|
||||
p.raiseError(tok, "was expecting token %s, but token stream is empty", tok)
|
||||
}
|
||||
if tok.typ != typ {
|
||||
p.raiseError(tok, "was expecting token %s, but got %s", typ, tok.typ)
|
||||
p.raiseError(tok, "was expecting token %s, but got %s instead", typ, tok)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,9 @@ func (p *parser) getToken() *token {
|
||||
func parseStart(p *parser) parserStateFn {
|
||||
tok := p.peek()
|
||||
|
||||
// prime position data with root tree instance
|
||||
p.tree.position = tok.Position
|
||||
|
||||
// end of stream, parsing is finished
|
||||
if tok == nil {
|
||||
return nil
|
||||
@@ -91,15 +94,16 @@ func parseStart(p *parser) parserStateFn {
|
||||
}
|
||||
|
||||
func parseGroupArray(p *parser) parserStateFn {
|
||||
p.getToken() // discard the [[
|
||||
start_token := p.getToken() // discard the [[
|
||||
key := p.getToken()
|
||||
if key.typ != tokenKeyGroupArray {
|
||||
p.raiseError(key, "unexpected token %s, was expecting a key group array", key)
|
||||
}
|
||||
|
||||
// get or create group array element at the indicated part in the path
|
||||
p.currentGroup = strings.Split(key.val, ".")
|
||||
dest_tree := p.tree.GetPath(p.currentGroup)
|
||||
keys := strings.Split(key.val, ".")
|
||||
p.tree.createSubTree(keys[:len(keys)-1]) // create parent entries
|
||||
dest_tree := p.tree.GetPath(keys)
|
||||
var array []*TomlTree
|
||||
if dest_tree == nil {
|
||||
array = make([]*TomlTree, 0)
|
||||
@@ -108,14 +112,31 @@ func parseGroupArray(p *parser) parserStateFn {
|
||||
} else {
|
||||
p.raiseError(key, "key %s is already assigned and not of type group array", key)
|
||||
}
|
||||
p.currentGroup = keys
|
||||
|
||||
// add a new tree to the end of the group array
|
||||
new_tree := make(TomlTree)
|
||||
array = append(array, &new_tree)
|
||||
new_tree := newTomlTree()
|
||||
new_tree.position = start_token.Position
|
||||
array = append(array, new_tree)
|
||||
p.tree.SetPath(p.currentGroup, array)
|
||||
|
||||
// remove all keys that were children of this group 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:]...)
|
||||
} else {
|
||||
found = (groupKey == key.val)
|
||||
ii++
|
||||
}
|
||||
}
|
||||
|
||||
// keep this key name from use by other kinds of assignments
|
||||
p.seenGroupKeys = append(p.seenGroupKeys, key.val)
|
||||
if !found {
|
||||
p.seenGroupKeys = append(p.seenGroupKeys, key.val)
|
||||
}
|
||||
|
||||
// move to next parser state
|
||||
p.assume(tokenDoubleRightBracket)
|
||||
@@ -123,7 +144,7 @@ func parseGroupArray(p *parser) parserStateFn {
|
||||
}
|
||||
|
||||
func parseGroup(p *parser) parserStateFn {
|
||||
p.getToken() // discard the [
|
||||
start_token := p.getToken() // discard the [
|
||||
key := p.getToken()
|
||||
if key.typ != tokenKeyGroup {
|
||||
p.raiseError(key, "unexpected token %s, was expecting a key group", key)
|
||||
@@ -133,12 +154,16 @@ func parseGroup(p *parser) parserStateFn {
|
||||
p.raiseError(key, "duplicated tables")
|
||||
}
|
||||
}
|
||||
|
||||
p.seenGroupKeys = append(p.seenGroupKeys, key.val)
|
||||
if err := p.tree.createSubTree(key.val); err != nil {
|
||||
keys := strings.Split(key.val, ".")
|
||||
if err := p.tree.createSubTree(keys); err != nil {
|
||||
p.raiseError(key, "%s", err)
|
||||
}
|
||||
p.assume(tokenRightBracket)
|
||||
p.currentGroup = strings.Split(key.val, ".")
|
||||
p.currentGroup = keys
|
||||
target_tree := p.tree.GetPath(p.currentGroup).(*TomlTree)
|
||||
target_tree.position = start_token.Position
|
||||
return parseStart(p)
|
||||
}
|
||||
|
||||
@@ -150,7 +175,7 @@ func parseAssign(p *parser) parserStateFn {
|
||||
if len(p.currentGroup) > 0 {
|
||||
group_key = p.currentGroup
|
||||
} else {
|
||||
group_key = make([]string, 0)
|
||||
group_key = []string{}
|
||||
}
|
||||
|
||||
// find the group to assign, looking out for arrays of groups
|
||||
@@ -161,16 +186,18 @@ func parseAssign(p *parser) parserStateFn {
|
||||
case *TomlTree:
|
||||
target_node = node
|
||||
default:
|
||||
p.raiseError(key, "Unknown group type for path %s", group_key)
|
||||
p.raiseError(key, "Unknown group type for path: %s",
|
||||
strings.Join(group_key, "."))
|
||||
}
|
||||
|
||||
// assign value to the found group
|
||||
local_key := []string{key.val}
|
||||
final_key := append(group_key, key.val)
|
||||
if target_node.GetPath(local_key) != nil {
|
||||
p.raiseError(key, "the following key was defined twice: %s", strings.Join(final_key, "."))
|
||||
p.raiseError(key, "The following key was defined twice: %s",
|
||||
strings.Join(final_key, "."))
|
||||
}
|
||||
target_node.SetPath(local_key, value)
|
||||
target_node.values[key.val] = &tomlValue{value, key.Position}
|
||||
return parseStart(p)
|
||||
}
|
||||
|
||||
@@ -251,14 +278,14 @@ func parseArray(p *parser) []interface{} {
|
||||
}
|
||||
|
||||
func parse(flow chan token) *TomlTree {
|
||||
result := make(TomlTree)
|
||||
result := newTomlTree()
|
||||
parser := &parser{
|
||||
flow: flow,
|
||||
tree: &result,
|
||||
tree: result,
|
||||
tokensBuffer: make([]token, 0),
|
||||
currentGroup: make([]string, 0),
|
||||
seenGroupKeys: make([]string, 0),
|
||||
}
|
||||
parser.run()
|
||||
return parser.tree
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user