Procházet zdrojové kódy

Unified conversions to Value. Fixes #453.

Dmitry Panov před 2 roky
rodič
revize
6c0d988379
5 změnil soubory, kde provedl 54 přidání a 19 odebrání
  1. 2 2
      object_gomap_reflect.go
  2. 5 9
      object_goreflect.go
  3. 39 0
      object_goreflect_test.go
  4. 7 7
      runtime.go
  5. 1 1
      runtime_test.go

+ 2 - 2
object_gomap_reflect.go

@@ -41,7 +41,7 @@ func (o *objectGoMapReflect) _get(n Value) Value {
 		return nil
 	}
 	if v := o.fieldsValue.MapIndex(key); v.IsValid() {
-		return o.val.runtime.ToValue(v.Interface())
+		return o.val.runtime.toValue(v.Interface(), v)
 	}
 
 	return nil
@@ -53,7 +53,7 @@ func (o *objectGoMapReflect) _getStr(name string) Value {
 		return nil
 	}
 	if v := o.fieldsValue.MapIndex(key); v.IsValid() {
-		return o.val.runtime.ToValue(v.Interface())
+		return o.val.runtime.toValue(v.Interface(), v)
 	}
 
 	return nil

+ 5 - 9
object_goreflect.go

@@ -234,17 +234,13 @@ func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
 
 func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrapper) {
 	if isContainer(ev.Kind()) {
-		if ev.Type() == reflectTypeArray {
-			a := o.val.runtime.newObjectGoSlice(ev.Addr().Interface().(*[]interface{}))
-			return a.val, a
-		}
-		ret := o.val.runtime.reflectValueToValue(ev)
+		ret := o.val.runtime.toValue(ev.Interface(), ev)
 		if obj, ok := ret.(*Object); ok {
 			if w, ok := obj.self.(reflectValueWrapper); ok {
 				return ret, w
 			}
 		}
-		panic("reflectValueToValue() returned a value which is not a reflectValueWrapper")
+		return ret, nil
 	}
 
 	for ev.Kind() == reflect.Interface {
@@ -255,7 +251,7 @@ func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrap
 		return _null, nil
 	}
 
-	return o.val.runtime.ToValue(ev.Interface()), nil
+	return o.val.runtime.toValue(ev.Interface(), ev), nil
 }
 
 func (o *objectGoReflect) _getFieldValue(name string) Value {
@@ -283,7 +279,7 @@ func (o *objectGoReflect) _get(name string) Value {
 	}
 
 	if v := o._getMethod(name); v.IsValid() {
-		return o.val.runtime.reflectValueToValue(v)
+		return o.val.runtime.toValue(v.Interface(), v)
 	}
 
 	return nil
@@ -303,7 +299,7 @@ func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
 
 	if v := o._getMethod(n); v.IsValid() {
 		return &valueProperty{
-			value:      o.val.runtime.reflectValueToValue(v),
+			value:      o.val.runtime.toValue(v.Interface(), v),
 			enumerable: true,
 		}
 	}

+ 39 - 0
object_goreflect_test.go

@@ -1520,3 +1520,42 @@ func TestGoReflectToPrimitive(t *testing.T) {
 		})
 	})
 }
+
+type testGoReflectFuncRt struct {
+}
+
+func (*testGoReflectFuncRt) M(call FunctionCall, r *Runtime) Value {
+	if r == nil {
+		panic(typeError("Runtime is nil"))
+	}
+	return call.Argument(0)
+}
+
+func (*testGoReflectFuncRt) C(call ConstructorCall, r *Runtime) *Object {
+	if r == nil {
+		panic(typeError("Runtime is nil in constructor"))
+	}
+	call.This.Set("r", call.Argument(0))
+	return nil
+}
+
+func TestGoReflectFuncWithRuntime(t *testing.T) {
+	vm := New()
+	var s testGoReflectFuncRt
+	vm.Set("s", &s)
+	res, err := vm.RunString("s.M(true)")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if res != valueTrue {
+		t.Fatal(res)
+	}
+
+	res, err = vm.RunString("new s.C(true).r")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if res != valueTrue {
+		t.Fatal(res)
+	}
+}

+ 7 - 7
runtime.go

@@ -1714,6 +1714,10 @@ Note that the underlying type is not lost, calling Export() returns the original
 reflect based types.
 */
 func (r *Runtime) ToValue(i interface{}) Value {
+	return r.toValue(i, reflect.Value{})
+}
+
+func (r *Runtime) toValue(i interface{}, origValue reflect.Value) Value {
 	switch i := i.(type) {
 	case nil:
 		return _null
@@ -1730,7 +1734,6 @@ func (r *Runtime) ToValue(i interface{}) Value {
 	case Value:
 		return i
 	case string:
-		// return newStringValue(i)
 		if len(i) <= 16 {
 			if u := unistring.Scan(i); u != nil {
 				return &importedString{s: i, u: u, scanned: true}
@@ -1807,9 +1810,6 @@ func (r *Runtime) ToValue(i interface{}) Value {
 		m.init()
 		return obj
 	case []interface{}:
-		if i == nil {
-			return _null
-		}
 		return r.newObjectGoSlice(&i).val
 	case *[]interface{}:
 		if i == nil {
@@ -1818,10 +1818,10 @@ func (r *Runtime) ToValue(i interface{}) Value {
 		return r.newObjectGoSlice(i).val
 	}
 
-	return r.reflectValueToValue(reflect.ValueOf(i))
-}
+	if !origValue.IsValid() {
+		origValue = reflect.ValueOf(i)
+	}
 
-func (r *Runtime) reflectValueToValue(origValue reflect.Value) Value {
 	value := origValue
 	for value.Kind() == reflect.Ptr {
 		value = value.Elem()

+ 1 - 1
runtime_test.go

@@ -1037,7 +1037,7 @@ func TestToValueNil(t *testing.T) {
 	}
 
 	var ar []interface{}
-	if v := vm.ToValue(ar); !IsNull(v) {
+	if v := vm.ToValue(ar); IsNull(v) {
 		t.Fatalf("[]interface{}: %v", v)
 	}