Skip to content

Commit

Permalink
Use pkg deref in vm
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmedv committed Feb 16, 2024
1 parent 4fbea91 commit 701448d
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 60 deletions.
3 changes: 1 addition & 2 deletions builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,8 +920,7 @@ var Builtins = []*Function{
var arr []any

for _, arg := range args {
arg = runtime.Deref(arg)
v := reflect.ValueOf(arg)
v := reflect.ValueOf(deref.Deref(arg))

if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, 0, fmt.Errorf("cannot concat %s", v.Kind())
Expand Down
29 changes: 7 additions & 22 deletions expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@ func ExampleOperator_Decimal() {
code := `A + B - C`

type Env struct {
A, B, C Decimal
Sub func(a, b Decimal) Decimal
Add func(a, b Decimal) Decimal
A, B, C Decimal
Sub func(a, b Decimal) Decimal
Add func(a, b Decimal) Decimal
}

options := []expr.Option{
Expand All @@ -334,11 +334,11 @@ func ExampleOperator_Decimal() {
}

env := Env{
A: Decimal{3},
B: Decimal{2},
C: Decimal{1},
A: Decimal{3},
B: Decimal{2},
C: Decimal{1},
Sub: func(a, b Decimal) Decimal { return Decimal{a.N - b.N} },
Add: func(a, b Decimal) Decimal { return Decimal{a.N + b.N} },
Add: func(a, b Decimal) Decimal { return Decimal{a.N + b.N} },
}

output, err := expr.Run(program, env)
Expand Down Expand Up @@ -1358,21 +1358,6 @@ func TestExpr_fetch_from_func(t *testing.T) {
assert.Contains(t, err.Error(), "cannot fetch Value from func()")
}

func TestExpr_fetch_from_interface(t *testing.T) {
type FooBar struct {
Value string
}
foobar := &FooBar{"waldo"}
var foobarAny any = foobar
var foobarPtrAny any = &foobarAny

res, err := expr.Eval("foo.Value", map[string]any{
"foo": foobarPtrAny,
})
assert.NoError(t, err)
assert.Equal(t, "waldo", res)
}

func TestExpr_map_default_values(t *testing.T) {
env := map[string]any{
"foo": map[string]string{},
Expand Down
16 changes: 16 additions & 0 deletions test/deref/deref_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/expr-lang/expr"
Expand Down Expand Up @@ -237,3 +238,18 @@ func TestDeref_сommutative(t *testing.T) {
})
}
}

func TestDeref_fetch_from_interface_mix_pointer(t *testing.T) {
type FooBar struct {
Value string
}
foobar := &FooBar{"waldo"}
var foobarAny any = foobar
var foobarPtrAny any = &foobarAny

res, err := expr.Eval("foo.Value", map[string]any{
"foo": foobarPtrAny,
})
assert.NoError(t, err)
assert.Equal(t, "waldo", res)
}
40 changes: 5 additions & 35 deletions vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,13 @@ import (
"fmt"
"math"
"reflect"
)

func deref(kind reflect.Kind, value reflect.Value) (reflect.Kind, reflect.Value) {
for kind == reflect.Ptr || kind == reflect.Interface {
value = value.Elem()
kind = value.Kind()
}
return kind, value
}
"github.com/expr-lang/expr/internal/deref"
)

func Fetch(from, i any) any {
v := reflect.ValueOf(from)
kind := v.Kind()
if kind == reflect.Invalid {
if v.Kind() == reflect.Invalid {
panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
}

Expand All @@ -37,11 +30,9 @@ func Fetch(from, i any) any {
// a value, when they are accessed through a pointer we don't want to
// copy them to a value.
// De-reference everything if necessary (interface and pointers)
kind, v = deref(kind, v)
v = deref.Value(v)

// TODO: We can create separate opcodes for each of the cases below to make
// the little bit faster.
switch kind {
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
index := ToInt(i)
if index < 0 {
Expand Down Expand Up @@ -144,27 +135,6 @@ func FetchMethod(from any, method *Method) any {
panic(fmt.Sprintf("cannot fetch %v from %T", method.Name, from))
}

func Deref(i any) any {
if i == nil {
return nil
}

v := reflect.ValueOf(i)

for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
if v.IsNil() {
return nil
}
v = v.Elem()
}

if v.IsValid() {
return v.Interface()
}

panic(fmt.Sprintf("cannot dereference %v", i))
}

func Slice(array, from, to any) any {
v := reflect.ValueOf(array)

Expand Down
3 changes: 2 additions & 1 deletion vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/expr-lang/expr/builtin"
"github.com/expr-lang/expr/file"
"github.com/expr-lang/expr/internal/deref"
"github.com/expr-lang/expr/vm/runtime"
)

Expand Down Expand Up @@ -436,7 +437,7 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) {

case OpDeref:
a := vm.pop()
vm.push(runtime.Deref(a))
vm.push(deref.Deref(a))

case OpIncrementIndex:
vm.scope().Index++
Expand Down

0 comments on commit 701448d

Please sign in to comment.