OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / pelletier / go-toml / query / match.go
1 package query
2
3 import (
4         "fmt"
5         "github.com/pelletier/go-toml"
6 )
7
8 // base match
9 type matchBase struct {
10         next pathFn
11 }
12
13 func (f *matchBase) setNext(next pathFn) {
14         f.next = next
15 }
16
17 // terminating functor - gathers results
18 type terminatingFn struct {
19         // empty
20 }
21
22 func newTerminatingFn() *terminatingFn {
23         return &terminatingFn{}
24 }
25
26 func (f *terminatingFn) setNext(next pathFn) {
27         // do nothing
28 }
29
30 func (f *terminatingFn) call(node interface{}, ctx *queryContext) {
31         ctx.result.appendResult(node, ctx.lastPosition)
32 }
33
34 // match single key
35 type matchKeyFn struct {
36         matchBase
37         Name string
38 }
39
40 func newMatchKeyFn(name string) *matchKeyFn {
41         return &matchKeyFn{Name: name}
42 }
43
44 func (f *matchKeyFn) call(node interface{}, ctx *queryContext) {
45         if array, ok := node.([]*toml.Tree); ok {
46                 for _, tree := range array {
47                         item := tree.Get(f.Name)
48                         if item != nil {
49                                 ctx.lastPosition = tree.GetPosition(f.Name)
50                                 f.next.call(item, ctx)
51                         }
52                 }
53         } else if tree, ok := node.(*toml.Tree); ok {
54                 item := tree.Get(f.Name)
55                 if item != nil {
56                         ctx.lastPosition = tree.GetPosition(f.Name)
57                         f.next.call(item, ctx)
58                 }
59         }
60 }
61
62 // match single index
63 type matchIndexFn struct {
64         matchBase
65         Idx int
66 }
67
68 func newMatchIndexFn(idx int) *matchIndexFn {
69         return &matchIndexFn{Idx: idx}
70 }
71
72 func (f *matchIndexFn) call(node interface{}, ctx *queryContext) {
73         if arr, ok := node.([]interface{}); ok {
74                 if f.Idx < len(arr) && f.Idx >= 0 {
75                         if treesArray, ok := node.([]*toml.Tree); ok {
76                                 if len(treesArray) > 0 {
77                                         ctx.lastPosition = treesArray[0].Position()
78                                 }
79                         }
80                         f.next.call(arr[f.Idx], ctx)
81                 }
82         }
83 }
84
85 // filter by slicing
86 type matchSliceFn struct {
87         matchBase
88         Start, End, Step int
89 }
90
91 func newMatchSliceFn(start, end, step int) *matchSliceFn {
92         return &matchSliceFn{Start: start, End: end, Step: step}
93 }
94
95 func (f *matchSliceFn) call(node interface{}, ctx *queryContext) {
96         if arr, ok := node.([]interface{}); ok {
97                 // adjust indexes for negative values, reverse ordering
98                 realStart, realEnd := f.Start, f.End
99                 if realStart < 0 {
100                         realStart = len(arr) + realStart
101                 }
102                 if realEnd < 0 {
103                         realEnd = len(arr) + realEnd
104                 }
105                 if realEnd < realStart {
106                         realEnd, realStart = realStart, realEnd // swap
107                 }
108                 // loop and gather
109                 for idx := realStart; idx < realEnd; idx += f.Step {
110                         if treesArray, ok := node.([]*toml.Tree); ok {
111                                 if len(treesArray) > 0 {
112                                         ctx.lastPosition = treesArray[0].Position()
113                                 }
114                         }
115                         f.next.call(arr[idx], ctx)
116                 }
117         }
118 }
119
120 // match anything
121 type matchAnyFn struct {
122         matchBase
123 }
124
125 func newMatchAnyFn() *matchAnyFn {
126         return &matchAnyFn{}
127 }
128
129 func (f *matchAnyFn) call(node interface{}, ctx *queryContext) {
130         if tree, ok := node.(*toml.Tree); ok {
131                 for _, k := range tree.Keys() {
132                         v := tree.Get(k)
133                         ctx.lastPosition = tree.GetPosition(k)
134                         f.next.call(v, ctx)
135                 }
136         }
137 }
138
139 // filter through union
140 type matchUnionFn struct {
141         Union []pathFn
142 }
143
144 func (f *matchUnionFn) setNext(next pathFn) {
145         for _, fn := range f.Union {
146                 fn.setNext(next)
147         }
148 }
149
150 func (f *matchUnionFn) call(node interface{}, ctx *queryContext) {
151         for _, fn := range f.Union {
152                 fn.call(node, ctx)
153         }
154 }
155
156 // match every single last node in the tree
157 type matchRecursiveFn struct {
158         matchBase
159 }
160
161 func newMatchRecursiveFn() *matchRecursiveFn {
162         return &matchRecursiveFn{}
163 }
164
165 func (f *matchRecursiveFn) call(node interface{}, ctx *queryContext) {
166         originalPosition := ctx.lastPosition
167         if tree, ok := node.(*toml.Tree); ok {
168                 var visit func(tree *toml.Tree)
169                 visit = func(tree *toml.Tree) {
170                         for _, k := range tree.Keys() {
171                                 v := tree.Get(k)
172                                 ctx.lastPosition = tree.GetPosition(k)
173                                 f.next.call(v, ctx)
174                                 switch node := v.(type) {
175                                 case *toml.Tree:
176                                         visit(node)
177                                 case []*toml.Tree:
178                                         for _, subtree := range node {
179                                                 visit(subtree)
180                                         }
181                                 }
182                         }
183                 }
184                 ctx.lastPosition = originalPosition
185                 f.next.call(tree, ctx)
186                 visit(tree)
187         }
188 }
189
190 // match based on an externally provided functional filter
191 type matchFilterFn struct {
192         matchBase
193         Pos  toml.Position
194         Name string
195 }
196
197 func newMatchFilterFn(name string, pos toml.Position) *matchFilterFn {
198         return &matchFilterFn{Name: name, Pos: pos}
199 }
200
201 func (f *matchFilterFn) call(node interface{}, ctx *queryContext) {
202         fn, ok := (*ctx.filters)[f.Name]
203         if !ok {
204                 panic(fmt.Sprintf("%s: query context does not have filter '%s'",
205                         f.Pos.String(), f.Name))
206         }
207         switch castNode := node.(type) {
208         case *toml.Tree:
209                 for _, k := range castNode.Keys() {
210                         v := castNode.Get(k)
211                         if fn(v) {
212                                 ctx.lastPosition = castNode.GetPosition(k)
213                                 f.next.call(v, ctx)
214                         }
215                 }
216         case []*toml.Tree:
217                 for _, v := range castNode {
218                         if fn(v) {
219                                 if len(castNode) > 0 {
220                                         ctx.lastPosition = castNode[0].Position()
221                                 }
222                                 f.next.call(v, ctx)
223                         }
224                 }
225         case []interface{}:
226                 for _, v := range castNode {
227                         if fn(v) {
228                                 f.next.call(v, ctx)
229                         }
230                 }
231         }
232 }