1
0
mirror of https://github.com/robertkrimen/otto synced 2025-09-28 18:45:22 +08:00
otto/stash.go
2012-10-05 18:47:53 -07:00

169 lines
4.0 KiB
Go

package otto
type _stash interface {
CanRead(string) bool
Read(string) Value
CanWrite(string) bool
Write(string, Value)
property(string) *_property
Delete(string)
Define(string, _defineProperty) bool
Enumerate(func(string))
writeValuePropertyMap(map[string]_valueProperty)
}
type _propertyStash struct {
canCreate bool
propertyMap map[string]*_property
}
func newPropertyStash(canCreate bool) *_propertyStash {
return &_propertyStash{
canCreate: canCreate,
propertyMap: make(map[string]*_property),
}
}
func (self *_propertyStash) CanRead(name string) bool {
_, exists := self.propertyMap[name]
return exists
}
func (self *_propertyStash) Read(name string) Value {
property := self.propertyMap[name]
if property == nil {
return UndefinedValue()
}
switch value := property.Value.(type) {
case Value:
return value
case _propertyGetSet:
if value[0] == nil {
return UndefinedValue()
}
return value[0].CallGet(name)
}
panic(hereBeDragons())
}
func (self *_propertyStash) CanWrite(name string) bool {
property, _ := self.propertyMap[name]
if property == nil {
return self.canCreate
}
switch propertyValue := property.Value.(type) {
case Value:
return property.CanWrite()
case _propertyGetSet:
return propertyValue[1] != nil
}
panic(hereBeDragons())
}
func (self *_propertyStash) Write(name string, value Value) {
property_, _ := self.propertyMap[name]
if property_ != nil {
switch propertyValue := property_.Value.(type) {
case Value:
if property_.CanWrite() {
property_.Value = value
}
case _propertyGetSet:
if propertyValue[1] != nil {
propertyValue[1].CallSet(name, value)
}
}
} else if self.canCreate {
self.propertyMap[name] = &_property{ value, propertyModeWriteEnumerateConfigure }
}
}
func (self *_propertyStash) property(name string) *_property {
property, _ := self.propertyMap[name]
return property
}
func (self *_propertyStash) Delete(name string) {
delete(self.propertyMap, name)
}
func (self *_propertyStash) Define(name string, define _defineProperty) bool {
canCreate := self.canCreate
property_, _ := self.propertyMap[name]
if property_ == nil {
if !canCreate {
return false
}
property_ = &_property{
Value: define.Value,
Mode: define.Mode(),
}
self.propertyMap[name] = property_
return true
}
if define.isEmpty() {
return true
}
// TODO Per 8.12.9.6 - We should shortcut here (returning true) if
// the current and new (define) properties are the same
canConfigure := property_.CanConfigure()
if !canConfigure {
if define.CanConfigure() {
return false
}
if define.Enumerate != propertyAttributeNotSet && define.CanEnumerate() != property_.CanEnumerate() {
return false
}
}
value, isDataDescriptor := property_.Value.(Value)
getSet, _ := property_.Value.(_propertyGetSet)
if define.IsGenericDescriptor() {
; // GenericDescriptor
} else if isDataDescriptor != define.IsDataDescriptor() {
var interface_ interface{}
if isDataDescriptor {
property_.Mode = property_.Mode & ^propertyModeWrite
property_.Value = interface_
} else {
property_.Mode |= propertyModeWrite
property_.Value = interface_
}
} else if isDataDescriptor && define.IsDataDescriptor() {
if !canConfigure {
if property_.CanWrite() != define.CanWrite() {
return false
} else if !sameValue(value, define.Value.(Value)) {
return false
}
}
} else {
if !canConfigure {
defineGetSet, _ := define.Value.(_propertyGetSet)
if getSet[0] != defineGetSet[0] || getSet[1] != defineGetSet[1] {
return false
}
}
}
define.CopyInto(property_)
return true
}
func (self *_propertyStash) Enumerate(each func(string)) {
for name, property_ := range self.propertyMap {
if property_.CanEnumerate() {
each(name)
}
}
}
func (self *_propertyStash) writeValuePropertyMap(valuePropertyMap map[string]_valueProperty) {
for name, _valueProperty := range valuePropertyMap {
self.propertyMap[name] = &_property{ Value: _valueProperty.Value, Mode: _valueProperty.Mode }
}
}