1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-12 20:27:30 +08:00

use consistent field access rules across read/write and argument conversion

This commit is contained in:
Conrad Pankoff 2018-12-16 11:52:39 +11:00
parent 15f95af6e7
commit 0f57984957
2 changed files with 52 additions and 40 deletions

View File

@ -285,6 +285,38 @@ func (self *_runtime) convertNumeric(v Value, t reflect.Type) reflect.Value {
panic(self.panicTypeError(fmt.Sprintf("unsupported type %v for numeric conversion", val.Type()))) panic(self.panicTypeError(fmt.Sprintf("unsupported type %v for numeric conversion", val.Type())))
} }
func fieldIndexByName(t reflect.Type, name string) []int {
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if !validGoStructName(f.Name) {
continue
}
if f.Anonymous {
if a := fieldIndexByName(f.Type, name); a != nil {
return append([]int{i}, a...)
}
}
if a := strings.SplitN(f.Tag.Get("json"), ",", 2); a[0] != "" {
if a[0] == "-" {
continue
}
if a[0] == name {
return []int{i}
}
}
if f.Name == name {
return []int{i}
}
}
return nil
}
var typeOfValue = reflect.TypeOf(Value{}) var typeOfValue = reflect.TypeOf(Value{})
// convertCallParameter converts request val to type t if possible. // convertCallParameter converts request val to type t if possible.
@ -467,41 +499,15 @@ func (self *_runtime) convertCallParameter(v Value, t reflect.Type) reflect.Valu
s := reflect.New(t) s := reflect.New(t)
for _, k := range o.propertyOrder { for _, k := range o.propertyOrder {
var f *reflect.StructField idx := fieldIndexByName(t, k)
for i := 0; i < t.NumField(); i++ { if idx == nil {
ff := t.Field(i)
if j := ff.Tag.Get("json"); j != "" {
if j == "-" {
continue
}
a := strings.Split(j, ",")
if a[0] == k {
f = &ff
break
}
}
if ff.Name == k {
f = &ff
break
}
if strings.EqualFold(ff.Name, k) {
f = &ff
}
}
if f == nil {
panic(self.panicTypeError("can't convert object; field %q was supplied but does not exist on target %v", k, t)) panic(self.panicTypeError("can't convert object; field %q was supplied but does not exist on target %v", k, t))
} }
ss := s ss := s
for _, i := range f.Index { for _, i := range idx {
if ss.Kind() == reflect.Ptr { if ss.Kind() == reflect.Ptr {
if ss.IsNil() { if ss.IsNil() {
if !ss.CanSet() { if !ss.CanSet() {
@ -572,7 +578,7 @@ func (self *_runtime) convertCallParameter(v Value, t reflect.Type) reflect.Valu
s = v.Class() s = v.Class()
} }
panic(self.panicTypeError("can't convert from %q to %q", s, t.String())) panic(self.panicTypeError("can't convert from %q to %q", s, t))
} }
func (self *_runtime) toValue(value interface{}) Value { func (self *_runtime) toValue(value interface{}) Value {

View File

@ -36,6 +36,10 @@ func _newGoStructObject(value reflect.Value) *_goStructObject {
} }
func (self _goStructObject) getValue(name string) reflect.Value { func (self _goStructObject) getValue(name string) reflect.Value {
if f, ok := self.field(name); ok {
return reflect.Indirect(self.value).FieldByIndex(f.Index)
}
if validGoStructName(name) { if validGoStructName(name) {
// Do not reveal hidden or unexported fields // Do not reveal hidden or unexported fields
if field := reflect.Indirect(self.value).FieldByName(name); (field != reflect.Value{}) { if field := reflect.Indirect(self.value).FieldByName(name); (field != reflect.Value{}) {
@ -51,24 +55,26 @@ func (self _goStructObject) getValue(name string) reflect.Value {
} }
func (self _goStructObject) field(name string) (reflect.StructField, bool) { func (self _goStructObject) field(name string) (reflect.StructField, bool) {
return reflect.Indirect(self.value).Type().FieldByName(name) t := reflect.Indirect(self.value).Type()
if idx := fieldIndexByName(t, name); len(idx) > 0 {
return t.FieldByIndex(idx), true
}
return reflect.StructField{}, false
} }
func (self _goStructObject) method(name string) (reflect.Method, bool) { func (self _goStructObject) method(name string) (reflect.Method, bool) {
return reflect.Indirect(self.value).Type().MethodByName(name) return reflect.Indirect(self.value).Type().MethodByName(name)
} }
func (self _goStructObject) setValue(name string, value Value) bool { func (self _goStructObject) setValue(rt *_runtime, name string, value Value) bool {
field, exists := self.field(name) if _, exists := self.field(name); !exists {
if !exists {
return false return false
} }
fieldValue := self.getValue(name) fieldValue := self.getValue(name)
reflectValue, err := value.toReflectValue(field.Type.Kind()) fieldValue.Set(rt.convertCallParameter(value, fieldValue.Type()))
if err != nil {
panic(err)
}
fieldValue.Set(reflectValue)
return true return true
} }
@ -128,7 +134,7 @@ func goStructCanPut(self *_object, name string) bool {
func goStructPut(self *_object, name string, value Value, throw bool) { func goStructPut(self *_object, name string, value Value, throw bool) {
object := self.value.(*_goStructObject) object := self.value.(*_goStructObject)
if object.setValue(name, value) { if object.setValue(self.runtime, name, value) {
return return
} }