Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use exported methods when setting go values #469

Merged
merged 1 commit into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"reflect"
"strings"
"testing"

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

type _abcStruct struct {
Expand Down Expand Up @@ -138,14 +140,16 @@ func (mno _mnoStruct) Func() string {
}

func TestReflect(t *testing.T) {
if true {
return
}
tt(t, func() {
// Testing dbgf
// These should panic
toValue("Xyzzy").toReflectValue(reflect.Ptr)
stringToReflectValue("Xyzzy", reflect.Ptr)
str := "test"
require.Panics(t, func() {
toValue("Xyzzy").toReflectValue(reflect.ValueOf(&str).Type())
})
require.Panics(t, func() {
stringToReflectValue("Xyzzy", reflect.Ptr)
})
})
}

Expand Down Expand Up @@ -708,7 +712,7 @@ func Test_reflectMapInterface(t *testing.T) {
`, "Nothing happens.,1,[object Object],[object Object]")

is(abc["xyz"], "pqr")
is(abc["ghi"], "[object Object]")
is(abc["ghi"], map[string]interface{}{})
is(abc["jkl"], float64(3.14159))
mno, valid := abc["mno"].(*_abcStruct)
is(valid, true)
Expand Down
2 changes: 1 addition & 1 deletion type_go_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (self _goArrayObject) setValue(index int64, value Value) bool {
if !exists {
return false
}
reflectValue, err := value.toReflectValue(reflect.Indirect(self.value).Type().Elem().Kind())
reflectValue, err := value.toReflectValue(reflect.Indirect(self.value).Type().Elem())
if err != nil {
panic(err)
}
Expand Down
12 changes: 6 additions & 6 deletions type_go_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ func (runtime *_runtime) newGoMapObject(value reflect.Value) *_object {

type _goMapObject struct {
value reflect.Value
keyKind reflect.Kind
valueKind reflect.Kind
keyType reflect.Type
valueType reflect.Type
}

func _newGoMapObject(value reflect.Value) *_goMapObject {
Expand All @@ -24,22 +24,22 @@ func _newGoMapObject(value reflect.Value) *_goMapObject {
}
self := &_goMapObject{
value: value,
keyKind: value.Type().Key().Kind(),
valueKind: value.Type().Elem().Kind(),
keyType: value.Type().Key(),
valueType: value.Type().Elem(),
}
return self
}

func (self _goMapObject) toKey(name string) reflect.Value {
reflectValue, err := stringToReflectValue(name, self.keyKind)
reflectValue, err := stringToReflectValue(name, self.keyType.Kind())
if err != nil {
panic(err)
}
return reflectValue
}

func (self _goMapObject) toValue(value Value) reflect.Value {
reflectValue, err := value.toReflectValue(self.valueKind)
reflectValue, err := value.toReflectValue(self.valueType)
if err != nil {
panic(err)
}
Expand Down
2 changes: 1 addition & 1 deletion type_go_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (self *_goSliceObject) setLength(value Value) {
}

func (self *_goSliceObject) setValue(index int64, value Value) bool {
reflectValue, err := value.toReflectValue(self.value.Type().Elem().Kind())
reflectValue, err := value.toReflectValue(self.value.Type().Elem())
if err != nil {
panic(err)
}
Expand Down
82 changes: 25 additions & 57 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,13 +645,6 @@ func (self Value) export() interface{} {
case *_goStructObject:
return value.value.Interface()
case *_goMapObject:
iter := value.value.MapRange()
for iter.Next() {
v := iter.Value()
if ov, ok := v.Interface().(Value); ok {
value.value.SetMapIndex(iter.Key(), reflect.ValueOf(ov.export()))
}
}
return value.value.Interface()
case *_goArrayObject:
return value.value.Interface()
Expand Down Expand Up @@ -756,42 +749,13 @@ func (self Value) evaluateBreak(labels []string) _resultKind {
return resultReturn
}

func (self Value) exportNative() interface{} {
switch self.kind {
case valueUndefined:
return self
case valueNull:
return nil
case valueNumber, valueBoolean:
return self.value
case valueString:
switch value := self.value.(type) {
case string:
return value
case []uint16:
return string(utf16.Decode(value))
}
case valueObject:
object := self._object()
switch value := object.value.(type) {
case *_goStructObject:
return value.value.Interface()
case *_goMapObject:
return value.value.Interface()
case *_goArrayObject:
return value.value.Interface()
case *_goSliceObject:
return value.value.Interface()
}
}

return self
}

// Make a best effort to return a reflect.Value corresponding to reflect.Kind, but
// fallback to just returning the Go value we have handy.
func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
if kind != reflect.Float32 && kind != reflect.Float64 && kind != reflect.Interface {
func (value Value) toReflectValue(typ reflect.Type) (reflect.Value, error) {
kind := typ.Kind()
switch kind {
case reflect.Float32, reflect.Float64, reflect.Interface:
default:
switch value := value.value.(type) {
case float32:
_, frac := math.Modf(float64(value))
Expand All @@ -808,36 +772,36 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {

switch kind {
case reflect.Bool: // Bool
return reflect.ValueOf(value.bool()), nil
return reflect.ValueOf(value.bool()).Convert(typ), nil
case reflect.Int: // Int
// We convert to float64 here because converting to int64 will not tell us
// if a value is outside the range of int64
tmp := toIntegerFloat(value)
if tmp < float_minInt || tmp > float_maxInt {
return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to int", tmp, value)
} else {
return reflect.ValueOf(int(tmp)), nil
return reflect.ValueOf(int(tmp)).Convert(typ), nil
}
case reflect.Int8: // Int8
tmp := value.number().int64
if tmp < int64_minInt8 || tmp > int64_maxInt8 {
return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to int8", tmp, value)
} else {
return reflect.ValueOf(int8(tmp)), nil
return reflect.ValueOf(int8(tmp)).Convert(typ), nil
}
case reflect.Int16: // Int16
tmp := value.number().int64
if tmp < int64_minInt16 || tmp > int64_maxInt16 {
return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to int16", tmp, value)
} else {
return reflect.ValueOf(int16(tmp)), nil
return reflect.ValueOf(int16(tmp)).Convert(typ), nil
}
case reflect.Int32: // Int32
tmp := value.number().int64
if tmp < int64_minInt32 || tmp > int64_maxInt32 {
return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to int32", tmp, value)
} else {
return reflect.ValueOf(int32(tmp)), nil
return reflect.ValueOf(int32(tmp)).Convert(typ), nil
}
case reflect.Int64: // Int64
// We convert to float64 here because converting to int64 will not tell us
Expand All @@ -846,7 +810,7 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
if tmp < float_minInt64 || tmp > float_maxInt64 {
return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to int", tmp, value)
} else {
return reflect.ValueOf(int64(tmp)), nil
return reflect.ValueOf(int64(tmp)).Convert(typ), nil
}
case reflect.Uint: // Uint
// We convert to float64 here because converting to int64 will not tell us
Expand All @@ -855,28 +819,28 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
if tmp < 0 || tmp > float_maxUint {
return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to uint", tmp, value)
} else {
return reflect.ValueOf(uint(tmp)), nil
return reflect.ValueOf(uint(tmp)).Convert(typ), nil
}
case reflect.Uint8: // Uint8
tmp := value.number().int64
if tmp < 0 || tmp > int64_maxUint8 {
return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to uint8", tmp, value)
} else {
return reflect.ValueOf(uint8(tmp)), nil
return reflect.ValueOf(uint8(tmp)).Convert(typ), nil
}
case reflect.Uint16: // Uint16
tmp := value.number().int64
if tmp < 0 || tmp > int64_maxUint16 {
return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to uint16", tmp, value)
} else {
return reflect.ValueOf(uint16(tmp)), nil
return reflect.ValueOf(uint16(tmp)).Convert(typ), nil
}
case reflect.Uint32: // Uint32
tmp := value.number().int64
if tmp < 0 || tmp > int64_maxUint32 {
return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to uint32", tmp, value)
} else {
return reflect.ValueOf(uint32(tmp)), nil
return reflect.ValueOf(uint32(tmp)).Convert(typ), nil
}
case reflect.Uint64: // Uint64
// We convert to float64 here because converting to int64 will not tell us
Expand All @@ -885,7 +849,7 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
if tmp < 0 || tmp > float_maxUint64 {
return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to uint64", tmp, value)
} else {
return reflect.ValueOf(uint64(tmp)), nil
return reflect.ValueOf(uint64(tmp)).Convert(typ), nil
}
case reflect.Float32: // Float32
tmp := value.float64()
Expand All @@ -896,13 +860,13 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
if tmp1 > 0 && (tmp1 < math.SmallestNonzeroFloat32 || tmp1 > math.MaxFloat32) {
return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to float32", tmp, value)
} else {
return reflect.ValueOf(float32(tmp)), nil
return reflect.ValueOf(float32(tmp)).Convert(typ), nil
}
case reflect.Float64: // Float64
value := value.float64()
return reflect.ValueOf(float64(value)), nil
return reflect.ValueOf(float64(value)).Convert(typ), nil
case reflect.String: // String
return reflect.ValueOf(value.string()), nil
return reflect.ValueOf(value.string()).Convert(typ), nil
case reflect.Invalid: // Invalid
case reflect.Complex64: // FIXME? Complex64
case reflect.Complex128: // FIXME? Complex128
Expand All @@ -924,7 +888,11 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
case *_goSliceObject: // Slice
return reflect.ValueOf(vl.value.Interface()), nil
}
return reflect.ValueOf(value.exportNative()), nil
exported := reflect.ValueOf(value.export())
if exported.Type().ConvertibleTo(typ) {
return exported.Convert(typ), nil
}
return reflect.Value{}, fmt.Errorf("TypeError: could not convert %v to reflect.Type: %v", exported, typ)
case valueEmpty, valueResult, valueReference:
// These are invalid, and should panic
default:
Expand All @@ -933,7 +901,7 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
}

// FIXME Should this end up as a TypeError?
panic(fmt.Errorf("invalid conversion of %v (%v) to reflect.Kind: %v", value.kind, value, kind))
panic(fmt.Errorf("invalid conversion of %v (%v) to reflect.Type: %v", value.kind, value, typ))
}

func stringToReflectValue(value string, kind reflect.Kind) (reflect.Value, error) {
Expand Down
2 changes: 1 addition & 1 deletion value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func TestExport(t *testing.T) {
func Test_toReflectValue(t *testing.T) {
tt(t, func() {
value := toValue(0.0)
tmp, err := value.toReflectValue(reflect.Float32)
tmp, err := value.toReflectValue(reflect.TypeOf(0.0))
is(tmp.Float(), 0.0)
is(err, nil)
})
Expand Down