diff --git a/object_goreflect.go b/object_goreflect.go index beb7df16..84738d1b 100644 --- a/object_goreflect.go +++ b/object_goreflect.go @@ -233,6 +233,16 @@ func (o *objectGoReflect) _getMethod(jsName string) reflect.Value { } func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrapper) { + if v, ok := ev.Interface().(ToValueConverter); ok { + ret := v.ToValue(o.val.runtime) + if obj, ok := ret.(*Object); ok { + if w, ok := obj.self.(reflectValueWrapper); ok { + return ret, w + } + } + return ret, nil + } + if isContainer(ev.Kind()) { if ev.Type() == reflectTypeArray { a := o.val.runtime.newObjectGoSlice(ev.Addr().Interface().(*[]interface{})) diff --git a/object_goreflect_test.go b/object_goreflect_test.go index cdf273ad..7d292ec5 100644 --- a/object_goreflect_test.go +++ b/object_goreflect_test.go @@ -1177,6 +1177,35 @@ func TestGoReflectSymbolEqualityQuirk(t *testing.T) { } } +type testToValue struct { + i int + j string +} + +func (s testToValue) ToValue(r *Runtime) Value { + if s.i == 0 { + return r.ToValue(s.j) + } + return r.ToValue(s.i) +} + +func TestGoReflectToValue(t *testing.T) { + vm := New() + vm.Set("s", testToValue{i: 3, j: "toto"}) + vm.Set("t", &testToValue{i: 0, j: "toto"}) + vm.Set("u", map[string][]testToValue{ + "y": {{i: 2, j: "toto"}}, + }) + res, err := vm.RunString(` + s===3 && t==="toto" && u.y[0]===2`) + if err != nil { + t.Fatal(err) + } + if res != valueTrue { + t.Fatal(res) + } +} + func TestGoObj__Proto__(t *testing.T) { type S struct { Field int diff --git a/runtime.go b/runtime.go index b10279ef..afdcc33d 100644 --- a/runtime.go +++ b/runtime.go @@ -1753,6 +1753,8 @@ func (r *Runtime) ToValue(i interface{}) Value { panic(r.NewTypeError("Illegal runtime transition of an Object")) } return i + case ToValueConverter: + return i.ToValue(r) case valueContainer: return i.toValue(r) case Value: @@ -1849,10 +1851,23 @@ func (r *Runtime) ToValue(i interface{}) Value { return r.reflectValueToValue(reflect.ValueOf(i)) } +type ToValueConverter interface { + ToValue(*Runtime) Value +} + func (r *Runtime) reflectValueToValue(origValue reflect.Value) Value { + if v, ok := origValue.Interface().(ToValueConverter); ok { + return v.ToValue(r) + } + value := origValue for value.Kind() == reflect.Ptr { value = value.Elem() + if value.IsValid() { + if v, ok := value.Interface().(ToValueConverter); ok { + return v.ToValue(r) + } + } } if !value.IsValid() {