]>
Commit | Line | Data |
---|---|---|
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 | } |