code.dwrz.net

Go monorepo.
Log | Files | Refs

interpreter.go (10508B)


      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 }