istanbul-tools/vendor/github.com/robertkrimen/otto/type_go_struct.go

147 lines
3.5 KiB
Go

package otto
import (
"encoding/json"
"reflect"
)
// FIXME Make a note about not being able to modify a struct unless it was
// passed as a pointer-to: &struct{ ... }
// This seems to be a limitation of the reflect package.
// This goes for the other Go constructs too.
// I guess we could get around it by either:
// 1. Creating a new struct every time
// 2. Creating an addressable? struct in the constructor
func (runtime *_runtime) newGoStructObject(value reflect.Value) *_object {
self := runtime.newObject()
self.class = "Object" // TODO Should this be something else?
self.objectClass = _classGoStruct
self.value = _newGoStructObject(value)
return self
}
type _goStructObject struct {
value reflect.Value
}
func _newGoStructObject(value reflect.Value) *_goStructObject {
if reflect.Indirect(value).Kind() != reflect.Struct {
dbgf("%/panic//%@: %v != reflect.Struct", value.Kind())
}
self := &_goStructObject{
value: value,
}
return self
}
func (self _goStructObject) getValue(name string) reflect.Value {
if validGoStructName(name) {
// Do not reveal hidden or unexported fields
if field := reflect.Indirect(self.value).FieldByName(name); (field != reflect.Value{}) {
return field
}
if method := self.value.MethodByName(name); (method != reflect.Value{}) {
return method
}
}
return reflect.Value{}
}
func (self _goStructObject) field(name string) (reflect.StructField, bool) {
return reflect.Indirect(self.value).Type().FieldByName(name)
}
func (self _goStructObject) method(name string) (reflect.Method, bool) {
return reflect.Indirect(self.value).Type().MethodByName(name)
}
func (self _goStructObject) setValue(name string, value Value) bool {
field, exists := self.field(name)
if !exists {
return false
}
fieldValue := self.getValue(name)
reflectValue, err := value.toReflectValue(field.Type.Kind())
if err != nil {
panic(err)
}
fieldValue.Set(reflectValue)
return true
}
func goStructGetOwnProperty(self *_object, name string) *_property {
object := self.value.(*_goStructObject)
value := object.getValue(name)
if value.IsValid() {
return &_property{self.runtime.toValue(value.Interface()), 0110}
}
return objectGetOwnProperty(self, name)
}
func validGoStructName(name string) bool {
if name == "" {
return false
}
return 'A' <= name[0] && name[0] <= 'Z' // TODO What about Unicode?
}
func goStructEnumerate(self *_object, all bool, each func(string) bool) {
object := self.value.(*_goStructObject)
// Enumerate fields
for index := 0; index < reflect.Indirect(object.value).NumField(); index++ {
name := reflect.Indirect(object.value).Type().Field(index).Name
if validGoStructName(name) {
if !each(name) {
return
}
}
}
// Enumerate methods
for index := 0; index < object.value.NumMethod(); index++ {
name := object.value.Type().Method(index).Name
if validGoStructName(name) {
if !each(name) {
return
}
}
}
objectEnumerate(self, all, each)
}
func goStructCanPut(self *_object, name string) bool {
object := self.value.(*_goStructObject)
value := object.getValue(name)
if value.IsValid() {
return true
}
return objectCanPut(self, name)
}
func goStructPut(self *_object, name string, value Value, throw bool) {
object := self.value.(*_goStructObject)
if object.setValue(name, value) {
return
}
objectPut(self, name, value, throw)
}
func goStructMarshalJSON(self *_object) json.Marshaler {
object := self.value.(*_goStructObject)
goValue := reflect.Indirect(object.value).Interface()
switch marshaler := goValue.(type) {
case json.Marshaler:
return marshaler
}
return nil
}