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 }