1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
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 idx := fieldIndexByName(reflect.Indirect(self.value).Type(), name); len(idx) > 0 {
return reflect.Indirect(self.value).FieldByIndex(idx)
}
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) fieldIndex(name string) []int {
return fieldIndexByName(reflect.Indirect(self.value).Type(), name)
}
func (self _goStructObject) method(name string) (reflect.Method, bool) {
return reflect.Indirect(self.value).Type().MethodByName(name)
}
func (self _goStructObject) setValue(rt *_runtime, name string, value Value) bool {
if idx := fieldIndexByName(reflect.Indirect(self.value).Type(), name); len(idx) == 0 {
return false
}
fieldValue := self.getValue(name)
converted, err := rt.convertCallParameter(value, fieldValue.Type())
if err != nil {
panic(rt.panicTypeError(err.Error()))
}
fieldValue.Set(converted)
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(self.runtime, 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
}
|