wip: correctness pass on the AST

This commit is contained in:
Thomas Pelletier
2021-03-28 22:12:19 -04:00
parent 829c005784
commit da21b0aecf
2 changed files with 112 additions and 4 deletions
+98
View File
@@ -0,0 +1,98 @@
package tracker
import (
"fmt"
"github.com/pelletier/go-toml/v2/internal/ast"
)
type keyKind uint8
const (
invalid keyKind = iota // also used for the root key
value
table
arrayTable
)
type key string
type builder struct {
prefix [][]byte
local [][]byte
}
func (b *builder) Reset(prefix [][]byte) {
b.prefix = prefix
b.local = b.local[:0]
}
// Computes the number of bytes required to store the full key.
func (b *builder) size() int {
size := len(b.prefix) + len(b.local) - 1
for _, p := range b.prefix {
size += len(p)
}
for _, p := range b.local {
size += len(p)
}
return size
}
func (b *builder) copy(firstJoin bool, from [][]byte, to []byte) int {
offset := 0
for i, p := range from {
if i > 0 || firstJoin {
to[offset] = 0x1E
offset++
}
copy(to[offset:], p)
offset += len(p)
}
return offset
}
func (b *builder) MakeKey() key {
k := make([]byte, b.size())
b.copy(false, b.prefix, k)
b.copy(len(b.prefix) > 0, b.local, k)
return key(k)
}
func (b *builder) Append(k []byte) {
b.local = append(b.local, k)
}
// Tracks which keys have been seen with which TOML type to flag duplicates
// and mismatches according to the spec.
type Seen struct {
keys map[key]keyKind
// scoping from the previous CheckExpression call.
current [][]byte
// key builder
builder builder
}
// CheckExpression takes a top-level node and checks that it does not contain keys
// that have been seen in previous calls, and validates that types are consistent.
func (s *Seen) CheckExpression(node ast.Node) error {
s.builder.Reset(s.current)
switch node.Kind {
case ast.KeyValue:
return s.checkKeyValue(node)
case ast.Table:
case ast.ArrayTable:
default:
panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
}
return nil
}
func (s *Seen) checkKeyValue(node ast.Node) error {
it := node.Key()
for it.Next() {
s.builder.Append(it.Node().Data)
}
}