diff options
Diffstat (limited to 'vendor/github.com/jmespath/go-jmespath')
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/LICENSE | 13 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/Makefile | 44 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/README.md | 7 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/api.go | 49 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/astnodetype_string.go | 16 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/functions.go | 842 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/interpreter.go | 418 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/lexer.go | 420 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/parser.go | 603 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/toktype_string.go | 16 | ||||
-rw-r--r-- | vendor/github.com/jmespath/go-jmespath/util.go | 185 |
11 files changed, 2613 insertions, 0 deletions
diff --git a/vendor/github.com/jmespath/go-jmespath/LICENSE b/vendor/github.com/jmespath/go-jmespath/LICENSE new file mode 100644 index 0000000..b03310a --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/LICENSE | |||
@@ -0,0 +1,13 @@ | |||
1 | Copyright 2015 James Saryerwinnie | ||
2 | |||
3 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | you may not use this file except in compliance with the License. | ||
5 | You may obtain a copy of the License at | ||
6 | |||
7 | http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | |||
9 | Unless required by applicable law or agreed to in writing, software | ||
10 | distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | See the License for the specific language governing permissions and | ||
13 | limitations under the License. | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/Makefile b/vendor/github.com/jmespath/go-jmespath/Makefile new file mode 100644 index 0000000..a828d28 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/Makefile | |||
@@ -0,0 +1,44 @@ | |||
1 | |||
2 | CMD = jpgo | ||
3 | |||
4 | help: | ||
5 | @echo "Please use \`make <target>' where <target> is one of" | ||
6 | @echo " test to run all the tests" | ||
7 | @echo " build to build the library and jp executable" | ||
8 | @echo " generate to run codegen" | ||
9 | |||
10 | |||
11 | generate: | ||
12 | go generate ./... | ||
13 | |||
14 | build: | ||
15 | rm -f $(CMD) | ||
16 | go build ./... | ||
17 | rm -f cmd/$(CMD)/$(CMD) && cd cmd/$(CMD)/ && go build ./... | ||
18 | mv cmd/$(CMD)/$(CMD) . | ||
19 | |||
20 | test: | ||
21 | go test -v ./... | ||
22 | |||
23 | check: | ||
24 | go vet ./... | ||
25 | @echo "golint ./..." | ||
26 | @lint=`golint ./...`; \ | ||
27 | lint=`echo "$$lint" | grep -v "astnodetype_string.go" | grep -v "toktype_string.go"`; \ | ||
28 | echo "$$lint"; \ | ||
29 | if [ "$$lint" != "" ]; then exit 1; fi | ||
30 | |||
31 | htmlc: | ||
32 | go test -coverprofile="/tmp/jpcov" && go tool cover -html="/tmp/jpcov" && unlink /tmp/jpcov | ||
33 | |||
34 | buildfuzz: | ||
35 | go-fuzz-build github.com/jmespath/go-jmespath/fuzz | ||
36 | |||
37 | fuzz: buildfuzz | ||
38 | go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/testdata | ||
39 | |||
40 | bench: | ||
41 | go test -bench . -cpuprofile cpu.out | ||
42 | |||
43 | pprof-cpu: | ||
44 | go tool pprof ./go-jmespath.test ./cpu.out | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/README.md b/vendor/github.com/jmespath/go-jmespath/README.md new file mode 100644 index 0000000..187ef67 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/README.md | |||
@@ -0,0 +1,7 @@ | |||
1 | # go-jmespath - A JMESPath implementation in Go | ||
2 | |||
3 | [![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath) | ||
4 | |||
5 | |||
6 | |||
7 | See http://jmespath.org for more info. | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/api.go b/vendor/github.com/jmespath/go-jmespath/api.go new file mode 100644 index 0000000..9cfa988 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/api.go | |||
@@ -0,0 +1,49 @@ | |||
1 | package jmespath | ||
2 | |||
3 | import "strconv" | ||
4 | |||
5 | // JmesPath is the epresentation of a compiled JMES path query. A JmesPath is | ||
6 | // safe for concurrent use by multiple goroutines. | ||
7 | type JMESPath struct { | ||
8 | ast ASTNode | ||
9 | intr *treeInterpreter | ||
10 | } | ||
11 | |||
12 | // Compile parses a JMESPath expression and returns, if successful, a JMESPath | ||
13 | // object that can be used to match against data. | ||
14 | func Compile(expression string) (*JMESPath, error) { | ||
15 | parser := NewParser() | ||
16 | ast, err := parser.Parse(expression) | ||
17 | if err != nil { | ||
18 | return nil, err | ||
19 | } | ||
20 | jmespath := &JMESPath{ast: ast, intr: newInterpreter()} | ||
21 | return jmespath, nil | ||
22 | } | ||
23 | |||
24 | // MustCompile is like Compile but panics if the expression cannot be parsed. | ||
25 | // It simplifies safe initialization of global variables holding compiled | ||
26 | // JMESPaths. | ||
27 | func MustCompile(expression string) *JMESPath { | ||
28 | jmespath, err := Compile(expression) | ||
29 | if err != nil { | ||
30 | panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error()) | ||
31 | } | ||
32 | return jmespath | ||
33 | } | ||
34 | |||
35 | // Search evaluates a JMESPath expression against input data and returns the result. | ||
36 | func (jp *JMESPath) Search(data interface{}) (interface{}, error) { | ||
37 | return jp.intr.Execute(jp.ast, data) | ||
38 | } | ||
39 | |||
40 | // Search evaluates a JMESPath expression against input data and returns the result. | ||
41 | func Search(expression string, data interface{}) (interface{}, error) { | ||
42 | intr := newInterpreter() | ||
43 | parser := NewParser() | ||
44 | ast, err := parser.Parse(expression) | ||
45 | if err != nil { | ||
46 | return nil, err | ||
47 | } | ||
48 | return intr.Execute(ast, data) | ||
49 | } | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go b/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go new file mode 100644 index 0000000..1cd2d23 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go | |||
@@ -0,0 +1,16 @@ | |||
1 | // generated by stringer -type astNodeType; DO NOT EDIT | ||
2 | |||
3 | package jmespath | ||
4 | |||
5 | import "fmt" | ||
6 | |||
7 | const _astNodeType_name = "ASTEmptyASTComparatorASTCurrentNodeASTExpRefASTFunctionExpressionASTFieldASTFilterProjectionASTFlattenASTIdentityASTIndexASTIndexExpressionASTKeyValPairASTLiteralASTMultiSelectHashASTMultiSelectListASTOrExpressionASTAndExpressionASTNotExpressionASTPipeASTProjectionASTSubexpressionASTSliceASTValueProjection" | ||
8 | |||
9 | var _astNodeType_index = [...]uint16{0, 8, 21, 35, 44, 65, 73, 92, 102, 113, 121, 139, 152, 162, 180, 198, 213, 229, 245, 252, 265, 281, 289, 307} | ||
10 | |||
11 | func (i astNodeType) String() string { | ||
12 | if i < 0 || i >= astNodeType(len(_astNodeType_index)-1) { | ||
13 | return fmt.Sprintf("astNodeType(%d)", i) | ||
14 | } | ||
15 | return _astNodeType_name[_astNodeType_index[i]:_astNodeType_index[i+1]] | ||
16 | } | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/functions.go b/vendor/github.com/jmespath/go-jmespath/functions.go new file mode 100644 index 0000000..9b7cd89 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/functions.go | |||
@@ -0,0 +1,842 @@ | |||
1 | package jmespath | ||
2 | |||
3 | import ( | ||
4 | "encoding/json" | ||
5 | "errors" | ||
6 | "fmt" | ||
7 | "math" | ||
8 | "reflect" | ||
9 | "sort" | ||
10 | "strconv" | ||
11 | "strings" | ||
12 | "unicode/utf8" | ||
13 | ) | ||
14 | |||
15 | type jpFunction func(arguments []interface{}) (interface{}, error) | ||
16 | |||
17 | type jpType string | ||
18 | |||
19 | const ( | ||
20 | jpUnknown jpType = "unknown" | ||
21 | jpNumber jpType = "number" | ||
22 | jpString jpType = "string" | ||
23 | jpArray jpType = "array" | ||
24 | jpObject jpType = "object" | ||
25 | jpArrayNumber jpType = "array[number]" | ||
26 | jpArrayString jpType = "array[string]" | ||
27 | jpExpref jpType = "expref" | ||
28 | jpAny jpType = "any" | ||
29 | ) | ||
30 | |||
31 | type functionEntry struct { | ||
32 | name string | ||
33 | arguments []argSpec | ||
34 | handler jpFunction | ||
35 | hasExpRef bool | ||
36 | } | ||
37 | |||
38 | type argSpec struct { | ||
39 | types []jpType | ||
40 | variadic bool | ||
41 | } | ||
42 | |||
43 | type byExprString struct { | ||
44 | intr *treeInterpreter | ||
45 | node ASTNode | ||
46 | items []interface{} | ||
47 | hasError bool | ||
48 | } | ||
49 | |||
50 | func (a *byExprString) Len() int { | ||
51 | return len(a.items) | ||
52 | } | ||
53 | func (a *byExprString) Swap(i, j int) { | ||
54 | a.items[i], a.items[j] = a.items[j], a.items[i] | ||
55 | } | ||
56 | func (a *byExprString) Less(i, j int) bool { | ||
57 | first, err := a.intr.Execute(a.node, a.items[i]) | ||
58 | if err != nil { | ||
59 | a.hasError = true | ||
60 | // Return a dummy value. | ||
61 | return true | ||
62 | } | ||
63 | ith, ok := first.(string) | ||
64 | if !ok { | ||
65 | a.hasError = true | ||
66 | return true | ||
67 | } | ||
68 | second, err := a.intr.Execute(a.node, a.items[j]) | ||
69 | if err != nil { | ||
70 | a.hasError = true | ||
71 | // Return a dummy value. | ||
72 | return true | ||
73 | } | ||
74 | jth, ok := second.(string) | ||
75 | if !ok { | ||
76 | a.hasError = true | ||
77 | return true | ||
78 | } | ||
79 | return ith < jth | ||
80 | } | ||
81 | |||
82 | type byExprFloat struct { | ||
83 | intr *treeInterpreter | ||
84 | node ASTNode | ||
85 | items []interface{} | ||
86 | hasError bool | ||
87 | } | ||
88 | |||
89 | func (a *byExprFloat) Len() int { | ||
90 | return len(a.items) | ||
91 | } | ||
92 | func (a *byExprFloat) Swap(i, j int) { | ||
93 | a.items[i], a.items[j] = a.items[j], a.items[i] | ||
94 | } | ||
95 | func (a *byExprFloat) Less(i, j int) bool { | ||
96 | first, err := a.intr.Execute(a.node, a.items[i]) | ||
97 | if err != nil { | ||
98 | a.hasError = true | ||
99 | // Return a dummy value. | ||
100 | return true | ||
101 | } | ||
102 | ith, ok := first.(float64) | ||
103 | if !ok { | ||
104 | a.hasError = true | ||
105 | return true | ||
106 | } | ||
107 | second, err := a.intr.Execute(a.node, a.items[j]) | ||
108 | if err != nil { | ||
109 | a.hasError = true | ||
110 | // Return a dummy value. | ||
111 | return true | ||
112 | } | ||
113 | jth, ok := second.(float64) | ||
114 | if !ok { | ||
115 | a.hasError = true | ||
116 | return true | ||
117 | } | ||
118 | return ith < jth | ||
119 | } | ||
120 | |||
121 | type functionCaller struct { | ||
122 | functionTable map[string]functionEntry | ||
123 | } | ||
124 | |||
125 | func newFunctionCaller() *functionCaller { | ||
126 | caller := &functionCaller{} | ||
127 | caller.functionTable = map[string]functionEntry{ | ||
128 | "length": { | ||
129 | name: "length", | ||
130 | arguments: []argSpec{ | ||
131 | {types: []jpType{jpString, jpArray, jpObject}}, | ||
132 | }, | ||
133 | handler: jpfLength, | ||
134 | }, | ||
135 | "starts_with": { | ||
136 | name: "starts_with", | ||
137 | arguments: []argSpec{ | ||
138 | {types: []jpType{jpString}}, | ||
139 | {types: []jpType{jpString}}, | ||
140 | }, | ||
141 | handler: jpfStartsWith, | ||
142 | }, | ||
143 | "abs": { | ||
144 | name: "abs", | ||
145 | arguments: []argSpec{ | ||
146 | {types: []jpType{jpNumber}}, | ||
147 | }, | ||
148 | handler: jpfAbs, | ||
149 | }, | ||
150 | "avg": { | ||
151 | name: "avg", | ||
152 | arguments: []argSpec{ | ||
153 | {types: []jpType{jpArrayNumber}}, | ||
154 | }, | ||
155 | handler: jpfAvg, | ||
156 | }, | ||
157 | "ceil": { | ||
158 | name: "ceil", | ||
159 | arguments: []argSpec{ | ||
160 | {types: []jpType{jpNumber}}, | ||
161 | }, | ||
162 | handler: jpfCeil, | ||
163 | }, | ||
164 | "contains": { | ||
165 | name: "contains", | ||
166 | arguments: []argSpec{ | ||
167 | {types: []jpType{jpArray, jpString}}, | ||
168 | {types: []jpType{jpAny}}, | ||
169 | }, | ||
170 | handler: jpfContains, | ||
171 | }, | ||
172 | "ends_with": { | ||
173 | name: "ends_with", | ||
174 | arguments: []argSpec{ | ||
175 | {types: []jpType{jpString}}, | ||
176 | {types: []jpType{jpString}}, | ||
177 | }, | ||
178 | handler: jpfEndsWith, | ||
179 | }, | ||
180 | "floor": { | ||
181 | name: "floor", | ||
182 | arguments: []argSpec{ | ||
183 | {types: []jpType{jpNumber}}, | ||
184 | }, | ||
185 | handler: jpfFloor, | ||
186 | }, | ||
187 | "map": { | ||
188 | name: "amp", | ||
189 | arguments: []argSpec{ | ||
190 | {types: []jpType{jpExpref}}, | ||
191 | {types: []jpType{jpArray}}, | ||
192 | }, | ||
193 | handler: jpfMap, | ||
194 | hasExpRef: true, | ||
195 | }, | ||
196 | "max": { | ||
197 | name: "max", | ||
198 | arguments: []argSpec{ | ||
199 | {types: []jpType{jpArrayNumber, jpArrayString}}, | ||
200 | }, | ||
201 | handler: jpfMax, | ||
202 | }, | ||
203 | "merge": { | ||
204 | name: "merge", | ||
205 | arguments: []argSpec{ | ||
206 | {types: []jpType{jpObject}, variadic: true}, | ||
207 | }, | ||
208 | handler: jpfMerge, | ||
209 | }, | ||
210 | "max_by": { | ||
211 | name: "max_by", | ||
212 | arguments: []argSpec{ | ||
213 | {types: []jpType{jpArray}}, | ||
214 | {types: []jpType{jpExpref}}, | ||
215 | }, | ||
216 | handler: jpfMaxBy, | ||
217 | hasExpRef: true, | ||
218 | }, | ||
219 | "sum": { | ||
220 | name: "sum", | ||
221 | arguments: []argSpec{ | ||
222 | {types: []jpType{jpArrayNumber}}, | ||
223 | }, | ||
224 | handler: jpfSum, | ||
225 | }, | ||
226 | "min": { | ||
227 | name: "min", | ||
228 | arguments: []argSpec{ | ||
229 | {types: []jpType{jpArrayNumber, jpArrayString}}, | ||
230 | }, | ||
231 | handler: jpfMin, | ||
232 | }, | ||
233 | "min_by": { | ||
234 | name: "min_by", | ||
235 | arguments: []argSpec{ | ||
236 | {types: []jpType{jpArray}}, | ||
237 | {types: []jpType{jpExpref}}, | ||
238 | }, | ||
239 | handler: jpfMinBy, | ||
240 | hasExpRef: true, | ||
241 | }, | ||
242 | "type": { | ||
243 | name: "type", | ||
244 | arguments: []argSpec{ | ||
245 | {types: []jpType{jpAny}}, | ||
246 | }, | ||
247 | handler: jpfType, | ||
248 | }, | ||
249 | "keys": { | ||
250 | name: "keys", | ||
251 | arguments: []argSpec{ | ||
252 | {types: []jpType{jpObject}}, | ||
253 | }, | ||
254 | handler: jpfKeys, | ||
255 | }, | ||
256 | "values": { | ||
257 | name: "values", | ||
258 | arguments: []argSpec{ | ||
259 | {types: []jpType{jpObject}}, | ||
260 | }, | ||
261 | handler: jpfValues, | ||
262 | }, | ||
263 | "sort": { | ||
264 | name: "sort", | ||
265 | arguments: []argSpec{ | ||
266 | {types: []jpType{jpArrayString, jpArrayNumber}}, | ||
267 | }, | ||
268 | handler: jpfSort, | ||
269 | }, | ||
270 | "sort_by": { | ||
271 | name: "sort_by", | ||
272 | arguments: []argSpec{ | ||
273 | {types: []jpType{jpArray}}, | ||
274 | {types: []jpType{jpExpref}}, | ||
275 | }, | ||
276 | handler: jpfSortBy, | ||
277 | hasExpRef: true, | ||
278 | }, | ||
279 | "join": { | ||
280 | name: "join", | ||
281 | arguments: []argSpec{ | ||
282 | {types: []jpType{jpString}}, | ||
283 | {types: []jpType{jpArrayString}}, | ||
284 | }, | ||
285 | handler: jpfJoin, | ||
286 | }, | ||
287 | "reverse": { | ||
288 | name: "reverse", | ||
289 | arguments: []argSpec{ | ||
290 | {types: []jpType{jpArray, jpString}}, | ||
291 | }, | ||
292 | handler: jpfReverse, | ||
293 | }, | ||
294 | "to_array": { | ||
295 | name: "to_array", | ||
296 | arguments: []argSpec{ | ||
297 | {types: []jpType{jpAny}}, | ||
298 | }, | ||
299 | handler: jpfToArray, | ||
300 | }, | ||
301 | "to_string": { | ||
302 | name: "to_string", | ||
303 | arguments: []argSpec{ | ||
304 | {types: []jpType{jpAny}}, | ||
305 | }, | ||
306 | handler: jpfToString, | ||
307 | }, | ||
308 | "to_number": { | ||
309 | name: "to_number", | ||
310 | arguments: []argSpec{ | ||
311 | {types: []jpType{jpAny}}, | ||
312 | }, | ||
313 | handler: jpfToNumber, | ||
314 | }, | ||
315 | "not_null": { | ||
316 | name: "not_null", | ||
317 | arguments: []argSpec{ | ||
318 | {types: []jpType{jpAny}, variadic: true}, | ||
319 | }, | ||
320 | handler: jpfNotNull, | ||
321 | }, | ||
322 | } | ||
323 | return caller | ||
324 | } | ||
325 | |||
326 | func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) { | ||
327 | if len(e.arguments) == 0 { | ||
328 | return arguments, nil | ||
329 | } | ||
330 | if !e.arguments[len(e.arguments)-1].variadic { | ||
331 | if len(e.arguments) != len(arguments) { | ||
332 | return nil, errors.New("incorrect number of args") | ||
333 | } | ||
334 | for i, spec := range e.arguments { | ||
335 | userArg := arguments[i] | ||
336 | err := spec.typeCheck(userArg) | ||
337 | if err != nil { | ||
338 | return nil, err | ||
339 | } | ||
340 | } | ||
341 | return arguments, nil | ||
342 | } | ||
343 | if len(arguments) < len(e.arguments) { | ||
344 | return nil, errors.New("Invalid arity.") | ||
345 | } | ||
346 | return arguments, nil | ||
347 | } | ||
348 | |||
349 | func (a *argSpec) typeCheck(arg interface{}) error { | ||
350 | for _, t := range a.types { | ||
351 | switch t { | ||
352 | case jpNumber: | ||
353 | if _, ok := arg.(float64); ok { | ||
354 | return nil | ||
355 | } | ||
356 | case jpString: | ||
357 | if _, ok := arg.(string); ok { | ||
358 | return nil | ||
359 | } | ||
360 | case jpArray: | ||
361 | if isSliceType(arg) { | ||
362 | return nil | ||
363 | } | ||
364 | case jpObject: | ||
365 | if _, ok := arg.(map[string]interface{}); ok { | ||
366 | return nil | ||
367 | } | ||
368 | case jpArrayNumber: | ||
369 | if _, ok := toArrayNum(arg); ok { | ||
370 | return nil | ||
371 | } | ||
372 | case jpArrayString: | ||
373 | if _, ok := toArrayStr(arg); ok { | ||
374 | return nil | ||
375 | } | ||
376 | case jpAny: | ||
377 | return nil | ||
378 | case jpExpref: | ||
379 | if _, ok := arg.(expRef); ok { | ||
380 | return nil | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types) | ||
385 | } | ||
386 | |||
387 | func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) { | ||
388 | entry, ok := f.functionTable[name] | ||
389 | if !ok { | ||
390 | return nil, errors.New("unknown function: " + name) | ||
391 | } | ||
392 | resolvedArgs, err := entry.resolveArgs(arguments) | ||
393 | if err != nil { | ||
394 | return nil, err | ||
395 | } | ||
396 | if entry.hasExpRef { | ||
397 | var extra []interface{} | ||
398 | extra = append(extra, intr) | ||
399 | resolvedArgs = append(extra, resolvedArgs...) | ||
400 | } | ||
401 | return entry.handler(resolvedArgs) | ||
402 | } | ||
403 | |||
404 | func jpfAbs(arguments []interface{}) (interface{}, error) { | ||
405 | num := arguments[0].(float64) | ||
406 | return math.Abs(num), nil | ||
407 | } | ||
408 | |||
409 | func jpfLength(arguments []interface{}) (interface{}, error) { | ||
410 | arg := arguments[0] | ||
411 | if c, ok := arg.(string); ok { | ||
412 | return float64(utf8.RuneCountInString(c)), nil | ||
413 | } else if isSliceType(arg) { | ||
414 | v := reflect.ValueOf(arg) | ||
415 | return float64(v.Len()), nil | ||
416 | } else if c, ok := arg.(map[string]interface{}); ok { | ||
417 | return float64(len(c)), nil | ||
418 | } | ||
419 | return nil, errors.New("could not compute length()") | ||
420 | } | ||
421 | |||
422 | func jpfStartsWith(arguments []interface{}) (interface{}, error) { | ||
423 | search := arguments[0].(string) | ||
424 | prefix := arguments[1].(string) | ||
425 | return strings.HasPrefix(search, prefix), nil | ||
426 | } | ||
427 | |||
428 | func jpfAvg(arguments []interface{}) (interface{}, error) { | ||
429 | // We've already type checked the value so we can safely use | ||
430 | // type assertions. | ||
431 | args := arguments[0].([]interface{}) | ||
432 | length := float64(len(args)) | ||
433 | numerator := 0.0 | ||
434 | for _, n := range args { | ||
435 | numerator += n.(float64) | ||
436 | } | ||
437 | return numerator / length, nil | ||
438 | } | ||
439 | func jpfCeil(arguments []interface{}) (interface{}, error) { | ||
440 | val := arguments[0].(float64) | ||
441 | return math.Ceil(val), nil | ||
442 | } | ||
443 | func jpfContains(arguments []interface{}) (interface{}, error) { | ||
444 | search := arguments[0] | ||
445 | el := arguments[1] | ||
446 | if searchStr, ok := search.(string); ok { | ||
447 | if elStr, ok := el.(string); ok { | ||
448 | return strings.Index(searchStr, elStr) != -1, nil | ||
449 | } | ||
450 | return false, nil | ||
451 | } | ||
452 | // Otherwise this is a generic contains for []interface{} | ||
453 | general := search.([]interface{}) | ||
454 | for _, item := range general { | ||
455 | if item == el { | ||
456 | return true, nil | ||
457 | } | ||
458 | } | ||
459 | return false, nil | ||
460 | } | ||
461 | func jpfEndsWith(arguments []interface{}) (interface{}, error) { | ||
462 | search := arguments[0].(string) | ||
463 | suffix := arguments[1].(string) | ||
464 | return strings.HasSuffix(search, suffix), nil | ||
465 | } | ||
466 | func jpfFloor(arguments []interface{}) (interface{}, error) { | ||
467 | val := arguments[0].(float64) | ||
468 | return math.Floor(val), nil | ||
469 | } | ||
470 | func jpfMap(arguments []interface{}) (interface{}, error) { | ||
471 | intr := arguments[0].(*treeInterpreter) | ||
472 | exp := arguments[1].(expRef) | ||
473 | node := exp.ref | ||
474 | arr := arguments[2].([]interface{}) | ||
475 | mapped := make([]interface{}, 0, len(arr)) | ||
476 | for _, value := range arr { | ||
477 | current, err := intr.Execute(node, value) | ||
478 | if err != nil { | ||
479 | return nil, err | ||
480 | } | ||
481 | mapped = append(mapped, current) | ||
482 | } | ||
483 | return mapped, nil | ||
484 | } | ||
485 | func jpfMax(arguments []interface{}) (interface{}, error) { | ||
486 | if items, ok := toArrayNum(arguments[0]); ok { | ||
487 | if len(items) == 0 { | ||
488 | return nil, nil | ||
489 | } | ||
490 | if len(items) == 1 { | ||
491 | return items[0], nil | ||
492 | } | ||
493 | best := items[0] | ||
494 | for _, item := range items[1:] { | ||
495 | if item > best { | ||
496 | best = item | ||
497 | } | ||
498 | } | ||
499 | return best, nil | ||
500 | } | ||
501 | // Otherwise we're dealing with a max() of strings. | ||
502 | items, _ := toArrayStr(arguments[0]) | ||
503 | if len(items) == 0 { | ||
504 | return nil, nil | ||
505 | } | ||
506 | if len(items) == 1 { | ||
507 | return items[0], nil | ||
508 | } | ||
509 | best := items[0] | ||
510 | for _, item := range items[1:] { | ||
511 | if item > best { | ||
512 | best = item | ||
513 | } | ||
514 | } | ||
515 | return best, nil | ||
516 | } | ||
517 | func jpfMerge(arguments []interface{}) (interface{}, error) { | ||
518 | final := make(map[string]interface{}) | ||
519 | for _, m := range arguments { | ||
520 | mapped := m.(map[string]interface{}) | ||
521 | for key, value := range mapped { | ||
522 | final[key] = value | ||
523 | } | ||
524 | } | ||
525 | return final, nil | ||
526 | } | ||
527 | func jpfMaxBy(arguments []interface{}) (interface{}, error) { | ||
528 | intr := arguments[0].(*treeInterpreter) | ||
529 | arr := arguments[1].([]interface{}) | ||
530 | exp := arguments[2].(expRef) | ||
531 | node := exp.ref | ||
532 | if len(arr) == 0 { | ||
533 | return nil, nil | ||
534 | } else if len(arr) == 1 { | ||
535 | return arr[0], nil | ||
536 | } | ||
537 | start, err := intr.Execute(node, arr[0]) | ||
538 | if err != nil { | ||
539 | return nil, err | ||
540 | } | ||
541 | switch t := start.(type) { | ||
542 | case float64: | ||
543 | bestVal := t | ||
544 | bestItem := arr[0] | ||
545 | for _, item := range arr[1:] { | ||
546 | result, err := intr.Execute(node, item) | ||
547 | if err != nil { | ||
548 | return nil, err | ||
549 | } | ||
550 | current, ok := result.(float64) | ||
551 | if !ok { | ||
552 | return nil, errors.New("invalid type, must be number") | ||
553 | } | ||
554 | if current > bestVal { | ||
555 | bestVal = current | ||
556 | bestItem = item | ||
557 | } | ||
558 | } | ||
559 | return bestItem, nil | ||
560 | case string: | ||
561 | bestVal := t | ||
562 | bestItem := arr[0] | ||
563 | for _, item := range arr[1:] { | ||
564 | result, err := intr.Execute(node, item) | ||
565 | if err != nil { | ||
566 | return nil, err | ||
567 | } | ||
568 | current, ok := result.(string) | ||
569 | if !ok { | ||
570 | return nil, errors.New("invalid type, must be string") | ||
571 | } | ||
572 | if current > bestVal { | ||
573 | bestVal = current | ||
574 | bestItem = item | ||
575 | } | ||
576 | } | ||
577 | return bestItem, nil | ||
578 | default: | ||
579 | return nil, errors.New("invalid type, must be number of string") | ||
580 | } | ||
581 | } | ||
582 | func jpfSum(arguments []interface{}) (interface{}, error) { | ||
583 | items, _ := toArrayNum(arguments[0]) | ||
584 | sum := 0.0 | ||
585 | for _, item := range items { | ||
586 | sum += item | ||
587 | } | ||
588 | return sum, nil | ||
589 | } | ||
590 | |||
591 | func jpfMin(arguments []interface{}) (interface{}, error) { | ||
592 | if items, ok := toArrayNum(arguments[0]); ok { | ||
593 | if len(items) == 0 { | ||
594 | return nil, nil | ||
595 | } | ||
596 | if len(items) == 1 { | ||
597 | return items[0], nil | ||
598 | } | ||
599 | best := items[0] | ||
600 | for _, item := range items[1:] { | ||
601 | if item < best { | ||
602 | best = item | ||
603 | } | ||
604 | } | ||
605 | return best, nil | ||
606 | } | ||
607 | items, _ := toArrayStr(arguments[0]) | ||
608 | if len(items) == 0 { | ||
609 | return nil, nil | ||
610 | } | ||
611 | if len(items) == 1 { | ||
612 | return items[0], nil | ||
613 | } | ||
614 | best := items[0] | ||
615 | for _, item := range items[1:] { | ||
616 | if item < best { | ||
617 | best = item | ||
618 | } | ||
619 | } | ||
620 | return best, nil | ||
621 | } | ||
622 | |||
623 | func jpfMinBy(arguments []interface{}) (interface{}, error) { | ||
624 | intr := arguments[0].(*treeInterpreter) | ||
625 | arr := arguments[1].([]interface{}) | ||
626 | exp := arguments[2].(expRef) | ||
627 | node := exp.ref | ||
628 | if len(arr) == 0 { | ||
629 | return nil, nil | ||
630 | } else if len(arr) == 1 { | ||
631 | return arr[0], nil | ||
632 | } | ||
633 | start, err := intr.Execute(node, arr[0]) | ||
634 | if err != nil { | ||
635 | return nil, err | ||
636 | } | ||
637 | if t, ok := start.(float64); ok { | ||
638 | bestVal := t | ||
639 | bestItem := arr[0] | ||
640 | for _, item := range arr[1:] { | ||
641 | result, err := intr.Execute(node, item) | ||
642 | if err != nil { | ||
643 | return nil, err | ||
644 | } | ||
645 | current, ok := result.(float64) | ||
646 | if !ok { | ||
647 | return nil, errors.New("invalid type, must be number") | ||
648 | } | ||
649 | if current < bestVal { | ||
650 | bestVal = current | ||
651 | bestItem = item | ||
652 | } | ||
653 | } | ||
654 | return bestItem, nil | ||
655 | } else if t, ok := start.(string); ok { | ||
656 | bestVal := t | ||
657 | bestItem := arr[0] | ||
658 | for _, item := range arr[1:] { | ||
659 | result, err := intr.Execute(node, item) | ||
660 | if err != nil { | ||
661 | return nil, err | ||
662 | } | ||
663 | current, ok := result.(string) | ||
664 | if !ok { | ||
665 | return nil, errors.New("invalid type, must be string") | ||
666 | } | ||
667 | if current < bestVal { | ||
668 | bestVal = current | ||
669 | bestItem = item | ||
670 | } | ||
671 | } | ||
672 | return bestItem, nil | ||
673 | } else { | ||
674 | return nil, errors.New("invalid type, must be number of string") | ||
675 | } | ||
676 | } | ||
677 | func jpfType(arguments []interface{}) (interface{}, error) { | ||
678 | arg := arguments[0] | ||
679 | if _, ok := arg.(float64); ok { | ||
680 | return "number", nil | ||
681 | } | ||
682 | if _, ok := arg.(string); ok { | ||
683 | return "string", nil | ||
684 | } | ||
685 | if _, ok := arg.([]interface{}); ok { | ||
686 | return "array", nil | ||
687 | } | ||
688 | if _, ok := arg.(map[string]interface{}); ok { | ||
689 | return "object", nil | ||
690 | } | ||
691 | if arg == nil { | ||
692 | return "null", nil | ||
693 | } | ||
694 | if arg == true || arg == false { | ||
695 | return "boolean", nil | ||
696 | } | ||
697 | return nil, errors.New("unknown type") | ||
698 | } | ||
699 | func jpfKeys(arguments []interface{}) (interface{}, error) { | ||
700 | arg := arguments[0].(map[string]interface{}) | ||
701 | collected := make([]interface{}, 0, len(arg)) | ||
702 | for key := range arg { | ||
703 | collected = append(collected, key) | ||
704 | } | ||
705 | return collected, nil | ||
706 | } | ||
707 | func jpfValues(arguments []interface{}) (interface{}, error) { | ||
708 | arg := arguments[0].(map[string]interface{}) | ||
709 | collected := make([]interface{}, 0, len(arg)) | ||
710 | for _, value := range arg { | ||
711 | collected = append(collected, value) | ||
712 | } | ||
713 | return collected, nil | ||
714 | } | ||
715 | func jpfSort(arguments []interface{}) (interface{}, error) { | ||
716 | if items, ok := toArrayNum(arguments[0]); ok { | ||
717 | d := sort.Float64Slice(items) | ||
718 | sort.Stable(d) | ||
719 | final := make([]interface{}, len(d)) | ||
720 | for i, val := range d { | ||
721 | final[i] = val | ||
722 | } | ||
723 | return final, nil | ||
724 | } | ||
725 | // Otherwise we're dealing with sort()'ing strings. | ||
726 | items, _ := toArrayStr(arguments[0]) | ||
727 | d := sort.StringSlice(items) | ||
728 | sort.Stable(d) | ||
729 | final := make([]interface{}, len(d)) | ||
730 | for i, val := range d { | ||
731 | final[i] = val | ||
732 | } | ||
733 | return final, nil | ||
734 | } | ||
735 | func jpfSortBy(arguments []interface{}) (interface{}, error) { | ||
736 | intr := arguments[0].(*treeInterpreter) | ||
737 | arr := arguments[1].([]interface{}) | ||
738 | exp := arguments[2].(expRef) | ||
739 | node := exp.ref | ||
740 | if len(arr) == 0 { | ||
741 | return arr, nil | ||
742 | } else if len(arr) == 1 { | ||
743 | return arr, nil | ||
744 | } | ||
745 | start, err := intr.Execute(node, arr[0]) | ||
746 | if err != nil { | ||
747 | return nil, err | ||
748 | } | ||
749 | if _, ok := start.(float64); ok { | ||
750 | sortable := &byExprFloat{intr, node, arr, false} | ||
751 | sort.Stable(sortable) | ||
752 | if sortable.hasError { | ||
753 | return nil, errors.New("error in sort_by comparison") | ||
754 | } | ||
755 | return arr, nil | ||
756 | } else if _, ok := start.(string); ok { | ||
757 | sortable := &byExprString{intr, node, arr, false} | ||
758 | sort.Stable(sortable) | ||
759 | if sortable.hasError { | ||
760 | return nil, errors.New("error in sort_by comparison") | ||
761 | } | ||
762 | return arr, nil | ||
763 | } else { | ||
764 | return nil, errors.New("invalid type, must be number of string") | ||
765 | } | ||
766 | } | ||
767 | func jpfJoin(arguments []interface{}) (interface{}, error) { | ||
768 | sep := arguments[0].(string) | ||
769 | // We can't just do arguments[1].([]string), we have to | ||
770 | // manually convert each item to a string. | ||
771 | arrayStr := []string{} | ||
772 | for _, item := range arguments[1].([]interface{}) { | ||
773 | arrayStr = append(arrayStr, item.(string)) | ||
774 | } | ||
775 | return strings.Join(arrayStr, sep), nil | ||
776 | } | ||
777 | func jpfReverse(arguments []interface{}) (interface{}, error) { | ||
778 | if s, ok := arguments[0].(string); ok { | ||
779 | r := []rune(s) | ||
780 | for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { | ||
781 | r[i], r[j] = r[j], r[i] | ||
782 | } | ||
783 | return string(r), nil | ||
784 | } | ||
785 | items := arguments[0].([]interface{}) | ||
786 | length := len(items) | ||
787 | reversed := make([]interface{}, length) | ||
788 | for i, item := range items { | ||
789 | reversed[length-(i+1)] = item | ||
790 | } | ||
791 | return reversed, nil | ||
792 | } | ||
793 | func jpfToArray(arguments []interface{}) (interface{}, error) { | ||
794 | if _, ok := arguments[0].([]interface{}); ok { | ||
795 | return arguments[0], nil | ||
796 | } | ||
797 | return arguments[:1:1], nil | ||
798 | } | ||
799 | func jpfToString(arguments []interface{}) (interface{}, error) { | ||
800 | if v, ok := arguments[0].(string); ok { | ||
801 | return v, nil | ||
802 | } | ||
803 | result, err := json.Marshal(arguments[0]) | ||
804 | if err != nil { | ||
805 | return nil, err | ||
806 | } | ||
807 | return string(result), nil | ||
808 | } | ||
809 | func jpfToNumber(arguments []interface{}) (interface{}, error) { | ||
810 | arg := arguments[0] | ||
811 | if v, ok := arg.(float64); ok { | ||
812 | return v, nil | ||
813 | } | ||
814 | if v, ok := arg.(string); ok { | ||
815 | conv, err := strconv.ParseFloat(v, 64) | ||
816 | if err != nil { | ||
817 | return nil, nil | ||
818 | } | ||
819 | return conv, nil | ||
820 | } | ||
821 | if _, ok := arg.([]interface{}); ok { | ||
822 | return nil, nil | ||
823 | } | ||
824 | if _, ok := arg.(map[string]interface{}); ok { | ||
825 | return nil, nil | ||
826 | } | ||
827 | if arg == nil { | ||
828 | return nil, nil | ||
829 | } | ||
830 | if arg == true || arg == false { | ||
831 | return nil, nil | ||
832 | } | ||
833 | return nil, errors.New("unknown type") | ||
834 | } | ||
835 | func jpfNotNull(arguments []interface{}) (interface{}, error) { | ||
836 | for _, arg := range arguments { | ||
837 | if arg != nil { | ||
838 | return arg, nil | ||
839 | } | ||
840 | } | ||
841 | return nil, nil | ||
842 | } | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/interpreter.go b/vendor/github.com/jmespath/go-jmespath/interpreter.go new file mode 100644 index 0000000..13c7460 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/interpreter.go | |||
@@ -0,0 +1,418 @@ | |||
1 | package jmespath | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "reflect" | ||
6 | "unicode" | ||
7 | "unicode/utf8" | ||
8 | ) | ||
9 | |||
10 | /* This is a tree based interpreter. It walks the AST and directly | ||
11 | interprets the AST to search through a JSON document. | ||
12 | */ | ||
13 | |||
14 | type treeInterpreter struct { | ||
15 | fCall *functionCaller | ||
16 | } | ||
17 | |||
18 | func newInterpreter() *treeInterpreter { | ||
19 | interpreter := treeInterpreter{} | ||
20 | interpreter.fCall = newFunctionCaller() | ||
21 | return &interpreter | ||
22 | } | ||
23 | |||
24 | type expRef struct { | ||
25 | ref ASTNode | ||
26 | } | ||
27 | |||
28 | // Execute takes an ASTNode and input data and interprets the AST directly. | ||
29 | // It will produce the result of applying the JMESPath expression associated | ||
30 | // with the ASTNode to the input data "value". | ||
31 | func (intr *treeInterpreter) Execute(node ASTNode, value interface{}) (interface{}, error) { | ||
32 | switch node.nodeType { | ||
33 | case ASTComparator: | ||
34 | left, err := intr.Execute(node.children[0], value) | ||
35 | if err != nil { | ||
36 | return nil, err | ||
37 | } | ||
38 | right, err := intr.Execute(node.children[1], value) | ||
39 | if err != nil { | ||
40 | return nil, err | ||
41 | } | ||
42 | switch node.value { | ||
43 | case tEQ: | ||
44 | return objsEqual(left, right), nil | ||
45 | case tNE: | ||
46 | return !objsEqual(left, right), nil | ||
47 | } | ||
48 | leftNum, ok := left.(float64) | ||
49 | if !ok { | ||
50 | return nil, nil | ||
51 | } | ||
52 | rightNum, ok := right.(float64) | ||
53 | if !ok { | ||
54 | return nil, nil | ||
55 | } | ||
56 | switch node.value { | ||
57 | case tGT: | ||
58 | return leftNum > rightNum, nil | ||
59 | case tGTE: | ||
60 | return leftNum >= rightNum, nil | ||
61 | case tLT: | ||
62 | return leftNum < rightNum, nil | ||
63 | case tLTE: | ||
64 | return leftNum <= rightNum, nil | ||
65 | } | ||
66 | case ASTExpRef: | ||
67 | return expRef{ref: node.children[0]}, nil | ||
68 | case ASTFunctionExpression: | ||
69 | resolvedArgs := []interface{}{} | ||
70 | for _, arg := range node.children { | ||
71 | current, err := intr.Execute(arg, value) | ||
72 | if err != nil { | ||
73 | return nil, err | ||
74 | } | ||
75 | resolvedArgs = append(resolvedArgs, current) | ||
76 | } | ||
77 | return intr.fCall.CallFunction(node.value.(string), resolvedArgs, intr) | ||
78 | case ASTField: | ||
79 | if m, ok := value.(map[string]interface{}); ok { | ||
80 | key := node.value.(string) | ||
81 | return m[key], nil | ||
82 | } | ||
83 | return intr.fieldFromStruct(node.value.(string), value) | ||
84 | case ASTFilterProjection: | ||
85 | left, err := intr.Execute(node.children[0], value) | ||
86 | if err != nil { | ||
87 | return nil, nil | ||
88 | } | ||
89 | sliceType, ok := left.([]interface{}) | ||
90 | if !ok { | ||
91 | if isSliceType(left) { | ||
92 | return intr.filterProjectionWithReflection(node, left) | ||
93 | } | ||
94 | return nil, nil | ||
95 | } | ||
96 | compareNode := node.children[2] | ||
97 | collected := []interface{}{} | ||
98 | for _, element := range sliceType { | ||
99 | result, err := intr.Execute(compareNode, element) | ||
100 | if err != nil { | ||
101 | return nil, err | ||
102 | } | ||
103 | if !isFalse(result) { | ||
104 | current, err := intr.Execute(node.children[1], element) | ||
105 | if err != nil { | ||
106 | return nil, err | ||
107 | } | ||
108 | if current != nil { | ||
109 | collected = append(collected, current) | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | return collected, nil | ||
114 | case ASTFlatten: | ||
115 | left, err := intr.Execute(node.children[0], value) | ||
116 | if err != nil { | ||
117 | return nil, nil | ||
118 | } | ||
119 | sliceType, ok := left.([]interface{}) | ||
120 | if !ok { | ||
121 | // If we can't type convert to []interface{}, there's | ||
122 | // a chance this could still work via reflection if we're | ||
123 | // dealing with user provided types. | ||
124 | if isSliceType(left) { | ||
125 | return intr.flattenWithReflection(left) | ||
126 | } | ||
127 | return nil, nil | ||
128 | } | ||
129 | flattened := []interface{}{} | ||
130 | for _, element := range sliceType { | ||
131 | if elementSlice, ok := element.([]interface{}); ok { | ||
132 | flattened = append(flattened, elementSlice...) | ||
133 | } else if isSliceType(element) { | ||
134 | reflectFlat := []interface{}{} | ||
135 | v := reflect.ValueOf(element) | ||
136 | for i := 0; i < v.Len(); i++ { | ||
137 | reflectFlat = append(reflectFlat, v.Index(i).Interface()) | ||
138 | } | ||
139 | flattened = append(flattened, reflectFlat...) | ||
140 | } else { | ||
141 | flattened = append(flattened, element) | ||
142 | } | ||
143 | } | ||
144 | return flattened, nil | ||
145 | case ASTIdentity, ASTCurrentNode: | ||
146 | return value, nil | ||
147 | case ASTIndex: | ||
148 | if sliceType, ok := value.([]interface{}); ok { | ||
149 | index := node.value.(int) | ||
150 | if index < 0 { | ||
151 | index += len(sliceType) | ||
152 | } | ||
153 | if index < len(sliceType) && index >= 0 { | ||
154 | return sliceType[index], nil | ||
155 | } | ||
156 | return nil, nil | ||
157 | } | ||
158 | // Otherwise try via reflection. | ||
159 | rv := reflect.ValueOf(value) | ||
160 | if rv.Kind() == reflect.Slice { | ||
161 | index := node.value.(int) | ||
162 | if index < 0 { | ||
163 | index += rv.Len() | ||
164 | } | ||
165 | if index < rv.Len() && index >= 0 { | ||
166 | v := rv.Index(index) | ||
167 | return v.Interface(), nil | ||
168 | } | ||
169 | } | ||
170 | return nil, nil | ||
171 | case ASTKeyValPair: | ||
172 | return intr.Execute(node.children[0], value) | ||
173 | case ASTLiteral: | ||
174 | return node.value, nil | ||
175 | case ASTMultiSelectHash: | ||
176 | if value == nil { | ||
177 | return nil, nil | ||
178 | } | ||
179 | collected := make(map[string]interface{}) | ||
180 | for _, child := range node.children { | ||
181 | current, err := intr.Execute(child, value) | ||
182 | if err != nil { | ||
183 | return nil, err | ||
184 | } | ||
185 | key := child.value.(string) | ||
186 | collected[key] = current | ||
187 | } | ||
188 | return collected, nil | ||
189 | case ASTMultiSelectList: | ||
190 | if value == nil { | ||
191 | return nil, nil | ||
192 | } | ||
193 | collected := []interface{}{} | ||
194 | for _, child := range node.children { | ||
195 | current, err := intr.Execute(child, value) | ||
196 | if err != nil { | ||
197 | return nil, err | ||
198 | } | ||
199 | collected = append(collected, current) | ||
200 | } | ||
201 | return collected, nil | ||
202 | case ASTOrExpression: | ||
203 | matched, err := intr.Execute(node.children[0], value) | ||
204 | if err != nil { | ||
205 | return nil, err | ||
206 | } | ||
207 | if isFalse(matched) { | ||
208 | matched, err = intr.Execute(node.children[1], value) | ||
209 | if err != nil { | ||
210 | return nil, err | ||
211 | } | ||
212 | } | ||
213 | return matched, nil | ||
214 | case ASTAndExpression: | ||
215 | matched, err := intr.Execute(node.children[0], value) | ||
216 | if err != nil { | ||
217 | return nil, err | ||
218 | } | ||
219 | if isFalse(matched) { | ||
220 | return matched, nil | ||
221 | } | ||
222 | return intr.Execute(node.children[1], value) | ||
223 | case ASTNotExpression: | ||
224 | matched, err := intr.Execute(node.children[0], value) | ||
225 | if err != nil { | ||
226 | return nil, err | ||
227 | } | ||
228 | if isFalse(matched) { | ||
229 | return true, nil | ||
230 | } | ||
231 | return false, nil | ||
232 | case ASTPipe: | ||
233 | result := value | ||
234 | var err error | ||
235 | for _, child := range node.children { | ||
236 | result, err = intr.Execute(child, result) | ||
237 | if err != nil { | ||
238 | return nil, err | ||
239 | } | ||
240 | } | ||
241 | return result, nil | ||
242 | case ASTProjection: | ||
243 | left, err := intr.Execute(node.children[0], value) | ||
244 | if err != nil { | ||
245 | return nil, err | ||
246 | } | ||
247 | sliceType, ok := left.([]interface{}) | ||
248 | if !ok { | ||
249 | if isSliceType(left) { | ||
250 | return intr.projectWithReflection(node, left) | ||
251 | } | ||
252 | return nil, nil | ||
253 | } | ||
254 | collected := []interface{}{} | ||
255 | var current interface{} | ||
256 | for _, element := range sliceType { | ||
257 | current, err = intr.Execute(node.children[1], element) | ||
258 | if err != nil { | ||
259 | return nil, err | ||
260 | } | ||
261 | if current != nil { | ||
262 | collected = append(collected, current) | ||
263 | } | ||
264 | } | ||
265 | return collected, nil | ||
266 | case ASTSubexpression, ASTIndexExpression: | ||
267 | left, err := intr.Execute(node.children[0], value) | ||
268 | if err != nil { | ||
269 | return nil, err | ||
270 | } | ||
271 | return intr.Execute(node.children[1], left) | ||
272 | case ASTSlice: | ||
273 | sliceType, ok := value.([]interface{}) | ||
274 | if !ok { | ||
275 | if isSliceType(value) { | ||
276 | return intr.sliceWithReflection(node, value) | ||
277 | } | ||
278 | return nil, nil | ||
279 | } | ||
280 | parts := node.value.([]*int) | ||
281 | sliceParams := make([]sliceParam, 3) | ||
282 | for i, part := range parts { | ||
283 | if part != nil { | ||
284 | sliceParams[i].Specified = true | ||
285 | sliceParams[i].N = *part | ||
286 | } | ||
287 | } | ||
288 | return slice(sliceType, sliceParams) | ||
289 | case ASTValueProjection: | ||
290 | left, err := intr.Execute(node.children[0], value) | ||
291 | if err != nil { | ||
292 | return nil, nil | ||
293 | } | ||
294 | mapType, ok := left.(map[string]interface{}) | ||
295 | if !ok { | ||
296 | return nil, nil | ||
297 | } | ||
298 | values := make([]interface{}, len(mapType)) | ||
299 | for _, value := range mapType { | ||
300 | values = append(values, value) | ||
301 | } | ||
302 | collected := []interface{}{} | ||
303 | for _, element := range values { | ||
304 | current, err := intr.Execute(node.children[1], element) | ||
305 | if err != nil { | ||
306 | return nil, err | ||
307 | } | ||
308 | if current != nil { | ||
309 | collected = append(collected, current) | ||
310 | } | ||
311 | } | ||
312 | return collected, nil | ||
313 | } | ||
314 | return nil, errors.New("Unknown AST node: " + node.nodeType.String()) | ||
315 | } | ||
316 | |||
317 | func (intr *treeInterpreter) fieldFromStruct(key string, value interface{}) (interface{}, error) { | ||
318 | rv := reflect.ValueOf(value) | ||
319 | first, n := utf8.DecodeRuneInString(key) | ||
320 | fieldName := string(unicode.ToUpper(first)) + key[n:] | ||
321 | if rv.Kind() == reflect.Struct { | ||
322 | v := rv.FieldByName(fieldName) | ||
323 | if !v.IsValid() { | ||
324 | return nil, nil | ||
325 | } | ||
326 | return v.Interface(), nil | ||
327 | } else if rv.Kind() == reflect.Ptr { | ||
328 | // Handle multiple levels of indirection? | ||
329 | if rv.IsNil() { | ||
330 | return nil, nil | ||
331 | } | ||
332 | rv = rv.Elem() | ||
333 | v := rv.FieldByName(fieldName) | ||
334 | if !v.IsValid() { | ||
335 | return nil, nil | ||
336 | } | ||
337 | return v.Interface(), nil | ||
338 | } | ||
339 | return nil, nil | ||
340 | } | ||
341 | |||
342 | func (intr *treeInterpreter) flattenWithReflection(value interface{}) (interface{}, error) { | ||
343 | v := reflect.ValueOf(value) | ||
344 | flattened := []interface{}{} | ||
345 | for i := 0; i < v.Len(); i++ { | ||
346 | element := v.Index(i).Interface() | ||
347 | if reflect.TypeOf(element).Kind() == reflect.Slice { | ||
348 | // Then insert the contents of the element | ||
349 | // slice into the flattened slice, | ||
350 | // i.e flattened = append(flattened, mySlice...) | ||
351 | elementV := reflect.ValueOf(element) | ||
352 | for j := 0; j < elementV.Len(); j++ { | ||
353 | flattened = append( | ||
354 | flattened, elementV.Index(j).Interface()) | ||
355 | } | ||
356 | } else { | ||
357 | flattened = append(flattened, element) | ||
358 | } | ||
359 | } | ||
360 | return flattened, nil | ||
361 | } | ||
362 | |||
363 | func (intr *treeInterpreter) sliceWithReflection(node ASTNode, value interface{}) (interface{}, error) { | ||
364 | v := reflect.ValueOf(value) | ||
365 | parts := node.value.([]*int) | ||
366 | sliceParams := make([]sliceParam, 3) | ||
367 | for i, part := range parts { | ||
368 | if part != nil { | ||
369 | sliceParams[i].Specified = true | ||
370 | sliceParams[i].N = *part | ||
371 | } | ||
372 | } | ||
373 | final := []interface{}{} | ||
374 | for i := 0; i < v.Len(); i++ { | ||
375 | element := v.Index(i).Interface() | ||
376 | final = append(final, element) | ||
377 | } | ||
378 | return slice(final, sliceParams) | ||
379 | } | ||
380 | |||
381 | func (intr *treeInterpreter) filterProjectionWithReflection(node ASTNode, value interface{}) (interface{}, error) { | ||
382 | compareNode := node.children[2] | ||
383 | collected := []interface{}{} | ||
384 | v := reflect.ValueOf(value) | ||
385 | for i := 0; i < v.Len(); i++ { | ||
386 | element := v.Index(i).Interface() | ||
387 | result, err := intr.Execute(compareNode, element) | ||
388 | if err != nil { | ||
389 | return nil, err | ||
390 | } | ||
391 | if !isFalse(result) { | ||
392 | current, err := intr.Execute(node.children[1], element) | ||
393 | if err != nil { | ||
394 | return nil, err | ||
395 | } | ||
396 | if current != nil { | ||
397 | collected = append(collected, current) | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | return collected, nil | ||
402 | } | ||
403 | |||
404 | func (intr *treeInterpreter) projectWithReflection(node ASTNode, value interface{}) (interface{}, error) { | ||
405 | collected := []interface{}{} | ||
406 | v := reflect.ValueOf(value) | ||
407 | for i := 0; i < v.Len(); i++ { | ||
408 | element := v.Index(i).Interface() | ||
409 | result, err := intr.Execute(node.children[1], element) | ||
410 | if err != nil { | ||
411 | return nil, err | ||
412 | } | ||
413 | if result != nil { | ||
414 | collected = append(collected, result) | ||
415 | } | ||
416 | } | ||
417 | return collected, nil | ||
418 | } | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/lexer.go b/vendor/github.com/jmespath/go-jmespath/lexer.go new file mode 100644 index 0000000..817900c --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/lexer.go | |||
@@ -0,0 +1,420 @@ | |||
1 | package jmespath | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "fmt" | ||
7 | "strconv" | ||
8 | "strings" | ||
9 | "unicode/utf8" | ||
10 | ) | ||
11 | |||
12 | type token struct { | ||
13 | tokenType tokType | ||
14 | value string | ||
15 | position int | ||
16 | length int | ||
17 | } | ||
18 | |||
19 | type tokType int | ||
20 | |||
21 | const eof = -1 | ||
22 | |||
23 | // Lexer contains information about the expression being tokenized. | ||
24 | type Lexer struct { | ||
25 | expression string // The expression provided by the user. | ||
26 | currentPos int // The current position in the string. | ||
27 | lastWidth int // The width of the current rune. This | ||
28 | buf bytes.Buffer // Internal buffer used for building up values. | ||
29 | } | ||
30 | |||
31 | // SyntaxError is the main error used whenever a lexing or parsing error occurs. | ||
32 | type SyntaxError struct { | ||
33 | msg string // Error message displayed to user | ||
34 | Expression string // Expression that generated a SyntaxError | ||
35 | Offset int // The location in the string where the error occurred | ||
36 | } | ||
37 | |||
38 | func (e SyntaxError) Error() string { | ||
39 | // In the future, it would be good to underline the specific | ||
40 | // location where the error occurred. | ||
41 | return "SyntaxError: " + e.msg | ||
42 | } | ||
43 | |||
44 | // HighlightLocation will show where the syntax error occurred. | ||
45 | // It will place a "^" character on a line below the expression | ||
46 | // at the point where the syntax error occurred. | ||
47 | func (e SyntaxError) HighlightLocation() string { | ||
48 | return e.Expression + "\n" + strings.Repeat(" ", e.Offset) + "^" | ||
49 | } | ||
50 | |||
51 | //go:generate stringer -type=tokType | ||
52 | const ( | ||
53 | tUnknown tokType = iota | ||
54 | tStar | ||
55 | tDot | ||
56 | tFilter | ||
57 | tFlatten | ||
58 | tLparen | ||
59 | tRparen | ||
60 | tLbracket | ||
61 | tRbracket | ||
62 | tLbrace | ||
63 | tRbrace | ||
64 | tOr | ||
65 | tPipe | ||
66 | tNumber | ||
67 | tUnquotedIdentifier | ||
68 | tQuotedIdentifier | ||
69 | tComma | ||
70 | tColon | ||
71 | tLT | ||
72 | tLTE | ||
73 | tGT | ||
74 | tGTE | ||
75 | tEQ | ||
76 | tNE | ||
77 | tJSONLiteral | ||
78 | tStringLiteral | ||
79 | tCurrent | ||
80 | tExpref | ||
81 | tAnd | ||
82 | tNot | ||
83 | tEOF | ||
84 | ) | ||
85 | |||
86 | var basicTokens = map[rune]tokType{ | ||
87 | '.': tDot, | ||
88 | '*': tStar, | ||
89 | ',': tComma, | ||
90 | ':': tColon, | ||
91 | '{': tLbrace, | ||
92 | '}': tRbrace, | ||
93 | ']': tRbracket, // tLbracket not included because it could be "[]" | ||
94 | '(': tLparen, | ||
95 | ')': tRparen, | ||
96 | '@': tCurrent, | ||
97 | } | ||
98 | |||
99 | // Bit mask for [a-zA-Z_] shifted down 64 bits to fit in a single uint64. | ||
100 | // When using this bitmask just be sure to shift the rune down 64 bits | ||
101 | // before checking against identifierStartBits. | ||
102 | const identifierStartBits uint64 = 576460745995190270 | ||
103 | |||
104 | // Bit mask for [a-zA-Z0-9], 128 bits -> 2 uint64s. | ||
105 | var identifierTrailingBits = [2]uint64{287948901175001088, 576460745995190270} | ||
106 | |||
107 | var whiteSpace = map[rune]bool{ | ||
108 | ' ': true, '\t': true, '\n': true, '\r': true, | ||
109 | } | ||
110 | |||
111 | func (t token) String() string { | ||
112 | return fmt.Sprintf("Token{%+v, %s, %d, %d}", | ||
113 | t.tokenType, t.value, t.position, t.length) | ||
114 | } | ||
115 | |||
116 | // NewLexer creates a new JMESPath lexer. | ||
117 | func NewLexer() *Lexer { | ||
118 | lexer := Lexer{} | ||
119 | return &lexer | ||
120 | } | ||
121 | |||
122 | func (lexer *Lexer) next() rune { | ||
123 | if lexer.currentPos >= len(lexer.expression) { | ||
124 | lexer.lastWidth = 0 | ||
125 | return eof | ||
126 | } | ||
127 | r, w := utf8.DecodeRuneInString(lexer.expression[lexer.currentPos:]) | ||
128 | lexer.lastWidth = w | ||
129 | lexer.currentPos += w | ||
130 | return r | ||
131 | } | ||
132 | |||
133 | func (lexer *Lexer) back() { | ||
134 | lexer.currentPos -= lexer.lastWidth | ||
135 | } | ||
136 | |||
137 | func (lexer *Lexer) peek() rune { | ||
138 | t := lexer.next() | ||
139 | lexer.back() | ||
140 | return t | ||
141 | } | ||
142 | |||
143 | // tokenize takes an expression and returns corresponding tokens. | ||
144 | func (lexer *Lexer) tokenize(expression string) ([]token, error) { | ||
145 | var tokens []token | ||
146 | lexer.expression = expression | ||
147 | lexer.currentPos = 0 | ||
148 | lexer.lastWidth = 0 | ||
149 | loop: | ||
150 | for { | ||
151 | r := lexer.next() | ||
152 | if identifierStartBits&(1<<(uint64(r)-64)) > 0 { | ||
153 | t := lexer.consumeUnquotedIdentifier() | ||
154 | tokens = append(tokens, t) | ||
155 | } else if val, ok := basicTokens[r]; ok { | ||
156 | // Basic single char token. | ||
157 | t := token{ | ||
158 | tokenType: val, | ||
159 | value: string(r), | ||
160 | position: lexer.currentPos - lexer.lastWidth, | ||
161 | length: 1, | ||
162 | } | ||
163 | tokens = append(tokens, t) | ||
164 | } else if r == '-' || (r >= '0' && r <= '9') { | ||
165 | t := lexer.consumeNumber() | ||
166 | tokens = append(tokens, t) | ||
167 | } else if r == '[' { | ||
168 | t := lexer.consumeLBracket() | ||
169 | tokens = append(tokens, t) | ||
170 | } else if r == '"' { | ||
171 | t, err := lexer.consumeQuotedIdentifier() | ||
172 | if err != nil { | ||
173 | return tokens, err | ||
174 | } | ||
175 | tokens = append(tokens, t) | ||
176 | } else if r == '\'' { | ||
177 | t, err := lexer.consumeRawStringLiteral() | ||
178 | if err != nil { | ||
179 | return tokens, err | ||
180 | } | ||
181 | tokens = append(tokens, t) | ||
182 | } else if r == '`' { | ||
183 | t, err := lexer.consumeLiteral() | ||
184 | if err != nil { | ||
185 | return tokens, err | ||
186 | } | ||
187 | tokens = append(tokens, t) | ||
188 | } else if r == '|' { | ||
189 | t := lexer.matchOrElse(r, '|', tOr, tPipe) | ||
190 | tokens = append(tokens, t) | ||
191 | } else if r == '<' { | ||
192 | t := lexer.matchOrElse(r, '=', tLTE, tLT) | ||
193 | tokens = append(tokens, t) | ||
194 | } else if r == '>' { | ||
195 | t := lexer.matchOrElse(r, '=', tGTE, tGT) | ||
196 | tokens = append(tokens, t) | ||
197 | } else if r == '!' { | ||
198 | t := lexer.matchOrElse(r, '=', tNE, tNot) | ||
199 | tokens = append(tokens, t) | ||
200 | } else if r == '=' { | ||
201 | t := lexer.matchOrElse(r, '=', tEQ, tUnknown) | ||
202 | tokens = append(tokens, t) | ||
203 | } else if r == '&' { | ||
204 | t := lexer.matchOrElse(r, '&', tAnd, tExpref) | ||
205 | tokens = append(tokens, t) | ||
206 | } else if r == eof { | ||
207 | break loop | ||
208 | } else if _, ok := whiteSpace[r]; ok { | ||
209 | // Ignore whitespace | ||
210 | } else { | ||
211 | return tokens, lexer.syntaxError(fmt.Sprintf("Unknown char: %s", strconv.QuoteRuneToASCII(r))) | ||
212 | } | ||
213 | } | ||
214 | tokens = append(tokens, token{tEOF, "", len(lexer.expression), 0}) | ||
215 | return tokens, nil | ||
216 | } | ||
217 | |||
218 | // Consume characters until the ending rune "r" is reached. | ||
219 | // If the end of the expression is reached before seeing the | ||
220 | // terminating rune "r", then an error is returned. | ||
221 | // If no error occurs then the matching substring is returned. | ||
222 | // The returned string will not include the ending rune. | ||
223 | func (lexer *Lexer) consumeUntil(end rune) (string, error) { | ||
224 | start := lexer.currentPos | ||
225 | current := lexer.next() | ||
226 | for current != end && current != eof { | ||
227 | if current == '\\' && lexer.peek() != eof { | ||
228 | lexer.next() | ||
229 | } | ||
230 | current = lexer.next() | ||
231 | } | ||
232 | if lexer.lastWidth == 0 { | ||
233 | // Then we hit an EOF so we never reached the closing | ||
234 | // delimiter. | ||
235 | return "", SyntaxError{ | ||
236 | msg: "Unclosed delimiter: " + string(end), | ||
237 | Expression: lexer.expression, | ||
238 | Offset: len(lexer.expression), | ||
239 | } | ||
240 | } | ||
241 | return lexer.expression[start : lexer.currentPos-lexer.lastWidth], nil | ||
242 | } | ||
243 | |||
244 | func (lexer *Lexer) consumeLiteral() (token, error) { | ||
245 | start := lexer.currentPos | ||
246 | value, err := lexer.consumeUntil('`') | ||
247 | if err != nil { | ||
248 | return token{}, err | ||
249 | } | ||
250 | value = strings.Replace(value, "\\`", "`", -1) | ||
251 | return token{ | ||
252 | tokenType: tJSONLiteral, | ||
253 | value: value, | ||
254 | position: start, | ||
255 | length: len(value), | ||
256 | }, nil | ||
257 | } | ||
258 | |||
259 | func (lexer *Lexer) consumeRawStringLiteral() (token, error) { | ||
260 | start := lexer.currentPos | ||
261 | currentIndex := start | ||
262 | current := lexer.next() | ||
263 | for current != '\'' && lexer.peek() != eof { | ||
264 | if current == '\\' && lexer.peek() == '\'' { | ||
265 | chunk := lexer.expression[currentIndex : lexer.currentPos-1] | ||
266 | lexer.buf.WriteString(chunk) | ||
267 | lexer.buf.WriteString("'") | ||
268 | lexer.next() | ||
269 | currentIndex = lexer.currentPos | ||
270 | } | ||
271 | current = lexer.next() | ||
272 | } | ||
273 | if lexer.lastWidth == 0 { | ||
274 | // Then we hit an EOF so we never reached the closing | ||
275 | // delimiter. | ||
276 | return token{}, SyntaxError{ | ||
277 | msg: "Unclosed delimiter: '", | ||
278 | Expression: lexer.expression, | ||
279 | Offset: len(lexer.expression), | ||
280 | } | ||
281 | } | ||
282 | if currentIndex < lexer.currentPos { | ||
283 | lexer.buf.WriteString(lexer.expression[currentIndex : lexer.currentPos-1]) | ||
284 | } | ||
285 | value := lexer.buf.String() | ||
286 | // Reset the buffer so it can reused again. | ||
287 | lexer.buf.Reset() | ||
288 | return token{ | ||
289 | tokenType: tStringLiteral, | ||
290 | value: value, | ||
291 | position: start, | ||
292 | length: len(value), | ||
293 | }, nil | ||
294 | } | ||
295 | |||
296 | func (lexer *Lexer) syntaxError(msg string) SyntaxError { | ||
297 | return SyntaxError{ | ||
298 | msg: msg, | ||
299 | Expression: lexer.expression, | ||
300 | Offset: lexer.currentPos - 1, | ||
301 | } | ||
302 | } | ||
303 | |||
304 | // Checks for a two char token, otherwise matches a single character | ||
305 | // token. This is used whenever a two char token overlaps a single | ||
306 | // char token, e.g. "||" -> tPipe, "|" -> tOr. | ||
307 | func (lexer *Lexer) matchOrElse(first rune, second rune, matchedType tokType, singleCharType tokType) token { | ||
308 | start := lexer.currentPos - lexer.lastWidth | ||
309 | nextRune := lexer.next() | ||
310 | var t token | ||
311 | if nextRune == second { | ||
312 | t = token{ | ||
313 | tokenType: matchedType, | ||
314 | value: string(first) + string(second), | ||
315 | position: start, | ||
316 | length: 2, | ||
317 | } | ||
318 | } else { | ||
319 | lexer.back() | ||
320 | t = token{ | ||
321 | tokenType: singleCharType, | ||
322 | value: string(first), | ||
323 | position: start, | ||
324 | length: 1, | ||
325 | } | ||
326 | } | ||
327 | return t | ||
328 | } | ||
329 | |||
330 | func (lexer *Lexer) consumeLBracket() token { | ||
331 | // There's three options here: | ||
332 | // 1. A filter expression "[?" | ||
333 | // 2. A flatten operator "[]" | ||
334 | // 3. A bare rbracket "[" | ||
335 | start := lexer.currentPos - lexer.lastWidth | ||
336 | nextRune := lexer.next() | ||
337 | var t token | ||
338 | if nextRune == '?' { | ||
339 | t = token{ | ||
340 | tokenType: tFilter, | ||
341 | value: "[?", | ||
342 | position: start, | ||
343 | length: 2, | ||
344 | } | ||
345 | } else if nextRune == ']' { | ||
346 | t = token{ | ||
347 | tokenType: tFlatten, | ||
348 | value: "[]", | ||
349 | position: start, | ||
350 | length: 2, | ||
351 | } | ||
352 | } else { | ||
353 | t = token{ | ||
354 | tokenType: tLbracket, | ||
355 | value: "[", | ||
356 | position: start, | ||
357 | length: 1, | ||
358 | } | ||
359 | lexer.back() | ||
360 | } | ||
361 | return t | ||
362 | } | ||
363 | |||
364 | func (lexer *Lexer) consumeQuotedIdentifier() (token, error) { | ||
365 | start := lexer.currentPos | ||
366 | value, err := lexer.consumeUntil('"') | ||
367 | if err != nil { | ||
368 | return token{}, err | ||
369 | } | ||
370 | var decoded string | ||
371 | asJSON := []byte("\"" + value + "\"") | ||
372 | if err := json.Unmarshal([]byte(asJSON), &decoded); err != nil { | ||
373 | return token{}, err | ||
374 | } | ||
375 | return token{ | ||
376 | tokenType: tQuotedIdentifier, | ||
377 | value: decoded, | ||
378 | position: start - 1, | ||
379 | length: len(decoded), | ||
380 | }, nil | ||
381 | } | ||
382 | |||
383 | func (lexer *Lexer) consumeUnquotedIdentifier() token { | ||
384 | // Consume runes until we reach the end of an unquoted | ||
385 | // identifier. | ||
386 | start := lexer.currentPos - lexer.lastWidth | ||
387 | for { | ||
388 | r := lexer.next() | ||
389 | if r < 0 || r > 128 || identifierTrailingBits[uint64(r)/64]&(1<<(uint64(r)%64)) == 0 { | ||
390 | lexer.back() | ||
391 | break | ||
392 | } | ||
393 | } | ||
394 | value := lexer.expression[start:lexer.currentPos] | ||
395 | return token{ | ||
396 | tokenType: tUnquotedIdentifier, | ||
397 | value: value, | ||
398 | position: start, | ||
399 | length: lexer.currentPos - start, | ||
400 | } | ||
401 | } | ||
402 | |||
403 | func (lexer *Lexer) consumeNumber() token { | ||
404 | // Consume runes until we reach something that's not a number. | ||
405 | start := lexer.currentPos - lexer.lastWidth | ||
406 | for { | ||
407 | r := lexer.next() | ||
408 | if r < '0' || r > '9' { | ||
409 | lexer.back() | ||
410 | break | ||
411 | } | ||
412 | } | ||
413 | value := lexer.expression[start:lexer.currentPos] | ||
414 | return token{ | ||
415 | tokenType: tNumber, | ||
416 | value: value, | ||
417 | position: start, | ||
418 | length: lexer.currentPos - start, | ||
419 | } | ||
420 | } | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/parser.go b/vendor/github.com/jmespath/go-jmespath/parser.go new file mode 100644 index 0000000..1240a17 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/parser.go | |||
@@ -0,0 +1,603 @@ | |||
1 | package jmespath | ||
2 | |||
3 | import ( | ||
4 | "encoding/json" | ||
5 | "fmt" | ||
6 | "strconv" | ||
7 | "strings" | ||
8 | ) | ||
9 | |||
10 | type astNodeType int | ||
11 | |||
12 | //go:generate stringer -type astNodeType | ||
13 | const ( | ||
14 | ASTEmpty astNodeType = iota | ||
15 | ASTComparator | ||
16 | ASTCurrentNode | ||
17 | ASTExpRef | ||
18 | ASTFunctionExpression | ||
19 | ASTField | ||
20 | ASTFilterProjection | ||
21 | ASTFlatten | ||
22 | ASTIdentity | ||
23 | ASTIndex | ||
24 | ASTIndexExpression | ||
25 | ASTKeyValPair | ||
26 | ASTLiteral | ||
27 | ASTMultiSelectHash | ||
28 | ASTMultiSelectList | ||
29 | ASTOrExpression | ||
30 | ASTAndExpression | ||
31 | ASTNotExpression | ||
32 | ASTPipe | ||
33 | ASTProjection | ||
34 | ASTSubexpression | ||
35 | ASTSlice | ||
36 | ASTValueProjection | ||
37 | ) | ||
38 | |||
39 | // ASTNode represents the abstract syntax tree of a JMESPath expression. | ||
40 | type ASTNode struct { | ||
41 | nodeType astNodeType | ||
42 | value interface{} | ||
43 | children []ASTNode | ||
44 | } | ||
45 | |||
46 | func (node ASTNode) String() string { | ||
47 | return node.PrettyPrint(0) | ||
48 | } | ||
49 | |||
50 | // PrettyPrint will pretty print the parsed AST. | ||
51 | // The AST is an implementation detail and this pretty print | ||
52 | // function is provided as a convenience method to help with | ||
53 | // debugging. You should not rely on its output as the internal | ||
54 | // structure of the AST may change at any time. | ||
55 | func (node ASTNode) PrettyPrint(indent int) string { | ||
56 | spaces := strings.Repeat(" ", indent) | ||
57 | output := fmt.Sprintf("%s%s {\n", spaces, node.nodeType) | ||
58 | nextIndent := indent + 2 | ||
59 | if node.value != nil { | ||
60 | if converted, ok := node.value.(fmt.Stringer); ok { | ||
61 | // Account for things like comparator nodes | ||
62 | // that are enums with a String() method. | ||
63 | output += fmt.Sprintf("%svalue: %s\n", strings.Repeat(" ", nextIndent), converted.String()) | ||
64 | } else { | ||
65 | output += fmt.Sprintf("%svalue: %#v\n", strings.Repeat(" ", nextIndent), node.value) | ||
66 | } | ||
67 | } | ||
68 | lastIndex := len(node.children) | ||
69 | if lastIndex > 0 { | ||
70 | output += fmt.Sprintf("%schildren: {\n", strings.Repeat(" ", nextIndent)) | ||
71 | childIndent := nextIndent + 2 | ||
72 | for _, elem := range node.children { | ||
73 | output += elem.PrettyPrint(childIndent) | ||
74 | } | ||
75 | } | ||
76 | output += fmt.Sprintf("%s}\n", spaces) | ||
77 | return output | ||
78 | } | ||
79 | |||
80 | var bindingPowers = map[tokType]int{ | ||
81 | tEOF: 0, | ||
82 | tUnquotedIdentifier: 0, | ||
83 | tQuotedIdentifier: 0, | ||
84 | tRbracket: 0, | ||
85 | tRparen: 0, | ||
86 | tComma: 0, | ||
87 | tRbrace: 0, | ||
88 | tNumber: 0, | ||
89 | tCurrent: 0, | ||
90 | tExpref: 0, | ||
91 | tColon: 0, | ||
92 | tPipe: 1, | ||
93 | tOr: 2, | ||
94 | tAnd: 3, | ||
95 | tEQ: 5, | ||
96 | tLT: 5, | ||
97 | tLTE: 5, | ||
98 | tGT: 5, | ||
99 | tGTE: 5, | ||
100 | tNE: 5, | ||
101 | tFlatten: 9, | ||
102 | tStar: 20, | ||
103 | tFilter: 21, | ||
104 | tDot: 40, | ||
105 | tNot: 45, | ||
106 | tLbrace: 50, | ||
107 | tLbracket: 55, | ||
108 | tLparen: 60, | ||
109 | } | ||
110 | |||
111 | // Parser holds state about the current expression being parsed. | ||
112 | type Parser struct { | ||
113 | expression string | ||
114 | tokens []token | ||
115 | index int | ||
116 | } | ||
117 | |||
118 | // NewParser creates a new JMESPath parser. | ||
119 | func NewParser() *Parser { | ||
120 | p := Parser{} | ||
121 | return &p | ||
122 | } | ||
123 | |||
124 | // Parse will compile a JMESPath expression. | ||
125 | func (p *Parser) Parse(expression string) (ASTNode, error) { | ||
126 | lexer := NewLexer() | ||
127 | p.expression = expression | ||
128 | p.index = 0 | ||
129 | tokens, err := lexer.tokenize(expression) | ||
130 | if err != nil { | ||
131 | return ASTNode{}, err | ||
132 | } | ||
133 | p.tokens = tokens | ||
134 | parsed, err := p.parseExpression(0) | ||
135 | if err != nil { | ||
136 | return ASTNode{}, err | ||
137 | } | ||
138 | if p.current() != tEOF { | ||
139 | return ASTNode{}, p.syntaxError(fmt.Sprintf( | ||
140 | "Unexpected token at the end of the expresssion: %s", p.current())) | ||
141 | } | ||
142 | return parsed, nil | ||
143 | } | ||
144 | |||
145 | func (p *Parser) parseExpression(bindingPower int) (ASTNode, error) { | ||
146 | var err error | ||
147 | leftToken := p.lookaheadToken(0) | ||
148 | p.advance() | ||
149 | leftNode, err := p.nud(leftToken) | ||
150 | if err != nil { | ||
151 | return ASTNode{}, err | ||
152 | } | ||
153 | currentToken := p.current() | ||
154 | for bindingPower < bindingPowers[currentToken] { | ||
155 | p.advance() | ||
156 | leftNode, err = p.led(currentToken, leftNode) | ||
157 | if err != nil { | ||
158 | return ASTNode{}, err | ||
159 | } | ||
160 | currentToken = p.current() | ||
161 | } | ||
162 | return leftNode, nil | ||
163 | } | ||
164 | |||
165 | func (p *Parser) parseIndexExpression() (ASTNode, error) { | ||
166 | if p.lookahead(0) == tColon || p.lookahead(1) == tColon { | ||
167 | return p.parseSliceExpression() | ||
168 | } | ||
169 | indexStr := p.lookaheadToken(0).value | ||
170 | parsedInt, err := strconv.Atoi(indexStr) | ||
171 | if err != nil { | ||
172 | return ASTNode{}, err | ||
173 | } | ||
174 | indexNode := ASTNode{nodeType: ASTIndex, value: parsedInt} | ||
175 | p.advance() | ||
176 | if err := p.match(tRbracket); err != nil { | ||
177 | return ASTNode{}, err | ||
178 | } | ||
179 | return indexNode, nil | ||
180 | } | ||
181 | |||
182 | func (p *Parser) parseSliceExpression() (ASTNode, error) { | ||
183 | parts := []*int{nil, nil, nil} | ||
184 | index := 0 | ||
185 | current := p.current() | ||
186 | for current != tRbracket && index < 3 { | ||
187 | if current == tColon { | ||
188 | index++ | ||
189 | p.advance() | ||
190 | } else if current == tNumber { | ||
191 | parsedInt, err := strconv.Atoi(p.lookaheadToken(0).value) | ||
192 | if err != nil { | ||
193 | return ASTNode{}, err | ||
194 | } | ||
195 | parts[index] = &parsedInt | ||
196 | p.advance() | ||
197 | } else { | ||
198 | return ASTNode{}, p.syntaxError( | ||
199 | "Expected tColon or tNumber" + ", received: " + p.current().String()) | ||
200 | } | ||
201 | current = p.current() | ||
202 | } | ||
203 | if err := p.match(tRbracket); err != nil { | ||
204 | return ASTNode{}, err | ||
205 | } | ||
206 | return ASTNode{ | ||
207 | nodeType: ASTSlice, | ||
208 | value: parts, | ||
209 | }, nil | ||
210 | } | ||
211 | |||
212 | func (p *Parser) match(tokenType tokType) error { | ||
213 | if p.current() == tokenType { | ||
214 | p.advance() | ||
215 | return nil | ||
216 | } | ||
217 | return p.syntaxError("Expected " + tokenType.String() + ", received: " + p.current().String()) | ||
218 | } | ||
219 | |||
220 | func (p *Parser) led(tokenType tokType, node ASTNode) (ASTNode, error) { | ||
221 | switch tokenType { | ||
222 | case tDot: | ||
223 | if p.current() != tStar { | ||
224 | right, err := p.parseDotRHS(bindingPowers[tDot]) | ||
225 | return ASTNode{ | ||
226 | nodeType: ASTSubexpression, | ||
227 | children: []ASTNode{node, right}, | ||
228 | }, err | ||
229 | } | ||
230 | p.advance() | ||
231 | right, err := p.parseProjectionRHS(bindingPowers[tDot]) | ||
232 | return ASTNode{ | ||
233 | nodeType: ASTValueProjection, | ||
234 | children: []ASTNode{node, right}, | ||
235 | }, err | ||
236 | case tPipe: | ||
237 | right, err := p.parseExpression(bindingPowers[tPipe]) | ||
238 | return ASTNode{nodeType: ASTPipe, children: []ASTNode{node, right}}, err | ||
239 | case tOr: | ||
240 | right, err := p.parseExpression(bindingPowers[tOr]) | ||
241 | return ASTNode{nodeType: ASTOrExpression, children: []ASTNode{node, right}}, err | ||
242 | case tAnd: | ||
243 | right, err := p.parseExpression(bindingPowers[tAnd]) | ||
244 | return ASTNode{nodeType: ASTAndExpression, children: []ASTNode{node, right}}, err | ||
245 | case tLparen: | ||
246 | name := node.value | ||
247 | var args []ASTNode | ||
248 | for p.current() != tRparen { | ||
249 | expression, err := p.parseExpression(0) | ||
250 | if err != nil { | ||
251 | return ASTNode{}, err | ||
252 | } | ||
253 | if p.current() == tComma { | ||
254 | if err := p.match(tComma); err != nil { | ||
255 | return ASTNode{}, err | ||
256 | } | ||
257 | } | ||
258 | args = append(args, expression) | ||
259 | } | ||
260 | if err := p.match(tRparen); err != nil { | ||
261 | return ASTNode{}, err | ||
262 | } | ||
263 | return ASTNode{ | ||
264 | nodeType: ASTFunctionExpression, | ||
265 | value: name, | ||
266 | children: args, | ||
267 | }, nil | ||
268 | case tFilter: | ||
269 | return p.parseFilter(node) | ||
270 | case tFlatten: | ||
271 | left := ASTNode{nodeType: ASTFlatten, children: []ASTNode{node}} | ||
272 | right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) | ||
273 | return ASTNode{ | ||
274 | nodeType: ASTProjection, | ||
275 | children: []ASTNode{left, right}, | ||
276 | }, err | ||
277 | case tEQ, tNE, tGT, tGTE, tLT, tLTE: | ||
278 | right, err := p.parseExpression(bindingPowers[tokenType]) | ||
279 | if err != nil { | ||
280 | return ASTNode{}, err | ||
281 | } | ||
282 | return ASTNode{ | ||
283 | nodeType: ASTComparator, | ||
284 | value: tokenType, | ||
285 | children: []ASTNode{node, right}, | ||
286 | }, nil | ||
287 | case tLbracket: | ||
288 | tokenType := p.current() | ||
289 | var right ASTNode | ||
290 | var err error | ||
291 | if tokenType == tNumber || tokenType == tColon { | ||
292 | right, err = p.parseIndexExpression() | ||
293 | if err != nil { | ||
294 | return ASTNode{}, err | ||
295 | } | ||
296 | return p.projectIfSlice(node, right) | ||
297 | } | ||
298 | // Otherwise this is a projection. | ||
299 | if err := p.match(tStar); err != nil { | ||
300 | return ASTNode{}, err | ||
301 | } | ||
302 | if err := p.match(tRbracket); err != nil { | ||
303 | return ASTNode{}, err | ||
304 | } | ||
305 | right, err = p.parseProjectionRHS(bindingPowers[tStar]) | ||
306 | if err != nil { | ||
307 | return ASTNode{}, err | ||
308 | } | ||
309 | return ASTNode{ | ||
310 | nodeType: ASTProjection, | ||
311 | children: []ASTNode{node, right}, | ||
312 | }, nil | ||
313 | } | ||
314 | return ASTNode{}, p.syntaxError("Unexpected token: " + tokenType.String()) | ||
315 | } | ||
316 | |||
317 | func (p *Parser) nud(token token) (ASTNode, error) { | ||
318 | switch token.tokenType { | ||
319 | case tJSONLiteral: | ||
320 | var parsed interface{} | ||
321 | err := json.Unmarshal([]byte(token.value), &parsed) | ||
322 | if err != nil { | ||
323 | return ASTNode{}, err | ||
324 | } | ||
325 | return ASTNode{nodeType: ASTLiteral, value: parsed}, nil | ||
326 | case tStringLiteral: | ||
327 | return ASTNode{nodeType: ASTLiteral, value: token.value}, nil | ||
328 | case tUnquotedIdentifier: | ||
329 | return ASTNode{ | ||
330 | nodeType: ASTField, | ||
331 | value: token.value, | ||
332 | }, nil | ||
333 | case tQuotedIdentifier: | ||
334 | node := ASTNode{nodeType: ASTField, value: token.value} | ||
335 | if p.current() == tLparen { | ||
336 | return ASTNode{}, p.syntaxErrorToken("Can't have quoted identifier as function name.", token) | ||
337 | } | ||
338 | return node, nil | ||
339 | case tStar: | ||
340 | left := ASTNode{nodeType: ASTIdentity} | ||
341 | var right ASTNode | ||
342 | var err error | ||
343 | if p.current() == tRbracket { | ||
344 | right = ASTNode{nodeType: ASTIdentity} | ||
345 | } else { | ||
346 | right, err = p.parseProjectionRHS(bindingPowers[tStar]) | ||
347 | } | ||
348 | return ASTNode{nodeType: ASTValueProjection, children: []ASTNode{left, right}}, err | ||
349 | case tFilter: | ||
350 | return p.parseFilter(ASTNode{nodeType: ASTIdentity}) | ||
351 | case tLbrace: | ||
352 | return p.parseMultiSelectHash() | ||
353 | case tFlatten: | ||
354 | left := ASTNode{ | ||
355 | nodeType: ASTFlatten, | ||
356 | children: []ASTNode{{nodeType: ASTIdentity}}, | ||
357 | } | ||
358 | right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) | ||
359 | if err != nil { | ||
360 | return ASTNode{}, err | ||
361 | } | ||
362 | return ASTNode{nodeType: ASTProjection, children: []ASTNode{left, right}}, nil | ||
363 | case tLbracket: | ||
364 | tokenType := p.current() | ||
365 | //var right ASTNode | ||
366 | if tokenType == tNumber || tokenType == tColon { | ||
367 | right, err := p.parseIndexExpression() | ||
368 | if err != nil { | ||
369 | return ASTNode{}, nil | ||
370 | } | ||
371 | return p.projectIfSlice(ASTNode{nodeType: ASTIdentity}, right) | ||
372 | } else if tokenType == tStar && p.lookahead(1) == tRbracket { | ||
373 | p.advance() | ||
374 | p.advance() | ||
375 | right, err := p.parseProjectionRHS(bindingPowers[tStar]) | ||
376 | if err != nil { | ||
377 | return ASTNode{}, err | ||
378 | } | ||
379 | return ASTNode{ | ||
380 | nodeType: ASTProjection, | ||
381 | children: []ASTNode{{nodeType: ASTIdentity}, right}, | ||
382 | }, nil | ||
383 | } else { | ||
384 | return p.parseMultiSelectList() | ||
385 | } | ||
386 | case tCurrent: | ||
387 | return ASTNode{nodeType: ASTCurrentNode}, nil | ||
388 | case tExpref: | ||
389 | expression, err := p.parseExpression(bindingPowers[tExpref]) | ||
390 | if err != nil { | ||
391 | return ASTNode{}, err | ||
392 | } | ||
393 | return ASTNode{nodeType: ASTExpRef, children: []ASTNode{expression}}, nil | ||
394 | case tNot: | ||
395 | expression, err := p.parseExpression(bindingPowers[tNot]) | ||
396 | if err != nil { | ||
397 | return ASTNode{}, err | ||
398 | } | ||
399 | return ASTNode{nodeType: ASTNotExpression, children: []ASTNode{expression}}, nil | ||
400 | case tLparen: | ||
401 | expression, err := p.parseExpression(0) | ||
402 | if err != nil { | ||
403 | return ASTNode{}, err | ||
404 | } | ||
405 | if err := p.match(tRparen); err != nil { | ||
406 | return ASTNode{}, err | ||
407 | } | ||
408 | return expression, nil | ||
409 | case tEOF: | ||
410 | return ASTNode{}, p.syntaxErrorToken("Incomplete expression", token) | ||
411 | } | ||
412 | |||
413 | return ASTNode{}, p.syntaxErrorToken("Invalid token: "+token.tokenType.String(), token) | ||
414 | } | ||
415 | |||
416 | func (p *Parser) parseMultiSelectList() (ASTNode, error) { | ||
417 | var expressions []ASTNode | ||
418 | for { | ||
419 | expression, err := p.parseExpression(0) | ||
420 | if err != nil { | ||
421 | return ASTNode{}, err | ||
422 | } | ||
423 | expressions = append(expressions, expression) | ||
424 | if p.current() == tRbracket { | ||
425 | break | ||
426 | } | ||
427 | err = p.match(tComma) | ||
428 | if err != nil { | ||
429 | return ASTNode{}, err | ||
430 | } | ||
431 | } | ||
432 | err := p.match(tRbracket) | ||
433 | if err != nil { | ||
434 | return ASTNode{}, err | ||
435 | } | ||
436 | return ASTNode{ | ||
437 | nodeType: ASTMultiSelectList, | ||
438 | children: expressions, | ||
439 | }, nil | ||
440 | } | ||
441 | |||
442 | func (p *Parser) parseMultiSelectHash() (ASTNode, error) { | ||
443 | var children []ASTNode | ||
444 | for { | ||
445 | keyToken := p.lookaheadToken(0) | ||
446 | if err := p.match(tUnquotedIdentifier); err != nil { | ||
447 | if err := p.match(tQuotedIdentifier); err != nil { | ||
448 | return ASTNode{}, p.syntaxError("Expected tQuotedIdentifier or tUnquotedIdentifier") | ||
449 | } | ||
450 | } | ||
451 | keyName := keyToken.value | ||
452 | err := p.match(tColon) | ||
453 | if err != nil { | ||
454 | return ASTNode{}, err | ||
455 | } | ||
456 | value, err := p.parseExpression(0) | ||
457 | if err != nil { | ||
458 | return ASTNode{}, err | ||
459 | } | ||
460 | node := ASTNode{ | ||
461 | nodeType: ASTKeyValPair, | ||
462 | value: keyName, | ||
463 | children: []ASTNode{value}, | ||
464 | } | ||
465 | children = append(children, node) | ||
466 | if p.current() == tComma { | ||
467 | err := p.match(tComma) | ||
468 | if err != nil { | ||
469 | return ASTNode{}, nil | ||
470 | } | ||
471 | } else if p.current() == tRbrace { | ||
472 | err := p.match(tRbrace) | ||
473 | if err != nil { | ||
474 | return ASTNode{}, nil | ||
475 | } | ||
476 | break | ||
477 | } | ||
478 | } | ||
479 | return ASTNode{ | ||
480 | nodeType: ASTMultiSelectHash, | ||
481 | children: children, | ||
482 | }, nil | ||
483 | } | ||
484 | |||
485 | func (p *Parser) projectIfSlice(left ASTNode, right ASTNode) (ASTNode, error) { | ||
486 | indexExpr := ASTNode{ | ||
487 | nodeType: ASTIndexExpression, | ||
488 | children: []ASTNode{left, right}, | ||
489 | } | ||
490 | if right.nodeType == ASTSlice { | ||
491 | right, err := p.parseProjectionRHS(bindingPowers[tStar]) | ||
492 | return ASTNode{ | ||
493 | nodeType: ASTProjection, | ||
494 | children: []ASTNode{indexExpr, right}, | ||
495 | }, err | ||
496 | } | ||
497 | return indexExpr, nil | ||
498 | } | ||
499 | func (p *Parser) parseFilter(node ASTNode) (ASTNode, error) { | ||
500 | var right, condition ASTNode | ||
501 | var err error | ||
502 | condition, err = p.parseExpression(0) | ||
503 | if err != nil { | ||
504 | return ASTNode{}, err | ||
505 | } | ||
506 | if err := p.match(tRbracket); err != nil { | ||
507 | return ASTNode{}, err | ||
508 | } | ||
509 | if p.current() == tFlatten { | ||
510 | right = ASTNode{nodeType: ASTIdentity} | ||
511 | } else { | ||
512 | right, err = p.parseProjectionRHS(bindingPowers[tFilter]) | ||
513 | if err != nil { | ||
514 | return ASTNode{}, err | ||
515 | } | ||
516 | } | ||
517 | |||
518 | return ASTNode{ | ||
519 | nodeType: ASTFilterProjection, | ||
520 | children: []ASTNode{node, right, condition}, | ||
521 | }, nil | ||
522 | } | ||
523 | |||
524 | func (p *Parser) parseDotRHS(bindingPower int) (ASTNode, error) { | ||
525 | lookahead := p.current() | ||
526 | if tokensOneOf([]tokType{tQuotedIdentifier, tUnquotedIdentifier, tStar}, lookahead) { | ||
527 | return p.parseExpression(bindingPower) | ||
528 | } else if lookahead == tLbracket { | ||
529 | if err := p.match(tLbracket); err != nil { | ||
530 | return ASTNode{}, err | ||
531 | } | ||
532 | return p.parseMultiSelectList() | ||
533 | } else if lookahead == tLbrace { | ||
534 | if err := p.match(tLbrace); err != nil { | ||
535 | return ASTNode{}, err | ||
536 | } | ||
537 | return p.parseMultiSelectHash() | ||
538 | } | ||
539 | return ASTNode{}, p.syntaxError("Expected identifier, lbracket, or lbrace") | ||
540 | } | ||
541 | |||
542 | func (p *Parser) parseProjectionRHS(bindingPower int) (ASTNode, error) { | ||
543 | current := p.current() | ||
544 | if bindingPowers[current] < 10 { | ||
545 | return ASTNode{nodeType: ASTIdentity}, nil | ||
546 | } else if current == tLbracket { | ||
547 | return p.parseExpression(bindingPower) | ||
548 | } else if current == tFilter { | ||
549 | return p.parseExpression(bindingPower) | ||
550 | } else if current == tDot { | ||
551 | err := p.match(tDot) | ||
552 | if err != nil { | ||
553 | return ASTNode{}, err | ||
554 | } | ||
555 | return p.parseDotRHS(bindingPower) | ||
556 | } else { | ||
557 | return ASTNode{}, p.syntaxError("Error") | ||
558 | } | ||
559 | } | ||
560 | |||
561 | func (p *Parser) lookahead(number int) tokType { | ||
562 | return p.lookaheadToken(number).tokenType | ||
563 | } | ||
564 | |||
565 | func (p *Parser) current() tokType { | ||
566 | return p.lookahead(0) | ||
567 | } | ||
568 | |||
569 | func (p *Parser) lookaheadToken(number int) token { | ||
570 | return p.tokens[p.index+number] | ||
571 | } | ||
572 | |||
573 | func (p *Parser) advance() { | ||
574 | p.index++ | ||
575 | } | ||
576 | |||
577 | func tokensOneOf(elements []tokType, token tokType) bool { | ||
578 | for _, elem := range elements { | ||
579 | if elem == token { | ||
580 | return true | ||
581 | } | ||
582 | } | ||
583 | return false | ||
584 | } | ||
585 | |||
586 | func (p *Parser) syntaxError(msg string) SyntaxError { | ||
587 | return SyntaxError{ | ||
588 | msg: msg, | ||
589 | Expression: p.expression, | ||
590 | Offset: p.lookaheadToken(0).position, | ||
591 | } | ||
592 | } | ||
593 | |||
594 | // Create a SyntaxError based on the provided token. | ||
595 | // This differs from syntaxError() which creates a SyntaxError | ||
596 | // based on the current lookahead token. | ||
597 | func (p *Parser) syntaxErrorToken(msg string, t token) SyntaxError { | ||
598 | return SyntaxError{ | ||
599 | msg: msg, | ||
600 | Expression: p.expression, | ||
601 | Offset: t.position, | ||
602 | } | ||
603 | } | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/toktype_string.go b/vendor/github.com/jmespath/go-jmespath/toktype_string.go new file mode 100644 index 0000000..dae79cb --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/toktype_string.go | |||
@@ -0,0 +1,16 @@ | |||
1 | // generated by stringer -type=tokType; DO NOT EDIT | ||
2 | |||
3 | package jmespath | ||
4 | |||
5 | import "fmt" | ||
6 | |||
7 | const _tokType_name = "tUnknowntStartDottFiltertFlattentLparentRparentLbrackettRbrackettLbracetRbracetOrtPipetNumbertUnquotedIdentifiertQuotedIdentifiertCommatColontLTtLTEtGTtGTEtEQtNEtJSONLiteraltStringLiteraltCurrenttExpreftAndtNottEOF" | ||
8 | |||
9 | var _tokType_index = [...]uint8{0, 8, 13, 17, 24, 32, 39, 46, 55, 64, 71, 78, 81, 86, 93, 112, 129, 135, 141, 144, 148, 151, 155, 158, 161, 173, 187, 195, 202, 206, 210, 214} | ||
10 | |||
11 | func (i tokType) String() string { | ||
12 | if i < 0 || i >= tokType(len(_tokType_index)-1) { | ||
13 | return fmt.Sprintf("tokType(%d)", i) | ||
14 | } | ||
15 | return _tokType_name[_tokType_index[i]:_tokType_index[i+1]] | ||
16 | } | ||
diff --git a/vendor/github.com/jmespath/go-jmespath/util.go b/vendor/github.com/jmespath/go-jmespath/util.go new file mode 100644 index 0000000..ddc1b7d --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/util.go | |||
@@ -0,0 +1,185 @@ | |||
1 | package jmespath | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "reflect" | ||
6 | ) | ||
7 | |||
8 | // IsFalse determines if an object is false based on the JMESPath spec. | ||
9 | // JMESPath defines false values to be any of: | ||
10 | // - An empty string array, or hash. | ||
11 | // - The boolean value false. | ||
12 | // - nil | ||
13 | func isFalse(value interface{}) bool { | ||
14 | switch v := value.(type) { | ||
15 | case bool: | ||
16 | return !v | ||
17 | case []interface{}: | ||
18 | return len(v) == 0 | ||
19 | case map[string]interface{}: | ||
20 | return len(v) == 0 | ||
21 | case string: | ||
22 | return len(v) == 0 | ||
23 | case nil: | ||
24 | return true | ||
25 | } | ||
26 | // Try the reflection cases before returning false. | ||
27 | rv := reflect.ValueOf(value) | ||
28 | switch rv.Kind() { | ||
29 | case reflect.Struct: | ||
30 | // A struct type will never be false, even if | ||
31 | // all of its values are the zero type. | ||
32 | return false | ||
33 | case reflect.Slice, reflect.Map: | ||
34 | return rv.Len() == 0 | ||
35 | case reflect.Ptr: | ||
36 | if rv.IsNil() { | ||
37 | return true | ||
38 | } | ||
39 | // If it's a pointer type, we'll try to deref the pointer | ||
40 | // and evaluate the pointer value for isFalse. | ||
41 | element := rv.Elem() | ||
42 | return isFalse(element.Interface()) | ||
43 | } | ||
44 | return false | ||
45 | } | ||
46 | |||
47 | // ObjsEqual is a generic object equality check. | ||
48 | // It will take two arbitrary objects and recursively determine | ||
49 | // if they are equal. | ||
50 | func objsEqual(left interface{}, right interface{}) bool { | ||
51 | return reflect.DeepEqual(left, right) | ||
52 | } | ||
53 | |||
54 | // SliceParam refers to a single part of a slice. | ||
55 | // A slice consists of a start, a stop, and a step, similar to | ||
56 | // python slices. | ||
57 | type sliceParam struct { | ||
58 | N int | ||
59 | Specified bool | ||
60 | } | ||
61 | |||
62 | // Slice supports [start:stop:step] style slicing that's supported in JMESPath. | ||
63 | func slice(slice []interface{}, parts []sliceParam) ([]interface{}, error) { | ||
64 | computed, err := computeSliceParams(len(slice), parts) | ||
65 | if err != nil { | ||
66 | return nil, err | ||
67 | } | ||
68 | start, stop, step := computed[0], computed[1], computed[2] | ||
69 | result := []interface{}{} | ||
70 | if step > 0 { | ||
71 | for i := start; i < stop; i += step { | ||
72 | result = append(result, slice[i]) | ||
73 | } | ||
74 | } else { | ||
75 | for i := start; i > stop; i += step { | ||
76 | result = append(result, slice[i]) | ||
77 | } | ||
78 | } | ||
79 | return result, nil | ||
80 | } | ||
81 | |||
82 | func computeSliceParams(length int, parts []sliceParam) ([]int, error) { | ||
83 | var start, stop, step int | ||
84 | if !parts[2].Specified { | ||
85 | step = 1 | ||
86 | } else if parts[2].N == 0 { | ||
87 | return nil, errors.New("Invalid slice, step cannot be 0") | ||
88 | } else { | ||
89 | step = parts[2].N | ||
90 | } | ||
91 | var stepValueNegative bool | ||
92 | if step < 0 { | ||
93 | stepValueNegative = true | ||
94 | } else { | ||
95 | stepValueNegative = false | ||
96 | } | ||
97 | |||
98 | if !parts[0].Specified { | ||
99 | if stepValueNegative { | ||
100 | start = length - 1 | ||
101 | } else { | ||
102 | start = 0 | ||
103 | } | ||
104 | } else { | ||
105 | start = capSlice(length, parts[0].N, step) | ||
106 | } | ||
107 | |||
108 | if !parts[1].Specified { | ||
109 | if stepValueNegative { | ||
110 | stop = -1 | ||
111 | } else { | ||
112 | stop = length | ||
113 | } | ||
114 | } else { | ||
115 | stop = capSlice(length, parts[1].N, step) | ||
116 | } | ||
117 | return []int{start, stop, step}, nil | ||
118 | } | ||
119 | |||
120 | func capSlice(length int, actual int, step int) int { | ||
121 | if actual < 0 { | ||
122 | actual += length | ||
123 | if actual < 0 { | ||
124 | if step < 0 { | ||
125 | actual = -1 | ||
126 | } else { | ||
127 | actual = 0 | ||
128 | } | ||
129 | } | ||
130 | } else if actual >= length { | ||
131 | if step < 0 { | ||
132 | actual = length - 1 | ||
133 | } else { | ||
134 | actual = length | ||
135 | } | ||
136 | } | ||
137 | return actual | ||
138 | } | ||
139 | |||
140 | // ToArrayNum converts an empty interface type to a slice of float64. | ||
141 | // If any element in the array cannot be converted, then nil is returned | ||
142 | // along with a second value of false. | ||
143 | func toArrayNum(data interface{}) ([]float64, bool) { | ||
144 | // Is there a better way to do this with reflect? | ||
145 | if d, ok := data.([]interface{}); ok { | ||
146 | result := make([]float64, len(d)) | ||
147 | for i, el := range d { | ||
148 | item, ok := el.(float64) | ||
149 | if !ok { | ||
150 | return nil, false | ||
151 | } | ||
152 | result[i] = item | ||
153 | } | ||
154 | return result, true | ||
155 | } | ||
156 | return nil, false | ||
157 | } | ||
158 | |||
159 | // ToArrayStr converts an empty interface type to a slice of strings. | ||
160 | // If any element in the array cannot be converted, then nil is returned | ||
161 | // along with a second value of false. If the input data could be entirely | ||
162 | // converted, then the converted data, along with a second value of true, | ||
163 | // will be returned. | ||
164 | func toArrayStr(data interface{}) ([]string, bool) { | ||
165 | // Is there a better way to do this with reflect? | ||
166 | if d, ok := data.([]interface{}); ok { | ||
167 | result := make([]string, len(d)) | ||
168 | for i, el := range d { | ||
169 | item, ok := el.(string) | ||
170 | if !ok { | ||
171 | return nil, false | ||
172 | } | ||
173 | result[i] = item | ||
174 | } | ||
175 | return result, true | ||
176 | } | ||
177 | return nil, false | ||
178 | } | ||
179 | |||
180 | func isSliceType(v interface{}) bool { | ||
181 | if v == nil { | ||
182 | return false | ||
183 | } | ||
184 | return reflect.TypeOf(v).Kind() == reflect.Slice | ||
185 | } | ||