forked from golang/hotime
220 lines
5.2 KiB
Go
220 lines
5.2 KiB
Go
package otto
|
|
|
|
// property
|
|
|
|
type _propertyMode int
|
|
|
|
const (
|
|
modeWriteMask _propertyMode = 0700
|
|
modeEnumerateMask = 0070
|
|
modeConfigureMask = 0007
|
|
modeOnMask = 0111
|
|
modeSetMask = 0222 // If value is 2, then mode is neither "On" nor "Off"
|
|
)
|
|
|
|
type _propertyGetSet [2]*_object
|
|
|
|
var _nilGetSetObject _object = _object{}
|
|
|
|
type _property struct {
|
|
value interface{}
|
|
mode _propertyMode
|
|
}
|
|
|
|
func (self _property) writable() bool {
|
|
return self.mode&modeWriteMask == modeWriteMask&modeOnMask
|
|
}
|
|
|
|
func (self *_property) writeOn() {
|
|
self.mode = (self.mode & ^modeWriteMask) | (modeWriteMask & modeOnMask)
|
|
}
|
|
|
|
func (self *_property) writeOff() {
|
|
self.mode &= ^modeWriteMask
|
|
}
|
|
|
|
func (self *_property) writeClear() {
|
|
self.mode = (self.mode & ^modeWriteMask) | (modeWriteMask & modeSetMask)
|
|
}
|
|
|
|
func (self _property) writeSet() bool {
|
|
return 0 == self.mode&modeWriteMask&modeSetMask
|
|
}
|
|
|
|
func (self _property) enumerable() bool {
|
|
return self.mode&modeEnumerateMask == modeEnumerateMask&modeOnMask
|
|
}
|
|
|
|
func (self *_property) enumerateOn() {
|
|
self.mode = (self.mode & ^modeEnumerateMask) | (modeEnumerateMask & modeOnMask)
|
|
}
|
|
|
|
func (self *_property) enumerateOff() {
|
|
self.mode &= ^modeEnumerateMask
|
|
}
|
|
|
|
func (self _property) enumerateSet() bool {
|
|
return 0 == self.mode&modeEnumerateMask&modeSetMask
|
|
}
|
|
|
|
func (self _property) configurable() bool {
|
|
return self.mode&modeConfigureMask == modeConfigureMask&modeOnMask
|
|
}
|
|
|
|
func (self *_property) configureOn() {
|
|
self.mode = (self.mode & ^modeConfigureMask) | (modeConfigureMask & modeOnMask)
|
|
}
|
|
|
|
func (self *_property) configureOff() {
|
|
self.mode &= ^modeConfigureMask
|
|
}
|
|
|
|
func (self _property) configureSet() bool {
|
|
return 0 == self.mode&modeConfigureMask&modeSetMask
|
|
}
|
|
|
|
func (self _property) copy() *_property {
|
|
property := self
|
|
return &property
|
|
}
|
|
|
|
func (self _property) get(this *_object) Value {
|
|
switch value := self.value.(type) {
|
|
case Value:
|
|
return value
|
|
case _propertyGetSet:
|
|
if value[0] != nil {
|
|
return value[0].call(toValue(this), nil, false, nativeFrame)
|
|
}
|
|
}
|
|
return Value{}
|
|
}
|
|
|
|
func (self _property) isAccessorDescriptor() bool {
|
|
setGet, test := self.value.(_propertyGetSet)
|
|
return test && (setGet[0] != nil || setGet[1] != nil)
|
|
}
|
|
|
|
func (self _property) isDataDescriptor() bool {
|
|
if self.writeSet() { // Either "On" or "Off"
|
|
return true
|
|
}
|
|
value, valid := self.value.(Value)
|
|
return valid && !value.isEmpty()
|
|
}
|
|
|
|
func (self _property) isGenericDescriptor() bool {
|
|
return !(self.isDataDescriptor() || self.isAccessorDescriptor())
|
|
}
|
|
|
|
func (self _property) isEmpty() bool {
|
|
return self.mode == 0222 && self.isGenericDescriptor()
|
|
}
|
|
|
|
// _enumerableValue, _enumerableTrue, _enumerableFalse?
|
|
// .enumerableValue() .enumerableExists()
|
|
|
|
func toPropertyDescriptor(rt *_runtime, value Value) (descriptor _property) {
|
|
objectDescriptor := value._object()
|
|
if objectDescriptor == nil {
|
|
panic(rt.panicTypeError())
|
|
}
|
|
|
|
{
|
|
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())
|
|
}
|
|
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())
|
|
}
|
|
setter = value._object()
|
|
getterSetter = true
|
|
} else {
|
|
setter = &_nilGetSetObject
|
|
getterSetter = true
|
|
}
|
|
}
|
|
|
|
if getterSetter {
|
|
if descriptor.writeSet() {
|
|
panic(rt.panicTypeError())
|
|
}
|
|
descriptor.value = _propertyGetSet{getter, setter}
|
|
}
|
|
|
|
if objectDescriptor.hasProperty("value") {
|
|
if getterSetter {
|
|
panic(rt.panicTypeError())
|
|
}
|
|
descriptor.value = objectDescriptor.get("value")
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (self *_runtime) fromPropertyDescriptor(descriptor _property) *_object {
|
|
object := self.newObject()
|
|
if descriptor.isDataDescriptor() {
|
|
object.defineProperty("value", descriptor.value.(Value), 0111, false)
|
|
object.defineProperty("writable", toValue_bool(descriptor.writable()), 0111, false)
|
|
} else if descriptor.isAccessorDescriptor() {
|
|
getSet := descriptor.value.(_propertyGetSet)
|
|
get := Value{}
|
|
if getSet[0] != nil {
|
|
get = toValue_object(getSet[0])
|
|
}
|
|
set := Value{}
|
|
if getSet[1] != nil {
|
|
set = toValue_object(getSet[1])
|
|
}
|
|
object.defineProperty("get", get, 0111, false)
|
|
object.defineProperty("set", set, 0111, false)
|
|
}
|
|
object.defineProperty("enumerable", toValue_bool(descriptor.enumerable()), 0111, false)
|
|
object.defineProperty("configurable", toValue_bool(descriptor.configurable()), 0111, false)
|
|
return object
|
|
}
|