Skip to content

Commit 83b8df3

Browse files
authored
code(builtin) - add reverse function (#553)
* code(builtin) - add reverse function * docs(language-definition.md) - add reverse function
1 parent 013c32f commit 83b8df3

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

Diff for: builtin/builtin.go

+34
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,40 @@ var Builtins = []*Function{
868868
return anyType, fmt.Errorf("cannot transform %s from pairs", args[0])
869869
},
870870
},
871+
{
872+
Name: "reverse",
873+
Func: func(args ...any) (any, error) {
874+
if len(args) != 1 {
875+
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
876+
}
877+
878+
v := reflect.ValueOf(args[0])
879+
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
880+
return nil, fmt.Errorf("cannot reverse %s", v.Kind())
881+
}
882+
883+
size := v.Len()
884+
arr := make([]any, size)
885+
886+
for i := 0; i < size; i++ {
887+
arr[i] = v.Index(size - i - 1).Interface()
888+
}
889+
890+
return arr, nil
891+
892+
},
893+
Validate: func(args []reflect.Type) (reflect.Type, error) {
894+
if len(args) != 1 {
895+
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
896+
}
897+
switch kind(args[0]) {
898+
case reflect.Interface, reflect.Slice, reflect.Array:
899+
return arrayType, nil
900+
default:
901+
return anyType, fmt.Errorf("cannot reverse %s", args[0])
902+
}
903+
},
904+
},
871905
{
872906
Name: "sort",
873907
Func: func(args ...any) (any, error) {

Diff for: builtin/builtin_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,38 @@ func TestBuiltin_type(t *testing.T) {
483483
}
484484
}
485485

486+
func TestBuiltin_reverse(t *testing.T) {
487+
env := map[string]any{
488+
"ArrayOfString": []string{"foo", "bar", "baz"},
489+
"ArrayOfInt": []int{2, 1, 3},
490+
"ArrayOfFloat": []float64{3.0, 2.0, 1.0},
491+
"ArrayOfFoo": []mock.Foo{{Value: "c"}, {Value: "a"}, {Value: "b"}},
492+
}
493+
tests := []struct {
494+
input string
495+
want any
496+
}{
497+
{`reverse([])`, []any{}},
498+
{`reverse(ArrayOfInt)`, []any{3, 1, 2}},
499+
{`reverse(ArrayOfFloat)`, []any{1.0, 2.0, 3.0}},
500+
{`reverse(ArrayOfFoo)`, []any{mock.Foo{Value: "b"}, mock.Foo{Value: "a"}, mock.Foo{Value: "c"}}},
501+
{`reverse([[1,2], [2,2]])`, []any{[]any{2, 2}, []any{1, 2}}},
502+
{`reverse(reverse([[1,2], [2,2]]))`, []any{[]any{1, 2}, []any{2, 2}}},
503+
{`reverse([{"test": true}, {id:4}, {name: "value"}])`, []any{map[string]any{"name": "value"}, map[string]any{"id": 4}, map[string]any{"test": true}}},
504+
}
505+
506+
for _, test := range tests {
507+
t.Run(test.input, func(t *testing.T) {
508+
program, err := expr.Compile(test.input, expr.Env(env))
509+
require.NoError(t, err)
510+
511+
out, err := expr.Run(program, env)
512+
require.NoError(t, err)
513+
assert.Equal(t, test.want, out)
514+
})
515+
}
516+
}
517+
486518
func TestBuiltin_sort(t *testing.T) {
487519
env := map[string]any{
488520
"ArrayOfString": []string{"foo", "bar", "baz"},

Diff for: docs/language-definition.md

+9
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,15 @@ Returns the first `n` elements from an array. If the array has fewer than `n` el
713713
take([1, 2, 3, 4], 2) == [1, 2]
714714
```
715715

716+
### reverse(array) {#reverse}
717+
718+
Return new reversed copy of the array.
719+
720+
```expr
721+
reverse([3, 1, 4]) == [4, 1, 3]
722+
reverse(reverse([3, 1, 4])) == [3, 1, 4]
723+
```
724+
716725
### sort(array[, order]) {#sort}
717726

718727
Sorts an array in ascending order. Optional `order` argument can be used to specify the order of sorting: `asc`

0 commit comments

Comments
 (0)