Skip to content

Commit

Permalink
Add toPairs() and fromPairs()
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmedv committed Aug 30, 2023
1 parent 323f23b commit 418fed5
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 1 deletion.
64 changes: 64 additions & 0 deletions builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions builtin/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}},
Expand Down
2 changes: 1 addition & 1 deletion builtin/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 418fed5

Please sign in to comment.