aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/pelletier/go-toml/match.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pelletier/go-toml/match.go')
-rw-r--r--vendor/github.com/pelletier/go-toml/match.go234
1 files changed, 234 insertions, 0 deletions
diff --git a/vendor/github.com/pelletier/go-toml/match.go b/vendor/github.com/pelletier/go-toml/match.go
new file mode 100644
index 0000000..48b0f2a
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/match.go
@@ -0,0 +1,234 @@
+package toml
+
+import (
+ "fmt"
+)
+
+// support function to set positions for tomlValues
+// NOTE: this is done to allow ctx.lastPosition to indicate the start of any
+// values returned by the query engines
+func tomlValueCheck(node interface{}, ctx *queryContext) interface{} {
+ switch castNode := node.(type) {
+ case *tomlValue:
+ ctx.lastPosition = castNode.position
+ return castNode.value
+ case []*TomlTree:
+ if len(castNode) > 0 {
+ ctx.lastPosition = castNode[0].position
+ }
+ return node
+ default:
+ return node
+ }
+}
+
+// base match
+type matchBase struct {
+ next pathFn
+}
+
+func (f *matchBase) setNext(next pathFn) {
+ f.next = next
+}
+
+// terminating functor - gathers results
+type terminatingFn struct {
+ // empty
+}
+
+func newTerminatingFn() *terminatingFn {
+ return &terminatingFn{}
+}
+
+func (f *terminatingFn) setNext(next pathFn) {
+ // do nothing
+}
+
+func (f *terminatingFn) call(node interface{}, ctx *queryContext) {
+ switch castNode := node.(type) {
+ case *TomlTree:
+ ctx.result.appendResult(node, castNode.position)
+ case *tomlValue:
+ ctx.result.appendResult(node, castNode.position)
+ default:
+ // use last position for scalars
+ ctx.result.appendResult(node, ctx.lastPosition)
+ }
+}
+
+// match single key
+type matchKeyFn struct {
+ matchBase
+ Name string
+}
+
+func newMatchKeyFn(name string) *matchKeyFn {
+ return &matchKeyFn{Name: name}
+}
+
+func (f *matchKeyFn) call(node interface{}, ctx *queryContext) {
+ if array, ok := node.([]*TomlTree); ok {
+ for _, tree := range array {
+ item := tree.values[f.Name]
+ if item != nil {
+ f.next.call(item, ctx)
+ }
+ }
+ } else if tree, ok := node.(*TomlTree); ok {
+ item := tree.values[f.Name]
+ if item != nil {
+ f.next.call(item, ctx)
+ }
+ }
+}
+
+// match single index
+type matchIndexFn struct {
+ matchBase
+ Idx int
+}
+
+func newMatchIndexFn(idx int) *matchIndexFn {
+ return &matchIndexFn{Idx: idx}
+}
+
+func (f *matchIndexFn) call(node interface{}, ctx *queryContext) {
+ if arr, ok := tomlValueCheck(node, ctx).([]interface{}); ok {
+ if f.Idx < len(arr) && f.Idx >= 0 {
+ f.next.call(arr[f.Idx], ctx)
+ }
+ }
+}
+
+// filter by slicing
+type matchSliceFn struct {
+ matchBase
+ Start, End, Step int
+}
+
+func newMatchSliceFn(start, end, step int) *matchSliceFn {
+ return &matchSliceFn{Start: start, End: end, Step: step}
+}
+
+func (f *matchSliceFn) call(node interface{}, ctx *queryContext) {
+ if arr, ok := tomlValueCheck(node, ctx).([]interface{}); ok {
+ // adjust indexes for negative values, reverse ordering
+ realStart, realEnd := f.Start, f.End
+ if realStart < 0 {
+ realStart = len(arr) + realStart
+ }
+ if realEnd < 0 {
+ realEnd = len(arr) + realEnd
+ }
+ if realEnd < realStart {
+ realEnd, realStart = realStart, realEnd // swap
+ }
+ // loop and gather
+ for idx := realStart; idx < realEnd; idx += f.Step {
+ f.next.call(arr[idx], ctx)
+ }
+ }
+}
+
+// match anything
+type matchAnyFn struct {
+ matchBase
+}
+
+func newMatchAnyFn() *matchAnyFn {
+ return &matchAnyFn{}
+}
+
+func (f *matchAnyFn) call(node interface{}, ctx *queryContext) {
+ if tree, ok := node.(*TomlTree); ok {
+ for _, v := range tree.values {
+ f.next.call(v, ctx)
+ }
+ }
+}
+
+// filter through union
+type matchUnionFn struct {
+ Union []pathFn
+}
+
+func (f *matchUnionFn) setNext(next pathFn) {
+ for _, fn := range f.Union {
+ fn.setNext(next)
+ }
+}
+
+func (f *matchUnionFn) call(node interface{}, ctx *queryContext) {
+ for _, fn := range f.Union {
+ fn.call(node, ctx)
+ }
+}
+
+// match every single last node in the tree
+type matchRecursiveFn struct {
+ matchBase
+}
+
+func newMatchRecursiveFn() *matchRecursiveFn {
+ return &matchRecursiveFn{}
+}
+
+func (f *matchRecursiveFn) call(node interface{}, ctx *queryContext) {
+ if tree, ok := node.(*TomlTree); ok {
+ var visit func(tree *TomlTree)
+ visit = func(tree *TomlTree) {
+ for _, v := range tree.values {
+ f.next.call(v, ctx)
+ switch node := v.(type) {
+ case *TomlTree:
+ visit(node)
+ case []*TomlTree:
+ for _, subtree := range node {
+ visit(subtree)
+ }
+ }
+ }
+ }
+ f.next.call(tree, ctx)
+ visit(tree)
+ }
+}
+
+// match based on an externally provided functional filter
+type matchFilterFn struct {
+ matchBase
+ Pos Position
+ Name string
+}
+
+func newMatchFilterFn(name string, pos Position) *matchFilterFn {
+ return &matchFilterFn{Name: name, Pos: pos}
+}
+
+func (f *matchFilterFn) call(node interface{}, ctx *queryContext) {
+ fn, ok := (*ctx.filters)[f.Name]
+ if !ok {
+ panic(fmt.Sprintf("%s: query context does not have filter '%s'",
+ f.Pos.String(), f.Name))
+ }
+ switch castNode := tomlValueCheck(node, ctx).(type) {
+ case *TomlTree:
+ for _, v := range castNode.values {
+ if tv, ok := v.(*tomlValue); ok {
+ if fn(tv.value) {
+ f.next.call(v, ctx)
+ }
+ } else {
+ if fn(v) {
+ f.next.call(v, ctx)
+ }
+ }
+ }
+ case []interface{}:
+ for _, v := range castNode {
+ if fn(v) {
+ f.next.call(v, ctx)
+ }
+ }
+ }
+}