package muesli type ObjectGetter func() Value type ObjectSetter func(Value) Value type ObjectMethod func(...Value) []Value // Object is an interface for a Value that has fields // which can be get, set or invoked. The field names must be strings. // It is allowed, but not mandatory that names for Get, Set and Invoke // are stored separately. type Object interface { Value Get(key string) Value Set(key string, to Value) Value Invoke(key string, args... Value) []Value } // BasicObject is strut that implements Object. // An object may have a parent it inherit's it's fields and methods from. // Include it in your own struct to endow it with getters and setters, // and methods more easily. type BasicObject struct { RedispatchCallable Parent * BasicObject Object interface{} Getters map[string] ObjectGetter Setters map[string] ObjectSetter Methods map[string] ObjectMethod } const ObjectType = TypeValue("Object") func (v BasicObject) Type() TypeValue { return ObjectType } func (val BasicObject) String() string { res := "{" sep := "" for k, v := range val.Getters { res = res + sep + k + "=>" + v().String() sep = ", " } res += "}" return res } // Adds a getter to an object func (o *BasicObject) Getter(name string, getter ObjectGetter) *BasicObject { o.Getters[name] = getter return o } // Adds a setter to an object func (o *BasicObject) Setter(name string, setter ObjectSetter) *BasicObject { o.Setters[name] = setter return o } // Adds a method to an object func (o *BasicObject) Method(name string, method ObjectMethod) *BasicObject { o.Methods[name] = method return o } func NewBasicObject(object interface {}, parent *BasicObject) *BasicObject { mv := &BasicObject{Object:object, Parent: parent, Getters: make(map[string] ObjectGetter), Setters: make(map[string] ObjectSetter), Methods: make(map[string] ObjectMethod), } mv.RedispatchCallable = NewRedispatchCallable("Object", mv) return mv } func (m *BasicObject) Get(key string) Value { var res ObjectGetter var ok bool if res, ok = m.Getters[key] ; !ok { if m.Parent != nil { return m.Parent.Get(key) } return NilValue } return res() } func (m *BasicObject) Set(key string, to Value) Value { var res ObjectSetter var ok bool if res, ok = m.Setters[key] ; !ok { if m.Parent != nil { return m.Parent.Set(key, to) } return NilValue } return res(to) } func (m *BasicObject) Invoke(key string, args... Value) []Value { var res ObjectMethod var ok bool if res, ok = m.Methods[key] ; !ok { if m.Parent != nil { return m.Parent.Invoke(key, args...) } return Fail(NewErrorValuef("No such method %s", key)) } return res(args...) } func (from *BasicObject) Convert(to interface{}) error { switch toPtr := to.(type) { case **BasicObject: (*toPtr) = from case *Value: (*toPtr) = from default: return NewErrorValuef("Cannot convert value %v to %v", from, to) } return nil } // BasicObject implements Object var _ Object = &BasicObject{} // Flex can have any field just by setting it, it can be wrapped in // an BasicObject. type Flex struct { Fields map [string]Value }