...

Source file src/github.com/jmespath/go-jmespath/interpreter.go

Documentation: github.com/jmespath/go-jmespath

     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  }
   419  

View as plain text