Skip to content

Commit

Permalink
Made nested structs addressable if possible. Closes dop251#129.
Browse files Browse the repository at this point in the history
  • Loading branch information
dop251 committed Mar 2, 2020
1 parent 281a94b commit ebfbf88
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 4 deletions.
9 changes: 5 additions & 4 deletions object_goreflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ func (o *objectGoReflect) get(n Value) Value {
func (o *objectGoReflect) _getField(jsName string) reflect.Value {
if info, exists := o.valueTypeInfo.Fields[jsName]; exists {
v := o.value.FieldByIndex(info.Index)
if info.Anonymous {
v = v.Addr()
}
return v
}

Expand Down Expand Up @@ -145,9 +142,13 @@ func (o *objectGoReflect) getPropStr(name string) Value {
func (o *objectGoReflect) getOwnProp(name string) Value {
if o.value.Kind() == reflect.Struct {
if v := o._getField(name); v.IsValid() {
canSet := v.CanSet()
if v.Kind() == reflect.Struct && v.CanAddr() {
v = v.Addr()
}
return &valueProperty{
value: o.val.runtime.ToValue(v.Interface()),
writable: v.CanSet(),
writable: canSet,
enumerable: true,
}
}
Expand Down
93 changes: 93 additions & 0 deletions object_goreflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -811,3 +811,96 @@ func BenchmarkGoReflectGet(b *testing.B) {
v.Get("Test")
}
}

func TestNestedStructSet(t *testing.T) {
type B struct {
Field int
}
type A struct {
B B
}

const SCRIPT = `
'use strict';
a.B.Field++;
if (a1.B.Field != 1) {
throw new Error("a1.B.Field = " + a1.B.Field);
}
var d = Object.getOwnPropertyDescriptor(a1.B, "Field");
if (d.writable) {
throw new Error("a1.B is writable");
}
var thrown = false;
try {
a1.B.Field = 42;
} catch (e) {
if (e instanceof TypeError) {
thrown = true;
}
}
if (!thrown) {
throw new Error("TypeError was not thrown");
}
`
a := A{
B: B{
Field: 1,
},
}
vm := New()
vm.Set("a", &a)
vm.Set("a1", a)
_, err := vm.RunString(SCRIPT)
if err != nil {
t.Fatal(err)
}

if v := a.B.Field; v != 2 {
t.Fatalf("Unexpected a.B.Field: %d", v)
}
}

func TestStructNonAddressableAnonStruct(t *testing.T) {

type C struct {
Z int64
X string
}

type B struct {
C
Y string
}

type A struct {
B B
}

a := A{
B: B{
C: C{
Z: 1,
X: "X2",
},
Y: "Y3",
},
}
const SCRIPT = `
"use strict";
var s = JSON.stringify(a);
s;
`

vm := New()
vm.Set("a", &a)
v, err := vm.RunString(SCRIPT)
if err != nil {
t.Fatal(err)
}

expected := `{"B":{"C":{"Z":1,"X":"X2"},"Z":1,"X":"X2","Y":"Y3"}}`
if expected != v.String() {
t.Fatalf("Expected '%s', got '%s'", expected, v.String())
}

}

0 comments on commit ebfbf88

Please sign in to comment.