aboutsummaryrefslogblamecommitdiffstats
path: root/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_struct.go
blob: 608ac66609c4b3979af112f76b0f76d747b54234 (plain) (tree)
1
2
3
4
5
6
7




                       

 






                                                                          























                                                                          














                                                                                                        



                                                                        













                                                                     
 









































































                                                                                    
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
}