mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
+22
-19
@@ -164,7 +164,7 @@ var Builtins = []*Function{
|
||||
if len(args) != 1 {
|
||||
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
switch kind(deref.Type(args[0])) {
|
||||
switch kind(args[0]) {
|
||||
case reflect.Interface:
|
||||
return integerType, nil
|
||||
case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
@@ -642,18 +642,21 @@ var Builtins = []*Function{
|
||||
if len(args) != 2 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 2, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(args[0])
|
||||
v := deref.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return nil, fmt.Errorf("cannot take from %s", v.Kind())
|
||||
}
|
||||
n := reflect.ValueOf(args[1])
|
||||
n := deref.ValueOf(args[1])
|
||||
if !n.CanInt() {
|
||||
return nil, fmt.Errorf("cannot take %s elements", n.Kind())
|
||||
}
|
||||
to := 0
|
||||
if n.Int() > int64(v.Len()) {
|
||||
return args[0], nil
|
||||
to = v.Len()
|
||||
} else {
|
||||
to = int(n.Int())
|
||||
}
|
||||
return v.Slice(0, int(n.Int())).Interface(), nil
|
||||
return v.Slice(0, to).Interface(), nil
|
||||
},
|
||||
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
||||
if len(args) != 2 {
|
||||
@@ -678,7 +681,7 @@ var Builtins = []*Function{
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(args[0])
|
||||
v := deref.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Map {
|
||||
return nil, fmt.Errorf("cannot get keys from %s", v.Kind())
|
||||
}
|
||||
@@ -708,7 +711,7 @@ var Builtins = []*Function{
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(args[0])
|
||||
v := deref.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Map {
|
||||
return nil, fmt.Errorf("cannot get values from %s", v.Kind())
|
||||
}
|
||||
@@ -738,7 +741,7 @@ var Builtins = []*Function{
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(args[0])
|
||||
v := deref.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Map {
|
||||
return nil, fmt.Errorf("cannot transform %s to pairs", v.Kind())
|
||||
}
|
||||
@@ -766,7 +769,7 @@ var Builtins = []*Function{
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(args[0])
|
||||
v := deref.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return nil, fmt.Errorf("cannot transform %s from pairs", v)
|
||||
}
|
||||
@@ -798,14 +801,14 @@ var Builtins = []*Function{
|
||||
},
|
||||
{
|
||||
Name: "reverse",
|
||||
Func: func(args ...any) (any, error) {
|
||||
Safe: func(args ...any) (any, uint, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(args[0])
|
||||
v := deref.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return nil, fmt.Errorf("cannot reverse %s", v.Kind())
|
||||
return nil, 0, fmt.Errorf("cannot reverse %s", v.Kind())
|
||||
}
|
||||
|
||||
size := v.Len()
|
||||
@@ -815,7 +818,7 @@ var Builtins = []*Function{
|
||||
arr[i] = v.Index(size - i - 1).Interface()
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
return arr, uint(size), nil
|
||||
|
||||
},
|
||||
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
||||
@@ -838,7 +841,7 @@ var Builtins = []*Function{
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(deref.Deref(args[0]))
|
||||
v := deref.ValueOf(deref.Deref(args[0]))
|
||||
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
|
||||
return nil, fmt.Errorf("cannot uniq %s", v.Kind())
|
||||
}
|
||||
@@ -892,7 +895,7 @@ var Builtins = []*Function{
|
||||
var arr []any
|
||||
|
||||
for _, arg := range args {
|
||||
v := reflect.ValueOf(deref.Deref(arg))
|
||||
v := deref.ValueOf(deref.Deref(arg))
|
||||
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return nil, 0, fmt.Errorf("cannot concat %s", v.Kind())
|
||||
@@ -914,7 +917,7 @@ var Builtins = []*Function{
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
switch kind(deref.Type(arg)) {
|
||||
switch kind(arg) {
|
||||
case reflect.Interface, reflect.Slice, reflect.Array:
|
||||
default:
|
||||
return anyType, fmt.Errorf("cannot concat %s", arg)
|
||||
@@ -931,7 +934,7 @@ var Builtins = []*Function{
|
||||
if len(args) != 1 {
|
||||
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(deref.Deref(args[0]))
|
||||
v := deref.ValueOf(deref.Deref(args[0]))
|
||||
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
|
||||
return nil, size, fmt.Errorf("cannot flatten %s", v.Kind())
|
||||
}
|
||||
@@ -945,7 +948,7 @@ var Builtins = []*Function{
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
switch kind(deref.Type(arg)) {
|
||||
switch kind(arg) {
|
||||
case reflect.Interface, reflect.Slice, reflect.Array:
|
||||
default:
|
||||
return anyType, fmt.Errorf("cannot flatten %s", arg)
|
||||
|
||||
+38
-7
@@ -639,15 +639,46 @@ func Test_int_unwraps_underlying_value(t *testing.T) {
|
||||
assert.Equal(t, true, out)
|
||||
}
|
||||
|
||||
func TestBuiltin_int_with_deref(t *testing.T) {
|
||||
func TestBuiltin_with_deref(t *testing.T) {
|
||||
x := 42
|
||||
arr := []any{1, 2, 3}
|
||||
m := map[string]any{"a": 1, "b": 2}
|
||||
env := map[string]any{
|
||||
"x": &x,
|
||||
"x": &x,
|
||||
"arr": &arr,
|
||||
"m": &m,
|
||||
}
|
||||
program, err := expr.Compile(`int(x)`, expr.Env(env))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, env)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 42, out)
|
||||
tests := []struct {
|
||||
input string
|
||||
want any
|
||||
}{
|
||||
{`int(x)`, 42},
|
||||
{`float(x)`, 42.0},
|
||||
{`abs(x)`, 42},
|
||||
{`first(arr)`, 1},
|
||||
{`last(arr)`, 3},
|
||||
{`take(arr, 1)`, []any{1}},
|
||||
{`take(arr, x)`, []any{1, 2, 3}},
|
||||
{`'a' in keys(m)`, true},
|
||||
{`1 in values(m)`, true},
|
||||
{`len(arr)`, 3},
|
||||
{`type(arr)`, "array"},
|
||||
{`type(m)`, "map"},
|
||||
{`reverse(arr)`, []any{3, 2, 1}},
|
||||
{`uniq(arr)`, []any{1, 2, 3}},
|
||||
{`concat(arr, arr)`, []any{1, 2, 3, 1, 2, 3}},
|
||||
{`flatten([arr, [arr]])`, []any{1, 2, 3, 1, 2, 3}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
program, err := expr.Compile(test.input, expr.Env(env))
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := expr.Run(program, env)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.want, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+7
-16
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func Len(x any) any {
|
||||
v := reflect.ValueOf(x)
|
||||
v := deref.ValueOf(x)
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.Map:
|
||||
return v.Len()
|
||||
@@ -26,16 +26,7 @@ func Type(arg any) any {
|
||||
if arg == nil {
|
||||
return "nil"
|
||||
}
|
||||
v := reflect.ValueOf(arg)
|
||||
for {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
} else if v.Kind() == reflect.Interface {
|
||||
v = v.Elem()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
v := deref.ValueOf(arg)
|
||||
if v.Type().Name() != "" && v.Type().PkgPath() != "" {
|
||||
return fmt.Sprintf("%s.%s", v.Type().PkgPath(), v.Type().Name())
|
||||
}
|
||||
@@ -66,7 +57,7 @@ func Type(arg any) any {
|
||||
}
|
||||
|
||||
func Abs(x any) any {
|
||||
switch x := x.(type) {
|
||||
switch x := deref.Deref(x).(type) {
|
||||
case float32:
|
||||
if x < 0 {
|
||||
return -x
|
||||
@@ -221,7 +212,7 @@ func Int(x any) any {
|
||||
}
|
||||
|
||||
func Float(x any) any {
|
||||
switch x := x.(type) {
|
||||
switch x := deref.Deref(x).(type) {
|
||||
case float32:
|
||||
return float64(x)
|
||||
case float64:
|
||||
@@ -264,7 +255,7 @@ func String(arg any) any {
|
||||
func minMax(name string, fn func(any, any) bool, args ...any) (any, error) {
|
||||
var val any
|
||||
for _, arg := range args {
|
||||
rv := reflect.ValueOf(deref.Deref(arg))
|
||||
rv := deref.ValueOf(arg)
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
size := rv.Len()
|
||||
@@ -307,7 +298,7 @@ func mean(args ...any) (int, float64, error) {
|
||||
var count int
|
||||
|
||||
for _, arg := range args {
|
||||
rv := reflect.ValueOf(deref.Deref(arg))
|
||||
rv := deref.ValueOf(arg)
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
size := rv.Len()
|
||||
@@ -339,7 +330,7 @@ func median(args ...any) ([]float64, error) {
|
||||
var values []float64
|
||||
|
||||
for _, arg := range args {
|
||||
rv := reflect.ValueOf(deref.Deref(arg))
|
||||
rv := deref.ValueOf(arg)
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
size := rv.Len()
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/expr-lang/expr/internal/deref"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,6 +22,7 @@ func kind(t reflect.Type) reflect.Kind {
|
||||
if t == nil {
|
||||
return reflect.Invalid
|
||||
}
|
||||
t = deref.Type(t)
|
||||
return t.Kind()
|
||||
}
|
||||
|
||||
|
||||
@@ -45,3 +45,7 @@ func Value(v reflect.Value) reflect.Value {
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func ValueOf(v any) reflect.Value {
|
||||
return Value(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user