Skip to content

Commit

Permalink
code(builtin) - add reverse function (#553)
Browse files Browse the repository at this point in the history
* code(builtin) - add reverse function

* docs(language-definition.md) - add reverse function
  • Loading branch information
PxyUp authored Feb 11, 2024
1 parent 013c32f commit 83b8df3
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 0 deletions.
34 changes: 34 additions & 0 deletions builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,40 @@ var Builtins = []*Function{
return anyType, fmt.Errorf("cannot transform %s from pairs", args[0])
},
},
{
Name: "reverse",
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 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, 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: "sort",
Func: func(args ...any) (any, error) {
Expand Down
32 changes: 32 additions & 0 deletions builtin/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,38 @@ func TestBuiltin_type(t *testing.T) {
}
}

func TestBuiltin_reverse(t *testing.T) {
env := map[string]any{
"ArrayOfString": []string{"foo", "bar", "baz"},
"ArrayOfInt": []int{2, 1, 3},
"ArrayOfFloat": []float64{3.0, 2.0, 1.0},
"ArrayOfFoo": []mock.Foo{{Value: "c"}, {Value: "a"}, {Value: "b"}},
}
tests := []struct {
input string
want any
}{
{`reverse([])`, []any{}},
{`reverse(ArrayOfInt)`, []any{3, 1, 2}},
{`reverse(ArrayOfFloat)`, []any{1.0, 2.0, 3.0}},
{`reverse(ArrayOfFoo)`, []any{mock.Foo{Value: "b"}, mock.Foo{Value: "a"}, mock.Foo{Value: "c"}}},
{`reverse([[1,2], [2,2]])`, []any{[]any{2, 2}, []any{1, 2}}},
{`reverse(reverse([[1,2], [2,2]]))`, []any{[]any{1, 2}, []any{2, 2}}},
{`reverse([{"test": true}, {id:4}, {name: "value"}])`, []any{map[string]any{"name": "value"}, map[string]any{"id": 4}, map[string]any{"test": true}}},
}

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)
})
}
}

func TestBuiltin_sort(t *testing.T) {
env := map[string]any{
"ArrayOfString": []string{"foo", "bar", "baz"},
Expand Down
9 changes: 9 additions & 0 deletions docs/language-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,15 @@ Returns the first `n` elements from an array. If the array has fewer than `n` el
take([1, 2, 3, 4], 2) == [1, 2]
```

### reverse(array) {#reverse}

Return new reversed copy of the array.

```expr
reverse([3, 1, 4]) == [4, 1, 3]
reverse(reverse([3, 1, 4])) == [3, 1, 4]
```

### sort(array[, order]) {#sort}

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

0 comments on commit 83b8df3

Please sign in to comment.