mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-12 18:51:02 +08:00
1070 lines
26 KiB
Go
1070 lines
26 KiB
Go
package builtin
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/expr-lang/expr/internal/deref"
|
|
"github.com/expr-lang/expr/vm/runtime"
|
|
)
|
|
|
|
var (
|
|
Index map[string]int
|
|
Names []string
|
|
)
|
|
|
|
func init() {
|
|
Index = make(map[string]int)
|
|
Names = make([]string, len(Builtins))
|
|
for i, fn := range Builtins {
|
|
Index[fn.Name] = i
|
|
Names[i] = fn.Name
|
|
}
|
|
}
|
|
|
|
var Builtins = []*Function{
|
|
{
|
|
Name: "all",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) bool)),
|
|
},
|
|
{
|
|
Name: "none",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) bool)),
|
|
},
|
|
{
|
|
Name: "any",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) bool)),
|
|
},
|
|
{
|
|
Name: "one",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) bool)),
|
|
},
|
|
{
|
|
Name: "filter",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) []any)),
|
|
},
|
|
{
|
|
Name: "map",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) any) []any)),
|
|
},
|
|
{
|
|
Name: "find",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) any)),
|
|
},
|
|
{
|
|
Name: "findIndex",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) int)),
|
|
},
|
|
{
|
|
Name: "findLast",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) any)),
|
|
},
|
|
{
|
|
Name: "findLastIndex",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) int)),
|
|
},
|
|
{
|
|
Name: "count",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) int)),
|
|
},
|
|
{
|
|
Name: "sum",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool) int)),
|
|
},
|
|
{
|
|
Name: "groupBy",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) any) map[any][]any)),
|
|
},
|
|
{
|
|
Name: "sortBy",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any) bool, string) []any)),
|
|
},
|
|
{
|
|
Name: "reduce",
|
|
Predicate: true,
|
|
Types: types(new(func([]any, func(any, any) any, any) any)),
|
|
},
|
|
{
|
|
Name: "len",
|
|
Fast: Len,
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Array, reflect.Map, reflect.Slice, reflect.String, reflect.Interface:
|
|
return integerType, nil
|
|
}
|
|
return anyType, fmt.Errorf("invalid argument for len (type %s)", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "type",
|
|
Fast: Type,
|
|
Types: types(new(func(any) string)),
|
|
},
|
|
{
|
|
Name: "abs",
|
|
Fast: Abs,
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
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, reflect.Interface:
|
|
return args[0], nil
|
|
}
|
|
return anyType, fmt.Errorf("invalid argument for abs (type %s)", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "ceil",
|
|
Fast: Ceil,
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
return validateRoundFunc("ceil", args)
|
|
},
|
|
},
|
|
{
|
|
Name: "floor",
|
|
Fast: Floor,
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
return validateRoundFunc("floor", args)
|
|
},
|
|
},
|
|
{
|
|
Name: "round",
|
|
Fast: Round,
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
return validateRoundFunc("round", args)
|
|
},
|
|
},
|
|
{
|
|
Name: "int",
|
|
Fast: Int,
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
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:
|
|
return integerType, nil
|
|
case reflect.String:
|
|
return integerType, nil
|
|
}
|
|
return anyType, fmt.Errorf("invalid argument for int (type %s)", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "float",
|
|
Fast: Float,
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface:
|
|
return floatType, 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:
|
|
return floatType, nil
|
|
case reflect.String:
|
|
return floatType, nil
|
|
}
|
|
return anyType, fmt.Errorf("invalid argument for float (type %s)", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "string",
|
|
Fast: String,
|
|
Types: types(new(func(any any) string)),
|
|
},
|
|
{
|
|
Name: "trim",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) == 1 {
|
|
return strings.TrimSpace(args[0].(string)), nil
|
|
} else if len(args) == 2 {
|
|
return strings.Trim(args[0].(string), args[1].(string)), nil
|
|
} else {
|
|
return nil, fmt.Errorf("invalid number of arguments for trim (expected 1 or 2, got %d)", len(args))
|
|
}
|
|
},
|
|
Types: types(
|
|
strings.TrimSpace,
|
|
strings.Trim,
|
|
),
|
|
},
|
|
{
|
|
Name: "trimPrefix",
|
|
Func: func(args ...any) (any, error) {
|
|
s := " "
|
|
if len(args) == 2 {
|
|
s = args[1].(string)
|
|
}
|
|
return strings.TrimPrefix(args[0].(string), s), nil
|
|
},
|
|
Types: types(
|
|
strings.TrimPrefix,
|
|
new(func(string) string),
|
|
),
|
|
},
|
|
{
|
|
Name: "trimSuffix",
|
|
Func: func(args ...any) (any, error) {
|
|
s := " "
|
|
if len(args) == 2 {
|
|
s = args[1].(string)
|
|
}
|
|
return strings.TrimSuffix(args[0].(string), s), nil
|
|
},
|
|
Types: types(
|
|
strings.TrimSuffix,
|
|
new(func(string) string),
|
|
),
|
|
},
|
|
{
|
|
Name: "upper",
|
|
Fast: func(arg any) any {
|
|
return strings.ToUpper(arg.(string))
|
|
},
|
|
Types: types(strings.ToUpper),
|
|
},
|
|
{
|
|
Name: "lower",
|
|
Fast: func(arg any) any {
|
|
return strings.ToLower(arg.(string))
|
|
},
|
|
Types: types(strings.ToLower),
|
|
},
|
|
{
|
|
Name: "split",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) == 2 {
|
|
return strings.Split(args[0].(string), args[1].(string)), nil
|
|
} else if len(args) == 3 {
|
|
return strings.SplitN(args[0].(string), args[1].(string), runtime.ToInt(args[2])), nil
|
|
} else {
|
|
return nil, fmt.Errorf("invalid number of arguments for split (expected 2 or 3, got %d)", len(args))
|
|
}
|
|
},
|
|
Types: types(
|
|
strings.Split,
|
|
strings.SplitN,
|
|
),
|
|
},
|
|
{
|
|
Name: "splitAfter",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) == 2 {
|
|
return strings.SplitAfter(args[0].(string), args[1].(string)), nil
|
|
} else if len(args) == 3 {
|
|
return strings.SplitAfterN(args[0].(string), args[1].(string), runtime.ToInt(args[2])), nil
|
|
} else {
|
|
return nil, fmt.Errorf("invalid number of arguments for splitAfter (expected 2 or 3, got %d)", len(args))
|
|
}
|
|
},
|
|
Types: types(
|
|
strings.SplitAfter,
|
|
strings.SplitAfterN,
|
|
),
|
|
},
|
|
{
|
|
Name: "replace",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) == 4 {
|
|
return strings.Replace(args[0].(string), args[1].(string), args[2].(string), runtime.ToInt(args[3])), nil
|
|
} else if len(args) == 3 {
|
|
return strings.ReplaceAll(args[0].(string), args[1].(string), args[2].(string)), nil
|
|
} else {
|
|
return nil, fmt.Errorf("invalid number of arguments for replace (expected 3 or 4, got %d)", len(args))
|
|
}
|
|
},
|
|
Types: types(
|
|
strings.Replace,
|
|
strings.ReplaceAll,
|
|
),
|
|
},
|
|
{
|
|
Name: "repeat",
|
|
Safe: func(args ...any) (any, uint, error) {
|
|
s := args[0].(string)
|
|
n := runtime.ToInt(args[1])
|
|
if n < 0 {
|
|
return nil, 0, fmt.Errorf("invalid argument for repeat (expected positive integer, got %d)", n)
|
|
}
|
|
if n > 1e6 {
|
|
return nil, 0, fmt.Errorf("memory budget exceeded")
|
|
}
|
|
return strings.Repeat(s, n), uint(len(s) * n), nil
|
|
},
|
|
Types: types(strings.Repeat),
|
|
},
|
|
{
|
|
Name: "join",
|
|
Func: func(args ...any) (any, error) {
|
|
glue := ""
|
|
if len(args) == 2 {
|
|
glue = args[1].(string)
|
|
}
|
|
switch args[0].(type) {
|
|
case []string:
|
|
return strings.Join(args[0].([]string), glue), nil
|
|
case []any:
|
|
var s []string
|
|
for _, arg := range args[0].([]any) {
|
|
s = append(s, arg.(string))
|
|
}
|
|
return strings.Join(s, glue), nil
|
|
}
|
|
return nil, fmt.Errorf("invalid argument for join (type %s)", reflect.TypeOf(args[0]))
|
|
},
|
|
Types: types(
|
|
strings.Join,
|
|
new(func([]any, string) string),
|
|
new(func([]any) string),
|
|
new(func([]string, string) string),
|
|
new(func([]string) string),
|
|
),
|
|
},
|
|
{
|
|
Name: "indexOf",
|
|
Func: func(args ...any) (any, error) {
|
|
return strings.Index(args[0].(string), args[1].(string)), nil
|
|
},
|
|
Types: types(strings.Index),
|
|
},
|
|
{
|
|
Name: "lastIndexOf",
|
|
Func: func(args ...any) (any, error) {
|
|
return strings.LastIndex(args[0].(string), args[1].(string)), nil
|
|
},
|
|
Types: types(strings.LastIndex),
|
|
},
|
|
{
|
|
Name: "hasPrefix",
|
|
Func: func(args ...any) (any, error) {
|
|
return strings.HasPrefix(args[0].(string), args[1].(string)), nil
|
|
},
|
|
Types: types(strings.HasPrefix),
|
|
},
|
|
{
|
|
Name: "hasSuffix",
|
|
Func: func(args ...any) (any, error) {
|
|
return strings.HasSuffix(args[0].(string), args[1].(string)), nil
|
|
},
|
|
Types: types(strings.HasSuffix),
|
|
},
|
|
{
|
|
Name: "max",
|
|
Func: func(args ...any) (any, error) {
|
|
return minMax("max", runtime.Less, args...)
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
return validateAggregateFunc("max", args)
|
|
},
|
|
},
|
|
{
|
|
Name: "min",
|
|
Func: func(args ...any) (any, error) {
|
|
return minMax("min", runtime.More, args...)
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
return validateAggregateFunc("min", args)
|
|
},
|
|
},
|
|
{
|
|
Name: "mean",
|
|
Func: func(args ...any) (any, error) {
|
|
count, sum, err := mean(args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if count == 0 {
|
|
return 0.0, nil
|
|
}
|
|
return sum / float64(count), nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
return validateAggregateFunc("mean", args)
|
|
},
|
|
},
|
|
{
|
|
Name: "median",
|
|
Func: func(args ...any) (any, error) {
|
|
values, err := median(args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if n := len(values); n > 0 {
|
|
sort.Float64s(values)
|
|
if n%2 == 1 {
|
|
return values[n/2], nil
|
|
}
|
|
return (values[n/2-1] + values[n/2]) / 2, nil
|
|
}
|
|
return 0.0, nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
return validateAggregateFunc("median", args)
|
|
},
|
|
},
|
|
{
|
|
Name: "toJSON",
|
|
Func: func(args ...any) (any, error) {
|
|
b, err := json.MarshalIndent(args[0], "", " ")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return string(b), nil
|
|
},
|
|
Types: types(new(func(any) string)),
|
|
},
|
|
{
|
|
Name: "fromJSON",
|
|
Func: func(args ...any) (any, error) {
|
|
var v any
|
|
err := json.Unmarshal([]byte(args[0].(string)), &v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return v, nil
|
|
},
|
|
Types: types(new(func(string) any)),
|
|
},
|
|
{
|
|
Name: "toBase64",
|
|
Func: func(args ...any) (any, error) {
|
|
return base64.StdEncoding.EncodeToString([]byte(args[0].(string))), nil
|
|
},
|
|
Types: types(new(func(string) string)),
|
|
},
|
|
{
|
|
Name: "fromBase64",
|
|
Func: func(args ...any) (any, error) {
|
|
b, err := base64.StdEncoding.DecodeString(args[0].(string))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return string(b), nil
|
|
},
|
|
Types: types(new(func(string) string)),
|
|
},
|
|
{
|
|
Name: "now",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) == 0 {
|
|
return time.Now(), nil
|
|
}
|
|
if len(args) == 1 {
|
|
if tz, ok := args[0].(*time.Location); ok {
|
|
return time.Now().In(tz), nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("invalid number of arguments (expected 0, got %d)", len(args))
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) == 0 {
|
|
return timeType, nil
|
|
}
|
|
if len(args) == 1 {
|
|
if args[0] != nil && args[0].AssignableTo(locationType) {
|
|
return timeType, nil
|
|
}
|
|
}
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 0, got %d)", len(args))
|
|
},
|
|
Deref: func(i int, arg reflect.Type) bool {
|
|
return false
|
|
},
|
|
},
|
|
{
|
|
Name: "duration",
|
|
Func: func(args ...any) (any, error) {
|
|
return time.ParseDuration(args[0].(string))
|
|
},
|
|
Types: types(time.ParseDuration),
|
|
},
|
|
{
|
|
Name: "date",
|
|
Func: func(args ...any) (any, error) {
|
|
tz, ok := args[0].(*time.Location)
|
|
if ok {
|
|
args = args[1:]
|
|
}
|
|
|
|
date := args[0].(string)
|
|
if len(args) == 2 {
|
|
layout := args[1].(string)
|
|
if tz != nil {
|
|
return time.ParseInLocation(layout, date, tz)
|
|
}
|
|
return time.Parse(layout, date)
|
|
}
|
|
if len(args) == 3 {
|
|
layout := args[1].(string)
|
|
timeZone := args[2].(string)
|
|
tz, err := time.LoadLocation(timeZone)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t, err := time.ParseInLocation(layout, date, tz)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return t, nil
|
|
}
|
|
|
|
layouts := []string{
|
|
"2006-01-02",
|
|
"15:04:05",
|
|
"2006-01-02 15:04:05",
|
|
time.RFC3339,
|
|
time.RFC822,
|
|
time.RFC850,
|
|
time.RFC1123,
|
|
}
|
|
for _, layout := range layouts {
|
|
if tz == nil {
|
|
t, err := time.Parse(layout, date)
|
|
if err == nil {
|
|
return t, nil
|
|
}
|
|
} else {
|
|
t, err := time.ParseInLocation(layout, date, tz)
|
|
if err == nil {
|
|
return t, nil
|
|
}
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("invalid date %s", date)
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) < 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected at least 1, got %d)", len(args))
|
|
}
|
|
if args[0] != nil && args[0].AssignableTo(locationType) {
|
|
args = args[1:]
|
|
}
|
|
if len(args) > 3 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected at most 3, got %d)", len(args))
|
|
}
|
|
return timeType, nil
|
|
},
|
|
Deref: func(i int, arg reflect.Type) bool {
|
|
if arg.AssignableTo(locationType) {
|
|
return false
|
|
}
|
|
return true
|
|
},
|
|
},
|
|
{
|
|
Name: "timezone",
|
|
Func: func(args ...any) (any, error) {
|
|
tz, err := time.LoadLocation(args[0].(string))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return tz, nil
|
|
},
|
|
Types: types(time.LoadLocation),
|
|
},
|
|
{
|
|
Name: "first",
|
|
Func: func(args ...any) (any, error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
return
|
|
}
|
|
}()
|
|
return runtime.Fetch(args[0], 0), nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface:
|
|
return anyType, nil
|
|
case reflect.Slice, reflect.Array:
|
|
return args[0].Elem(), nil
|
|
}
|
|
return anyType, fmt.Errorf("cannot get first element from %s", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "last",
|
|
Func: func(args ...any) (any, error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
return
|
|
}
|
|
}()
|
|
return runtime.Fetch(args[0], -1), nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface:
|
|
return anyType, nil
|
|
case reflect.Slice, reflect.Array:
|
|
return args[0].Elem(), nil
|
|
}
|
|
return anyType, fmt.Errorf("cannot get last element from %s", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "get",
|
|
Func: get,
|
|
},
|
|
{
|
|
Name: "take",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) != 2 {
|
|
return nil, fmt.Errorf("invalid number of arguments (expected 2, got %d)", len(args))
|
|
}
|
|
v := reflect.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])
|
|
if !n.CanInt() {
|
|
return nil, fmt.Errorf("cannot take %s elements", n.Kind())
|
|
}
|
|
to := 0
|
|
if n.Int() > int64(v.Len()) {
|
|
to = v.Len()
|
|
} else {
|
|
to = int(n.Int())
|
|
}
|
|
return v.Slice(0, to).Interface(), nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 2 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 2, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface, reflect.Slice, reflect.Array:
|
|
default:
|
|
return anyType, fmt.Errorf("cannot take from %s", args[0])
|
|
}
|
|
switch kind(args[1]) {
|
|
case reflect.Interface, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
default:
|
|
return anyType, fmt.Errorf("cannot take %s elements", args[1])
|
|
}
|
|
return args[0], nil
|
|
},
|
|
},
|
|
{
|
|
Name: "keys",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) != 1 {
|
|
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
v := reflect.ValueOf(args[0])
|
|
if v.Kind() != reflect.Map {
|
|
return nil, fmt.Errorf("cannot get keys from %s", v.Kind())
|
|
}
|
|
keys := v.MapKeys()
|
|
out := make([]any, len(keys))
|
|
for i, key := range keys {
|
|
out[i] = key.Interface()
|
|
}
|
|
return out, nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface:
|
|
return arrayType, nil
|
|
case reflect.Map:
|
|
return arrayType, nil
|
|
}
|
|
return anyType, fmt.Errorf("cannot get keys from %s", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "values",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) != 1 {
|
|
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
v := reflect.ValueOf(args[0])
|
|
if v.Kind() != reflect.Map {
|
|
return nil, fmt.Errorf("cannot get values from %s", v.Kind())
|
|
}
|
|
keys := v.MapKeys()
|
|
out := make([]any, len(keys))
|
|
for i, key := range keys {
|
|
out[i] = v.MapIndex(key).Interface()
|
|
}
|
|
return out, nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface:
|
|
return arrayType, nil
|
|
case reflect.Map:
|
|
return arrayType, nil
|
|
}
|
|
return anyType, fmt.Errorf("cannot get values from %s", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "toPairs",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) != 1 {
|
|
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
v := reflect.ValueOf(args[0])
|
|
if v.Kind() != reflect.Map {
|
|
return nil, fmt.Errorf("cannot transform %s to pairs", v.Kind())
|
|
}
|
|
keys := v.MapKeys()
|
|
out := make([][2]any, len(keys))
|
|
for i, key := range keys {
|
|
out[i] = [2]any{key.Interface(), v.MapIndex(key).Interface()}
|
|
}
|
|
return out, nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface, reflect.Map:
|
|
return arrayType, nil
|
|
}
|
|
return anyType, fmt.Errorf("cannot transform %s to pairs", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "fromPairs",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) != 1 {
|
|
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
v := reflect.ValueOf(args[0])
|
|
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
|
return nil, fmt.Errorf("cannot transform %s from pairs", v)
|
|
}
|
|
out := reflect.MakeMap(mapType)
|
|
for i := 0; i < v.Len(); i++ {
|
|
pair := deref.Value(v.Index(i))
|
|
if pair.Kind() != reflect.Array && pair.Kind() != reflect.Slice {
|
|
return nil, fmt.Errorf("invalid pair %v", pair)
|
|
}
|
|
if pair.Len() != 2 {
|
|
return nil, fmt.Errorf("invalid pair length %v", pair)
|
|
}
|
|
key := pair.Index(0)
|
|
value := pair.Index(1)
|
|
out.SetMapIndex(key, value)
|
|
}
|
|
return out.Interface(), nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface, reflect.Slice, reflect.Array:
|
|
return mapType, nil
|
|
}
|
|
return anyType, fmt.Errorf("cannot transform %s from pairs", args[0])
|
|
},
|
|
},
|
|
{
|
|
Name: "reverse",
|
|
Safe: func(args ...any) (any, uint, error) {
|
|
if len(args) != 1 {
|
|
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
|
|
v := reflect.ValueOf(args[0])
|
|
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
|
return nil, 0, fmt.Errorf("cannot reverse %s", v.Kind())
|
|
}
|
|
|
|
size := v.Len()
|
|
arr := make([]any, size)
|
|
|
|
for i := 0; i < size; i++ {
|
|
arr[i] = v.Index(size - i - 1).Interface()
|
|
}
|
|
|
|
return arr, uint(size), nil
|
|
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
switch kind(args[0]) {
|
|
case reflect.Interface, reflect.Slice, reflect.Array:
|
|
return arrayType, nil
|
|
default:
|
|
return anyType, fmt.Errorf("cannot reverse %s", args[0])
|
|
}
|
|
},
|
|
},
|
|
|
|
{
|
|
Name: "uniq",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) != 1 {
|
|
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
|
|
v := reflect.ValueOf(args[0])
|
|
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
|
|
return nil, fmt.Errorf("cannot uniq %s", v.Kind())
|
|
}
|
|
|
|
size := v.Len()
|
|
ret := []any{}
|
|
|
|
eq := func(i int) bool {
|
|
for _, r := range ret {
|
|
if runtime.Equal(v.Index(i).Interface(), r) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
for i := 0; i < size; i += 1 {
|
|
if eq(i) {
|
|
continue
|
|
}
|
|
|
|
ret = append(ret, v.Index(i).Interface())
|
|
}
|
|
|
|
return ret, nil
|
|
},
|
|
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
|
|
switch kind(args[0]) {
|
|
case reflect.Interface, reflect.Slice, reflect.Array:
|
|
return arrayType, nil
|
|
default:
|
|
return anyType, fmt.Errorf("cannot uniq %s", args[0])
|
|
}
|
|
},
|
|
},
|
|
|
|
{
|
|
Name: "concat",
|
|
Safe: func(args ...any) (any, uint, error) {
|
|
if len(args) == 0 {
|
|
return nil, 0, fmt.Errorf("invalid number of arguments (expected at least 1, got 0)")
|
|
}
|
|
|
|
var size uint
|
|
var arr []any
|
|
|
|
for _, arg := range args {
|
|
v := reflect.ValueOf(arg)
|
|
|
|
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
|
return nil, 0, fmt.Errorf("cannot concat %s", v.Kind())
|
|
}
|
|
|
|
size += uint(v.Len())
|
|
|
|
for i := 0; i < v.Len(); i++ {
|
|
item := v.Index(i)
|
|
arr = append(arr, item.Interface())
|
|
}
|
|
}
|
|
|
|
return arr, size, nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) == 0 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected at least 1, got 0)")
|
|
}
|
|
|
|
for _, arg := range args {
|
|
switch kind(arg) {
|
|
case reflect.Interface, reflect.Slice, reflect.Array:
|
|
default:
|
|
return anyType, fmt.Errorf("cannot concat %s", arg)
|
|
}
|
|
}
|
|
|
|
return arrayType, nil
|
|
},
|
|
},
|
|
{
|
|
Name: "flatten",
|
|
Safe: func(args ...any) (any, uint, error) {
|
|
var size uint
|
|
if len(args) != 1 {
|
|
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
v := reflect.ValueOf(args[0])
|
|
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
|
|
return nil, size, fmt.Errorf("cannot flatten %s", v.Kind())
|
|
}
|
|
ret := flatten(v)
|
|
size = uint(len(ret))
|
|
return ret, size, nil
|
|
},
|
|
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
|
if len(args) != 1 {
|
|
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
|
}
|
|
|
|
for _, arg := range args {
|
|
switch kind(arg) {
|
|
case reflect.Interface, reflect.Slice, reflect.Array:
|
|
default:
|
|
return anyType, fmt.Errorf("cannot flatten %s", arg)
|
|
}
|
|
}
|
|
|
|
return arrayType, nil
|
|
},
|
|
},
|
|
{
|
|
Name: "sort",
|
|
Safe: func(args ...any) (any, uint, error) {
|
|
if len(args) != 1 && len(args) != 2 {
|
|
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1 or 2, got %d)", len(args))
|
|
}
|
|
|
|
var array []any
|
|
|
|
switch in := args[0].(type) {
|
|
case []any:
|
|
array = make([]any, len(in))
|
|
copy(array, in)
|
|
case []int:
|
|
array = make([]any, len(in))
|
|
for i, v := range in {
|
|
array[i] = v
|
|
}
|
|
case []float64:
|
|
array = make([]any, len(in))
|
|
for i, v := range in {
|
|
array[i] = v
|
|
}
|
|
case []string:
|
|
array = make([]any, len(in))
|
|
for i, v := range in {
|
|
array[i] = v
|
|
}
|
|
}
|
|
|
|
var desc bool
|
|
if len(args) == 2 {
|
|
switch args[1].(string) {
|
|
case "asc":
|
|
desc = false
|
|
case "desc":
|
|
desc = true
|
|
default:
|
|
return nil, 0, fmt.Errorf("invalid order %s, expected asc or desc", args[1])
|
|
}
|
|
}
|
|
|
|
sortable := &runtime.Sort{
|
|
Desc: desc,
|
|
Array: array,
|
|
}
|
|
sort.Sort(sortable)
|
|
|
|
return sortable.Array, uint(len(array)), nil
|
|
},
|
|
Types: types(
|
|
new(func([]any, string) []any),
|
|
new(func([]int, string) []any),
|
|
new(func([]float64, string) []any),
|
|
new(func([]string, string) []any),
|
|
|
|
new(func([]any) []any),
|
|
new(func([]float64) []any),
|
|
new(func([]string) []any),
|
|
new(func([]int) []any),
|
|
),
|
|
},
|
|
bitFunc("bitand", func(x, y int) (any, error) {
|
|
return x & y, nil
|
|
}),
|
|
bitFunc("bitor", func(x, y int) (any, error) {
|
|
return x | y, nil
|
|
}),
|
|
bitFunc("bitxor", func(x, y int) (any, error) {
|
|
return x ^ y, nil
|
|
}),
|
|
bitFunc("bitnand", func(x, y int) (any, error) {
|
|
return x &^ y, nil
|
|
}),
|
|
bitFunc("bitshl", func(x, y int) (any, error) {
|
|
if y < 0 {
|
|
return nil, fmt.Errorf("invalid operation: negative shift count %d (type int)", y)
|
|
}
|
|
return x << y, nil
|
|
}),
|
|
bitFunc("bitshr", func(x, y int) (any, error) {
|
|
if y < 0 {
|
|
return nil, fmt.Errorf("invalid operation: negative shift count %d (type int)", y)
|
|
}
|
|
return x >> y, nil
|
|
}),
|
|
bitFunc("bitushr", func(x, y int) (any, error) {
|
|
if y < 0 {
|
|
return nil, fmt.Errorf("invalid operation: negative shift count %d (type int)", y)
|
|
}
|
|
return int(uint(x) >> y), nil
|
|
}),
|
|
{
|
|
Name: "bitnot",
|
|
Func: func(args ...any) (any, error) {
|
|
if len(args) != 1 {
|
|
return nil, fmt.Errorf("invalid number of arguments for bitnot (expected 1, got %d)", len(args))
|
|
}
|
|
x, err := toInt(args[0])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v to call bitnot", err)
|
|
}
|
|
return ^x, nil
|
|
},
|
|
Types: types(new(func(int) int)),
|
|
},
|
|
}
|