Browse Source

Merge pull request #88 from documatrix/export_to

Improved Runtime.ExportTo() to support anonymous structs and pointer types
Dmitry Panov 6 years ago
parent
commit
a1cf0d5579
2 changed files with 142 additions and 3 deletions
  1. 20 3
      runtime.go
  2. 122 0
      runtime_test.go

+ 20 - 3
runtime.go

@@ -1256,7 +1256,7 @@ func (r *Runtime) toReflectValue(v Value, typ reflect.Type) (reflect.Value, erro
 					item := o.self.get(intToValue(int64(i)))
 					itemval, err := r.toReflectValue(item, elemTyp)
 					if err != nil {
-						return reflect.Value{}, fmt.Errorf("Could not convert array element %v to %v at %d", v, typ, i)
+						return reflect.Value{}, fmt.Errorf("Could not convert array element %v to %v at %d: %s", v, typ, i, err)
 					}
 					s.Index(i).Set(itemval)
 				}
@@ -1303,11 +1303,17 @@ func (r *Runtime) toReflectValue(v Value, typ reflect.Type) (reflect.Value, erro
 			for i := 0; i < typ.NumField(); i++ {
 				field := typ.Field(i)
 				if ast.IsExported(field.Name) {
-					v := o.self.getStr(field.Name)
+					var v Value
+					if field.Anonymous {
+						v = o
+					} else {
+						v = o.self.getStr(field.Name)
+					}
+
 					if v != nil {
 						vv, err := r.toReflectValue(v, field.Type)
 						if err != nil {
-							return reflect.Value{}, fmt.Errorf("Could not convert struct value %v to %v for field %s", v, field.Type, field.Name)
+							return reflect.Value{}, fmt.Errorf("Could not convert struct value %v to %v for field %s: %s", v, field.Type, field.Name, err)
 
 						}
 						s.Field(i).Set(vv)
@@ -1320,6 +1326,17 @@ func (r *Runtime) toReflectValue(v Value, typ reflect.Type) (reflect.Value, erro
 		if fn, ok := AssertFunction(v); ok {
 			return reflect.MakeFunc(typ, r.wrapJSFunc(fn, typ)), nil
 		}
+	case reflect.Ptr:
+		elemTyp := typ.Elem()
+		v, err := r.toReflectValue(v, elemTyp)
+		if err != nil {
+			return reflect.Value{}, err
+		}
+
+		ptrVal := reflect.New(v.Type())
+		ptrVal.Elem().Set(v)
+
+		return ptrVal, nil
 	}
 
 	return reflect.Value{}, fmt.Errorf("Could not convert %v to %v", v, typ)

+ 122 - 0
runtime_test.go

@@ -467,6 +467,128 @@ func TestRuntime_ExportToStruct(t *testing.T) {
 
 }
 
+func TestRuntime_ExportToStructPtr(t *testing.T) {
+	const SCRIPT = `
+	var m = {
+		Test: 1,
+	}
+	m;
+	`
+	vm := New()
+	v, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var o *testGoReflectMethod_O
+	err = vm.ExportTo(v, &o)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if o.Test != "1" {
+		t.Fatalf("Unexpected value: '%s'", o.Test)
+	}
+
+}
+
+func TestRuntime_ExportToStructAnonymous(t *testing.T) {
+	type BaseTestStruct struct {
+		A int64
+		B int64
+	}
+
+	type TestStruct struct {
+		BaseTestStruct
+		C string
+	}
+
+	const SCRIPT = `
+	var m = {
+		A: 1,
+		B: 2,
+		C: "testC"
+	}
+	m;
+	`
+	vm := New()
+	v, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	test := &TestStruct{}
+	err = vm.ExportTo(v, test)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if test.A != 1 {
+		t.Fatalf("Unexpected value: '%d'", test.A)
+	}
+	if test.B != 2 {
+		t.Fatalf("Unexpected value: '%d'", test.B)
+	}
+	if test.C != "testC" {
+		t.Fatalf("Unexpected value: '%s'", test.C)
+	}
+
+}
+
+func TestRuntime_ExportToStructWithPtrValues(t *testing.T) {
+	type BaseTestStruct struct {
+		A int64
+		B *int64
+	}
+
+	type TestStruct2 struct {
+		E string
+	}
+
+	type TestStruct struct {
+		BaseTestStruct
+		C *string
+		D *TestStruct2
+	}
+
+	const SCRIPT = `
+	var m = {
+		A: 1,
+		B: 2,
+		C: "testC",
+		D: {
+			E: "testE",
+		}
+	}
+	m;
+	`
+	vm := New()
+	v, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	test := &TestStruct{}
+	err = vm.ExportTo(v, test)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if test.A != 1 {
+		t.Fatalf("Unexpected value: '%d'", test.A)
+	}
+	if test.B == nil || *test.B != 2 {
+		t.Fatalf("Unexpected value: '%v'", test.B)
+	}
+	if test.C == nil || *test.C != "testC" {
+		t.Fatalf("Unexpected value: '%v'", test.C)
+	}
+	if test.D == nil || test.D.E != "testE" {
+		t.Fatalf("Unexpected value: '%s'", test.D.E)
+	}
+
+}
+
 func TestRuntime_ExportToFunc(t *testing.T) {
 	const SCRIPT = `
 	function f(param) {