github.com/expr-lang/expr@v1.16.9/vm/runtime/runtime.go (about)

     1  package runtime
     2  
     3  //go:generate sh -c "go run ./helpers > ./helpers[generated].go"
     4  
     5  import (
     6  	"fmt"
     7  	"math"
     8  	"reflect"
     9  
    10  	"github.com/expr-lang/expr/internal/deref"
    11  )
    12  
    13  func Fetch(from, i any) any {
    14  	v := reflect.ValueOf(from)
    15  	if v.Kind() == reflect.Invalid {
    16  		panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
    17  	}
    18  
    19  	// Methods can be defined on any type.
    20  	if v.NumMethod() > 0 {
    21  		if methodName, ok := i.(string); ok {
    22  			method := v.MethodByName(methodName)
    23  			if method.IsValid() {
    24  				return method.Interface()
    25  			}
    26  		}
    27  	}
    28  
    29  	// Structs, maps, and slices can be access through a pointer or through
    30  	// a value, when they are accessed through a pointer we don't want to
    31  	// copy them to a value.
    32  	// De-reference everything if necessary (interface and pointers)
    33  	v = deref.Value(v)
    34  
    35  	switch v.Kind() {
    36  	case reflect.Array, reflect.Slice, reflect.String:
    37  		index := ToInt(i)
    38  		l := v.Len()
    39  		if index < 0 {
    40  			index = l + index
    41  		}
    42  		if index < 0 || index >= l {
    43  			panic(fmt.Sprintf("index out of range: %v (array length is %v)", index, l))
    44  		}
    45  		value := v.Index(index)
    46  		if value.IsValid() {
    47  			return value.Interface()
    48  		}
    49  
    50  	case reflect.Map:
    51  		var value reflect.Value
    52  		if i == nil {
    53  			value = v.MapIndex(reflect.Zero(v.Type().Key()))
    54  		} else {
    55  			value = v.MapIndex(reflect.ValueOf(i))
    56  		}
    57  		if value.IsValid() {
    58  			return value.Interface()
    59  		} else {
    60  			elem := reflect.TypeOf(from).Elem()
    61  			return reflect.Zero(elem).Interface()
    62  		}
    63  
    64  	case reflect.Struct:
    65  		fieldName := i.(string)
    66  		value := v.FieldByNameFunc(func(name string) bool {
    67  			field, _ := v.Type().FieldByName(name)
    68  			if field.Tag.Get("expr") == fieldName {
    69  				return true
    70  			}
    71  			return name == fieldName
    72  		})
    73  		if value.IsValid() {
    74  			return value.Interface()
    75  		}
    76  	}
    77  	panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
    78  }
    79  
    80  type Field struct {
    81  	Index []int
    82  	Path  []string
    83  }
    84  
    85  func FetchField(from any, field *Field) any {
    86  	v := reflect.ValueOf(from)
    87  	if v.Kind() != reflect.Invalid {
    88  		v = reflect.Indirect(v)
    89  
    90  		// We can use v.FieldByIndex here, but it will panic if the field
    91  		// is not exists. And we need to recover() to generate a more
    92  		// user-friendly error message.
    93  		// Also, our fieldByIndex() function is slightly faster than the
    94  		// v.FieldByIndex() function as we don't need to verify what a field
    95  		// is a struct as we already did it on compilation step.
    96  		value := fieldByIndex(v, field)
    97  		if value.IsValid() {
    98  			return value.Interface()
    99  		}
   100  	}
   101  	panic(fmt.Sprintf("cannot get %v from %T", field.Path[0], from))
   102  }
   103  
   104  func fieldByIndex(v reflect.Value, field *Field) reflect.Value {
   105  	if len(field.Index) == 1 {
   106  		return v.Field(field.Index[0])
   107  	}
   108  	for i, x := range field.Index {
   109  		if i > 0 {
   110  			if v.Kind() == reflect.Ptr {
   111  				if v.IsNil() {
   112  					panic(fmt.Sprintf("cannot get %v from %v", field.Path[i], field.Path[i-1]))
   113  				}
   114  				v = v.Elem()
   115  			}
   116  		}
   117  		v = v.Field(x)
   118  	}
   119  	return v
   120  }
   121  
   122  type Method struct {
   123  	Index int
   124  	Name  string
   125  }
   126  
   127  func FetchMethod(from any, method *Method) any {
   128  	v := reflect.ValueOf(from)
   129  	kind := v.Kind()
   130  	if kind != reflect.Invalid {
   131  		// Methods can be defined on any type, no need to dereference.
   132  		method := v.Method(method.Index)
   133  		if method.IsValid() {
   134  			return method.Interface()
   135  		}
   136  	}
   137  	panic(fmt.Sprintf("cannot fetch %v from %T", method.Name, from))
   138  }
   139  
   140  func Slice(array, from, to any) any {
   141  	v := reflect.ValueOf(array)
   142  
   143  	switch v.Kind() {
   144  	case reflect.Array, reflect.Slice, reflect.String:
   145  		length := v.Len()
   146  		a, b := ToInt(from), ToInt(to)
   147  		if a < 0 {
   148  			a = length + a
   149  		}
   150  		if a < 0 {
   151  			a = 0
   152  		}
   153  		if b < 0 {
   154  			b = length + b
   155  		}
   156  		if b < 0 {
   157  			b = 0
   158  		}
   159  		if b > length {
   160  			b = length
   161  		}
   162  		if a > b {
   163  			a = b
   164  		}
   165  		value := v.Slice(a, b)
   166  		if value.IsValid() {
   167  			return value.Interface()
   168  		}
   169  
   170  	case reflect.Ptr:
   171  		value := v.Elem()
   172  		if value.IsValid() {
   173  			return Slice(value.Interface(), from, to)
   174  		}
   175  
   176  	}
   177  	panic(fmt.Sprintf("cannot slice %v", from))
   178  }
   179  
   180  func In(needle any, array any) bool {
   181  	if array == nil {
   182  		return false
   183  	}
   184  	v := reflect.ValueOf(array)
   185  
   186  	switch v.Kind() {
   187  
   188  	case reflect.Array, reflect.Slice:
   189  		for i := 0; i < v.Len(); i++ {
   190  			value := v.Index(i)
   191  			if value.IsValid() {
   192  				if Equal(value.Interface(), needle) {
   193  					return true
   194  				}
   195  			}
   196  		}
   197  		return false
   198  
   199  	case reflect.Map:
   200  		var value reflect.Value
   201  		if needle == nil {
   202  			value = v.MapIndex(reflect.Zero(v.Type().Key()))
   203  		} else {
   204  			value = v.MapIndex(reflect.ValueOf(needle))
   205  		}
   206  		if value.IsValid() {
   207  			return true
   208  		}
   209  		return false
   210  
   211  	case reflect.Struct:
   212  		n := reflect.ValueOf(needle)
   213  		if !n.IsValid() || n.Kind() != reflect.String {
   214  			panic(fmt.Sprintf("cannot use %T as field name of %T", needle, array))
   215  		}
   216  		value := v.FieldByName(n.String())
   217  		if value.IsValid() {
   218  			return true
   219  		}
   220  		return false
   221  
   222  	case reflect.Ptr:
   223  		value := v.Elem()
   224  		if value.IsValid() {
   225  			return In(needle, value.Interface())
   226  		}
   227  		return false
   228  	}
   229  
   230  	panic(fmt.Sprintf(`operator "in" not defined on %T`, array))
   231  }
   232  
   233  func Len(a any) int {
   234  	v := reflect.ValueOf(a)
   235  	switch v.Kind() {
   236  	case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
   237  		return v.Len()
   238  	default:
   239  		panic(fmt.Sprintf("invalid argument for len (type %T)", a))
   240  	}
   241  }
   242  
   243  func Negate(i any) any {
   244  	switch v := i.(type) {
   245  	case float32:
   246  		return -v
   247  	case float64:
   248  		return -v
   249  	case int:
   250  		return -v
   251  	case int8:
   252  		return -v
   253  	case int16:
   254  		return -v
   255  	case int32:
   256  		return -v
   257  	case int64:
   258  		return -v
   259  	case uint:
   260  		return -v
   261  	case uint8:
   262  		return -v
   263  	case uint16:
   264  		return -v
   265  	case uint32:
   266  		return -v
   267  	case uint64:
   268  		return -v
   269  	default:
   270  		panic(fmt.Sprintf("invalid operation: - %T", v))
   271  	}
   272  }
   273  
   274  func Exponent(a, b any) float64 {
   275  	return math.Pow(ToFloat64(a), ToFloat64(b))
   276  }
   277  
   278  func MakeRange(min, max int) []int {
   279  	size := max - min + 1
   280  	if size <= 0 {
   281  		return []int{}
   282  	}
   283  	rng := make([]int, size)
   284  	for i := range rng {
   285  		rng[i] = min + i
   286  	}
   287  	return rng
   288  }
   289  
   290  func ToInt(a any) int {
   291  	switch x := a.(type) {
   292  	case float32:
   293  		return int(x)
   294  	case float64:
   295  		return int(x)
   296  	case int:
   297  		return x
   298  	case int8:
   299  		return int(x)
   300  	case int16:
   301  		return int(x)
   302  	case int32:
   303  		return int(x)
   304  	case int64:
   305  		return int(x)
   306  	case uint:
   307  		return int(x)
   308  	case uint8:
   309  		return int(x)
   310  	case uint16:
   311  		return int(x)
   312  	case uint32:
   313  		return int(x)
   314  	case uint64:
   315  		return int(x)
   316  	default:
   317  		panic(fmt.Sprintf("invalid operation: int(%T)", x))
   318  	}
   319  }
   320  
   321  func ToInt64(a any) int64 {
   322  	switch x := a.(type) {
   323  	case float32:
   324  		return int64(x)
   325  	case float64:
   326  		return int64(x)
   327  	case int:
   328  		return int64(x)
   329  	case int8:
   330  		return int64(x)
   331  	case int16:
   332  		return int64(x)
   333  	case int32:
   334  		return int64(x)
   335  	case int64:
   336  		return x
   337  	case uint:
   338  		return int64(x)
   339  	case uint8:
   340  		return int64(x)
   341  	case uint16:
   342  		return int64(x)
   343  	case uint32:
   344  		return int64(x)
   345  	case uint64:
   346  		return int64(x)
   347  	default:
   348  		panic(fmt.Sprintf("invalid operation: int64(%T)", x))
   349  	}
   350  }
   351  
   352  func ToFloat64(a any) float64 {
   353  	switch x := a.(type) {
   354  	case float32:
   355  		return float64(x)
   356  	case float64:
   357  		return x
   358  	case int:
   359  		return float64(x)
   360  	case int8:
   361  		return float64(x)
   362  	case int16:
   363  		return float64(x)
   364  	case int32:
   365  		return float64(x)
   366  	case int64:
   367  		return float64(x)
   368  	case uint:
   369  		return float64(x)
   370  	case uint8:
   371  		return float64(x)
   372  	case uint16:
   373  		return float64(x)
   374  	case uint32:
   375  		return float64(x)
   376  	case uint64:
   377  		return float64(x)
   378  	default:
   379  		panic(fmt.Sprintf("invalid operation: float(%T)", x))
   380  	}
   381  }
   382  
   383  func IsNil(v any) bool {
   384  	if v == nil {
   385  		return true
   386  	}
   387  	r := reflect.ValueOf(v)
   388  	switch r.Kind() {
   389  	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
   390  		return r.IsNil()
   391  	default:
   392  		return false
   393  	}
   394  }