...

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

Documentation: github.com/jmespath/go-jmespath

     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  	jpNumber      jpType = "number"
    21  	jpString      jpType = "string"
    22  	jpArray       jpType = "array"
    23  	jpObject      jpType = "object"
    24  	jpArrayNumber jpType = "array[number]"
    25  	jpArrayString jpType = "array[string]"
    26  	jpExpref      jpType = "expref"
    27  	jpAny         jpType = "any"
    28  )
    29  
    30  type functionEntry struct {
    31  	name      string
    32  	arguments []argSpec
    33  	handler   jpFunction
    34  	hasExpRef bool
    35  }
    36  
    37  type argSpec struct {
    38  	types    []jpType
    39  	variadic bool
    40  }
    41  
    42  type byExprString struct {
    43  	intr     *treeInterpreter
    44  	node     ASTNode
    45  	items    []interface{}
    46  	hasError bool
    47  }
    48  
    49  func (a *byExprString) Len() int {
    50  	return len(a.items)
    51  }
    52  func (a *byExprString) Swap(i, j int) {
    53  	a.items[i], a.items[j] = a.items[j], a.items[i]
    54  }
    55  func (a *byExprString) Less(i, j int) bool {
    56  	first, err := a.intr.Execute(a.node, a.items[i])
    57  	if err != nil {
    58  		a.hasError = true
    59  		// Return a dummy value.
    60  		return true
    61  	}
    62  	ith, ok := first.(string)
    63  	if !ok {
    64  		a.hasError = true
    65  		return true
    66  	}
    67  	second, err := a.intr.Execute(a.node, a.items[j])
    68  	if err != nil {
    69  		a.hasError = true
    70  		// Return a dummy value.
    71  		return true
    72  	}
    73  	jth, ok := second.(string)
    74  	if !ok {
    75  		a.hasError = true
    76  		return true
    77  	}
    78  	return ith < jth
    79  }
    80  
    81  type byExprFloat struct {
    82  	intr     *treeInterpreter
    83  	node     ASTNode
    84  	items    []interface{}
    85  	hasError bool
    86  }
    87  
    88  func (a *byExprFloat) Len() int {
    89  	return len(a.items)
    90  }
    91  func (a *byExprFloat) Swap(i, j int) {
    92  	a.items[i], a.items[j] = a.items[j], a.items[i]
    93  }
    94  func (a *byExprFloat) Less(i, j int) bool {
    95  	first, err := a.intr.Execute(a.node, a.items[i])
    96  	if err != nil {
    97  		a.hasError = true
    98  		// Return a dummy value.
    99  		return true
   100  	}
   101  	ith, ok := first.(float64)
   102  	if !ok {
   103  		a.hasError = true
   104  		return true
   105  	}
   106  	second, err := a.intr.Execute(a.node, a.items[j])
   107  	if err != nil {
   108  		a.hasError = true
   109  		// Return a dummy value.
   110  		return true
   111  	}
   112  	jth, ok := second.(float64)
   113  	if !ok {
   114  		a.hasError = true
   115  		return true
   116  	}
   117  	return ith < jth
   118  }
   119  
   120  type functionCaller struct {
   121  	functionTable map[string]functionEntry
   122  }
   123  
   124  func newFunctionCaller() *functionCaller {
   125  	caller := &functionCaller{}
   126  	caller.functionTable = map[string]functionEntry{
   127  		"length": {
   128  			name: "length",
   129  			arguments: []argSpec{
   130  				{types: []jpType{jpString, jpArray, jpObject}},
   131  			},
   132  			handler: jpfLength,
   133  		},
   134  		"starts_with": {
   135  			name: "starts_with",
   136  			arguments: []argSpec{
   137  				{types: []jpType{jpString}},
   138  				{types: []jpType{jpString}},
   139  			},
   140  			handler: jpfStartsWith,
   141  		},
   142  		"abs": {
   143  			name: "abs",
   144  			arguments: []argSpec{
   145  				{types: []jpType{jpNumber}},
   146  			},
   147  			handler: jpfAbs,
   148  		},
   149  		"avg": {
   150  			name: "avg",
   151  			arguments: []argSpec{
   152  				{types: []jpType{jpArrayNumber}},
   153  			},
   154  			handler: jpfAvg,
   155  		},
   156  		"ceil": {
   157  			name: "ceil",
   158  			arguments: []argSpec{
   159  				{types: []jpType{jpNumber}},
   160  			},
   161  			handler: jpfCeil,
   162  		},
   163  		"contains": {
   164  			name: "contains",
   165  			arguments: []argSpec{
   166  				{types: []jpType{jpArray, jpString}},
   167  				{types: []jpType{jpAny}},
   168  			},
   169  			handler: jpfContains,
   170  		},
   171  		"ends_with": {
   172  			name: "ends_with",
   173  			arguments: []argSpec{
   174  				{types: []jpType{jpString}},
   175  				{types: []jpType{jpString}},
   176  			},
   177  			handler: jpfEndsWith,
   178  		},
   179  		"floor": {
   180  			name: "floor",
   181  			arguments: []argSpec{
   182  				{types: []jpType{jpNumber}},
   183  			},
   184  			handler: jpfFloor,
   185  		},
   186  		"map": {
   187  			name: "amp",
   188  			arguments: []argSpec{
   189  				{types: []jpType{jpExpref}},
   190  				{types: []jpType{jpArray}},
   191  			},
   192  			handler:   jpfMap,
   193  			hasExpRef: true,
   194  		},
   195  		"max": {
   196  			name: "max",
   197  			arguments: []argSpec{
   198  				{types: []jpType{jpArrayNumber, jpArrayString}},
   199  			},
   200  			handler: jpfMax,
   201  		},
   202  		"merge": {
   203  			name: "merge",
   204  			arguments: []argSpec{
   205  				{types: []jpType{jpObject}, variadic: true},
   206  			},
   207  			handler: jpfMerge,
   208  		},
   209  		"max_by": {
   210  			name: "max_by",
   211  			arguments: []argSpec{
   212  				{types: []jpType{jpArray}},
   213  				{types: []jpType{jpExpref}},
   214  			},
   215  			handler:   jpfMaxBy,
   216  			hasExpRef: true,
   217  		},
   218  		"sum": {
   219  			name: "sum",
   220  			arguments: []argSpec{
   221  				{types: []jpType{jpArrayNumber}},
   222  			},
   223  			handler: jpfSum,
   224  		},
   225  		"min": {
   226  			name: "min",
   227  			arguments: []argSpec{
   228  				{types: []jpType{jpArrayNumber, jpArrayString}},
   229  			},
   230  			handler: jpfMin,
   231  		},
   232  		"min_by": {
   233  			name: "min_by",
   234  			arguments: []argSpec{
   235  				{types: []jpType{jpArray}},
   236  				{types: []jpType{jpExpref}},
   237  			},
   238  			handler:   jpfMinBy,
   239  			hasExpRef: true,
   240  		},
   241  		"type": {
   242  			name: "type",
   243  			arguments: []argSpec{
   244  				{types: []jpType{jpAny}},
   245  			},
   246  			handler: jpfType,
   247  		},
   248  		"keys": {
   249  			name: "keys",
   250  			arguments: []argSpec{
   251  				{types: []jpType{jpObject}},
   252  			},
   253  			handler: jpfKeys,
   254  		},
   255  		"values": {
   256  			name: "values",
   257  			arguments: []argSpec{
   258  				{types: []jpType{jpObject}},
   259  			},
   260  			handler: jpfValues,
   261  		},
   262  		"sort": {
   263  			name: "sort",
   264  			arguments: []argSpec{
   265  				{types: []jpType{jpArrayString, jpArrayNumber}},
   266  			},
   267  			handler: jpfSort,
   268  		},
   269  		"sort_by": {
   270  			name: "sort_by",
   271  			arguments: []argSpec{
   272  				{types: []jpType{jpArray}},
   273  				{types: []jpType{jpExpref}},
   274  			},
   275  			handler:   jpfSortBy,
   276  			hasExpRef: true,
   277  		},
   278  		"join": {
   279  			name: "join",
   280  			arguments: []argSpec{
   281  				{types: []jpType{jpString}},
   282  				{types: []jpType{jpArrayString}},
   283  			},
   284  			handler: jpfJoin,
   285  		},
   286  		"reverse": {
   287  			name: "reverse",
   288  			arguments: []argSpec{
   289  				{types: []jpType{jpArray, jpString}},
   290  			},
   291  			handler: jpfReverse,
   292  		},
   293  		"to_array": {
   294  			name: "to_array",
   295  			arguments: []argSpec{
   296  				{types: []jpType{jpAny}},
   297  			},
   298  			handler: jpfToArray,
   299  		},
   300  		"to_string": {
   301  			name: "to_string",
   302  			arguments: []argSpec{
   303  				{types: []jpType{jpAny}},
   304  			},
   305  			handler: jpfToString,
   306  		},
   307  		"to_number": {
   308  			name: "to_number",
   309  			arguments: []argSpec{
   310  				{types: []jpType{jpAny}},
   311  			},
   312  			handler: jpfToNumber,
   313  		},
   314  		"not_null": {
   315  			name: "not_null",
   316  			arguments: []argSpec{
   317  				{types: []jpType{jpAny}, variadic: true},
   318  			},
   319  			handler: jpfNotNull,
   320  		},
   321  	}
   322  	return caller
   323  }
   324  
   325  func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) {
   326  	if len(e.arguments) == 0 {
   327  		return arguments, nil
   328  	}
   329  	if !e.arguments[len(e.arguments)-1].variadic {
   330  		if len(e.arguments) != len(arguments) {
   331  			return nil, errors.New("incorrect number of args")
   332  		}
   333  		for i, spec := range e.arguments {
   334  			userArg := arguments[i]
   335  			err := spec.typeCheck(userArg)
   336  			if err != nil {
   337  				return nil, err
   338  			}
   339  		}
   340  		return arguments, nil
   341  	}
   342  	if len(arguments) < len(e.arguments) {
   343  		return nil, errors.New("invalid arity")
   344  	}
   345  	return arguments, nil
   346  }
   347  
   348  func (a *argSpec) typeCheck(arg interface{}) error {
   349  	for _, t := range a.types {
   350  		switch t {
   351  		case jpNumber:
   352  			if _, ok := arg.(float64); ok {
   353  				return nil
   354  			}
   355  		case jpString:
   356  			if _, ok := arg.(string); ok {
   357  				return nil
   358  			}
   359  		case jpArray:
   360  			if isSliceType(arg) {
   361  				return nil
   362  			}
   363  		case jpObject:
   364  			if _, ok := arg.(map[string]interface{}); ok {
   365  				return nil
   366  			}
   367  		case jpArrayNumber:
   368  			if _, ok := toArrayNum(arg); ok {
   369  				return nil
   370  			}
   371  		case jpArrayString:
   372  			if _, ok := toArrayStr(arg); ok {
   373  				return nil
   374  			}
   375  		case jpAny:
   376  			return nil
   377  		case jpExpref:
   378  			if _, ok := arg.(expRef); ok {
   379  				return nil
   380  			}
   381  		}
   382  	}
   383  	return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types)
   384  }
   385  
   386  func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) {
   387  	entry, ok := f.functionTable[name]
   388  	if !ok {
   389  		return nil, errors.New("unknown function: " + name)
   390  	}
   391  	resolvedArgs, err := entry.resolveArgs(arguments)
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  	if entry.hasExpRef {
   396  		var extra []interface{}
   397  		extra = append(extra, intr)
   398  		resolvedArgs = append(extra, resolvedArgs...)
   399  	}
   400  	return entry.handler(resolvedArgs)
   401  }
   402  
   403  func jpfAbs(arguments []interface{}) (interface{}, error) {
   404  	num := arguments[0].(float64)
   405  	return math.Abs(num), nil
   406  }
   407  
   408  func jpfLength(arguments []interface{}) (interface{}, error) {
   409  	arg := arguments[0]
   410  	if c, ok := arg.(string); ok {
   411  		return float64(utf8.RuneCountInString(c)), nil
   412  	} else if isSliceType(arg) {
   413  		v := reflect.ValueOf(arg)
   414  		return float64(v.Len()), nil
   415  	} else if c, ok := arg.(map[string]interface{}); ok {
   416  		return float64(len(c)), nil
   417  	}
   418  	return nil, errors.New("could not compute length()")
   419  }
   420  
   421  func jpfStartsWith(arguments []interface{}) (interface{}, error) {
   422  	search := arguments[0].(string)
   423  	prefix := arguments[1].(string)
   424  	return strings.HasPrefix(search, prefix), nil
   425  }
   426  
   427  func jpfAvg(arguments []interface{}) (interface{}, error) {
   428  	// We've already type checked the value so we can safely use
   429  	// type assertions.
   430  	args := arguments[0].([]interface{})
   431  	length := float64(len(args))
   432  	numerator := 0.0
   433  	for _, n := range args {
   434  		numerator += n.(float64)
   435  	}
   436  	return numerator / length, nil
   437  }
   438  func jpfCeil(arguments []interface{}) (interface{}, error) {
   439  	val := arguments[0].(float64)
   440  	return math.Ceil(val), nil
   441  }
   442  func jpfContains(arguments []interface{}) (interface{}, error) {
   443  	search := arguments[0]
   444  	el := arguments[1]
   445  	if searchStr, ok := search.(string); ok {
   446  		if elStr, ok := el.(string); ok {
   447  			return strings.Contains(searchStr, elStr), nil
   448  		}
   449  		return false, nil
   450  	}
   451  	// Otherwise this is a generic contains for []interface{}
   452  	general := search.([]interface{})
   453  	for _, item := range general {
   454  		if item == el {
   455  			return true, nil
   456  		}
   457  	}
   458  	return false, nil
   459  }
   460  func jpfEndsWith(arguments []interface{}) (interface{}, error) {
   461  	search := arguments[0].(string)
   462  	suffix := arguments[1].(string)
   463  	return strings.HasSuffix(search, suffix), nil
   464  }
   465  func jpfFloor(arguments []interface{}) (interface{}, error) {
   466  	val := arguments[0].(float64)
   467  	return math.Floor(val), nil
   468  }
   469  func jpfMap(arguments []interface{}) (interface{}, error) {
   470  	intr := arguments[0].(*treeInterpreter)
   471  	exp := arguments[1].(expRef)
   472  	node := exp.ref
   473  	arr := arguments[2].([]interface{})
   474  	mapped := make([]interface{}, 0, len(arr))
   475  	for _, value := range arr {
   476  		current, err := intr.Execute(node, value)
   477  		if err != nil {
   478  			return nil, err
   479  		}
   480  		mapped = append(mapped, current)
   481  	}
   482  	return mapped, nil
   483  }
   484  func jpfMax(arguments []interface{}) (interface{}, error) {
   485  	if items, ok := toArrayNum(arguments[0]); ok {
   486  		if len(items) == 0 {
   487  			return nil, nil
   488  		}
   489  		if len(items) == 1 {
   490  			return items[0], nil
   491  		}
   492  		best := items[0]
   493  		for _, item := range items[1:] {
   494  			if item > best {
   495  				best = item
   496  			}
   497  		}
   498  		return best, nil
   499  	}
   500  	// Otherwise we're dealing with a max() of strings.
   501  	items, _ := toArrayStr(arguments[0])
   502  	if len(items) == 0 {
   503  		return nil, nil
   504  	}
   505  	if len(items) == 1 {
   506  		return items[0], nil
   507  	}
   508  	best := items[0]
   509  	for _, item := range items[1:] {
   510  		if item > best {
   511  			best = item
   512  		}
   513  	}
   514  	return best, nil
   515  }
   516  func jpfMerge(arguments []interface{}) (interface{}, error) {
   517  	final := make(map[string]interface{})
   518  	for _, m := range arguments {
   519  		mapped := m.(map[string]interface{})
   520  		for key, value := range mapped {
   521  			final[key] = value
   522  		}
   523  	}
   524  	return final, nil
   525  }
   526  func jpfMaxBy(arguments []interface{}) (interface{}, error) {
   527  	intr := arguments[0].(*treeInterpreter)
   528  	arr := arguments[1].([]interface{})
   529  	exp := arguments[2].(expRef)
   530  	node := exp.ref
   531  	if len(arr) == 0 {
   532  		return nil, nil
   533  	} else if len(arr) == 1 {
   534  		return arr[0], nil
   535  	}
   536  	start, err := intr.Execute(node, arr[0])
   537  	if err != nil {
   538  		return nil, err
   539  	}
   540  	switch t := start.(type) {
   541  	case float64:
   542  		bestVal := t
   543  		bestItem := arr[0]
   544  		for _, item := range arr[1:] {
   545  			result, err := intr.Execute(node, item)
   546  			if err != nil {
   547  				return nil, err
   548  			}
   549  			current, ok := result.(float64)
   550  			if !ok {
   551  				return nil, errors.New("invalid type, must be number")
   552  			}
   553  			if current > bestVal {
   554  				bestVal = current
   555  				bestItem = item
   556  			}
   557  		}
   558  		return bestItem, nil
   559  	case string:
   560  		bestVal := t
   561  		bestItem := arr[0]
   562  		for _, item := range arr[1:] {
   563  			result, err := intr.Execute(node, item)
   564  			if err != nil {
   565  				return nil, err
   566  			}
   567  			current, ok := result.(string)
   568  			if !ok {
   569  				return nil, errors.New("invalid type, must be string")
   570  			}
   571  			if current > bestVal {
   572  				bestVal = current
   573  				bestItem = item
   574  			}
   575  		}
   576  		return bestItem, nil
   577  	default:
   578  		return nil, errors.New("invalid type, must be number of string")
   579  	}
   580  }
   581  func jpfSum(arguments []interface{}) (interface{}, error) {
   582  	items, _ := toArrayNum(arguments[0])
   583  	sum := 0.0
   584  	for _, item := range items {
   585  		sum += item
   586  	}
   587  	return sum, nil
   588  }
   589  
   590  func jpfMin(arguments []interface{}) (interface{}, error) {
   591  	if items, ok := toArrayNum(arguments[0]); ok {
   592  		if len(items) == 0 {
   593  			return nil, nil
   594  		}
   595  		if len(items) == 1 {
   596  			return items[0], nil
   597  		}
   598  		best := items[0]
   599  		for _, item := range items[1:] {
   600  			if item < best {
   601  				best = item
   602  			}
   603  		}
   604  		return best, nil
   605  	}
   606  	items, _ := toArrayStr(arguments[0])
   607  	if len(items) == 0 {
   608  		return nil, nil
   609  	}
   610  	if len(items) == 1 {
   611  		return items[0], nil
   612  	}
   613  	best := items[0]
   614  	for _, item := range items[1:] {
   615  		if item < best {
   616  			best = item
   617  		}
   618  	}
   619  	return best, nil
   620  }
   621  
   622  func jpfMinBy(arguments []interface{}) (interface{}, error) {
   623  	intr := arguments[0].(*treeInterpreter)
   624  	arr := arguments[1].([]interface{})
   625  	exp := arguments[2].(expRef)
   626  	node := exp.ref
   627  	if len(arr) == 0 {
   628  		return nil, nil
   629  	} else if len(arr) == 1 {
   630  		return arr[0], nil
   631  	}
   632  	start, err := intr.Execute(node, arr[0])
   633  	if err != nil {
   634  		return nil, err
   635  	}
   636  	if t, ok := start.(float64); ok {
   637  		bestVal := t
   638  		bestItem := arr[0]
   639  		for _, item := range arr[1:] {
   640  			result, err := intr.Execute(node, item)
   641  			if err != nil {
   642  				return nil, err
   643  			}
   644  			current, ok := result.(float64)
   645  			if !ok {
   646  				return nil, errors.New("invalid type, must be number")
   647  			}
   648  			if current < bestVal {
   649  				bestVal = current
   650  				bestItem = item
   651  			}
   652  		}
   653  		return bestItem, nil
   654  	} else if t, ok := start.(string); ok {
   655  		bestVal := t
   656  		bestItem := arr[0]
   657  		for _, item := range arr[1:] {
   658  			result, err := intr.Execute(node, item)
   659  			if err != nil {
   660  				return nil, err
   661  			}
   662  			current, ok := result.(string)
   663  			if !ok {
   664  				return nil, errors.New("invalid type, must be string")
   665  			}
   666  			if current < bestVal {
   667  				bestVal = current
   668  				bestItem = item
   669  			}
   670  		}
   671  		return bestItem, nil
   672  	} else {
   673  		return nil, errors.New("invalid type, must be number of string")
   674  	}
   675  }
   676  func jpfType(arguments []interface{}) (interface{}, error) {
   677  	arg := arguments[0]
   678  	if _, ok := arg.(float64); ok {
   679  		return "number", nil
   680  	}
   681  	if _, ok := arg.(string); ok {
   682  		return "string", nil
   683  	}
   684  	if _, ok := arg.([]interface{}); ok {
   685  		return "array", nil
   686  	}
   687  	if _, ok := arg.(map[string]interface{}); ok {
   688  		return "object", nil
   689  	}
   690  	if arg == nil {
   691  		return "null", nil
   692  	}
   693  	if arg == true || arg == false {
   694  		return "boolean", nil
   695  	}
   696  	return nil, errors.New("unknown type")
   697  }
   698  func jpfKeys(arguments []interface{}) (interface{}, error) {
   699  	arg := arguments[0].(map[string]interface{})
   700  	collected := make([]interface{}, 0, len(arg))
   701  	for key := range arg {
   702  		collected = append(collected, key)
   703  	}
   704  	return collected, nil
   705  }
   706  func jpfValues(arguments []interface{}) (interface{}, error) {
   707  	arg := arguments[0].(map[string]interface{})
   708  	collected := make([]interface{}, 0, len(arg))
   709  	for _, value := range arg {
   710  		collected = append(collected, value)
   711  	}
   712  	return collected, nil
   713  }
   714  func jpfSort(arguments []interface{}) (interface{}, error) {
   715  	if items, ok := toArrayNum(arguments[0]); ok {
   716  		d := sort.Float64Slice(items)
   717  		sort.Stable(d)
   718  		final := make([]interface{}, len(d))
   719  		for i, val := range d {
   720  			final[i] = val
   721  		}
   722  		return final, nil
   723  	}
   724  	// Otherwise we're dealing with sort()'ing strings.
   725  	items, _ := toArrayStr(arguments[0])
   726  	d := sort.StringSlice(items)
   727  	sort.Stable(d)
   728  	final := make([]interface{}, len(d))
   729  	for i, val := range d {
   730  		final[i] = val
   731  	}
   732  	return final, nil
   733  }
   734  func jpfSortBy(arguments []interface{}) (interface{}, error) {
   735  	intr := arguments[0].(*treeInterpreter)
   736  	arr := arguments[1].([]interface{})
   737  	exp := arguments[2].(expRef)
   738  	node := exp.ref
   739  	if len(arr) == 0 {
   740  		return arr, nil
   741  	} else if len(arr) == 1 {
   742  		return arr, nil
   743  	}
   744  	start, err := intr.Execute(node, arr[0])
   745  	if err != nil {
   746  		return nil, err
   747  	}
   748  	if _, ok := start.(float64); ok {
   749  		sortable := &byExprFloat{intr, node, arr, false}
   750  		sort.Stable(sortable)
   751  		if sortable.hasError {
   752  			return nil, errors.New("error in sort_by comparison")
   753  		}
   754  		return arr, nil
   755  	} else if _, ok := start.(string); ok {
   756  		sortable := &byExprString{intr, node, arr, false}
   757  		sort.Stable(sortable)
   758  		if sortable.hasError {
   759  			return nil, errors.New("error in sort_by comparison")
   760  		}
   761  		return arr, nil
   762  	} else {
   763  		return nil, errors.New("invalid type, must be number of string")
   764  	}
   765  }
   766  func jpfJoin(arguments []interface{}) (interface{}, error) {
   767  	sep := arguments[0].(string)
   768  	// We can't just do arguments[1].([]string), we have to
   769  	// manually convert each item to a string.
   770  	arrayStr := []string{}
   771  	for _, item := range arguments[1].([]interface{}) {
   772  		arrayStr = append(arrayStr, item.(string))
   773  	}
   774  	return strings.Join(arrayStr, sep), nil
   775  }
   776  func jpfReverse(arguments []interface{}) (interface{}, error) {
   777  	if s, ok := arguments[0].(string); ok {
   778  		r := []rune(s)
   779  		for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
   780  			r[i], r[j] = r[j], r[i]
   781  		}
   782  		return string(r), nil
   783  	}
   784  	items := arguments[0].([]interface{})
   785  	length := len(items)
   786  	reversed := make([]interface{}, length)
   787  	for i, item := range items {
   788  		reversed[length-(i+1)] = item
   789  	}
   790  	return reversed, nil
   791  }
   792  func jpfToArray(arguments []interface{}) (interface{}, error) {
   793  	if _, ok := arguments[0].([]interface{}); ok {
   794  		return arguments[0], nil
   795  	}
   796  	return arguments[:1:1], nil
   797  }
   798  func jpfToString(arguments []interface{}) (interface{}, error) {
   799  	if v, ok := arguments[0].(string); ok {
   800  		return v, nil
   801  	}
   802  	result, err := json.Marshal(arguments[0])
   803  	if err != nil {
   804  		return nil, err
   805  	}
   806  	return string(result), nil
   807  }
   808  func jpfToNumber(arguments []interface{}) (interface{}, error) {
   809  	arg := arguments[0]
   810  	if v, ok := arg.(float64); ok {
   811  		return v, nil
   812  	}
   813  	if v, ok := arg.(string); ok {
   814  		conv, err := strconv.ParseFloat(v, 64)
   815  		if err != nil {
   816  			return nil, nil
   817  		}
   818  		return conv, nil
   819  	}
   820  	if _, ok := arg.([]interface{}); ok {
   821  		return nil, nil
   822  	}
   823  	if _, ok := arg.(map[string]interface{}); ok {
   824  		return nil, nil
   825  	}
   826  	if arg == nil {
   827  		return nil, nil
   828  	}
   829  	if arg == true || arg == false {
   830  		return nil, nil
   831  	}
   832  	return nil, errors.New("unknown type")
   833  }
   834  func jpfNotNull(arguments []interface{}) (interface{}, error) {
   835  	for _, arg := range arguments {
   836  		if arg != nil {
   837  			return arg, nil
   838  		}
   839  	}
   840  	return nil, nil
   841  }
   842  

View as plain text