Add toPairs() and fromPairs()

This commit is contained in:
Anton Medvedev
2023-08-30 12:47:22 +02:00
parent cea6c64ab2
commit 7d18813005
3 changed files with 69 additions and 1 deletions
+64
View File
@@ -584,6 +584,70 @@ var Builtins = []*ast.Function{
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(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: "sort",
Func: func(args ...any) (any, error) {
+4
View File
@@ -94,6 +94,10 @@ func TestBuiltin(t *testing.T) {
{`get({foo: 1, bar: 2}, "unknown")`, nil},
{`"foo" in keys({foo: 1, bar: 2})`, true},
{`1 in values({foo: 1, bar: 2})`, true},
{`len(toPairs({foo: 1, bar: 2}))`, 2},
{`len(toPairs({}))`, 0},
{`fromPairs([["foo", 1], ["bar", 2]])`, map[any]any{"foo": 1, "bar": 2}},
{`fromPairs(toPairs({foo: 1, bar: 2}))`, map[any]any{"foo": 1, "bar": 2}},
{`groupBy(1..9, # % 2)`, map[any][]any{0: {2, 4, 6, 8}, 1: {1, 3, 5, 7, 9}}},
{`groupBy(1..9, # % 2)[0]`, []any{2, 4, 6, 8}},
{`groupBy(1..3, # > 1)[true]`, []any{2, 3}},
+1 -1
View File
@@ -9,8 +9,8 @@ var (
anyType = reflect.TypeOf(new(any)).Elem()
integerType = reflect.TypeOf(0)
floatType = reflect.TypeOf(float64(0))
stringType = reflect.TypeOf("")
arrayType = reflect.TypeOf([]any{})
mapType = reflect.TypeOf(map[any]any{})
)
func kind(t reflect.Type) reflect.Kind {