10 /* This is a tree based interpreter. It walks the AST and directly
11 interprets the AST to search through a JSON document.
14 type treeInterpreter struct {
18 func newInterpreter() *treeInterpreter {
19 interpreter := treeInterpreter{}
20 interpreter.fCall = newFunctionCaller()
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 {
34 left, err := intr.Execute(node.children[0], value)
38 right, err := intr.Execute(node.children[1], value)
44 return objsEqual(left, right), nil
46 return !objsEqual(left, right), nil
48 leftNum, ok := left.(float64)
52 rightNum, ok := right.(float64)
58 return leftNum > rightNum, nil
60 return leftNum >= rightNum, nil
62 return leftNum < rightNum, nil
64 return leftNum <= rightNum, nil
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)
75 resolvedArgs = append(resolvedArgs, current)
77 return intr.fCall.CallFunction(node.value.(string), resolvedArgs, intr)
79 if m, ok := value.(map[string]interface{}); ok {
80 key := node.value.(string)
83 return intr.fieldFromStruct(node.value.(string), value)
84 case ASTFilterProjection:
85 left, err := intr.Execute(node.children[0], value)
89 sliceType, ok := left.([]interface{})
91 if isSliceType(left) {
92 return intr.filterProjectionWithReflection(node, left)
96 compareNode := node.children[2]
97 collected := []interface{}{}
98 for _, element := range sliceType {
99 result, err := intr.Execute(compareNode, element)
103 if !isFalse(result) {
104 current, err := intr.Execute(node.children[1], element)
109 collected = append(collected, current)
113 return collected, nil
115 left, err := intr.Execute(node.children[0], value)
119 sliceType, ok := left.([]interface{})
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)
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())
139 flattened = append(flattened, reflectFlat...)
141 flattened = append(flattened, element)
144 return flattened, nil
145 case ASTIdentity, ASTCurrentNode:
148 if sliceType, ok := value.([]interface{}); ok {
149 index := node.value.(int)
151 index += len(sliceType)
153 if index < len(sliceType) && index >= 0 {
154 return sliceType[index], nil
158 // Otherwise try via reflection.
159 rv := reflect.ValueOf(value)
160 if rv.Kind() == reflect.Slice {
161 index := node.value.(int)
165 if index < rv.Len() && index >= 0 {
167 return v.Interface(), nil
172 return intr.Execute(node.children[0], value)
174 return node.value, nil
175 case ASTMultiSelectHash:
179 collected := make(map[string]interface{})
180 for _, child := range node.children {
181 current, err := intr.Execute(child, value)
185 key := child.value.(string)
186 collected[key] = current
188 return collected, nil
189 case ASTMultiSelectList:
193 collected := []interface{}{}
194 for _, child := range node.children {
195 current, err := intr.Execute(child, value)
199 collected = append(collected, current)
201 return collected, nil
202 case ASTOrExpression:
203 matched, err := intr.Execute(node.children[0], value)
207 if isFalse(matched) {
208 matched, err = intr.Execute(node.children[1], value)
214 case ASTAndExpression:
215 matched, err := intr.Execute(node.children[0], value)
219 if isFalse(matched) {
222 return intr.Execute(node.children[1], value)
223 case ASTNotExpression:
224 matched, err := intr.Execute(node.children[0], value)
228 if isFalse(matched) {
235 for _, child := range node.children {
236 result, err = intr.Execute(child, result)
243 left, err := intr.Execute(node.children[0], value)
247 sliceType, ok := left.([]interface{})
249 if isSliceType(left) {
250 return intr.projectWithReflection(node, left)
254 collected := []interface{}{}
255 var current interface{}
256 for _, element := range sliceType {
257 current, err = intr.Execute(node.children[1], element)
262 collected = append(collected, current)
265 return collected, nil
266 case ASTSubexpression, ASTIndexExpression:
267 left, err := intr.Execute(node.children[0], value)
271 return intr.Execute(node.children[1], left)
273 sliceType, ok := value.([]interface{})
275 if isSliceType(value) {
276 return intr.sliceWithReflection(node, value)
280 parts := node.value.([]*int)
281 sliceParams := make([]sliceParam, 3)
282 for i, part := range parts {
284 sliceParams[i].Specified = true
285 sliceParams[i].N = *part
288 return slice(sliceType, sliceParams)
289 case ASTValueProjection:
290 left, err := intr.Execute(node.children[0], value)
294 mapType, ok := left.(map[string]interface{})
298 values := make([]interface{}, len(mapType))
299 for _, value := range mapType {
300 values = append(values, value)
302 collected := []interface{}{}
303 for _, element := range values {
304 current, err := intr.Execute(node.children[1], element)
309 collected = append(collected, current)
312 return collected, nil
314 return nil, errors.New("Unknown AST node: " + node.nodeType.String())
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)
326 return v.Interface(), nil
327 } else if rv.Kind() == reflect.Ptr {
328 // Handle multiple levels of indirection?
333 v := rv.FieldByName(fieldName)
337 return v.Interface(), nil
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++ {
354 flattened, elementV.Index(j).Interface())
357 flattened = append(flattened, element)
360 return flattened, nil
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 {
369 sliceParams[i].Specified = true
370 sliceParams[i].N = *part
373 final := []interface{}{}
374 for i := 0; i < v.Len(); i++ {
375 element := v.Index(i).Interface()
376 final = append(final, element)
378 return slice(final, sliceParams)
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)
391 if !isFalse(result) {
392 current, err := intr.Execute(node.children[1], element)
397 collected = append(collected, current)
401 return collected, nil
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)
414 collected = append(collected, result)
417 return collected, nil