package otto // property type propertyMode int const ( modeWriteMask propertyMode = 0o700 modeEnumerateMask propertyMode = 0o070 modeConfigureMask propertyMode = 0o007 modeOnMask propertyMode = 0o111 modeSetMask propertyMode = 0o222 // If value is 2, then mode is neither "On" nor "Off" ) type propertyGetSet [2]*object var nilGetSetObject = object{} type property struct { value interface{} mode propertyMode } func (p property) writable() bool { return p.mode&modeWriteMask == modeWriteMask&modeOnMask } func (p *property) writeOn() { p.mode = (p.mode & ^modeWriteMask) | (modeWriteMask & modeOnMask) } func (p *property) writeOff() { p.mode &= ^modeWriteMask } func (p *property) writeClear() { p.mode = (p.mode & ^modeWriteMask) | (modeWriteMask & modeSetMask) } func (p property) writeSet() bool { return p.mode&modeWriteMask&modeSetMask == 0 } func (p property) enumerable() bool { return p.mode&modeEnumerateMask == modeEnumerateMask&modeOnMask } func (p *property) enumerateOn() { p.mode = (p.mode & ^modeEnumerateMask) | (modeEnumerateMask & modeOnMask) } func (p *property) enumerateOff() { p.mode &= ^modeEnumerateMask } func (p property) enumerateSet() bool { return p.mode&modeEnumerateMask&modeSetMask == 0 } func (p property) configurable() bool { return p.mode&modeConfigureMask == modeConfigureMask&modeOnMask } func (p *property) configureOn() { p.mode = (p.mode & ^modeConfigureMask) | (modeConfigureMask & modeOnMask) } func (p *property) configureOff() { p.mode &= ^modeConfigureMask } func (p property) configureSet() bool { //nolint: unused return p.mode&modeConfigureMask&modeSetMask == 0 } func (p property) copy() *property { //nolint: unused cpy := p return &cpy } func (p property) get(this *object) Value { switch value := p.value.(type) { case Value: return value case propertyGetSet: if value[0] != nil { return value[0].call(toValue(this), nil, false, nativeFrame) } } return Value{} } func (p property) isAccessorDescriptor() bool { setGet, test := p.value.(propertyGetSet) return test && (setGet[0] != nil || setGet[1] != nil) } func (p property) isDataDescriptor() bool { if p.writeSet() { // Either "On" or "Off" return true } value, valid := p.value.(Value) return valid && !value.isEmpty() } func (p property) isGenericDescriptor() bool { return !(p.isDataDescriptor() || p.isAccessorDescriptor()) } func (p property) isEmpty() bool { return p.mode == 0o222 && p.isGenericDescriptor() } // _enumerableValue, _enumerableTrue, _enumerableFalse? // .enumerableValue() .enumerableExists() func toPropertyDescriptor(rt *runtime, value Value) property { objectDescriptor := value.object() if objectDescriptor == nil { panic(rt.panicTypeError("toPropertyDescriptor on nil")) } var descriptor property descriptor.mode = modeSetMask // Initially nothing is set if objectDescriptor.hasProperty("enumerable") { if objectDescriptor.get("enumerable").bool() { descriptor.enumerateOn() } else { descriptor.enumerateOff() } } if objectDescriptor.hasProperty("configurable") { if objectDescriptor.get("configurable").bool() { descriptor.configureOn() } else { descriptor.configureOff() } } if objectDescriptor.hasProperty("writable") { if objectDescriptor.get("writable").bool() { descriptor.writeOn() } else { descriptor.writeOff() } } var getter, setter *object getterSetter := false if objectDescriptor.hasProperty("get") { value := objectDescriptor.get("get") if value.IsDefined() { if !value.isCallable() { panic(rt.panicTypeError("toPropertyDescriptor get not callable")) } getter = value.object() getterSetter = true } else { getter = &nilGetSetObject getterSetter = true } } if objectDescriptor.hasProperty("set") { value := objectDescriptor.get("set") if value.IsDefined() { if !value.isCallable() { panic(rt.panicTypeError("toPropertyDescriptor set not callable")) } setter = value.object() getterSetter = true } else { setter = &nilGetSetObject getterSetter = true } } if getterSetter { if descriptor.writeSet() { panic(rt.panicTypeError("toPropertyDescriptor descriptor writeSet")) } descriptor.value = propertyGetSet{getter, setter} } if objectDescriptor.hasProperty("value") { if getterSetter { panic(rt.panicTypeError("toPropertyDescriptor value getterSetter")) } descriptor.value = objectDescriptor.get("value") } return descriptor } func (rt *runtime) fromPropertyDescriptor(descriptor property) *object { obj := rt.newObject() if descriptor.isDataDescriptor() { obj.defineProperty("value", descriptor.value.(Value), 0o111, false) obj.defineProperty("writable", boolValue(descriptor.writable()), 0o111, false) } else if descriptor.isAccessorDescriptor() { getSet := descriptor.value.(propertyGetSet) get := Value{} if getSet[0] != nil { get = objectValue(getSet[0]) } set := Value{} if getSet[1] != nil { set = objectValue(getSet[1]) } obj.defineProperty("get", get, 0o111, false) obj.defineProperty("set", set, 0o111, false) } obj.defineProperty("enumerable", boolValue(descriptor.enumerable()), 0o111, false) obj.defineProperty("configurable", boolValue(descriptor.configurable()), 0o111, false) return obj }